Browse Source

新增了基于channels的websocket支持,新增了knock_knock设施,用于提醒客户端请求数据

Shellmiao 3 years ago
parent
commit
fb3c94545e

+ 20 - 0
MeChat/asgi.py

@@ -0,0 +1,20 @@
+import os
+
+from channels.auth import AuthMiddlewareStack
+from channels.routing import ProtocolTypeRouter, URLRouter
+from django.core.asgi import get_asgi_application
+import infrastructure.routing
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MeChat.settings")
+
+application = ProtocolTypeRouter({
+    # http请求使用这个
+    "http": get_asgi_application(),
+
+    # websocket请求使用这个
+    "websocket": AuthMiddlewareStack(
+        URLRouter(
+            infrastructure.routing.websocket_urlpatterns
+        )
+    ),
+})

+ 13 - 1
MeChat/settings.py

@@ -24,7 +24,7 @@ SECRET_KEY = 'r!s)05+7&3kdwkm+&symsmf013o7jfxb%%^2-2zl^^z%_sqeln'
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = True
 
-ALLOWED_HOSTS = ['10.122.237.112', '127.0.0.1']
+ALLOWED_HOSTS = ['10.122.237.112', '127.0.0.1', '10.122.234.72']
 
 # Application definition
 
@@ -39,6 +39,7 @@ INSTALLED_APPS = [
     'account',
     'infrastructure',
     'friends',
+    'channels',  # channels应用
 ]
 
 MIDDLEWARE = [
@@ -46,6 +47,7 @@ MIDDLEWARE = [
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
     #    'django.middleware.csrf.CsrfViewMiddleware',
+    #    'dwebsocket.middle.ware.WebSocketMiddleWare'
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
@@ -123,3 +125,13 @@ STATICFILES_DIRS = (
 
 MEDIA_URL = '/media/'
 MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
+
+# 设置ASGI应用
+ASGI_APPLICATION = 'MeChat.asgi.application'
+
+# WebSocket
+CHANNEL_LAYERS = {
+    'default': {
+        "BACKEND": "channels.layers.InMemoryChannelLayer"
+    },
+}

+ 4 - 2
chat/views.py

@@ -5,6 +5,7 @@ from django.contrib.auth.models import User
 from django.contrib.auth.decorators import login_required
 import json
 from friends.models import Friends
+from infrastructure.consumers import knock_knock
 
 from .form import StoreDataForm
 from .models import Message
@@ -48,6 +49,7 @@ def send_message(request):
                         toUser=user.get(),
                         plaintext=data['plaintext'],
                     )
+                    knock_knock(user.get().username, 'request_message')
                     return HttpResponse(status=200)
                 else:
                     return HttpResponse(status=423)
@@ -85,9 +87,9 @@ def filter_messages(request):
         user = User.objects.filter(username=data['username'])
         if user:
             temp_friends_1 = Friends.objects.filter(
-                user=User.objects.filter(username=data["toUsername"]).get(), friend=request.user)
+                user=user, friend=request.user)
             temp_friends_2 = Friends.objects.filter(
-                friend=User.objects.filter(username=data["toUsername"]).get(), user=request.user)
+                friend=user, user=request.user)
             if temp_friends_1 or temp_friends_2:
                 # to_user = User.objects.filter(username=data['username'])
                 # messages = Message.objects.filter(

BIN
db.sqlite3


+ 2 - 0
friends/views.py

@@ -6,6 +6,7 @@ from django.contrib.auth.decorators import login_required
 from django.shortcuts import render
 from django.contrib.auth.models import User
 from .models import Friends, FriendRequest
+from infrastructure.consumers import knock_knock
 
 DEBUG = True
 
@@ -70,6 +71,7 @@ def add_friend(request):
                     friend_request = FriendRequest.objects.filter(requester__username=request.user.username)
                     friend_request = friend_request.filter(receiver__username=data['username'])
                     if friend_request:
