Search code examples
pythonwebsocketgeventgreenlets

Why cant I use gevent websockets inside a greenlet


I'm trying to receive websocket messages in a greenlet, but it doent seem to be working. I have this code:

import gevent
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from geventwebsocket import WebSocketServer, WebSocketApplication, Resource



def recvWs(ws):
    gevent.sleep(0)
    recvedData = ws.receive()
    rData = json.loads(recvedData)
    print(rData)

def app(environ, start_response):


    websocket = environ['wsgi.websocket']

    while True:
        gevent.spawn(recvWs,websocket)
        gevent.sleep(0)

if __name__ == '__main__':
    server = WSGIServer(("0.0.0.0", 80), app,handler_class=WebSocketHandler)
    server.serve_forever()

And when running, it returns this error:

<Greenlet "Greenlet-0" at 0x23fa4306148: 
recvWs(<geventwebsocket.websocket.WebSocket object at 0x0)> failed with 
RuntimeError

As well as:

line 197, in read_frame
header = Header.decode_header(self.stream)

How do I fix this?


Solution

  • Here is an example of what I have done that works very well.
    Python with bottle and gevent:

    from gevent import sleep as gsleep, Timeout
    from geventwebsocket import WebSocketError
    from bottle import Bottle, get, post, route, request, response, template, redirect, abort
    
    @route('/ws/app')
    def handle_websocket():
        wsock = request.environ.get('wsgi.websocket')
        if not wsock:
            abort(400, 'Expected WebSocket request.')
        # Send initial data here
        wsock.send(json.dumps(data))
        while 1:
            try:
                #Process incoming message.  2 second timeout to not block
                message = {}
                with Timeout(2, False) as timeout:
                    message = wsock.receive()
                if message:
                    message = json.loads(message)
                    if isinstance(message, dict):
                         # Do something with data and return
                         wsock.send(json.dumps(result))
                # Add an additional second just for sanity.  Not necessarily needed
                gsleep(1)
            except WebSocketError:
                break
            except Exception as exc:
                traceback.print_exc()
                gsleep(2)
    

    Then in your javascript you open a websocket connection and send and recieve the data as you would normally.