miguelgrinberg / Flask-SocketIO-Chat

A simple chat application that demonstrates how to structure a Flask-SocketIO application.
http://blog.miguelgrinberg.com/post/easy-websockets-with-flask-and-gevent
MIT License
673 stars 239 forks source link

Best way to embed Flask-SocketIO-Chat into another app? #1

Closed scheung38 closed 5 years ago

scheung38 commented 8 years ago

Say we have another standalone running Flask app, how to embed and launch Flask-SocketIO-Chat when one of its navigational tabs is clicked:

@app.route(/chat):
def chat():
    return render_template(launch Flask-SocketIO-Chat here)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, debug=True)

Since Flask-SocketIO-Chat is already launched from within chat.py?

miguelgrinberg commented 8 years ago

You can choose to merge the chat functionality into your application, or keep it separate.

If you merge it, then you will have a chat route that serves the chat template that contains the client-side javascript for the page.

If you keep it separate, you need to run the application and the chat separately (on separate ports), and the application will have to be configured to know what URL to use to embed the chat.

scheung38 commented 8 years ago

Thanks, is it a lot of work for both options? Or better and easier to maintain separate apps and do a lot of importing? Not sure where to start in terms of the configuration needed.

miguelgrinberg commented 8 years ago

I would combine everything in a single application. Just put the chat portion under a /chat route, so that it does not collide with the application routes.

scheung38 commented 8 years ago

Alternatively merging your Flask-SocketIO-Chat as one of the tabs in your microblog? So after login and authenticated, 'Chat' will be next to the Logout or other available tabs.

scheung38 commented 8 years ago
  1. Refactored package names in Flask-SocketIO-Chat to chat-app
  2. Refactored package names in microblog to main-app before copying all folders from Flask-SocketIO-Chat into microblog to avoid package name clashes.
  3. Then changed run.py in microblog:
from gevent import monkey
monkey.patch_all()
from app_main import create_app, socketio

app = create_app(True)
# app.run(debug=True)
if __name__ == '__main__':
    socketio.run(app)

and now the microblog/app_main/ __init__.py:

def create_app(debug=False):
    global app, db, lm, oid, mail, babel
    app = Flask(__name__)
    app.config.from_object('config')
    db = SQLAlchemy(app)
    lm = LoginManager()
    lm.init_app(app)
    lm.login_view = 'login'
    lm.login_message = lazy_gettext('Please log in to access this page.')
    oid = OpenID(app, os.path.join(basedir, 'tmp'))
    mail = Mail(app)
    babel = Babel(app)

    app.debug = debug
    app.config['SECRET_KEY'] = 'gjr39dkjn344_!67#'
    from app_chat.main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    socketio.init_app(app)
    return app

But app is still not global? Because I get:

app.json_encoder = CustomJSONEncoder
NameError: global name 'app' is not defined

Could this be related this this question: http://stackoverflow.com/questions/21028254/nameerror-name-app-is-not-defined-with-flask

miguelgrinberg commented 8 years ago

I don't see where you have the reference to app.json_encoder, so I can't really tell you what the problem is.

Also the global app is suspicious. If you are using the app factory pattern then you do not need to make app a global variable.

scheung38 commented 8 years ago

In microblog(app - > app_main)-> __init__.py, but does defining global app inside create_app already makes it global?

def create_app(debug=False):
    global app, db, lm, oid, mail, babel
    app = Flask(__name__)
    app.config.from_object('config')
    db = SQLAlchemy(app)
    lm = LoginManager()
    lm.init_app(app)
    lm.login_view = 'login'
    lm.login_message = lazy_gettext('Please log in to access this page.')
    oid = OpenID(app, os.path.join(basedir, 'tmp'))
    mail = Mail(app)
    babel = Babel(app)

    app.debug = debug
    app.config['SECRET_KEY'] = 'gjr39dkjn344_!67#'
    from app_chat.main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    socketio.init_app(app)
    return app

class CustomJSONEncoder(JSONEncoder):
    """This class adds support for lazy translation texts to Flask's
    JSON encoder. This is necessary when flashing translated texts."""
    def default(self, obj):
        from speaklater import is_lazy_string
        if is_lazy_string(obj):
            try:
                return unicode(obj)  # python 2
            except NameError:
                return str(obj)  # python 3
        return super(CustomJSONEncoder, self).default(obj)

app.json_encoder = CustomJSONEncoder
miguelgrinberg commented 8 years ago

Yeah, okay. You can't access app in the global scope if you are working with an app factory function. That needs to go in the factory function.

scheung38 commented 8 years ago

Sorry the factory function is located in?

miguelgrinberg commented 8 years ago

Doesn't matter where you put the factory function. It can go in the __init__.py file, or in a different module inside the application package.

It seems to me you are trying to convert microblog to use an app factory function, but you did not go all the way with the conversion. Any references to app as a global variable need to go, there is no app global when you structure your application in this form.

scheung38 commented 8 years ago

Sorry, I meant how do you make a factory function as opposed to the file location.

miguelgrinberg commented 8 years ago

This repository has a factory function in this file, that should be a good example.

If you want to see one a bit more complex, the one in my Flasky repository is a good one to study.

scheung38 commented 8 years ago

Thanks I thought it was blueprint related.

alexwaters commented 8 years ago

I'm also looking to implement this under a larger web application. Any recommendations for storing a history of the messages?

miguelgrinberg commented 8 years ago

@alexwaters It depends on your needs. Storing them in memory, a file or a database should all work.

KunleMichaels commented 6 years ago

hello Miguelgrinberg

KunleMichaels commented 6 years ago

How can i work with Flask socketio blueprints to pull data from Ibm watson

miguelgrinberg commented 6 years ago

@KunleMichaels not sure what you are asking. What do you mean by "flask socketio blueprints"? Presumably Watson has some API mechanism for clients to get data? I don't see what Flask-SocketIO has to do with it.

KunleMichaels commented 6 years ago

Thanks for the reply Miguel, I'm not so good with the terms but I will try to be as clear as possible

KunleMichaels commented 6 years ago

I'm building a bot that carries out financial services based on requests from users I'm working with IBM dashdb, how can I use a flask framework without sqlalchemy and sqlite. Since IBM dashdb doesn't support sqlalchemy

miguelgrinberg commented 6 years ago

Flask does not require sqlalchemy, you can use any database that you like. For dashdb, you can use https://pypi.python.org/pypi/ibmdbpy.

KunleMichaels commented 6 years ago

Thanks a whole lot @miguelgrinberg

miguelgrinberg commented 5 years ago

This issue will be automatically closed due to being inactive for more than six months. Seeing that I haven't responded to your last comment, it is quite possible that I have dropped the ball on this issue and I apologize about that. If that is the case, do not take the closing of the issue personally as it is an automated process doing it, just reopen it and I'll get back to you.