Option 2. Create a new Flask app.

$ mkdir python-websockets-chat
$ cd python-websockets-chat

Functionality

The sample application is a simple chat application that will open a WebSocket to the backend. Any time a chat message is sent from the browser, it’s sent to the server and then broadcasted to each connecting client and displayed on the page.

There are a few key pieces to this whole thing. We’re using Flask-Sockets that provides the standard WebSockets API. This allows us to build a simple Flask application that also responds to WebSocket requests. JavaScript on the browser opens a WebSocket connection to the server and responds to a WebSocket message being received from the server to display the chat message. Let’s take a look at both the backend and frontend in more detail.

This class allows us to subscribe once (per process) to incoming messages
from Redis in the background, while updating each connected WebSocket client
asyncronously:

chats = ChatBackend()
chats.start()

Next, let’s setup a standard URL endpoint:

@app.route('/')
defhello():
return render_template('index.html')

Endpoints

With Flask-Sockets, we can create WebSocket endpoints, much like standard ones.
In this case, we’ll have one endpoint for sending and one for receiving messages.

Flask-Sockets will automatically upgrade incoming requests to /submit
and /receive to WebSocket connections. The first parameter to these functions
(e.g. ws) is the raw websocket connection. Because we’re using Gevent, each
process can have thousands of concurrent connections.

Our first endpoint is /submit. This WebSocket endpoint will be used for
submitting new messages to the chat service. Incoming messages are received via
ws.receive() as standard Python strings. We’ll take those messages and insert
them into our Redis subscription channel, so all connected servers can receive
updates.

Our second endpoint is /receive. This WebSocket endpoint will be used for
receiving new messages from our Redis subscription channel, and sending them to
the connected client. Because we only want one Redis connection per process,
we’ll send our WebSocket instance to the ChatBackend discussed earlier. It’ll
handle things from there, but we need to keep the socket open so it can receive
updates. To do this, we’ll just run gevent.sleep() perpetually, to trigger a
Gevent context switch.

The index page uses Bootstrap for CSS and
jQuery JavaScript help. We’re storing all of our
static assets in the static folder. Flask by default will serve
static files in public/. We’ll need to get these files.

Now back to WebSockets. Let’s write the static/js/application.js that gets
loaded by the main page. First, let’s open our WebSocket connections to the server.
We’ll be using reconnecting-websocket,
which will automatically reconnect any disrupted connections in the browser.

With an open WebSocket, the browser will receive messages and we’ll define a function to handle this. The messages we’re using will be a JSON response with two keys: handle (user’s handle) and text (user’s message). When the message is received, it needs to be parsed by JSON and then inserted as a new entry in the page. We’ll spruce it up with a bit of jQuery animate.

The now that the page can receive messages from the server, we need a way to actually send messages. We’re going to override how the submit button works in our input form. We’ll be using event.preventDefault() to stop the form from actually sending a POST to the form. Instead, we want to grab the the values from the form and send them as a JSON message over the WebSocket to the server.

Next Steps

Now that you have deployed your app and understand the very basics we’ll want
to expand the app to be a bit more robust. This won’t encompass everything
you’d want to do before going public, but it will get you along the a path
where you’ll be thinking about the right things.

Using Redis locally, add to .env

To connect to Redis locally, add a .env file with your environment variables,
including REDISCLOUD_URL. You can easily copy all of Heroku’s variables to a
local .env file:

$ heroku config -s > .env

Foreman will automatically include these values when it is run.

Security

Remember, this is only a demo application and is likely vulnerable to various
attacks. Please refer to WebSockets Security
for more general guidelines on securing your WebSocket application.

WebSockets + TLS = wss://

The first easy thing we can do here is ensure that all of our production
traffic is going through the wss:// protocol to encrypt our traffic
similiar to https://. To do this, you can simply change the ws://
strings in to wss:// in application.js for secure requests.