Search code examples
pythonredisdjango-channelschannel

Stuck at AsyncWebsocketConsumer implementation


I am trying to develop a consumer (AsyncWebsocketConsumer type) which will be connected with a websocket and make changes to the frontend using JavaScript. The first thing that I am failing to implement is the consumer's functions (connect, send, disconnect). Also , using Redis.

my settings.py is

ASGI_APPLICATION = "myapp.routing.application"

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            'hosts': [('localhost', 6379)],
        },
    }
}


and my routing.py is

application = ProtocolTypeRouter({
    "channel": ChannelNameRouter({
        "example": ExampleConsumer,
    }),
})

Last, my consumers.py is

class ExampleConsumer(AsyncWebsocketConsumer):

    async def connect(self,msg):
        # Called on connection.
        # To accept the connection call:
        await self.accept()
        print('Channel connected')

When I tried the :

channel_layer = get_channel_layer()
async_to_sync(channel_layer.send)('example', {'type': 'connect'})

so that I could call the connect and see the connected-message that will let me know that the socket is connected , and then continue by sending a message , I get the :

raise NotImplementedError("You must implement application_send()") You must implement application_send()

I am pretty sure that I have misunderstood so many things but I am looking how to solve this problem for a long time and I couldn't find anything useful for my case , like an example or good documentation , so whatever helps will be appreciated!


Solution

  • You are using ChannelLayers wrong. They are for communicating between different instances of an application. Not for actual establishing WebSocket connections.

    Try this:

    settings.py

    ASGI_APPLICATION = "myapp.routing.application" # make sure your project is called 'myapp' ;-)
    

    routing.py

    application = ProtocolTypeRouter({
        'websocket': AuthMiddlewareStack(
            URLRouter([
                 path('ws/example/', consumers.ExampleConsumer),
            ])
        ),
    })
    

    consumers.py

    class ExampleConsumer(AsyncWebsocketConsumer):
    
        async def connect(self,msg):
            # Called on connection.
            # To accept the connection call:
            await self.accept()
            print('Channel connected')
    
        async def receive(self, data):
            # do something with data
            print(data)
            # send response back to connected client
            await self.send('We received your message')
    

    You can use a Simple Websocket Client to test your ws-endpoint.

    1. Connect to http://localhost:8000/ws/example/: You should see "Channel connected" on the console, as well as a message that a client connected.
    2. Send a request with some data. This data should get logged in the console and you will get a response back to your client.

    Hope that helps to get you started.