six_001
This commit is contained in:
@@ -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())
|
||||
@@ -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"))
|
||||
@@ -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不在允许列表中,此中间件会拒绝连接。
|
||||
@@ -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)
|
||||
@@ -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"})
|
||||
Reference in New Issue
Block a user