+                        knock_knock(data['username'], 'get_friends_requests')
                         return HttpResponse(status=200)
                     else:
                         new_friend_request = FriendRequest()

+ 22 - 0
infrastructure/consumers.py

@@ -0,0 +1,22 @@
+from channels.generic.websocket import WebsocketConsumer
+import json
+
+user_dict = {}
+
+
+class KnockConsumer(WebsocketConsumer):
+    # websocket建立连接时执行方法
+    def connect(self):
+        self.accept()
+        username = self.scope.get("url_route").get("kwargs").get("username")
+        user_dict[username] = self
+        print(user_dict)
+        return True
+
+
+def knock_knock(username, message):
+    ws = user_dict.get(username)
+    message = json.dumps({'message': message})
+    ws.send(message)
+    print(message)
+    return True

+ 6 - 0
infrastructure/routing.py

@@ -0,0 +1,6 @@
+from django.urls import re_path
+from .consumers import KnockConsumer
+
+websocket_urlpatterns = [
+    re_path(r'ws/(?P<username>\w+)/$', KnockConsumer.as_asgi()),
+]

+ 29 - 0
infrastructure/templates/test.html

@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html lang="zh-cn">
+<head>
+    <meta charset="utf-8"/>
+    <title>test</title>
+</head>
+<body>
+<textarea id="chat-log" cols="100" rows="20"></textarea><br>
+<input id="chat-message-input" type="text" size="100"><br>
+<input id="chat-message-submit" type="button" value="Send">
+{{ room_name|json_script:"room-name" }}
+
+<script>
+    // 根据roomName拼接websocket请求地址,建立长连接
+    //  请求url地址为/ws/chat/<room_name>/
+    const username = "test"
+    const wss_protocol = (window.location.protocol == 'https:') ? 'wss://' : 'ws://';
+    const chatSocket = new WebSocket(
+        wss_protocol + window.location.host + '/ws/' + username + '/'
+    );
+    // 从后台接收到数据时触发此方法
+    // 接收到后台数据后对其解析,并加入到聊天记录chat-log
+    chatSocket.onmessage = function (e) {
+        const data = JSON.parse(e.data);
+        document.querySelector('#chat-log').value += (data.message + '\n');
+    };
+</script>
+</body>
+</html>

+ 1 - 0
infrastructure/urls.py

@@ -4,4 +4,5 @@ from . import views
 urlpatterns = [
     path('add_public_key/', views.add_public_key, name='add_public_key'),
     path('get_public_key/', views.get_public_key, name='get_public_key'),
+    path('test/', views.test)
 ]

+ 27 - 1
infrastructure/views.py

@@ -3,11 +3,37 @@ from .models import PublicKey
 from .form import AddPublicKeyForm
 from django.http import HttpResponse
 from django.contrib.auth.decorators import login_required
+# from dwebsocket.decorators import accept_websocket
 import json
 
 DEBUG = True
 
 
+# WS_DIC = {}
+#
+#
+# # 接收ws连接
+# @accept_websocket
+# def connect_user(request):
+#     if request.is_websocket():
+#         WS_DIC[request.user.username] = request.websocket
+#     else:
+#         return HttpResponse(status=400)
+#
+#
+# def knock_knock(username, flag):
+#     if username in WS_DIC.keys:
+#         websocket = WS_DIC[username]
+#         websocket.send(flag)
+#         return True
+#     else:
+#         return False
+
+@login_required(login_url='/account/login/')
+def test(request):
+    return render(request, 'test.html')
+
+
 @login_required(login_url='/account/login/')
 def add_public_key(request):
     if request.method == 'POST':
@@ -42,7 +68,7 @@ def get_public_key(request):
         response = []
         for public_key in public_keys:
             response.append(public_key.public_key)
-        return HttpResponse(json.dumps(response),status=200)
+        return HttpResponse(json.dumps(response), status=200)
     # 用于测试
     elif request.method == 'GET':
         if DEBUG: