'gevent-socketio with Python bottle

I'm trying to put together a Python bottle application that uses gevent-socketio and am having trouble. I'm using the following versions of software:

Python: 2.7.5
socketio: 0.3.5
socket.io.js: 1.3.5

In my main code I'm running the app this way:

SocketIOServer(("0.0.0.0", port), application, resource="socket.io", transports=["websocket"]).serve_forever()

And this is what part of my server handler looks like:

class PingPongNamespace(BaseNamespace):
    '''This class defines the websocket handler for
    the press controller status system
    '''
    def __init__(self):
        v = 1
        
    def on_ping(self, msg):
        self.emit("pong")
        
        
from socketio import socketio_manage

@app.route(mount("/socket.io/1/<path:path>"))
def pingpong(path):
    socketio_manage(request.environ, {"/pingpong": PingPongNamespace}, request)

My JavaScript looks like this:

$(document).ready(function() {
    "use strict"; 

    localStorage.debug = "*";    
    
    var socket = io.connect("http://" + window.location.host + "/pingpong");
    
    socket.on("connect", function(data) {
        console.log("join");
    });
    
    socket.on("pong", function(data) {
        console.log("pong: " + data);
    });
    
    setInterval(function() {
        console.log("ping");
        socket.emit("ping");
    }, 10 * 1000);
});

The server runs, but I never get a connection from the client to the server, I keep seeing

KeyError: "socketio"

because "socketio" isn't defined in the server environ variable. I've looked around on Google, but so far nothing I've tried has helped.



Solution 1:[1]

Here is an example of what has worked extremely well for me. You really should use the websocket library built in gevent, this simplifies the entire connection handling. Obviously you would need to import your own API route if you want to use this...

from gevent import monkey
monkey.patch_all()
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
import bottle

#websocket
@route('/ws/api')
def handle_websocket():
    ws = request.environ.get('wsgi.websocket')
    if not ws:
        abort(400, 'Expected WebSocket request.')
    while 1:
        message = None
        try:
            with Timeout(2, False) as timeout: #keeps the websocket cycling so you can refresh data without waiting forever for input. 
                message = ws.receive()
            if message:
                message = json.dictcheck(message)
                # print(message)
                for command, payload in message.items():
                    wapi = a.API(payload) # call your api here
                    func = getattr(wapi, command, None)
                    if callable(func):
                        try:
                            x = func()
                            ws.send(json.jsoncheck({command:x}))
                        except Exception as exc:
                            traceback.print_exc()
                            ws.send(json.jsoncheck({'status': 'Error'}))
        except WebSocketError:
            break
        except Exception as exc:
            traceback.print_exc()
            sleep(1)
if __name__ == '__main__':
    botapp = bottle.app()
    server = WSGIServer(("0.0.0.0", 80), botapp , handler_class=WebSocketHandler)
    server.serve_forever()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1