diff --git a/requirements.dev.txt b/requirements.dev.txt index cf6269b..fa9a2a4 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -7,6 +7,7 @@ channels-redis charset-normalizer==3.4.4 coverage cssselect==1.3.0 +daphne dj-database-url Django==6.0 django-compressor diff --git a/requirements.txt b/requirements.txt index 423d5da..c3451d0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,7 @@ celery channels channels-redis cssselect==1.3.0 +daphne Django==6.0 dj-database-url django-compressor diff --git a/src/apps/epic/consumers.py b/src/apps/epic/consumers.py index 60defaf..bc19fba 100644 --- a/src/apps/epic/consumers.py +++ b/src/apps/epic/consumers.py @@ -1 +1,18 @@ -# RoomConsumer goes here \ No newline at end of file +from channels.generic.websocket import AsyncJsonWebsocketConsumer + + +class RoomConsumer(AsyncJsonWebsocketConsumer): + async def connect(self): + self.room_slug = self.scope["url_route"]["kwargs"]["room_slug"] + self.group_name = f"room_{self.room_slug}" + await self.channel_layer.group_add(self.group_name, self.channel_name) + await self.accept() + + async def disconnect(self, close_code): + await self.channel_layer.group_discard(self.group_name, self.channel_name) + + async def receive_json(self, content): + pass # handlers added as events introduced + + async def gate_update(self, event): + await self.send_json(event) diff --git a/src/apps/epic/routing.py b/src/apps/epic/routing.py index b3600a3..e2d472c 100644 --- a/src/apps/epic/routing.py +++ b/src/apps/epic/routing.py @@ -1 +1,8 @@ -websocket_urlpatterns = [] +from django.urls import path + +from . import consumers + + +websocket_urlpatterns = [ + path('ws/room//', consumers.RoomConsumer.as_asgi()), +] diff --git a/src/apps/epic/tests/integrated/test_consumers.py b/src/apps/epic/tests/integrated/test_consumers.py new file mode 100644 index 0000000..53eda18 --- /dev/null +++ b/src/apps/epic/tests/integrated/test_consumers.py @@ -0,0 +1,37 @@ +from channels.testing.websocket import WebsocketCommunicator +from channels.layers import get_channel_layer +from django.test import SimpleTestCase, override_settings + +from core.asgi import application + + +TEST_CHANNEL_LAYERS = { + "default": { + "BACKEND": "channels.layers.InMemoryChannelLayer", + } +} + + +@override_settings(CHANNEL_LAYERS=TEST_CHANNEL_LAYERS) +class RoomConsumerTest(SimpleTestCase): + async def test_can_connect_and_disconnect(self): + communicator = WebsocketCommunicator(application, "/ws/room/test-room/") + connected, _ = await communicator.connect() + self.assertTrue(connected) + await communicator.disconnect() + + async def test_receives_gate_update_broadcast(self): + communicator = WebsocketCommunicator(application, "/ws/room/test-room/") + await communicator.connect() + + channel_layer = get_channel_layer() + await channel_layer.group_send( + "room_test-room", + {"type": "gate_update", "gate_state": "some_state"}, + ) + + response = await communicator.receive_json_from() + self.assertEqual(response["type"], "gate_update") + self.assertEqual(response["gate_state"], "some_state") + + await communicator.disconnect()