Reputation: 75
Is it possible to run (mount in cherrypy tree) autobahnn's websocket class to run on same port but different URL?
For example:
This is my autobahn configuration & run:
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
factory = WebSocketServerFactory("ws://0.0.0.0:8081", debug = False)
factory.protocol = WSA.SocketClient
coro = self.loop.create_server(factory, "0.0.0.0", 8081)
server = self.loop.run_until_complete(coro)
self.loop.run_forever()
This is my cherrypy configuration & run:
cherrypy.config.update({
'server.socket_host' : '0.0.0.0',
'server.socket_port' : 80,
})
cherrypy.tree.mount(WebApi.Web(), '/web', {
'/': {
"tools.staticdir.on": True,
"tools.staticdir.root": os.path.dirname(os.path.abspath(__file__)),
"tools.staticdir.dir": "Web",
"tools.staticdir.index": "index.html"
}
})
cherrypy.engine.start()
At this point, WebSocket server runs on port 8081, but I would like to run it on same port as web (8080). If it is possible..
Upvotes: 1
Views: 779
Reputation: 25263
Answering your question literally, is to say you can't do it with CherryPy and Autobahn. CherryPy's normal request handling is synchronous and moreover it is a threaded-server. In other words it's not feasible to dedicate a thread to a WebSocket connection. CherryPy's ability to mount separate WSGI app makes no sense here, because WSGI is inherently a synchronous protocol. And WebSockets are inherently asynchronous. But that doesn't make you can't do it in little different way.
Luckily, because of smart design of CherryPy it isn't limited to WSGI and allows extension. This fact is employed in nice library by CherryPy contributor Sylvain Hellegouarch, ws4py. It has CherryPy integration.
#!/usr/bin/env python3
import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import WebSocket
class Ws:
@cherrypy.expose
def a(self):
'''WebSocket upgrade method.
Method must exist for ``WebSocketTool`` to work, 404 returned otherwise.
'''
@cherrypy.expose
def b(self):
pass
class HandlerA(WebSocket):
def received_message(self, message):
self.send('"A" is my reply')
class HandlerB(WebSocket):
def received_message(self, message):
self.send('"B" is my reply')
class App:
@cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<body>
<table cellspacing='10'>
<tr>
<td id='a'></td>
<td id='b'></td>
</tr>
</table>
<script type='application/javascript'>
var wsA = new WebSocket('ws://127.0.0.1:8080/websocket/a');
wsA.onmessage = function(event)
{
document.getElementById('a').innerHTML += event.data + '<br/>';
};
var wsB = new WebSocket('ws://127.0.0.1:8080/websocket/b');
wsB.onmessage = function(event)
{
document.getElementById('b').innerHTML += event.data + '<br/>';
};
setInterval(function()
{
wsA.send('foo');
wsB.send('bar');
}, 1000);
</script>
</body>
</html>
'''
if __name__ == '__main__':
cherrypy.config.update({
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
})
cherrypy.tools.websocket = WebSocketTool()
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tree.mount(Ws(), '/websocket', {
'/a' : {
'tools.websocket.on' : True,
'tools.websocket.handler_cls' : HandlerA
},
'/b' : {
'tools.websocket.on' : True,
'tools.websocket.handler_cls' : HandlerB
}
})
cherrypy.tree.mount(App(), '/')
cherrypy.engine.signals.subscribe()
cherrypy.engine.start()
cherrypy.engine.block()
Since 1.3 nginx supports WebSockets. So you can easily multiplex different backends.
server {
listen 80;
server_name localhost;
location /web {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /websocket {
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Upvotes: 2
Reputation: 300
Try using cherrypy.tree.graft
to mount WSA on a different endpoint (called "script_name" in the cherrypy docs).
See the example here of mounting WSGI apps on a different endpoint as the static files: http://rhodesmill.org/brandon/2011/wsgi-under-cherrypy/
More docs here: http://cherrypy.readthedocs.org/en/latest/advanced.html#host-a-foreign-wsgi-application-in-cherrypy
Upvotes: 0