0

I've got a setup where I want to run multiple WSGI apps on one server and use a Flask-SocketIO socketio-server for communication in one of those apps.

I've got my WSGI-apps served via gunicorn with eventlet, as is suggested by the Flask-SocketIO manual with the following command:

gunicorn --worker-class eventlet -w 1 myapp:application

This serves the apps all-right, the internal code for setup looks like this (__init__.py):

from flask import Flask
from werkzeug.wsgi import DispatcherMiddleware
from Pyro4.utils.httpgateway import pyro_app as gateway

from myapp.extensions import socketio
from myapp.views.vue_js import vue
from config import PYRO_REGEX


def configure_blueprints(app):
    app.register_blueprint(vue)


def register_extensions(app):
    socketio.init_app(app)



app = Flask(__name__, instance_relative_config=True, template_folder='static', static_url_path='')
app.config.from_object('config')

configure_blueprints(app)
register_extensions(app)

# Set up WSGI application middleware to serve both the pyro httpgateway and this application
# through the same server
application = DispatcherMiddleware(gateway, {
        '/app': app
})

This works as it should, but my application now has no websocket connection anymore. How can I make Flask-SocketIO work in this configuration?

The problem is that the javascript connection to the socketio server is getting a 404 error when trying to connect to /socketio.

Do I need to hand the Javascript side the subdomain of my app? How would a connection string have to look if that's the case? Right now my connection string looks like this: 'http://' + document.domain + ':' + location.port + '/' on the Javascript side

PS: The reason I'm doing this is that I need to serve the Pyro4 gateway from the same domain as the rest of the application, since otherwise the browser applies same-origin-policy restrictions to my REST calls to pyro4. So if this is too convoluted, and an easier way exists to get to my end-goal, I'm also open for that.

random_error
  • 365
  • 4
  • 16

3 Answers3

1

I did some experiment with DispatchMiddleware where one of the mounts is a Flask app utilising socket.io

self.app.wsgi_app = DispatcherMiddleware(self.app.wsgi_app,{'/aaa/bbb':sockioapp,
 '/ccc/ddd':normalapp})

Here, sockioapp is a Flask object with SocketIO enabled, normalapp is not.

So the url for sockioapp will be http://localhost:3000/aaa/bbb, while the socket.io endpoint is /socket.io, and it couldn't make the connection (as expected) - I want to change the endpoint to /aaa/bbb/socket.io

For this, I added the path to Socket.IO client.

socket = io.connect({transports: ["websocket"], path:"/aaa/bbb/socket.io" });

Now the SocketIO server. I wasn't sure if I had to do this or not. I was hoping DispatcherMiddleware will magically add the /aaa/bbb path to /socket.io, and it appeared to be the case. So the server stays put, no need to add path.

socketio = SocketIO(socketioapp, host="0.0.0.0")

This was enough. Everything on the server side is handled magically, and no need to change the dispatcher middleware.

If you have more than one apps utilising socket.io, I think it is a good idea to have separate namespaces.

sungeunbae
  • 88
  • 5
  • 1
    Hey @sungeunbae , I've not used this in a while now, so I can't check if your answer is actually working, but I still give you the answer mark, since it looks good, and is probably more helpful than what I've done :) – random_error Jul 14 '19 at 16:15
0

The Socket.IO endpoint is, by default /socket.io. Since the first entry point of your app is the DispatcherMiddleware, that does not map to the application.

I have not tried this, but maybe if you add a duplicate entry for your app on the dispatcher middleware under the /socket.io prefix, then the Socket.IO requests will be routed to the right place.

Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
0

I kind of fixed my problem, but sadly it's not a real fix but more of a workaround.

The reason why I had my application not on the default route was that the other wsgi-app (the pyro httpgateway) is doing some redirects itself, which led to endless redirects when I tried putting it on the /pyro route.

I've now modified that part of the code, and put the pyro application on the above mentioned route, while keeping my application on the main path /.

This allows for SocketIO to work for my main application, although as said above is more of a workaround than a complete fix.

random_error
  • 365
  • 4
  • 16