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

news2024/11/22 17:51:56

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

我初步研究通道先用的内存
在setting文件中
 

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels.layers.InMemoryChannelLayer",
    },
}

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

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

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

} 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);
            }
        }

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

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的内容实现了,也就是鼠标移动的部分

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了,增加了一点点服务器压力

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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2245468.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实验三:构建园区网(静态路由)

目录 一、实验简介 二、实验目的 三、实验需求 四、实验拓扑 五、实验任务及要求 1、任务 1:完成网络部署 2、任务 2:设计全网 IP 地址 3、任务 3:实现全网各主机之间的互访 六、实验步骤 1、在 eNSP 中部署网络 2、配置各主机 IP …

Figma插件指南:12款提升设计生产力的插件

在当今的设计领域,Figma已经成为许多UI设计师和团队的首选原型和数字设计软件。随着Figma的不断更新和插件库的扩展,这些工具极大地提升了设计工作的效率。本文将介绍12款实用的Figma插件,帮助你在UI设计中更加高效。 即时AI 即时AI利用先进…

解决IDEA报包不存在,但实际存在的问题

前言 最近在把一个亿老项目交割给同事,同事在导入项目运行时遇到IDEA报包不存在,但实际存在的问题,最终通过以下方式解决 现象 在IDEA里启动运行项目,报某个类有问题,引入的包不存在。 点击这个引入的包,可…

SemiDrive E3 硬件设计系列---唤醒电路设计

一、前言 E3 系列芯片是芯驰半导体高功能安全的车规级 MCU,对于 MCU 的硬件设计部分,本系列将会分模块进行讲解,旨在介绍 E3 系列芯片在硬件设计方面的注意事项与经验,本文主要讲解 E3 硬件设计中唤醒电路部分的设计。 二、RTC 模…

vue中路由缓存

vue中路由缓存 问题描述及截图解决思路关键代码及打印信息截图 问题描述及截图 在使用某一平台时发现当列表页码切换后点击某一卡片进入详情页后,再返回列表页时页面刷新了。这样用户每次看完详情回到列表页都得再重新输入自己的查询条件,或者切换分页到…

Qt桌面应用开发 第五天(常用控件 自定义控件)

目录 1.QPushButton和ToolButton 1.1QPushButton 1.2ToolButton 2.RadioButton和CheckBox 2.1RadioButton单选按钮 2.2CheckBox多选按钮 3.ListWidget 4.TreeWidget控件 5.TableWidget控件 6.Containers控件 6.1QScrollArea 6.2QToolBox 6.3QTabWidget 6.4QStacke…

android studio无法下载,Could not GET xxx, Received status code 400

-- 1. 使用下面的地址代替 原地址: distributionUrlhttps\://services.gradle.org/distributions/gradle-6.5-all.zip 镜像地址: distributionUrlhttps\://downloads.gradle-dn.com/distributions/gradle-6.5-all.zips 上面的已经不好用了 https\://mirrors.cloud.tencent.c…

【SpringBoot】【log】 自定义logback日志配置

前言:默认情况下,SpringBoot内部使用logback作为系统日志实现的框架,将日志输出到控制台,不会写到日志文件。如果在application.properties或application.yml配置,这样只能配置简单的场景,保存路径、日志格…

【FPGA开发】AXI-Full总线接口介绍、FPGA搭建仿真平台

文章目录 协议解读接口介绍AW—写地址通道W—写数据通道B—写响应通道AR—读地址通道R—读数据通道 FPGA搭建仿真平台 本文主要介绍AXI-FULL的相关基础内容,AXI-Lite请移步: 【FPGA开发】AXI-Lite总线协议解读、Verilog逻辑开发与仿真、Alex Forencich代…

网络安全,文明上网(1)享科技,提素养

前言 在这个信息化飞速发展的时代,科技的快速进步极大地丰富了我们的生活,并为我们提供了无限的可能性。然而,随着网络世界的不断扩张,增强我们的网络素养成为了一个迫切需要解决的问题。 与科技同行,培育网络素养 技术…

springboot基于Spring Boot的古城景区管理系统的设计与实现docx

摘 要 古城景区管理系统是一个集景区导游功能于一体的综合管理平台,旨在提升游客的参观体验和提高管理效率。系统通过提供详尽的热门景点、客房类型、酒店信息、美食类型、特色美食、文创产品及导游服务,使游客能够深入了解古城的历史与文化。该系统集成…

安装JDK

1、JDK下载 Java Downloads | Oracle 中国 确保从Oracle的官网下载最新的稳定版JDK: 选择合适的操作系统与安装包,找到Java SE 23的下载链接Download,下载安装即可。Windows优先选x64 MSI Installer。 安装过程直接双击下一步即可&#xf…

掌握移动端性能测试利器:深入JMeter手机录制功能

引言 在当今移动互联网时代,应用程序的性能和用户体验至关重要。为了确保应用程序在不同设备和网络环境下都能稳定运行,性能测试成为了不可或缺的一环。Apache JMeter作为一款强大的开源性能测试工具,不仅支持传统的PC端性能测试&#xff0c…

初始ArkUI

一. 什么是ArkUI ArkUI基于方舟UI框架为应用的UI开发提供了完整的基础设施,UI语法更加简洁,丰富的UI功能(组件、布局、动画以及交互事件),以及实现界面预览工具等,可以支持开发者进行可视化界面开发。 &a…

springboot基于数据挖掘的广州招聘可视化分析系统

摘 要 基于数据挖掘的广州招聘可视化分析系统是一个创新的在线平台,旨在通过深入分析大数据来优化和改善广州地区的招聘流程。系统利用Java语言、MySQL数据库,结合目前流行的 B/S架构,将广州招聘可视化分析管理的各个方面都集中到数据库中&a…

NuGet如何支持HTTP源

今天是2024年11月21号,最近更新了VisualStudio后发现HTTP的包源已经默认禁止使用了,生成时会直接报错。如下图: 官方也明确指出了要想使用HTTP包源的解决办法,这里就简单总结一下。 一、全局配置 1、全局NuGet包的配置文件路径在…

go 学习网站,go例子 go demo go学习视频

1. 代码例子: Go by Example 2. b站 视频: 尚硅谷视频: 004_尚硅谷_程序的基本概念_哔哩哔哩_bilibili 3. go技术文档: fmt Go语言中文文档

如何快速将Excel数据导入到SQL Server数据库

工作中,我们经常需要将Excel数据导入到数据库,但是对于数据库小白来说,这可能并非易事;对于数据库专家来说,这又可能非常繁琐。 这篇文章将介绍如何帮助您快速的将Excel数据导入到sql server数据库。 准备工作 这里&…

Spring Web入门练习

加法计算器 约定前后端交互接⼝ 约定 "前后端交互接⼝" 是进⾏ Web 开发中的关键环节. 接⼝⼜叫 API(Application Programming Interface), 我们⼀般讲到接⼝或者 API,指的都是同⼀个东西. 是指应⽤程序对外提供的服务的描述, ⽤于交换信息…

day26作业

1使用多线程基于TCP协议的并发执行&#xff0c;一个服务器对应多个客户端实现通信实验 #include <myhead.h> //主线程负责监听客户端连接请求 //子线程负责数据收发 #define IP "192.168.60.77" #define PORT 5555 #define BACKLOG 10 typedef struct {struct…