This commit is contained in:
doudou201703
2026-08-02 14:07:04 +08:00
commit 046fac6dc1
339 changed files with 19435 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
"""注释"""
# consumers.py
# 推荐解决方案:事件驱动架构
# 修改实现为事件驱动模式:
import asyncio
import json
import time
from channels.generic.http import AsyncHttpConsumer
# 全局消息队列 (生产环境用Redis等分布式队列)
MESSAGE_QUEUE = asyncio.Queue()
class SSEConsumer(AsyncHttpConsumer):
async def handle(self, body):
# 设置SSE响应头
await self.send_headers(
headers=[
(b"Content-Type", b"text/event-stream"),
(b"Cache-Control", b"no-cache"),
(b"Connection", b"keep-alive"),
]
)
# 事件循环监听
while True:
# 异步等待新消息(挂起状态)
data = await MESSAGE_QUEUE.get()
# 推送消息给客户端
await self.send_body(f"event: message\ndata: {data}\n\n".encode())
async def disconnect(self):
# 客户端断开时清理资源
print(f"Client {self.scope['client']} disconnected")
# 其他Django视图或后台任务中
# 生产者触发更新示例
async def trigger_update():
"""模拟外部事件触发更新"""
# 创建新消息
message = {"time": time.time(), "event": "DataUpdated"}
# 将消息推送到全局队列
await MESSAGE_QUEUE.put(json.dumps(message))
# 测试代码
async def xiaozizi():
"""从队列中获取消息并打印"""
print("等待消息...")
d = await MESSAGE_QUEUE.get()
print(f"收到消息: {d}")
return d
# 在脚本末尾添加(如果需要测试)
async def main():
"""主测试函数"""
print("开始测试...")
# 启动一个任务来监听消息
listen_task = asyncio.create_task(xiaozizi())
# 稍等一下再发送消息,确保监听任务已经启动
await asyncio.sleep(0.1)
# 发送测试消息
# await trigger_update()
# 等待监听任务完成
result = await listen_task
print(f"测试完成,结果: {result}")
if __name__ == "__main__":
asyncio.run(main())
View File
+43
View File
@@ -0,0 +1,43 @@
"""2"""
import pydash
from asgiref.sync import async_to_sync
from sixGuoDjango import RedisClientManager
redia_socket_5 = RedisClientManager().get_client(db_name="redis_5")
"""consumers"""
import orjson
from channels.generic.websocket import WebsocketConsumer
class ChatConsumer(WebsocketConsumer):
def connect(self):
print("连接请求进来了", self.channel_name)
room_id = pydash.get(obj=self.scope, path="url_route.kwargs.room_id")
self.accept() # 接受连接
redia_socket_5.set(name=room_id, value=self.channel_name)
# self.channel_layer.group_add(group="demo_name", channel=self.channel_name)
async_to_sync(self.channel_layer.group_add)(group="demo_name", channel=self.channel_name)
async_to_sync(self.channel_layer.group_add)(group="demo_xiaozizi", channel=self.channel_name)
def receive(self, text_data=None, bytes_data=None):
# text_data 已经是字符串,直接使用
if text_data == "ping":
self.send(text_data=orjson.dumps({"type": "监听心跳", "text": {"xiao": "xiaozizi"}},
option=orjson.OPT_SORT_KEYS).decode(encoding="utf-8"))
else:
# 处理其他消息
# print("判断生成了哟", text_data)
self.send(text_data=orjson.dumps({"type": "chat_msg", "text": {"xiao": "xiaozizi"}},
option=orjson.OPT_SORT_KEYS).decode(encoding="utf-8"))
def disconnect(self, code):
room_id = pydash.get(obj=self.scope, path="url_route.kwargs.room_id") # 断开连接后可以拿到参数
print("连接断开,code:", code, room_id)
async_to_sync(self.channel_layer.group_discard)(group="demo_name", channel=self.channel_name)
async_to_sync(self.channel_layer.group_discard)(group="demo_xiaozizi", channel=self.channel_name)
def update_更新用户头像(self, event):
self.send(text_data=orjson.dumps(event, option=orjson.OPT_SORT_KEYS).decode(encoding="utf-8"))
+37
View File
@@ -0,0 +1,37 @@
# routing.py
"""
ASGI config for django_cat project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
from sixGuoDjango.settings import BASE_DIR
"""asgi路由"""
import os
os.environ.setdefault(key='DJANGO_SETTINGS_MODULE', value=f"{BASE_DIR.name}.settings")
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from django_channels import consumers, tableConsumer
from django.urls import path
application = ProtocolTypeRouter(
{
"http": get_asgi_application(), # 如果处理http请求就走这里
"websocket": URLRouter(
[
# re_path(r'room/(?P<group>\w+)/$', consumers.ChatConsumer.as_asgi()),
path(route="room/", view=consumers.ChatConsumer.as_asgi()), # 调用第一个类处理业务
# path("web/<str:params>/", tableConsumer.TableConsumer.as_asgi()), # 调用第二个类处理业务
],
)
},
)
# AllowedHostsOriginValidator:
# 这是一个安全中间件,用于验证WebSocket连接请求的Origin头部是否包含在ALLOWED_HOSTS设置中。
# 这是防止跨站伪造攻击(Cross-Site Request Forgery, CSRF)的一种措施,
# 确保只有来自信任源(通常是应用自己的域名)的WebSocket连接请求才能被接受。
# 如果请求的Origin不在允许列表中,此中间件会拒绝连接。
+101
View File
@@ -0,0 +1,101 @@
import pydash
from asgiref.sync import async_to_sync
from channels.exceptions import StopConsumer
from channels.generic.websocket import JsonWebsocketConsumer
from channels.layers import get_channel_layer
from sixGuoDjango import redis_5
# channel_layer: RedisChannelLayer = get_channel_layer("default")
channel_layer = get_channel_layer(alias="default")
default_group_name = "default_group_name"
class websocket(JsonWebsocketConsumer):
def connect(self) -> None:
"""
首次连拉时触发方法前端请求的语法为 "wss://wecom.fujugongxiang.com/web/room_name_value/"
room_name_value: 就是前端路由配置的room_name的值 path("web/<str:room_name>/", tableConsumer.websocket.as_asgi()),
并且最末尾要带有 / 斜杠
"""
user_openid = self.scope["url_route"]["kwargs"].get("room_name", "")
print("websocket:=>", user_openid, self.channel_name)
if not user_openid:
self.close(code=4001) # 关闭连接(可选)
return
self.accept()
# 将进来的用户保存到redis数据库中
redis_5.set(value=self.channel_name, name=user_openid)
# 将用户添加到自己的组里面 (只能异步,否则添加不成功的)
self.send_json(content={"channel_name": self.channel_name})
async_to_sync(awaitable=self.channel_layer.group_add)(group=default_group_name, channel=self.channel_name)
def disconnect(self, ):
user_openid = self.scope["url_route"]["kwargs"].get("room_name", None)
async_to_sync(self.channel_layer.group_discard)(group=user_openid, channel=self.channel_name, ) # 只能异步的删除;
async_to_sync(self.channel_layer.group_discard)(group=default_group_name, channel=self.channel_name, )
raise StopConsumer()
def receive_json(self, content, **kwargs) -> None:
print(content, "是在这里吗")
# self.send()
self.send_json(content={"xiao": "xiaozizi"})
pass
def chat_messages(self, event) -> None:
"""
:param event:
"""
data = pydash.get(obj=event, path="message")
self.send_json(content="messagemessagemessagemessage")
def chat_subMsg(self, event):
"""
:param event:
:type event:
"""
# 处理消息回调的函数
print("事件没有调用了吗")
self.send_json(content=event)
def chat_hongBao(self, event):
"""
:param event:
:type event:
"""
# 处理首次领红包的业务
user_openid = self.scope["url_route"]["kwargs"].get("room_name", None)
print(user_openid)
print("我得调用一下:chat_hongBao")
channelID = pydash.get(obj=event, path="message.channelID")
self.send_json(content={"chat": "chat_hongBao", })
def chat_Lucky拼团(self, event):
print("socked事件调用幸运拼团数据更新: 🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏", event)
self.send_json(content=event)
def commandsSendStr(self, event):
"""
:param event:
:type event:
"""
self.send_json(content={"commands": "demo这是个测试的数据", "type": "commands"})
def chat_demo(self, event):
"""
:param event:
:type event:
"""
print(event, "函数被调用了,")
self.send_json(content={"demo": "demo_test"})
def 消息提示(self, event):
"""事件"""
print(event)
print("这只是个用来测试的方法")
self.send_json(content="这只是个用来测试的方法")
def update_更新用户头像(self, event):
print(event)
+81
View File
@@ -0,0 +1,81 @@
"""注释"""
import pydash
from channels.generic.websocket import AsyncJsonWebsocketConsumer
class websocket(AsyncJsonWebsocketConsumer):
async def connect(self) -> None:
"""
前端请求: wss://wecom.fujugongxiang.com/web/room_name_value/
room_name_value 来自 URL 路径: path("web/<str:room_name>/", websocket.as_asgi())
"""
# 获取 URL 参数
user_openid = self.scope["url_route"]["kwargs"].get("room_name", "")
if not user_openid:
await self.close(code=4001) # 关闭连接(可选)
return
# 接受连接
await self.accept()
# 将用户加入组(异步直接 await)
await self.channel_layer.group_add(group=user_openid, channel=self.channel_name, )
# 返回 channel_name 给前端(可选)
await self.send_json(content={"channel_name": self.channel_name})
async def disconnect(self, close_code) -> None:
"""
断开连接时触发
"""
user_openid = self.scope["url_route"]["kwargs"].get("room_name", "")
if user_openid:
# 从组中移除(异步)
await self.channel_layer.group_discard(group=user_openid, channel=self.channel_name, ) # 自动清理,无需 raise StopConsumer()
async def receive_json(self, content, **kwargs) -> None:
"""
收到前端发来的 JSON 消息
"""
print("收到消息:", content)
# 回显
await self.send_json(content=content)
# 自定义事件处理器(会被 group_send 触发)
async def chat_messages(self, event) -> None:
"""
处理 chat_messages 事件
"""
data = pydash.get(event, "message")
print("chat_messages 收到数据:", data)
await self.send_json(content=data)
async def chat_subMsg(self, event):
"""
处理 subMsg 回调
"""
pass
async def chat_hongBao(self, event):
"""
处理红包事件
"""
print(event, "========== chat_hongBao 被触发 ============")
channel_id = pydash.get(event, "message.channelID")
await self.receive_json(content={"demo": "text"})
async def commandsSendStr(self, event):
"""
发送命令
"""
await self.send_json(content={"commands": "demo这是个测试的数据", "type": "commands"})
async def chat_demo(self, event):
"""
demo 测试事件
"""
print("chat_demo 被调用:", event)
await self.receive_json(content={"demo": "demo_test"})