WebSocketHandler is used for persistent connections and server-side push.
Here is a sample configuration:
url:
pingbot:
pattern: /pingbot
handler: WebSocketHandler
kwargs:
open: # When websocket is opened
function: pingbot.open # call open(handler) in pingbot.py
on_message: # When client sends a message
function: pingbot.on_message # call on_message(handler, msg) in pingbot.py
on_close: # When websocket is closed
function: pingbot.on_close # call on_close(handler) in pingbot.py
origins: # Optional: Allow only from these domains.
- gramener.com # If unspecified, all domains are allowed.
- localhost
- 127.0.0.1
# You can also add the auth: configuration like other handlers. For example:
# auth: true
open
, on_message
and on_close
are expressions or pipelines.
Here’s a sample definition from pingbot.py
:
def open(handler):
print('Chatbot opened for', handler.session['id'])
def on_message(handler, message):
print('Got message', message, 'for', handler.session['id'])
handler.write_message('Got message: ' + message)
def on_close(handler):
print('Chatbot closed for', handler.session['id'])
Now we can use WebSockets in JavaScript to open and interact with the websocket. Paste this in a browser’s JavaScript console. You should see the message returned by the server.
// Open the websocket
var url = location.href.replace(/^http/, "ws") + "pingbot";
var ws = new WebSocket(url);
// When we receive any message, log it to the console
ws.onmessage = console.log;
// Send a message to the server a second later.
setTimeout(function () {
ws.send("Hello world");
}, 1000);
// You may use ws.close() to close the socket. Sockets automatically close
// when the user closes the page, so this is not often used.
// ws.close()
This simple server messages.py
uses blinker to send a message to all connected clients,
creating a sort of chat room.
from blinker import signal
def open(handler):
signal('msg-queue').connect(handler.write_message)
def on_message(handler, message):
signal('msg-queue').send(message)
Using this gramex.yaml:
url:
websockethandler/messages:
pattern: /$YAMLURL/messages
handler: WebSocketHandler
kwargs:
open:
function: messages.open
on_message:
function: messages.on_message
… and this JavaScript in messages.html:
// Set up websockets. When we receive a message, add it to the screen
var url = location.href.replace(/^http/, "ws").replace(/\/[^/]*$/, "/messages");
var ws = new WebSocket(url);
var chats = document.querySelector("#chats");
ws.onmessage = function (event) {
chats.insertAdjacentHTML("beforeend", `<li>${event.data}</li>`);
};
// When the user types a message, send it to the server
var input = document.querySelector("#message");
input.focus();
document.querySelector("form").addEventListener(
"submit",
function (e) {
e.preventDefault();
ws.send(input.value);
input.value = "";
},
false,
);
Messages example
You can also have the server trigger scheduled messages using Tornado’s PeriodicCallback. The example below shows how to send an idle message at random intervals.
Chatbot example
To serve WebSockets from behind an nginx reverse proxy, use the following config:
http {
# Add this configuration inside the http section
# ----------------------------------------------
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
location / {
proxy_pass ...;
# Add this configuration inside the http > server > location section
# ------------------------------------------------------------------
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Scheme $scheme;
}
}
}