Intention:
I aim to create an async WebSocket consumer capable of handling various handlers. These handlers can connect to the consumer, send messages through the channel layer, and receive messages either directly or through the consumer’s registry. The handlers are part of the same Django app, so I intend to use the channel layer to establish internal communication between different parts of my application.
Coding:
-
Async WebSocket Consumer (consumer.py):
import asyncio from channels.generic.websocket import AsyncWebsocketConsumer from uuid import uuid4 class MyWebSocketConsumer(AsyncWebsocketConsumer): registered_handlers = {} async def connect(self): await self.channel_layer.group_add("websocket_group", self.channel_name) await self.accept() async def disconnect(self, close_code): self.registered_handlers = {} await self.channel_layer.group_discard("websocket_group", self.channel_name) async def receive(self, text_data): # Check target and message and either route to other handler based on target parameter received and channel_name retrieved from registry or if None, perform other actions pass async def register_handler(self, data): handler_name = data.get("handler_name") channel_name = data.get("channel_name") self.registered_handlers[handler_name] = channel_name
-
Example Handler (example_handler.py):
import asyncio from channels.layers import get_channel_layer from uuid import uuid4 class ExampleHandler: def initialize_handler(): handler_name = "example" channel_name = str(uuid4()) message = { "type": "register_handler", "handler_name": handler_name, "channel_name": channel_name } channel_layer = get_channel_layer() def send_message(); message = { "message": "test_message", "target": None #Specify other handler or None if intended for consumer } channel_layer = get_channel_layer() async_to_sync(channel_layer.group_send) ("websocket_group", message)
-
Routing File (routing.py):
from django.urls import path from .consumers import MyWebSocketConsumer websocket_urlpatterns = [ path("ws/test/", MyWebSocketConsumer.as_asgi()), ]
-
ASGI File (asgi.py):
import os from django.core.asgi import get_asgi_application from channels.routing import ProtocolTypeRouter, URLRouter from django.urls import path from .routing import websocket_urlpatterns os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": AuthMiddlewareStack(URLRouter(websocket_urlpatterns)), })
———-
I am using Daphne and Redis (Redis is running in the background and I can see the register message being displayed there) and I want to run my server and afterwards run the initialise method of each handler with a management command in another terminal, so that they can connect to the consumer.
However my problem is now that the connection does not get established as when I am logging something in the methods from the consumer, I do not see this in the terminal. What is the issue with the coding?
- Do I have to do something with the url pattern as right now it is not really used at all?
- Is something wrong with the group?
- Also a question is, how can I receive messages back from the consumer in my handlers (as I am expecting messages from the consumer not only as a direct response, but also as a result from another handler)? Do I need to run an infinite loop for this with channel_layer.receive(_channel_name_of_the_handler)? If so, where would I have to implement this - after I registered the handler inside the initialise would probably block the remaining other initialisations?
I would appreciate any suggestions! @KenWhitesell as you were responding on related articles in this forum, maybe you have any ideas here. Would be much appreciated!