Channelstream

Friendly and scalable websocket server for applications

First Application

As mentioned in introduction page to connect browser to websocket server you need to do following steps:

Step 1: Initialize javascript client

import {ChannelStreamConnection} from '@channelstream/channelstream';
let connection = new ChannelStreamConnection();
// this points to your application view
connection.connectUrl = '/connect';
connection.messageUrl = '/message';
// this points to channelstream
connection.websocketUrl = 'ws://127.0.0.1:8000/ws';
connection.longPollUrl = 'http://127.0.0.1:8000/listen';

connection.listenMessageCallback = (messages) => {
    for (let message of messages) {
        console.log('channelstream message', message);
        // Do something on message received
    }
};
// optional
connection.listenOpenedCallback = () => {
    // Do something on websocket opened
};
// this will try to obtain connection UUID from `connectUrl` endpoint of your WEB application via XHR call
// and then use it to make websocket connection
connection.connect();

Step 2: Implement /connect endpoint in your application

We need to tell the server that user "someuser" connects to "/tutorial" channel.

Channelstream requires all API calls to be signed with a shared secret, the default implementation used is TimestampSigner from itsdangerous package.

# python example
import requests
from itsdangerous import TimestampSigner

# create auth header for backend request
signer = TimestampSigner("secret")
sig_for_server = signer.sign("channelstream")
secret_headers = {
    "x-channelstream-secret": sig_for_server,
    "Content-Type": "application/json",
}
# connect user
payload = {
    "username": "someuser",
    "channels": ["/tutorial-1"]
}
response = requests.post("http://127.0.0.1:8000/connect", data=json.dumps(payload), headers=secret_headers)
response.json() # contains connection UUID

Simulate the /connect API call to the server

Notice how "channels_info" get updated when you subscribe new users/create new channels. If no actual websocket/long-polling connections are made by the clients those objects will get garbage collected.

        {
            "username": "someuser",
            "channels": ["/tutorial-1"]
        }
    

Step 3: Send message to users listening on /tutorial-1 channel

# python example
import requests
from itsdangerous import TimestampSigner

# create auth header for backend request
signer = TimestampSigner("secret")
sig_for_server = signer.sign("channelstream")
secret_headers = {
    "x-channelstream-secret": sig_for_server,
    "Content-Type": "application/json",
}
# send messages
payload = [
    {
        "user": "system",
        "channel": "/tutorial-1",
        "message": {
            "text": "This can serve as notification",
            "level": "warning"
        }
    }
]
response = requests.post("http://127.0.0.1:8000/connect", data=json.dumps(payload), headers=secret_headers)

Send the message via /message API call to the server

If you open up index page you will see that the connection there did not receive the message sent here - this is because they are subscribed to different channels and this is determined securely on your application side. However if you open this page in multiple windows/browsers you will see everyone subscribed to this channel will receive the message.

    [
        {
            "user": "system",
            "channel": "/tutorial-1",
            "message": {
                "text": "This can serve as notification",
                "level": "warning"
            }
        }
    ]
    

Demo Applications

Now that you know all the basics of application flow, you can explore demo implementations in Flask and Pyramid for inspiration.