Overrride websocket events like Open, error, message,close using sanic

I am developing a websocket application using sanic and need to do stuff on websocket event like open, error,message,close but i was not able to understand how to do it using sanic websocket module
https://github.com/huge-success/sanic/blob/master/sanic/websocket.py

1 Like

What are you using to create your websocket client? Is it a web-based (Javascript) client?

Typically, handling events on websockets is a client side thing. Which, in Javascript might look like this:

const socket = new WebSocket(url);

socket.onopen = () => {
    ....
};

socket.onmessage = e => {
    ....
};

socket.onerror = e => {
    ....
};

socket.onclose = e => {
    ....
};

yes, its a normal client written in javascript, and want to create something similar in sanic at it is done in tornado like below

class EchoWebSocket(tornado.websocket.WebSocketHandler):
    def open(self):
        print("WebSocket opened")

    def on_message(self, message):
        self.write_message(u"You said: " + message)

    def on_close(self):
        print("WebSocket closed")

So, the use case is of using mongo db change stream over a websocket, https://docs.mongodb.com/manual/changeStreams/
so once there is an update on db i want to push event to web but before that i need to do something when the connection opens

Sanic exposes a layer on top of the websockets package. Which provides the mechanism to do the handshake, upgrade, socket connection, etc.

It leaves much room for the developer to create something that works for his/her implementation, and is not opinionated on how you do that.

The very simple example in the documentation is:

@app.websocket('/feed')
async def feed(request, ws):
    while True:
        data = 'hello!'
        print('Sending: ' + data)
        await ws.send(data)
        data = await ws.recv()
        print('Received: ' + data)

Of course, this does not have much logic built in.

Using this, you would put event handlers like this:

@app.websocket('/feed')
async def feed(request, ws):
    on_open()
    while True:
        try:
            data = await ws.recv()
            on_message()
        except websockets.exceptions.ConnectionClosed:
            on_close()

I would suggest taking a look here to see a potential solution to creating both a consumer and producer task for incoming and outgoing messages.

I use something like this (for example) so that I can listen to a pubsub channel and have two way communication.

Are you only pushing information to the client, or should the client be able to also send messages over this socket?

yes, its two way communication

Okay, then what you will want to do is use the add_task method to create a handler for both consumer (incoming messages, data = await ws.recv()) and producer (outgoing messages, await ws.send(data)).

Thanks for the above solution,
I worked for me

1 Like

Glad to hear it. If you are able to, would you mind sharing some sample code (relevant parts only) for the benefit of anyone in the future that stumbles upon this?

I recently found this gist by @ahopkins

https://gist.github.com/ahopkins/52bcd7d15de1e0356ee22f82b6cbf9c8

1 Like

Thanks for sharing this. I forgot I had that out there. I have a nicer version of this that I could share, and probably should write up something nicer and post it as a blog. Or, feel free to do that if you are so inclined.

Oh i wanna learn too so can you please share ^^