diff --git a/backend/application/routing.py b/backend/application/routing.py new file mode 100644 index 0000000..166857b --- /dev/null +++ b/backend/application/routing.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from channels.auth import AuthMiddlewareStack +from channels.routing import ProtocolTypeRouter, URLRouter +from dvadmin.system import routing as dvadminRouting + + +application = ProtocolTypeRouter({ + 'websocket': AuthMiddlewareStack( + URLRouter( + dvadminRouting.websocket_urlpatterns# 指明路由文件是devops/routing.py + ) + ), +}) \ No newline at end of file diff --git a/backend/application/settings.py b/backend/application/settings.py index c8ce5e9..6112247 100644 --- a/backend/application/settings.py +++ b/backend/application/settings.py @@ -57,6 +57,7 @@ INSTALLED_APPS = [ "dvadmin.system", "drf_yasg", "captcha", + 'channels', ] MIDDLEWARE = [ @@ -164,6 +165,19 @@ CORS_ORIGIN_ALLOW_ALL = True # 允许cookie CORS_ALLOW_CREDENTIALS = True # 指明在跨域访问中,后端是否支持对cookie的操作 +# ================================================= # +# ********************* channels配置 ******************* # +# ================================================= # +ASGI_APPLICATION = 'application.routing.application' +CHANNEL_LAYERS = { + 'default': { + 'BACKEND': 'channels_redis.core.RedisChannelLayer', + 'CONFIG': { + "hosts": [('127.0.0.1', 6379)], #需修改 + }, + }, +} + # ================================================= # # ********************* 日志配置 ******************* # # ================================================= # diff --git a/backend/dvadmin/system/consumers.py b/backend/dvadmin/system/consumers.py new file mode 100644 index 0000000..d7290fc --- /dev/null +++ b/backend/dvadmin/system/consumers.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +import urllib + +from asgiref.sync import sync_to_async +from channels.db import database_sync_to_async +from channels.generic.websocket import AsyncJsonWebsocketConsumer, AsyncWebsocketConsumer +import json + +from jwt import InvalidSignatureError + +from application import settings +from dvadmin.system.models import MessageCenter + +send_dict = {} + +# 发送消息结构体 +def message(sender, msg_type, msg): + text = { + 'sender': sender, + 'contentType': msg_type, + 'content': msg, + } + return text + +#异步获取消息中心的目标用户 +@database_sync_to_async +def _get_message_center_instance(message_id): + _MessageCenter = MessageCenter.objects.filter(id=message_id).values_list('target_user',flat=True) + if _MessageCenter: + return _MessageCenter + else: + return [] + + +def request_data(scope): + query_string = scope.get('query_string', b'').decode('utf-8') + qs = urllib.parse.parse_qs(query_string) + return qs + +class DvadminWebSocket(AsyncJsonWebsocketConsumer): + async def connect(self): + try: + import jwt + self.service_uid = self.scope["url_route"]["kwargs"]["service_uid"] + params = request_data(self.scope) + room = params.get('room')[0] + decoded_result = jwt.decode(self.service_uid, settings.SECRET_KEY, algorithms=["HS256"]) + if decoded_result: + self.user_id = decoded_result.get('user_id') + self.chat_group_name = room + #收到连接时候处理, + await self.channel_layer.group_add( + self.chat_group_name, + self.channel_name + ) + # 将该客户端的信息发送函数与客户端的唯一身份标识绑定,保存至自定义的字典中 + if len(send_dict)==0: + send_dict.setdefault(self.chat_group_name, {}) + for room in send_dict.keys(): + if room == self.chat_group_name: + send_dict[self.chat_group_name][self.user_id] = self.send + else: + send_dict.setdefault(self.chat_group_name,{}) + await self.accept() + await self.send_json(message('system', 'INFO', '连接成功')) + except InvalidSignatureError: + await self.disconnect(None) + + + async def disconnect(self, close_code): + # 删除 send_dict 中对应的信息 + del send_dict[self.chat_group_name][self.user_id] + # Leave room group + await self.channel_layer.group_discard(self.chat_group_name, self.channel_name) + print("连接关闭") + await self.close(close_code) + + async def receive(self, text_data=None, byte_text_data=None): + print(text_data) + try: + text_data_json = json.loads(text_data) + except Exception as e: + print('数据无法被json格式化', e) + await self.disconnect(400) + else: + print(123,text_data_json) + # 获取将要推送信息的目标身份标识,调用保存在 send_dict中的信息发送函数 + message_id = text_data_json.get('message_id', None) + user_list = await _get_message_center_instance(message_id) + for send_user in user_list: + await send_dict[self.chat_group_name][send_user](text_data=json.dumps(text_data_json)) \ No newline at end of file diff --git a/backend/dvadmin/system/routing.py b/backend/dvadmin/system/routing.py new file mode 100644 index 0000000..79372d1 --- /dev/null +++ b/backend/dvadmin/system/routing.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +from django.urls import path +from . import consumers + +websocket_urlpatterns = [ + path('ws//', consumers.DvadminWebSocket.as_asgi()), #consumers.DvadminWebSocket 是该路由的消费者 +] \ No newline at end of file diff --git a/web/src/api/websocket.js b/web/src/api/websocket.js index a06bdfc..53e7828 100644 --- a/web/src/api/websocket.js +++ b/web/src/api/websocket.js @@ -3,7 +3,7 @@ import util from '@/libs/util' function initWebSocket (e) { const token = util.cookies.get('token') if (token) { - const wsUri = 'ws://127.0.0.1:8000/?auth=' + token + const wsUri = 'ws://127.0.0.1:8000/ws/' + token + '/?room=message_center' this.socket = new WebSocket(wsUri)// 这里面的this都指向vue this.socket.onerror = webSocketOnError this.socket.onmessage = webSocketOnMessage @@ -56,11 +56,11 @@ function closeWebsocket () { close() } function close () { - this.socket.close() // 关闭 websocket - this.socket.onclose = function (e) { - console.log(e)// 监听关闭事件 - console.log('关闭') - } + // this.socket.close() // 关闭 websocket + // this.socket.onclose = function (e) { + // console.log(e)// 监听关闭事件 + // console.log('关闭') + // } } function webSocketSend (message) { this.socket.send(JSON.stringify(message)) diff --git a/web/src/components/table-selector/table-selector.vue b/web/src/components/table-selector/table-selector.vue index 45833ad..de2f998 100644 --- a/web/src/components/table-selector/table-selector.vue +++ b/web/src/components/table-selector/table-selector.vue @@ -201,7 +201,7 @@ export default { // this.dict = d2CrudPlus.util.dict.mergeDefault(this.dict, true) // } // this.initData() - console.log(this) + this.searchTableData() }, computed: { _elProps () {