LuckySheet协同编辑后端示例(Django+Channel,Websocket通信)

其他的配置不赘述了,直接网上搜一下django使用channel的配置方法

我初步研究通道先用的内存

在setting文件中

python 复制代码
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels.layers.InMemoryChannelLayer",
    },
}

这里我重点说一下luckysheet源码的部分

首先是websocket,这部分代码在源码的server.js中,通过研究源码,才解决了问题

pako解压的问题尝试了很多次都没不太对,于是直接把pako部分的源码给注释掉了,直接传过去的就是json字符串

javascript 复制代码
} else {
            // let msg = pako.gzip(encodeURIComponent(JSON.stringify(d)), {to: "string"});
			let msg = JSON.stringify(d);
			//console.info(msg);
            if (_this.websocket != null) {
                _this.websocket.send(msg);
            }
        }

后端的消费者类的主要代码如下

python 复制代码
from channels.generic.websocket import AsyncJsonWebsocketConsumer
from urllib.parse import parse_qs
import json

class TableConsumer(AsyncJsonWebsocketConsumer):
    table = None
    gridKey = None

    async def connect(self):
        query = self.scope['query_string'].decode('utf-8')
        t = parse_qs(query)['t'][0]
        self.gridKey = parse_qs(query)['g'][0]
        await self.channel_layer.group_add(f'table_{self.gridKey}', self.channel_name)
        await self.accept()
        print('建立连接')

    async def disconnect(self, close_code):
        print('断开连接')
        await self.channel_layer.group_discard(f'table_{self.gridKey}', self.channel_name)

    async def receive(self, text_data=None, bytes_data=None):
        # 使用json.loads方法将JSON字符串解析为Python的字典对象
        if text_data !='rub':
            parsed_data = json.loads(text_data)
            print(parsed_data)
            # 这里构造要广播的数据
            broadcast_data = dict()
            broadcast_data['type'] = 3
            broadcast_data['data'] = text_data
            broadcast_data['username'] = 'test'
            broadcast_event = {
                "type": "broadcast_message",
                "message": broadcast_data
            }
            # 向对应的组发送广播事件,触发broadcast_message方法来实际发送给组内成员
            await self.channel_layer.group_send(f'table_{self.gridKey}', broadcast_event)

    async def broadcast_message(self, event):
        message = event["message"]
        await self.send_json(message)

之前对websocket和channel不太了解,看了前端代码后把type和message给改了,后来多次尝试发现这个千万别改,他会在send的时候卡住而且不报任何错误(因为协程),如果是广播的话只需要修改broadcast_data的内容就行,通过解读前端的代码,在后端构建返回的json,成果把type=3的内容实现了,也就是鼠标移动的部分

