Combining websockets and WSGI in a python app
Asked Answered
P

2

17

I'm working on a scientific experiment where about two dozen test persons play a turn-based game with/against each other. Right now, it's a Python web app with a WSGI interface. I'd like to augment the usability with websockets: When all players have finished their turns, I'd like to notify all clients to update their status. Right now, everyone has to either wait for the turn timeout, or continually reload and wait for the "turn is still in progress" error message not to appear again (busy waiting, effectively).

I read through multiple websocket libraries' documentation and I understand how websockets work, but I'm not sure about the architecture for mixing WSGI and websockets: Can I have a websockets and a WSGI server in the same process (and if so, how, using really any websockets library) and just call my_websocket.send_message() from a WSGI handler, or should I have a separate websockets server and do some IPC? Or should I not mix them at all?

edit, 6 months later: I ended up starting a separate websockets server process (using Autobahn), instead of integrating it with the WSGI server. The reason was that it's much easier and cleaner to separate the two of them, and talking to the websockets server from the WSGI process (server to server communication) was straight forward and worked on the first attempt using websocket-client.

Plumate answered 30/10, 2012 at 10:52 Comment(3)
Which python web framework are you using, if you're using one?Solita
None right now, but I'm open to any suggestion.Plumate
well in that case I second oberstet's suggestion to use flask.Solita
D
16

Here is an example that does what you want:

It runs a WSGI web app (Flask-based in this case, but can be anything WSGI conforming) plus a WebSocket server under 1 server and 1 port.

You can send WS messages from within Web handlers. Autobahn also provides PubSub on top of WebSocket, which greatly simplifies the sending of notifications (via WampServerProtocol.dispatch) like in your case.

Disclosure: I am author of Autobahn and work for Tavendo.

Desegregate answered 30/10, 2012 at 11:49 Comment(4)
Awesome, that's exactly what I was looking for! Also, I didn't know about protocols on top of Websockets yet.Plumate
For a quick intro to WAMP (=RPC+PubSub over WebSocket), check out wamp.wsDesegregate
I deployed as an Azure app service and get this error message: (index):20 Mixed Content: The page at 'MYAPP.azurewebsites.net' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://MYAPP.azurewebsites.net:8080/ws'. This request has been blocked; this endpoint must be available over WSS. window.onload @ (index):20 (index):20 Uncaught DOMException: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS. at window.onload (MYAPP.azurewebsites.net/:20:23)Bezel
it is explicitly disallowed by the websocket spec (rfc6455) for a web browser acting as a websocket client to have the HTML page with the JS opening the websocket connection to have been loaded over HTTPS (that is secure) in non-secure mode (WS rather than WSS). solution: either host your HTML/JS etc on a HTTP endpoint OR connected over WSS to your websocket servverDesegregate
K
2

but I'm not sure about the architecture for mixing WSGI and websockets

I made it

use WSocket

Simple WSGI HTTP + Websocket Server, Framework, Middleware And App.

Includes

  • Server(WSGI) included - works with any WSGI framework
  • Middleware - adds Websocket support for any WSGI framework
  • Framework - simple Websocket WSGI web application framework
  • App - Event based app for Websocket communication When external server used, some clients like Firefox requires http 1.1 Server. for Middleware, Framework, App
  • Handler - adds Websocket support to wsgiref(python builtin WSGI server)
  • Client -Coming soon...

Common Features

  • only single file less than 1000 lines
  • websocket sub protocol supported
  • websocket message compression supported (works if client asks)
  • receive and send pong and ping messages(with automatic pong sender)
  • receive and send binary or text messages
  • works for messages with or without mask
  • closing messages supported
  • auto and manual close

example using bottle web framework and WSocket middleware

from bottle import request, Bottle
from wsocket import WSocketApp, WebSocketError, logger, run
from time import sleep

logger.setLevel(10)  # for debugging

bottle = Bottle()
app = WSocketApp(bottle)
# app = WSocketApp(bottle, "WAMP")

@bottle.route("/")
def handle_websocket():
    wsock = request.environ.get("wsgi.websocket")
    if not wsock:
        return "Hello World!"

    while True:
        try:
            message = wsock.receive()
            if message != None:
                print("participator : " + message)
                
            wsock.send("you : "+message)
            sleep(2)
            wsock.send("you : "+message)
            
        except WebSocketError:
            break
            
run(app)
Klaipeda answered 20/11, 2020 at 17:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.