is it possible to host a normal Bottle application and a WebSocket one (example: https://github.com/defnull/bottle/blob/master/docs/async.rst) in the same application (same port)? So that /ws will go to WebSocket handler and all other will be normally routed to other bottle handlers.
Asked
Active
Viewed 8,983 times
2 Answers
22
It sure is.
The server:
#!/usr/bin/python
import json
from bottle import route, run, request, abort, Bottle ,static_file
from pymongo import Connection
from gevent import monkey; monkey.patch_all()
from time import sleep
app = Bottle()
@app.route('/websocket')
def handle_websocket():
wsock = request.environ.get('wsgi.websocket')
if not wsock:
abort(400, 'Expected WebSocket request.')
while True:
try:
message = wsock.receive()
wsock.send("Your message was: %r" % message)
sleep(3)
wsock.send("Your message was: %r" % message)
except WebSocketError:
break
@app.route('/<filename:path>')
def send_html(filename):
return static_file(filename, root='./static', mimetype='text/html')
from gevent.pywsgi import WSGIServer
from geventwebsocket import WebSocketHandler, WebSocketError
host = "127.0.0.1"
port = 8080
server = WSGIServer((host, port), app,
handler_class=WebSocketHandler)
print "access @ http://%s:%s/websocket.html" % (host,port)
server.serve_forever()
The html page that holds the javascript:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
var ws = new WebSocket("ws://localhost:8080/websocket");
ws.onopen = function() {
ws.send("Hello, world");
};
ws.onmessage = function (evt) {
alert(evt.data);
};
</script>
</head>
<body>
</body>
</html>
A client:
#!/usr/bin/python
from websocket import create_connection
ws = create_connection("ws://localhost:8080/websocket")
print "Sending 'Hello, World'..."
ws.send("Hello, World")
print "Sent"
print "Reeiving..."
result = ws.recv()
print "Received '%s'" % result
ws.close()
![](../../users/profiles/457269.webp)
Bryan Hunt
- 3,265
- 2
- 22
- 34
-
1Often bottle applications are started like this: run(server='gevent', host='localhost', port=8192, debug=True, reloader=True) where now would those parameters go? – Spacen Jasset Aug 20 '15 at 09:50
-
@spacen-jasset run also takes it as a param. like: `bottle.run(app=config.application, host='0.0.0.0', port=3001, reloader=True, server='gevent', handler_class=WebSocketHandler)` – keredson Jun 16 '16 at 18:02
-
1I tried to to add the above to an existing bottle application, ensured I had all the imports, the `/websocket` route, and all Python code below `from gevent.pywsgi import WSGIServer`. Javascript code used is as shown. I have pip installed `gevent` and `gevent-websocket` in `virtualenv` and I get error: `from geventwebsocket import WebSocketHandler, WebSocketError [Tue Aug 23 14:20:10.425900 2016] [wsgi:error] [pid 7245:tid 139987894220544] [client 127.0.0.1:58218] ImportError: cannot import name WebSocketHandler` – user1063287 Aug 23 '16 at 04:25
-
1@user1063287 use `from geventwebsocket import WebSocketError from geventwebsocket.handler import WebSocketHandler` Even with no errors, the answer fails to route to '/' or any other non websocket paths. – azmath May 18 '17 at 05:02
5
This most likely isn't the easiest answer but I just got done setting up a test environment that works using Nginx and uWSGI over Pyramid and once you've got it setup you can extend it very very easily, for instance if your /ws is pulling too many resources, it's trivial with Nginx+uWSGI to relocate /ws to different hardware. My background is Pyramid and my uWSGI experience has only been with testing but in my reading it seems a solution that should work well. The bottle instructions were the result of a quick google search.
The Concept:
The concept is to take your app, ie your app = make_wsgi_app.from_config(config) before the app.serve_forever() call and instead use uwsgi to 'serve' your app to a socket app1.sock. There are many ways to configure uWSGI. The uWSGI site has documentation for more ways to configure uWSGI to talk to your app. Nginx comes with configuration to use uWSGI sockets natively at least in the current version. You just pass the uwsgi_pass unix:///tmp/app1.sock; path to the sites configuration along with the params. Do this twice in the same site conf file, once for location / { and once for location /ws { pointing to their respective app sock files and you should be good to go.The concept of serving an app to a socket as file was new to me when I was setting up the testing environment, I hope this helps.
What to get:
nginxuWSGI