javascript 复制代码
else if(type == 3){ //多人操作不同选区("t": "mv")(用不同颜色显示其他人所操作的选区)
	                let id = data.id;
	                let username = data.username;
	                let item = JSON.parse(data.data);
	                let type = item.t,
	                    index = item.i,
	                    value = item.v;

剩余的部分我就先不写了,具体操作应该是根据前端过来的json内容来自行判断返回的type,然后进行消息的分发!!!!

重点:读源码读源码读源码!!!!!

又写了两种type,批量的没写到type=4的情况,因为他前端写的感觉有问题还造成了后端的麻烦,于是后端写成多个type=2了,增加了一点点服务器压力

python 复制代码
from channels.generic.websocket import AsyncJsonWebsocketConsumer
from urllib.parse import parse_qs
import json

from pyasn1_modules.rfc5639 import brainpoolP160r1


class TableConsumer(AsyncJsonWebsocketConsumer):
    table = None
    gridKey = None

    async def connect(self):
        query = self.scope['query_string'].decode('utf-8')
        t = parse_qs(query)['t'][0]
        self.gridKey = parse_qs(query)['g'][0]
        await self.channel_layer.group_add(f'table_{self.gridKey}', self.channel_name)
        await self.accept()
        print('建立连接')

    async def disconnect(self, close_code):
        print('断开连接')
        await self.channel_layer.group_discard(f'table_{self.gridKey}', self.channel_name)

    async def receive(self, text_data=None, bytes_data=None):
        # 使用json.loads方法将JSON字符串解析为Python的字典对象
        if text_data !='rub':
            parsed_data = json.loads(text_data)
            print(parsed_data)
            if parsed_data['t'] == 'mv':
                # 这里构造要广播的事件数据,假设要原封不动广播接收到的数据,将其放入'message'字段
                broadcast_data = dict()
                broadcast_data['type'] = 3
                broadcast_data['data'] = text_data
                broadcast_data['username'] = 'test'
                broadcast_event = {
                    "type": "broadcast_message",
                    "message": broadcast_data
                }
                # 向对应的组发送广播事件,触发broadcast_message方法来实际发送给组内成员
                await self.channel_layer.group_send(f'table_{self.gridKey}', broadcast_event)
            if parsed_data['t'] == 'v':
                # 这里构造要广播的事件数据,假设要原封不动广播接收到的数据,将其放入'message'字段
                broadcast_data = dict()
                broadcast_data['type'] = 2
                broadcast_data['data'] = text_data
                broadcast_data['username'] = 'test'
                broadcast_event = {
                    "type": "broadcast_message",
                    "message": broadcast_data
                }
                # 向对应的组发送广播事件,触发broadcast_message方法来实际发送给组内成员
                await self.channel_layer.group_send(f'table_{self.gridKey}', broadcast_event)
            if parsed_data['t'] == 'rv':

                row = parsed_data['range']['row']
                column = parsed_data['range']['column']
                for j in range(column[0], column[1]+1):
                    numj = j-column[0]
                    for i in range(row[0], row[1] + 1):
                        numi = i-row[0]
                        try:
                            broadcast_data = dict()
                            broadcast_data['type'] = 2
                            # data = list()
                            broadcast_data['username'] = 'test'
                            data = dict()
                            data['t'] = 'v'
                            data['i'] = 0
                            data['v'] = parsed_data['v'][numi][numj]
                            data['r'] = i
                            data['c'] = j
                            broadcast_data['data'] = json.dumps(data)
                            broadcast_event = {
                                "type": "broadcast_message",
                                "message": broadcast_data
                            }
                            await self.channel_layer.group_send(f'table_{self.gridKey}', broadcast_event)

                        except Exception as e:
                            print(e)



    async def broadcast_message(self, event):
        message = event["message"]
        await self.send_json(message)
相关推荐
傻啦嘿哟17 分钟前
某短视频平台视频爬虫实战:抓取推荐流视频信息,绕过反爬的3种技巧
开发语言·爬虫·python
迷迭香yy40 分钟前
集合竞价数据挖掘实战:用Python构建开盘信号识别系统
人工智能·python·数据挖掘
烬羽1 小时前
React Router v7 完全指南:一个 Demo 吃透前端路由
javascript·react.js·前端框架
烬羽1 小时前
从"整个页面刷新"到"丝滑切换":手写一个 HashRouter 彻底搞懂前端路由
javascript·前端框架·全栈
用户938515635071 小时前
从零理解 React Router v6:每一个 API 都是怎么工作的
前端·javascript·全栈
李昊哲小课3 小时前
fastapi sse websocket 奶茶店实时订单看板
人工智能·python·websocket·网络协议·fastapi·sse
江南十四行4 小时前
Spring框架核心(上)——IoC控制反转与DI依赖注入详解
java·后端·spring
kyriewen4 小时前
别再这样写条件渲染了——你的React组件里藏着这5种定时炸弹
前端·javascript·react.js
IT_陈寒5 小时前
Redis缓存击穿把我坑惨了,原来这样设过期时间才靠谱
前端·人工智能·后端
梦想CAD控件5 小时前
网页端CAD的图形选择、编辑与夹点操作教程
前端·javascript·node.js