From 76044606267a60c1c11e516513c4ea81f1e7981f Mon Sep 17 00:00:00 2001 From: Process-ing Date: Tue, 10 Sep 2024 17:56:58 +0100 Subject: [PATCH 1/9] Add dependencies --- django/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/django/requirements.txt b/django/requirements.txt index 8e7901e..1ff9000 100644 --- a/django/requirements.txt +++ b/django/requirements.txt @@ -8,3 +8,5 @@ psycopg2==2.9.9 celery==5.2.7 redis==3.5.3 python-dotenv==1.0.1 +channels==4.1.0 +daphne==4.1.2 From 9934e4312e172fe5c23bdcf87ab230378b505a70 Mon Sep 17 00:00:00 2001 From: Process-ing Date: Thu, 19 Sep 2024 18:44:31 +0100 Subject: [PATCH 2/9] Implement WebSocket communication --- django/tts_be/asgi.py | 8 ++++++-- django/tts_be/settings.py | 6 +++++- django/university/routing.py | 6 ++++++ django/university/websocket.py | 17 +++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 django/university/routing.py create mode 100644 django/university/websocket.py diff --git a/django/tts_be/asgi.py b/django/tts_be/asgi.py index 54873d2..70c4e4c 100644 --- a/django/tts_be/asgi.py +++ b/django/tts_be/asgi.py @@ -8,9 +8,13 @@ """ import os - +from channels.routing import ProtocolTypeRouter, URLRouter from django.core.asgi import get_asgi_application +from university.routing import websocket_urlpatterns os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tts_be.settings') -application = get_asgi_application() +application = ProtocolTypeRouter({ + 'http': get_asgi_application(), + 'websocket': URLRouter(websocket_urlpatterns), +}) diff --git a/django/tts_be/settings.py b/django/tts_be/settings.py index 2966293..a32857f 100644 --- a/django/tts_be/settings.py +++ b/django/tts_be/settings.py @@ -24,7 +24,7 @@ SECRET_KEY = os.getenv('SECRET_KEY') -DEBUG = False if int(os.getenv('DEBUG')) == 0 else True +DEBUG = int(os.getenv('DEBUG')) != 0 ALLOWED_HOSTS = ['0.0.0.0', 'localhost', 'tts.niaefeup.pt', 'tts-staging.niaefeup.pt'] @@ -32,6 +32,7 @@ INSTALLED_APPS = [ 'corsheaders', + 'daphne', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -40,6 +41,7 @@ 'rest_framework', 'django.contrib.staticfiles', 'university', + 'channels', ] MIDDLEWARE = [ @@ -74,6 +76,8 @@ WSGI_APPLICATION = 'tts_be.wsgi.application' +ASGI_APPLICATION = 'tts_be.asgi.application' + # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases diff --git a/django/university/routing.py b/django/university/routing.py new file mode 100644 index 0000000..fbaf8cd --- /dev/null +++ b/django/university/routing.py @@ -0,0 +1,6 @@ +from django.urls import path +from .websocket import TestConsumer + +websocket_urlpatterns = [ + path('ws/chat//', TestConsumer.as_asgi()), +] \ No newline at end of file diff --git a/django/university/websocket.py b/django/university/websocket.py new file mode 100644 index 0000000..db6a269 --- /dev/null +++ b/django/university/websocket.py @@ -0,0 +1,17 @@ +from channels.generic.websocket import WebsocketConsumer + +class TestConsumer(WebsocketConsumer): + def connect(self): + print("Connected") + + self.accept() + + def disconnect(self, close_code): + print("Disconnected") + + def receive(self, text_data): + self.send(text_data=text_data) + + def chat_message(self, event): + message = event['message'] + self.send(text_data=message) \ No newline at end of file From a0235781b899066d6a7085f1eb8707b5dab38024 Mon Sep 17 00:00:00 2001 From: Process-ing Date: Thu, 19 Sep 2024 18:45:02 +0100 Subject: [PATCH 3/9] Fix type hint error in settings.py --- django/tts_be/settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/django/tts_be/settings.py b/django/tts_be/settings.py index a32857f..8aa93d4 100644 --- a/django/tts_be/settings.py +++ b/django/tts_be/settings.py @@ -24,7 +24,8 @@ SECRET_KEY = os.getenv('SECRET_KEY') -DEBUG = int(os.getenv('DEBUG')) != 0 +DEBUG = os.getenv('DEBUG') +DEBUG = int(DEBUG) != 0 if DEBUG else False ALLOWED_HOSTS = ['0.0.0.0', 'localhost', 'tts.niaefeup.pt', 'tts-staging.niaefeup.pt'] From 5389e1c3cdec0ed0b2164a9460d898c5add0f0b1 Mon Sep 17 00:00:00 2001 From: Process-ing Date: Tue, 24 Sep 2024 17:10:01 +0100 Subject: [PATCH 4/9] Add Socket.IO dependency --- django/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/django/requirements.txt b/django/requirements.txt index 1ff9000..7172056 100644 --- a/django/requirements.txt +++ b/django/requirements.txt @@ -10,3 +10,4 @@ redis==3.5.3 python-dotenv==1.0.1 channels==4.1.0 daphne==4.1.2 +python-socketio==5.11.4 From f37260bf21b1a3603c42526f042dfd7d83ad844f Mon Sep 17 00:00:00 2001 From: Process-ing Date: Tue, 1 Oct 2024 16:33:07 +0100 Subject: [PATCH 5/9] Add Socket.IO --- django/tts_be/asgi.py | 12 ++++++++---- django/university/socket/views.py | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 django/university/socket/views.py diff --git a/django/tts_be/asgi.py b/django/tts_be/asgi.py index 70c4e4c..8b0cb7b 100644 --- a/django/tts_be/asgi.py +++ b/django/tts_be/asgi.py @@ -11,10 +11,14 @@ from channels.routing import ProtocolTypeRouter, URLRouter from django.core.asgi import get_asgi_application from university.routing import websocket_urlpatterns +from channels.auth import AuthMiddlewareStack +from channels.security.websocket import AllowedHostsOriginValidator + +import socketio +from university.socket.views import sio os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tts_be.settings') -application = ProtocolTypeRouter({ - 'http': get_asgi_application(), - 'websocket': URLRouter(websocket_urlpatterns), -}) +django_app = get_asgi_application() + +application = socketio.ASGIApp(sio, django_app) diff --git a/django/university/socket/views.py b/django/university/socket/views.py new file mode 100644 index 0000000..7ef2808 --- /dev/null +++ b/django/university/socket/views.py @@ -0,0 +1,24 @@ +import os +import socketio + +async_mode = None + +basedir = os.path.dirname(os.path.realpath(__file__)) +sio = socketio.AsyncServer( + async_mode='asgi', + cors_allowed_origins="*", +) + +@sio.event +async def connect(sid, environ): + print('Client connected') + await sio.emit('my_response', {'data': 'Connected', 'count': 0}, room=sid) + + +@sio.event +def disconnect(sid): + print('Client disconnected') + +@sio.event +async def test(sid, environ): + await sio.emit('response', 'ya') \ No newline at end of file From 17db26368d6a8ac4fe8fbaa25d405b765b885953 Mon Sep 17 00:00:00 2001 From: Process-ing Date: Tue, 1 Oct 2024 16:53:26 +0100 Subject: [PATCH 6/9] Remove (pure) WebSocket files --- django/university/routing.py | 6 ------ django/university/websocket.py | 17 ----------------- 2 files changed, 23 deletions(-) delete mode 100644 django/university/routing.py delete mode 100644 django/university/websocket.py diff --git a/django/university/routing.py b/django/university/routing.py deleted file mode 100644 index fbaf8cd..0000000 --- a/django/university/routing.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.urls import path -from .websocket import TestConsumer - -websocket_urlpatterns = [ - path('ws/chat//', TestConsumer.as_asgi()), -] \ No newline at end of file diff --git a/django/university/websocket.py b/django/university/websocket.py deleted file mode 100644 index db6a269..0000000 --- a/django/university/websocket.py +++ /dev/null @@ -1,17 +0,0 @@ -from channels.generic.websocket import WebsocketConsumer - -class TestConsumer(WebsocketConsumer): - def connect(self): - print("Connected") - - self.accept() - - def disconnect(self, close_code): - print("Disconnected") - - def receive(self, text_data): - self.send(text_data=text_data) - - def chat_message(self, event): - message = event['message'] - self.send(text_data=message) \ No newline at end of file From ee41ba884485719ae8397bf5e040b27131d55397 Mon Sep 17 00:00:00 2001 From: Process-ing Date: Tue, 1 Oct 2024 17:49:36 +0100 Subject: [PATCH 7/9] Fix broken imports --- django/tts_be/asgi.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/django/tts_be/asgi.py b/django/tts_be/asgi.py index 8b0cb7b..88764b8 100644 --- a/django/tts_be/asgi.py +++ b/django/tts_be/asgi.py @@ -8,11 +8,7 @@ """ import os -from channels.routing import ProtocolTypeRouter, URLRouter from django.core.asgi import get_asgi_application -from university.routing import websocket_urlpatterns -from channels.auth import AuthMiddlewareStack -from channels.security.websocket import AllowedHostsOriginValidator import socketio from university.socket.views import sio From e855c42c4b2a88fbe873ef534bc79a128741c09a Mon Sep 17 00:00:00 2001 From: Process-ing Date: Tue, 1 Oct 2024 22:15:30 +0100 Subject: [PATCH 8/9] Create SessionsServer --- django/university/socket/sessionsserver.py | 11 +++++++++++ django/university/socket/views.py | 19 +++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 django/university/socket/sessionsserver.py diff --git a/django/university/socket/sessionsserver.py b/django/university/socket/sessionsserver.py new file mode 100644 index 0000000..1414b46 --- /dev/null +++ b/django/university/socket/sessionsserver.py @@ -0,0 +1,11 @@ +import uuid + +class SessionsServer: + def __init__(self, sio): + self.sio = sio + + def valid_token(self, token): + return True + + def event(self, event): + return self.sio.event(event) \ No newline at end of file diff --git a/django/university/socket/views.py b/django/university/socket/views.py index 7ef2808..3484056 100644 --- a/django/university/socket/views.py +++ b/django/university/socket/views.py @@ -1,6 +1,8 @@ import os import socketio +from university.socket.sessionsserver import SessionsServer + async_mode = None basedir = os.path.dirname(os.path.realpath(__file__)) @@ -8,17 +10,22 @@ async_mode='asgi', cors_allowed_origins="*", ) + +session_server = SessionsServer(sio) -@sio.event -async def connect(sid, environ): - print('Client connected') - await sio.emit('my_response', {'data': 'Connected', 'count': 0}, room=sid) +@session_server.event +async def connect(sid, environ, auth): + if session_server.valid_token(auth['token']): + print('Client connected') + await sio.emit('my_response', {'data': 'Connected', 'count': 0}, room=sid) + else: + raise ConnectionRefusedError('Authentication failed: Invalid token') -@sio.event +@session_server.event def disconnect(sid): print('Client disconnected') -@sio.event +@session_server.event async def test(sid, environ): await sio.emit('response', 'ya') \ No newline at end of file From dec36e5c4a2d95d89d7b770a1e6f3f3dfa3d14f5 Mon Sep 17 00:00:00 2001 From: Process-ing Date: Sat, 9 Nov 2024 13:50:48 +0000 Subject: [PATCH 9/9] Improve authentication error handling --- django/university/socket/views.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/django/university/socket/views.py b/django/university/socket/views.py index 3484056..ca0d395 100644 --- a/django/university/socket/views.py +++ b/django/university/socket/views.py @@ -15,11 +15,13 @@ @session_server.event async def connect(sid, environ, auth): - if session_server.valid_token(auth['token']): + if auth is None or 'token' not in auth: + raise ConnectionRefusedError('Authentication failed: No token provided') + elif not session_server.valid_token(auth['token']): + raise ConnectionRefusedError('Authentication failed: Invalid token') + else: print('Client connected') await sio.emit('my_response', {'data': 'Connected', 'count': 0}, room=sid) - else: - raise ConnectionRefusedError('Authentication failed: Invalid token') @session_server.event