123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806 |
- /*eslint-disable*/
- /**
- * 用于处理websocket实时通讯使用
- */
- export class MyWebSocket {
- // 每次 new 出对象则会调用这个构造函数
- constructor() {
-
- // 端口号
- this.prot = 3000;
- // new出webSocket通讯对象
- this.objWebSocket = null;
- // webSocket 服务端ip
- this.ip = "127.0.0.1";
- // 如果是平时开发后,发布到服务器,域名访问,那么就用这个
- // this.ip = document.domain;
- // 用于触发重连的计时器
- this.webSocketRestConnectTime = null;
- // 记录当前进入的房间号
- this.room = null;
- // 记录当前自己的socketId值
- this.socketId = null;
- /**
- * 记录当前的userId,用户登陆后
- * 就会固定唯一的 userId, 之后就不会在改变
- * 这里的userId 可以是数据库的,没有数据库的
- * 可以用第一次登陆的 socketId 作为记录
- *
- * 用于后续统一通讯告诉大家例如角色,还是别的数据使用
- * 不会因为后续每次断开重连,导致 socketId 的变化
- * 而要重置已经存在在别的地方的渲染数据使用
- */
- this.userId = null;
- /**
- * 记录当前用户自己本身的参数
- */
- this.myConfig = null;
- // 昵称
- this.nickname = null;
- // 记录最后一次进入的房间号,用于后续触发重连的逻辑
- this.roomId = null;
- // 当断开连接,重置false,后面触发重连进入房间逻辑
- this.joinRoomBool = false;
- /**
- * 记录当前房间号的用户列表 json 结构
- * 每当用户进入,或者退出,该参数优先更新逻辑
- */
- this.roomListJson = {
- // "唯一cid" : "对应json数据",
- };
- /**
- * 记录当前房间号的用户列表
- * 对应 cid 的数据记录在 this.roomListJson
- */
- this.roomList = [];
- /**
- * 每当房间里发送变化的时候触发回调
- *
- * type 类型
- * roomUserExit 有用户退出
- * roomUserJoin 有用户加入
- * roomUserDbUpdate 用户数据发送了变化
- *
- * cidJson 加入或者退出的用户的 json数据
- * dbUpdate 当 type 是 roomUserDbUpdate 的时候,才有的参数回调,具体变化的字段数据
- *
- */
- this.roomUpdateCallback = null;
- /**
- * 每次房间里有群发消息的时候回调
- * cidJson 用户的 json数据
- * message 消息的内容
- */
- this.roomChatAllCallback = null;
- /**
- * 每次有其他用户单独发送消息给你回调
- * sendCidJson 发起消息用户的json数据
- * getCidJson 接收消息用户的json数据
- * message 消息内容
- */
- this.cidSendCallback = null;
- }
- // 实现单例模式
- static find() {
- if (!MyWebSocket.instance) {
- MyWebSocket.instance = new MyWebSocket();
- }
- return MyWebSocket.instance;
- }
-
- /**
- * webSocket 初始化连接
- * */
- webSocketInit = function() {
- let thisClass = this;
- // 只有是空的时候
- if (thisClass.objWebSocket == null || thisClass.objWebSocket == 'undefined') {
- var webSocketUrl = "ws://" + this.ip + ":" + this.prot;
- // 连接 webSocket
- thisClass.objWebSocket = new WebSocket(webSocketUrl);
- thisClass.webSocketEvent();
- }
- }
- /**
- * 断开后,自动触发重新连接通讯逻辑
- */
- webSocketRestConnect = function() {
- let thisClass = this;
- if (thisClass.webSocketRestConnectTime != null && thisClass.webSocketRestConnectTime != 'undefined') {
- return this;
- }
- if (thisClass.objWebSocket != null && thisClass.objWebSocket != 'undefined') {
- return this;
- }
- thisClass.joinRoomBool = false;
- thisClass.webSocketRestConnectTime = setInterval(function() {
- clearInterval(thisClass.webSocketRestConnectTime);
- thisClass.webSocketRestConnectTime = null;
- thisClass.webSocketInit();
- }, 1000);
- }
- /**
- * 连接成功后,调用该方法,设置 objWebSocket 的事件
- * */
- webSocketEvent = function() {
- let thisClass = this;
- /**
- * 实例对象的 onopen 属性
- * 当WebSocket客户端与服务器建立连接并完成握手后会回调此函数。
- * 参数 evt 就是 数据的返回
- * */
- thisClass.objWebSocket.onopen = function(evt) {
- console.log([ "连接成功", evt ]);
- }
- /**
- * 实例对象的 onmessage 属性
- * 当服务器收到来自客户端的数据帧时会回调此函数。
- * 参数 evt 就是 数据的返回
- * */
- thisClass.objWebSocket.onmessage = function(evt) {
- // console.log("onmessage 回调数据");
- // console.log(evt);
- // console.log(evt.data);
- thisClass.commonMessage(evt.data);
- }
- /**
- * 实例对象的 onclose 属性
- * 目标客户端id 退出关闭的时候,会触发该事件
- * 服务端关闭也会触发该事件
- * 参数 evt 就是 数据的返回
- * */
- thisClass.objWebSocket.onclose = function(evt) {
- // console.log("onclose 回调数据");
- // console.log(evt);
- // 此时将目标对象重置为null,方便后续重新连接
- thisClass.objWebSocket = null;
- thisClass.webSocketRestConnect();
- }
- /**
- * 报错的时候执行这里,例如连接失败
- * */
- thisClass.objWebSocket.onerror = function(evt, e) {
- // console.log("onerror 回调数据");
- // console.log(evt);
- // // console.log(evt.data);
- // 此时将目标对象重置为null,方便后续重新连接
- thisClass.objWebSocket = null;
- thisClass.webSocketRestConnect();
-
- }
- }
-
- /**
- * 统一处理接收到的消息
- * serverData 接收服务端的消息
- */
- commonMessage = function(serverData) {
- let thisClass = this;
- let json = {};
- try {
- json = JSON.parse(serverData);
- } catch(e) {
- return thisClass;
- }
- // console.log("commonMessage", json);
-
- // 当前是哪个cid发来的消息
- let cid = json["cid"];
- let data = json["data"];
- let dataType = data["type"];
- console.log("commonMessage", json, dataType, data);
- if (typeof dataType == "string") {
-
- switch (dataType) {
- // 心跳包的ping,用于验证用户是否还在正常连接,没有回复pong,则服务端强制退出
- case "ping":
- thisClass.commonSend("pong", "");
- break;
- // 第一次连接通讯后,服务端发来的消息
- case "login":
- thisClass.loginEvent(json);
- break;
- // 每次用户自己在服务器成功更新了哪些字段数据,则得到对应更新的字段数据
- case "myDbUpdate":
- thisClass.myDbUpdateEvent(json);
- // 如果自己已经加入过房间号,则自动再触发进入房间逻辑,实现重连后进入房间的逻辑
- if (
- thisClass.roomId != null && thisClass.roomId != undefined
- && thisClass.joinRoomBool == false
- ) {
- thisClass.joinRoom(room);
- }
- break;
- // 当房间里有新用户进入的时候,给当前房间号的所有用户发送消息
- case "roomUserJoin":
- thisClass.roomUserJoinEvent(json);
- break;
- // 当房间里有用户退出离开的时候的时候,给当前房间号的所有用户发送消息
- case "roomUserExit":
- thisClass.roomUserExitEvent(json);
- break;
- // 当房间里某个用户更新了数据字段的时候
- case "roomUserDbUpdate":
- thisClass.roomUserDbUpdateEvent(json);
- break;
- // 当前房间接收到聊天群发的消息
- case "roomChatAll":
- thisClass.roomChatAllEvent(json);
- break;
- // 给指定用户私聊
- case "cidSend":
- thisClass.cidSendEvent(json);
- break;
- }
- }
-
- return thisClass;
- }
-
- /**
- * 统一发送消息给服务端格式
- * 服务端会根据接收不同的类型,执行操作,例如更新用户数据,或者是群发消息,或者是进入房间,或者是给指定的用户单独发送消息等逻辑触发
- *
- * type 类型,不同的类型,会触发的逻辑不一样
- * upUser 更新当前用户的参数,例如昵称,或者坐标点
- * joinRoom 用户进入房间或者切换到另外一个房间
- * roomSendAll 房间里群发消息,房间里所有用户可以接收到消息,是一个通用的传输数据
- * 这里只做实时通讯消息发送,具体最后前端进行逻辑处理
- * cidSend 给指定用户私聊
- *
- * message 给服务端发送的消息,可以是字符串,也可以是json结构
- *
- * * */
- commonSend = function(type, message) {
- let thisClass = this;
- if (thisClass.objWebSocket == null || thisClass.objWebSocket == undefined) {
- return thisClass;
- }
- // 设置发送消息的时间戳,精确到毫秒
- let thisTime = new Date().getTime();
- // 消息传输统一格式,格式不正确则无法正常通讯
- var submitJson = {
- "type" : type,
- "message" : message,
- // // 客户端发送时间
- // "sendTime" : new Date().Format("yyyy-MM-dd hh:mm:ss"),
- "thisTime" : thisTime,
- };
- thisClass.objWebSocket.send(JSON.stringify(submitJson));
- return thisClass;
- }
- /**
- * 处理当前用户第一次登陆的时候的逻辑
- * json 接收服务端的参数
- */
- loginEvent = function(json) {
- let thisClass = this;
- // 当前是哪个cid发来的消息
- let cid = json["cid"];
- let data = json["data"];
-
- let dataMessage = data["message"];
- let dataMessageUserDb = dataMessage["userDb"];
- let dataMessageUserDbCid = dataMessageUserDb["cid"];
-
- thisClass.socketId = dataMessageUserDbCid;
- if (thisClass.userId == null || thisClass.userId == undefined) {
- thisClass.userId = dataMessageUserDbCid;
- }
- thisClass.myConfig = dataMessageUserDb;
- // console.log(
- // thisClass.socketId,
- // thisClass.myConfig,
- // thisClass.userId
- // );
- thisClass.loginUserUpdate();
-
- return thisClass;
- }
- /**
- * 登陆后,先更新初始的用户数据
- */
- loginUserUpdate = function() {
- let thisClass = this;
-
- thisClass.commonSend(
- "upUser",
- {
- "name" : thisClass.nickname,
- "userId" : thisClass.userId,
- }
- );
- return thisClass;
- }
- /**
- * 每次用户自己在服务器成功更新了哪些字段数据,则得到对应更新的字段数据
- * json
- */
- myDbUpdateEvent = function(json) {
- let thisClass = this;
- // 当前是哪个cid发来的消息
- let cid = json["cid"];
- let data = json["data"];
-
- let dataMessage = data["message"];
- let updateJson = dataMessage["updateJson"];
-
- // 更新的字段数据
- for (let key in updateJson) {
- let val = updateJson[key];
- thisClass.myConfig[key] = val;
- }
-
- return thisClass;
- }
-
- /**
- * 进入房间
- * room 房间号
- */
- joinRoom = function(room) {
-
- let thisClass = this;
- if (thisClass.userId == null && thisClass.userId == undefined) {
- console.log("连接通讯后请先更新 userId 字段才可进入房间");
- return;
- }
-
- var submitJson = {
- "roomId" : room,
- };
- thisClass.roomId = room;
- thisClass.commonSend(
- "joinRoom",
- submitJson
- );
- thisClass.joinRoomBool = true;
- return thisClass;
- }
- /**
- * 当房间里有新用户进入的时候,给当前房间号的所有用户发送消息
- * json
- */
- roomUserJoinEvent = function(json) {
- let thisClass = this;
-
- // 当前是哪个cid发来的消息
- let cid = json["cid"];
- let data = json["data"];
-
- let dataMessage = data["message"];
-
- // 此时是该cid进入房间
- let sendCid = dataMessage["sendCid"];
- // 得到当前房间列表的所有用户信息
- let roomList = dataMessage["message"];
- // 加入用户的数据
- let joinUser = null;
- // 循环更新对应房间数据
- for (let i = 0; i < roomList.length; i++) {
- let objRoomList = roomList[i];
- let objRoomListCid = objRoomList["cid"];
- // 此时说明是该用户加入的房间
- if (objRoomListCid == sendCid) {
- // console.log("用户加入房间", objRoomList);
- joinUser = objRoomList;
- }
-
- thisClass.roomListJson[objRoomListCid] = objRoomList;
- }
- // 更新房间列表用户数据
- thisClass.roomList = roomList;
- if (thisClass.roomUpdateCallback != null && thisClass.roomUpdateCallback != undefined) {
- thisClass.roomUpdateCallback("roomUserJoin", joinUser, null);
- }
-
- return thisClass;
- }
- /**
- * 当房间里有用户退出离开的时候的时候,给当前房间号的所有用户发送消息
- * json
- */
- roomUserExitEvent = function(json) {
- let thisClass = this;
- // 当前是哪个cid发来的消息
- let cid = json["cid"];
- let data = json["data"];
-
- let dataMessage = data["message"];
- // 此时是该cid退出房间
- let sendCid = dataMessage["sendCid"];
- // 得到当前房间列表的所有用户信息
- let roomList = dataMessage["message"];
- // 循环更新对应房间数据
- for (let i = 0; i < roomList.length; i++) {
- let objRoomList = roomList[i];
- let objRoomListCid = objRoomList["cid"];
- thisClass.roomListJson[objRoomListCid] = objRoomList;
- }
- // 更新房间列表用户数据
- thisClass.roomList = roomList;
-
- // 退出的用户数据
- let userExit = null;
- // 找到哪个用户退出
- if (thisClass.roomListJson[sendCid] != null && thisClass.roomListJson[sendCid] != undefined) {
- // 这里进行一个转换,让它变成独立的对象
- userExit = JSON.parse(JSON.stringify(thisClass.roomListJson[sendCid]));
- // console.log("用户退出房间", userExit);
- // 退出用户的数据清除
- thisClass.roomListJson[sendCid] = null;
- delete thisClass.roomListJson[sendCid];
- }
- if (thisClass.roomUpdateCallback != null && thisClass.roomUpdateCallback != undefined) {
- thisClass.roomUpdateCallback("roomUserExit", userExit, null);
- }
-
- return thisClass;
- }
- /**
- * 当房间里某个用户更新了数据字段的时候
- * json
- */
- roomUserDbUpdateEvent = function(json) {
- let thisClass = this;
- // 当前是哪个cid发来的消息
- let cid = json["cid"];
- let data = json["data"];
- let dataMessage = data["message"];
- // 此时是该cid更新的字段数据
- let sendCid = dataMessage["sendCid"];
- // 更新了哪些字段数据
- let dbUpdate = dataMessage["message"];
- console.log(
- "当房间里某个用户更新了数据字段的时候 roomUserDbUpdateEvent ",
- // json,
- sendCid,
- dbUpdate,
- // this.roomListJson,
- // this.roomList
- );
-
- let dbUpdateUserId = null;
- // 如果更新的字段带有 userId
- if (dbUpdate["userId"] != null && dbUpdate["userId"] != null) {
- dbUpdateUserId = dbUpdate["userId"];
- }
- // 找到被更新的用户数据
- let updateUser = null;
- // 循环房间的所有数据
- for (let i = 0; i < this.roomList.length; i++) {
- let objRoomList = this.roomList[i];
- let objRoomListCid = objRoomList["cid"];
- let objRoomListUserId = objRoomList["userId"];
- // console.log(
- // "roomUserDbUpdateEvent objRoomList ===》", objRoomList
- // );
- // 是否找到
- let objBool = false;
- // 优先以 userId 进行寻找对象
- if (
- dbUpdateUserId != null && dbUpdateUserId != undefined
- && dbUpdateUserId == objRoomListUserId
- ) {
- objBool = true;
- } else if (objRoomListCid == sendCid) {
- objBool = true;
- }
- if (objBool == true) {
- // console.log(
- // "roomUserDbUpdateEvent objBool ===》", objRoomList
- // );
- // 开始更新对应的字段数据
- for (var key in dbUpdate) {
- objRoomList[key] = dbUpdate[key];
- }
- // 更新指定目标cid的用户相关数据
- if (this.roomListJson[objRoomListCid] != null && this.roomListJson[objRoomListCid] != undefined) {
- // 开始更新对应的字段数据
- for (var key in dbUpdate) {
- this.roomListJson[objRoomListCid][key] = dbUpdate[key];
- }
- }
- updateUser = objRoomList;
- }
-
- }
- // console.log(
- // "roomUserDbUpdateEvent ===》", this.roomListJson, this.roomList
- // );
- if (thisClass.roomUpdateCallback != null && thisClass.roomUpdateCallback != undefined) {
- thisClass.roomUpdateCallback("roomUserDbUpdate", updateUser, dbUpdate);
- }
-
- return thisClass;
- }
- /**
- * 给当前自己所在房间号发送消息
- * type 自定义类型,该类型你定义的是什么,在返回的房间里,就会返回什么类型
- * 如果你是通知所有房间群发聊天填写 chatAll
- * 否则你填写别的类型,然后再根据这个类型,单独处理逻辑
- *
- * message 给服务端发送的消息,可以是字符串,也可以是json结构
- * 该参数后续根据 type 参数,来配合开发新的逻辑
- * 例如我填写 type = chatAll , 该参数就传字符串聊天的内容
- * 如果传别的类型,可以传json结构,然后通过该接收的消息,进行特殊处理别的逻辑
- */
- roomSend = function(type, message) {
- let thisClass = this;
- if (this.myConfig == null || this.myConfig == undefined) {
- return thisClass;
- }
- if (this.myConfig["roomId"] == null || this.myConfig["roomId"] == undefined) {
- return thisClass;
- }
- let roomId = this.myConfig["roomId"];
- // console.log("roomSend myConfig", this.myConfig, type, message, roomId);
- let submit = {
- "roomId" : roomId,
- "type" : type,
- "content" : message,
- };
-
- thisClass.commonSend("roomSendAll", submit);
- return thisClass;
- }
- /**
- * 给指定cid私聊发送消息
- * type 自定义类型,该类型你定义的是什么,就会返回什么类型
- * 如果你是单独处理聊天则填写 chat
- * 否则你填写别的类型,然后再根据这个类型,单独处理逻辑
- *
- * cid 跟对方私聊的cid值
- *
- * message 给服务端发送的消息,可以是字符串,也可以是json结构
- * 该参数后续根据 type 参数,来配合开发新的逻辑
- * 例如我填写 type = chat , 该参数就传字符串聊天的内容
- * 如果传别的类型,可以传json结构,然后通过该接收的消息,进行特殊处理别的逻辑
- */
- cidSend = function(type, cid, message) {
- let thisClass = this;
- let submit = {
- "cid" : cid,
- "type" : type,
- "content" : message,
- };
-
- thisClass.commonSend("cidSend", submit);
- return thisClass;
- }
- /**
- * 当前房间接收到聊天群发的消息
- * json
- */
- roomChatAllEvent = function(json) {
- let thisClass = this;
- // console.log("roomChatAllEvent", json);
- let cid = json["cid"];
- let data = json["data"];
- let dataMessage = data["message"];
- let dataMessageSendCid = dataMessage["sendCid"];
- let dataMessageMessage = dataMessage["message"];
-
- // console.log("roomChatAllEvent", dataMessageSendCid, dataMessageMessage);
- if (thisClass.roomListJson[dataMessageSendCid] == null || thisClass.roomListJson[dataMessageSendCid] == undefined) {
- return thisClass;
- }
- let cidJson = thisClass.roomListJson[dataMessageSendCid];
- if (typeof thisClass.roomChatAllCallback == 'function') {
- thisClass.roomChatAllCallback(cidJson, dataMessageMessage);
- }
- return thisClass;
- }
-
- /**
- * 给指定用户发送消息
- * json
- */
- cidSendEvent = function(json) {
- let thisClass = this;
- // console.log( "cidSendEvent", json );
- let cid = json["cid"];
- let data = json["data"];
- let dataMessage = data["message"];
- // 哪个cid发起的
- let dataMessageSendCid = dataMessage["sendCid"];
- // 接收消息的cid
- let dataMessageGetCid = dataMessage["getCid"];
- let dataMessageSubmitJson = dataMessage["submitJson"];
- let dataMessageSubmitJsonMessage = dataMessageSubmitJson["message"];
-
- if (thisClass.roomListJson[dataMessageSendCid] == null || thisClass.roomListJson[dataMessageSendCid] == undefined) {
- return thisClass;
- }
- if (thisClass.roomListJson[dataMessageGetCid] == null || thisClass.roomListJson[dataMessageGetCid] == undefined) {
- return thisClass;
- }
- let sendCidJson = thisClass.roomListJson[dataMessageSendCid];
- let getCidJson = thisClass.roomListJson[dataMessageGetCid];
- // console.log(
- // "cidSendEvent",
- // dataMessageSendCid,
- // dataMessageSubmitJson,
- // dataMessageSubmitJsonMessage,
- // dataMessageGetCid,
- // sendCidJson,
- // getCidJson
- // );
- if (typeof thisClass.cidSendCallback == 'function') {
- thisClass.cidSendCallback(sendCidJson, getCidJson, dataMessageSubmitJsonMessage);
- }
- return thisClass;
- }
-
- }
|