diff --git a/doc/gitbook/FEATURE_LIST.md b/doc/gitbook/FEATURE_LIST.md new file mode 100644 index 0000000..947a124 --- /dev/null +++ b/doc/gitbook/FEATURE_LIST.md @@ -0,0 +1 @@ +# 待完善补充... \ No newline at end of file diff --git a/doc/gitbook/SETTING.md b/doc/gitbook/SETTING.md index 1866cc8..b55c2fd 100644 --- a/doc/gitbook/SETTING.md +++ b/doc/gitbook/SETTING.md @@ -40,6 +40,10 @@ chatgpt聊天框的对话上下文的简单处理。 开启设置后,你创建的房间,同一个局域网用户进入网页后将看到你创建的房间。 +### 系统通知 (开发中) 【此设置刷新网页后有效,长久保存】 + +开启设置后,当收到消息或者提示时,会使用浏览器自带的桌面消息提示,进行及时的音效,横幅提示 + ### 文件分片传输大小 【此开关刷新网页后失效,需重新设置】 由于网站的文件传输是分片传输,但是由于webrtc的数据传输通道有限制,所以项目提供了一个合理范围的可选项,用于自定义控制每次webrtc的数据通道发送数据时的分片大小。默认是 16KB,最大可调整到64KB(不同浏览器实现可能不同,16~64是我认为比较合适的可选范围) diff --git a/doc/gitbook/SUMMARY.md b/doc/gitbook/SUMMARY.md index 39d7553..d8dc309 100644 --- a/doc/gitbook/SUMMARY.md +++ b/doc/gitbook/SUMMARY.md @@ -22,50 +22,150 @@ * [配置简要说明](ENV_SETTING.md) + * [主要功能](FEATURE_LIST.md) + + * [发送文字](FEATURE_LIST.md) + + * [公共聊天](FEATURE_LIST.md) + + * [群聊](FEATURE_LIST.md) + + * [私聊](FEATURE_LIST.md) + + * [文字复制](FEATURE_LIST.md) + + * [富文本](FEATURE_LIST.md) + + * [图片](FEATURE_LIST.md) + + * [表情](FEATURE_LIST.md) + + * [发送文件](FEATURE_LIST.md) + + * [群发](FEATURE_LIST.md) + + * [私发](FEATURE_LIST.md) + + * [排队发](FEATURE_LIST.md) + + * [同时发](FEATURE_LIST.md) + + * [多文件拖拽](FEATURE_LIST.md) + + * [indexedDb存储](FEATURE_LIST.md) + + * [在线文件预览](FEATURE_LIST.md) + + * [文件暂存](FEATURE_LIST.md) + + * [自定义文件分片大小](FEATURE_LIST.md) + + * [自定义文件预览大小](FEATURE_LIST.md) + + * [屏幕共享](FEATURE_LIST.md) + + * [多人共享](FEATURE_LIST.md) + + * [屏幕开关](FEATURE_LIST.md) + + * [音频开关](FEATURE_LIST.md) + + * [视频通话](FEATURE_LIST.md) + + * [多人视频](FEATURE_LIST.md) + + * [视频开关](FEATURE_LIST.md) + + * [摄像头切换](FEATURE_LIST.md) + + * [音频开关](FEATURE_LIST.md) + + * [开始直播](FEATURE_LIST.md) + + * [视频直播](FEATURE_LIST.md) + + * [屏幕直播](FEATURE_LIST.md) + + * [视频开关](FEATURE_LIST.md) + + * [摄像头切换](FEATURE_LIST.md) + + * [音频开关](FEATURE_LIST.md) + + * [开播端](FEATURE_LIST.md) + + * [观众端](FEATURE_LIST.md) + + * [语音连麦](FEATURE_LIST.md) + + * [音频开关](FEATURE_LIST.md) + + * [取件号码](FEATURE_LIST.md) + + * [文件下载](FEATURE_LIST.md) + + * [远程画笔](FEATURE_LIST.md) + + * [多人画笔同步](FEATURE_LIST.md) + + * [密码房间](FEATURE_LIST.md) + + * [自定义密码](FEATURE_LIST.md) + + * [屏幕录制](FEATURE_LIST.md) + + * [录制文件下载](FEATURE_LIST.md) + + * [chatGPT](FEATURE_LIST.md) + + * [次要功能](FEATURE_LIST.md) + + * [多语言版本](FEATURE_LIST.md) + + * [微信扫码登录](FEATURE_LIST.md) + + * [分享房间](FEATURE_LIST.md) + + * [网站通知](FEATURE_LIST.md) + + * [日志记录](FEATURE_LIST.md) + + * [自定义日志数量限制](FEATURE_LIST.md) + + * [中继设置](FEATURE_LIST.md) + + * [自定义昵称](FEATURE_LIST.md) + + * [在线人数统计](FEATURE_LIST.md) + + * [消息红点开关](FEATURE_LIST.md) + + * [固定房间号](FEATURE_LIST.md) + + * [局域网房间扫描](FEATURE_LIST.md) + + * [自定义socket地址](FEATURE_LIST.md) + + * [后台管理统计](FEATURE_LIST.md) + + * [后台开关设置](FEATURE_LIST.md) + + * [敏感词过滤](FEATURE_LIST.md) + + * [心跳检测](FEATURE_LIST.md) + + * [webrtc连接展示](FEATURE_LIST.md) + + + * [tl-rtc-file-开发手册](README_DEV.md) * [设计简介](dev/INTRO.md) - * [客户端](dev/client/CLIENT.md) - - * [文字聊天](dev/client/CHAT.md) - - * [文件传输](dev/client/FILE.md) - - * [多人音视频](dev/client/VIDEO.md) - - * [多人屏幕共享](dev/client/SCREEN.md) - - * [单人直播](dev/client/LIVE.md) - - * [多人语音](dev/client/AUDIO.md) - - * [文件暂存/取件码](dev/client/FILE_CODE.md) - - * [多人画笔](dev/client/DRAW.md) - - * [屏幕录制](dev/client/RECODE.md) + * [客户端](dev/CLIENT.md) * [服务端](dev/SVR.md) - * [文字聊天](dev/svr/CHAT.md) - - * [文件传输](dev/svr/FILE.md) - - * [多人音视频](dev/svr/VIDEO.md) - - * [多人屏幕共享](dev/svr/SCREEN.md) - - * [单人直播](dev/svr/LIVE.md) - - * [多人语音](dev/svr/AUDIO.md) - - * [文件暂存/取件码](dev/svr/FILE_CODE.md) - - * [多人画笔](dev/svr/DRAW.md) - - * [屏幕录制](dev/svr/RECODE.md) - * [tl-rtc-file-设置选项说明](SETTING.md) * [tl-rtc-file-常见问题列表](FAQ.md) diff --git a/doc/gitbook/dev/INTRO.md b/doc/gitbook/dev/INTRO.md index 9110c94..71c9f5d 100644 --- a/doc/gitbook/dev/INTRO.md +++ b/doc/gitbook/dev/INTRO.md @@ -1 +1,2 @@ -# 项目设计简介 \ No newline at end of file +# 项目简介 + diff --git a/doc/gitbook/dev/client/AUDIO.md b/doc/gitbook/dev/client/AUDIO.md deleted file mode 100644 index 8378b8b..0000000 --- a/doc/gitbook/dev/client/AUDIO.md +++ /dev/null @@ -1 +0,0 @@ -# 多人语音 \ No newline at end of file diff --git a/doc/gitbook/dev/client/CHAT.md b/doc/gitbook/dev/client/CHAT.md deleted file mode 100644 index 80bca23..0000000 --- a/doc/gitbook/dev/client/CHAT.md +++ /dev/null @@ -1 +0,0 @@ -# 文字聊天 \ No newline at end of file diff --git a/doc/gitbook/dev/client/DRAW.md b/doc/gitbook/dev/client/DRAW.md deleted file mode 100644 index e536004..0000000 --- a/doc/gitbook/dev/client/DRAW.md +++ /dev/null @@ -1 +0,0 @@ -# 多人画笔 \ No newline at end of file diff --git a/doc/gitbook/dev/client/FILE.md b/doc/gitbook/dev/client/FILE.md deleted file mode 100644 index 38e9a87..0000000 --- a/doc/gitbook/dev/client/FILE.md +++ /dev/null @@ -1 +0,0 @@ -# 文件传输 \ No newline at end of file diff --git a/doc/gitbook/dev/client/FILE_CODE.md b/doc/gitbook/dev/client/FILE_CODE.md deleted file mode 100644 index 6ceb9fa..0000000 --- a/doc/gitbook/dev/client/FILE_CODE.md +++ /dev/null @@ -1 +0,0 @@ -# 文件暂存/取件码 \ No newline at end of file diff --git a/doc/gitbook/dev/client/LIVE.md b/doc/gitbook/dev/client/LIVE.md deleted file mode 100644 index 946e2e5..0000000 --- a/doc/gitbook/dev/client/LIVE.md +++ /dev/null @@ -1 +0,0 @@ -# 单人直播 \ No newline at end of file diff --git a/doc/gitbook/dev/client/RECODE.md b/doc/gitbook/dev/client/RECODE.md deleted file mode 100644 index 1dbae2a..0000000 --- a/doc/gitbook/dev/client/RECODE.md +++ /dev/null @@ -1 +0,0 @@ -# 屏幕录制 \ No newline at end of file diff --git a/doc/gitbook/dev/client/SCREEN.md b/doc/gitbook/dev/client/SCREEN.md deleted file mode 100644 index 76cbd32..0000000 --- a/doc/gitbook/dev/client/SCREEN.md +++ /dev/null @@ -1 +0,0 @@ -# 多人屏幕共享 \ No newline at end of file diff --git a/doc/gitbook/dev/client/VIDEO.md b/doc/gitbook/dev/client/VIDEO.md deleted file mode 100644 index 04727ad..0000000 --- a/doc/gitbook/dev/client/VIDEO.md +++ /dev/null @@ -1 +0,0 @@ -# 多人音视频 \ No newline at end of file diff --git a/doc/gitbook/dev/svr/AUDIO.md b/doc/gitbook/dev/svr/AUDIO.md deleted file mode 100644 index 8378b8b..0000000 --- a/doc/gitbook/dev/svr/AUDIO.md +++ /dev/null @@ -1 +0,0 @@ -# 多人语音 \ No newline at end of file diff --git a/doc/gitbook/dev/svr/CHAT.md b/doc/gitbook/dev/svr/CHAT.md deleted file mode 100644 index 80bca23..0000000 --- a/doc/gitbook/dev/svr/CHAT.md +++ /dev/null @@ -1 +0,0 @@ -# 文字聊天 \ No newline at end of file diff --git a/doc/gitbook/dev/svr/DRAW.md b/doc/gitbook/dev/svr/DRAW.md deleted file mode 100644 index e536004..0000000 --- a/doc/gitbook/dev/svr/DRAW.md +++ /dev/null @@ -1 +0,0 @@ -# 多人画笔 \ No newline at end of file diff --git a/doc/gitbook/dev/svr/FILE.md b/doc/gitbook/dev/svr/FILE.md deleted file mode 100644 index 38e9a87..0000000 --- a/doc/gitbook/dev/svr/FILE.md +++ /dev/null @@ -1 +0,0 @@ -# 文件传输 \ No newline at end of file diff --git a/doc/gitbook/dev/svr/FILE_CODE.md b/doc/gitbook/dev/svr/FILE_CODE.md deleted file mode 100644 index 6ceb9fa..0000000 --- a/doc/gitbook/dev/svr/FILE_CODE.md +++ /dev/null @@ -1 +0,0 @@ -# 文件暂存/取件码 \ No newline at end of file diff --git a/doc/gitbook/dev/svr/LIVE.md b/doc/gitbook/dev/svr/LIVE.md deleted file mode 100644 index 946e2e5..0000000 --- a/doc/gitbook/dev/svr/LIVE.md +++ /dev/null @@ -1 +0,0 @@ -# 单人直播 \ No newline at end of file diff --git a/doc/gitbook/dev/svr/RECODE.md b/doc/gitbook/dev/svr/RECODE.md deleted file mode 100644 index 1dbae2a..0000000 --- a/doc/gitbook/dev/svr/RECODE.md +++ /dev/null @@ -1 +0,0 @@ -# 屏幕录制 \ No newline at end of file diff --git a/doc/gitbook/dev/svr/SCREEN.md b/doc/gitbook/dev/svr/SCREEN.md deleted file mode 100644 index 76cbd32..0000000 --- a/doc/gitbook/dev/svr/SCREEN.md +++ /dev/null @@ -1 +0,0 @@ -# 多人屏幕共享 \ No newline at end of file diff --git a/doc/gitbook/dev/svr/VIDEO.md b/doc/gitbook/dev/svr/VIDEO.md deleted file mode 100644 index 04727ad..0000000 --- a/doc/gitbook/dev/svr/VIDEO.md +++ /dev/null @@ -1 +0,0 @@ -# 多人音视频 \ No newline at end of file diff --git a/svr/conf/cfg.json b/svr/conf/cfg.json index 4cfff82..e82c6ba 100644 --- a/svr/conf/cfg.json +++ b/svr/conf/cfg.json @@ -1,5 +1,5 @@ { - "version": "10.5.0", + "version": "10.5.1", "socket": { "port": "请到 tlrtcfile.env 中进行配置", "host": "请到 tlrtcfile.env 中进行配置" diff --git a/svr/src/controller/login/login.js b/svr/src/controller/login/login.js index b2cb51d..0a3d2b3 100644 --- a/svr/src/controller/login/login.js +++ b/svr/src/controller/login/login.js @@ -5,6 +5,7 @@ const bussinessNotify = require("./../../bussiness/notify/notifyHandler") const wxapi = require("./../../bussiness/wxapi/wxapi") const { CookieKey } = require("./../../bussiness/cache/key") const scanCache = require("./../../bussiness/cache/scan/scanCache") +const utils = require("../../utils/utils"); const uuid = require("uuid") // 扫码状态 @@ -39,13 +40,14 @@ async function loginWechat(req, res) { const { session_key, openid, unionid } = openIdInfo; - const userId = await user.addWxUser({ + const { userId, flag } = await user.addWxUser({ openid: openid, avatar: userInfo.avatarUrl, uname: userInfo.nickName, pwd: '', solt: '', role: 'user', + flag : 0, }, tables, dbClient); //设置登录信息缓存 @@ -55,6 +57,7 @@ async function loginWechat(req, res) { userId : userId, avatar : userInfo.avatarUrl, nickName : userInfo.nickName, + flag : flag, loginTime : Date.now(), }); @@ -226,10 +229,15 @@ async function getTokenState(req, res){ const loginInfo = scanCache.getLoginInfo(token); const avatar = loginInfo.avatar || "/image/44826979.png"; - const username = loginInfo.nickName || ""; + const username = loginInfo.nickName || " -- "; + const flag = loginInfo.flag || 0; + const subscribeNotify = utils.checkBit(flag, req.ctx.tables.UserOther.Flag.IS_SUBSCRIBE_WEBSITE_NOTIFY) if(Object.keys(loginInfo).length > 0){ - res.json({ code: 200, login: true, token, avatar, username }); + res.json({ + code: 200, login: true, loginInfo, + token, avatar, username, subscribeNotify + }); }else{ res.json({ code: 200, login: false }); } @@ -276,7 +284,10 @@ async function getLoginInfo(req, res){ const loginInfo = scanCache.getLoginInfo(token); - res.json({ code: 200, userId : loginInfo.userId }); + res.json({ code: 200, userInfo :{ + userId : loginInfo.userId, + flag : loginInfo.flag, + }}); } diff --git a/svr/src/dao/user/user.js b/svr/src/dao/user/user.js index fed9b79..012665c 100644 --- a/svr/src/dao/user/user.js +++ b/svr/src/dao/user/user.js @@ -39,14 +39,14 @@ async function addWxUser(params, tables, dbClient) { role: params.role, }); - return data && data.dataValues ? data.dataValues.id : 0; + return data && data.dataValues ? dataValues : { id : 0 }; } if(users && users.length === 1){ - return users[0].dataValues.id; + return users[0].dataValues; } - return 0; + return { id : 0 }; }catch(e){ console.error(e); return {}; @@ -54,11 +54,46 @@ async function addWxUser(params, tables, dbClient) { } +/** + * 更新用户标识 + * @param {*} params + * @param {*} tables + * @param {*} dbClient + */ +async function updateUserFlag(params, tables, dbClient){ + if(!tables || !dbClient){ + return {}; + } + + if(!params){ + params = {}; + } + + if(!params.id){ + return {}; + } + + let data = await tables.User.update({ + flag: params.flag, + }, { + where: { + id: params.id + } + }); + + utils.tlConsole("更新用户标识 : ", params, data) + + return data; +} + module.exports = dbOpen ? { - addWxUser + addWxUser, updateUserFlag } : { addWxUser : function(){ return {} + }, + updateUserFlag : function(){ + return {} } } \ No newline at end of file diff --git a/svr/src/socket/connect.js b/svr/src/socket/connect.js index a76dd93..c566b2d 100644 --- a/svr/src/socket/connect.js +++ b/svr/src/socket/connect.js @@ -20,6 +20,7 @@ const rtcHeartbeat = require("./rtcHeartbeat/heartbeat"); const rtcAddCodeFile = require("./rtcCodeFile/addCodeFile"); const rtcGetCodeFile = require("./rtcCodeFile/getCodeFile"); const rtcLocalNetRoom = require("./rtcLocalNetRoom/localNetRoom"); +const rtcSubscribe = require("./rtcSubscribe/subscribe"); const rtcServerEvent = require("./rtcConstant").rtcServerEvent const rtcToken = require("./rtcToken/token") @@ -32,11 +33,6 @@ module.exports = (io, socket, tables, dbClient) => { // 在线人数统计 rtcCount.count(io, socket, tables, dbClient, {}) - // 局域网房间发现列表 - rtcLocalNetRoom.localNetRoom(io, socket, tables, dbClient, { - toCurrentSocket : true - }) - // 断开连接 socket.on(rtcServerEvent.disconnect, (data)=>{ rtcDisConnect.disconnect(io, socket, tables, dbClient, data) @@ -141,4 +137,14 @@ module.exports = (io, socket, tables, dbClient) => { socket.on(rtcServerEvent.changeNickName, (data) => { rtcChangeNickName.changeNickName(io, socket, tables, dbClient, data) }); + + // 订阅网站通知 + socket.on(rtcServerEvent.subscribeNofity, (data) => { + rtcSubscribe.subscribeNofity(io, socket, tables, dbClient, data) + }); + + // 局域网房间发现列表 + socket.on(rtcServerEvent.localNetRoom, (data)=>{ + rtcLocalNetRoom.localNetRoomForConnect(io, socket, tables, dbClient, data) + }); } \ No newline at end of file diff --git a/svr/src/socket/rtcConstant.js b/svr/src/socket/rtcConstant.js index 18ba6ce..40a50fa 100644 --- a/svr/src/socket/rtcConstant.js +++ b/svr/src/socket/rtcConstant.js @@ -48,6 +48,10 @@ const rtcServerEvent = { heartbeat : "heartbeat", //修改昵称 changeNickName : "changeNickName", + //订阅网站通知 + subscribeNofity : "subscribeNofity", + //局域网房间发现列表 + localNetRoom : "localNetRoom", } /** @@ -84,7 +88,7 @@ let rtcServerMessageEvent = { //开始远程画笔 startRemoteDraw : "startRemoteDraw", //结束远程画笔 - stopRemoteDraw : "stopRemoteDraw", + stopRemoteDraw : "stopRemoteDraw" } /** @@ -134,6 +138,8 @@ let rtcClientEvent = { changeNickName : "changeNickName", //局域网房间发现列表 localNetRoom : "localNetRoom", + //订阅网站通知 + subscribeNofity : "subscribeNofity" } /** diff --git a/svr/src/socket/rtcCount/count.js b/svr/src/socket/rtcCount/count.js index fca8bf5..a6f873b 100644 --- a/svr/src/socket/rtcCount/count.js +++ b/svr/src/socket/rtcCount/count.js @@ -1,7 +1,6 @@ const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent const utils = require("../../../src/utils/utils"); -const rtcLocalNetRoom = require("../rtcLocalNetRoom/localNetRoom"); /** * 在线人数统计广播 @@ -18,11 +17,6 @@ async function count(io, socket, tables, dbClient, data){ io.sockets.emit(rtcClientEvent.count, { mc : allManCount }) - - rtcLocalNetRoom.localNetRoom(io, socket, tables, dbClient, { - toAll : true - }); - }catch(e){ utils.tlConsole(e) } diff --git a/svr/src/socket/rtcCreateJoin/createJoin.js b/svr/src/socket/rtcCreateJoin/createJoin.js index adaaf68..93ee6c6 100644 --- a/svr/src/socket/rtcCreateJoin/createJoin.js +++ b/svr/src/socket/rtcCreateJoin/createJoin.js @@ -21,12 +21,12 @@ const rtcLocalNetRoom = require("../rtcLocalNetRoom/localNetRoom"); * @returns */ async function userCreateAndJoin(io, socket, tables, dbClient, data){ - let {handshake, userAgent, ip, address} = utils.getSocketClientInfo(socket); + let { handshake, userAgent, ip, address } = utils.getSocketClientInfo(socket); let { room = '', type = 'file', nickName = '', password = '', langMode = 'zh', ua = '', network = '', liveShareRole = '', - localNetRoom = false + localNetRoom = false, ips = [] } = data; if (room && room.length > 15) { @@ -66,7 +66,7 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){ io.sockets.connected[socket.id].langMode = langMode; io.sockets.connected[socket.id].ua = ua; io.sockets.connected[socket.id].network = network; - io.sockets.connected[socket.id].ip = ip; + io.sockets.connected[socket.id].ips = ips; const joinTime = utils.formateDateTime(new Date(), "yyyy-MM-dd hh:mm:ss") io.sockets.connected[socket.id].joinTime = joinTime; io.sockets.connected[socket.id].userAgent = userAgent; @@ -120,26 +120,25 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){ }); //设置为房主 io.sockets.connected[socket.id].owner = true; + io.sockets.adapter.rooms[room].owner = socket.id; - //设置房主ip为房间号ip, address - io.sockets.adapter.rooms[room].ip = ip; - io.sockets.adapter.rooms[room].address = address; - - //房间是否可以被局域网发现 - io.sockets.adapter.rooms[room].localNetRoom = localNetRoom; - if(localNetRoom){ - rtcLocalNetRoom.localNetRoom(io, socket, tables, dbClient, { - toAll : true - }); - } + //设置房主上报的ip为房间号ip + io.sockets.adapter.rooms[room].ips = ips; //设置房间类型 io.sockets.adapter.rooms[room].type = type; + + //房间是否可以被局域网发现 + io.sockets.adapter.rooms[room].localNetRoom = localNetRoom; //密码房间设置密码 if(type === 'password'){ io.sockets.adapter.rooms[room].password = password } + + //房间创建时间 + io.sockets.adapter.rooms[room].createTime = utils.formateDateTime(new Date(), "yyyy-MM-dd hh:mm:ss"); + }else { //加入时,房间类型不匹配,提示并退出 const createdRoomType = io.sockets.adapter.rooms[room].type; @@ -244,9 +243,11 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){ }); } + //人数变更通知 rtcCount.count(io, socket, tables, dbClient, data); - io.sockets.adapter.rooms[room].createTime = utils.formateDateTime(new Date(), "yyyy-MM-dd hh:mm:ss") + //局域网房间变动通知 + rtcLocalNetRoom.localNetRoomForJoin(io, socket, tables, dbClient, { room }); if(password && password.length > 0){ bussinessNotify.sendCreateJoinPasswordRoomNotify({ diff --git a/svr/src/socket/rtcDisConnect/disconnect.js b/svr/src/socket/rtcDisConnect/disconnect.js index ca112fc..0df1f70 100644 --- a/svr/src/socket/rtcDisConnect/disconnect.js +++ b/svr/src/socket/rtcDisConnect/disconnect.js @@ -1,7 +1,8 @@ const daoRoom = require("./../../dao/room/room") const rtcCount = require("./../rtcCount/count"); const rtcConstant = require("../rtcConstant"); -const rtcClientEvent = rtcConstant.rtcClientEvent +const rtcClientEvent = rtcConstant.rtcClientEvent; +const rtcLocalNetRoom = require("../rtcLocalNetRoom/localNetRoom"); /** * 断开连接的操作 @@ -18,7 +19,7 @@ async function disconnect(io, socket, tables, dbClient, data){ await daoRoom.exitRoomBySid({ socket_id: socket.id }, tables, dbClient); - rtcCount.count(io, socket, tables, dbClient, data) + rtcCount.count(io, socket, tables, dbClient, data); } module.exports = { diff --git a/svr/src/socket/rtcExit/exit.js b/svr/src/socket/rtcExit/exit.js index bec1fd6..213d0d1 100644 --- a/svr/src/socket/rtcExit/exit.js +++ b/svr/src/socket/rtcExit/exit.js @@ -3,8 +3,8 @@ const bussinessNotify = require("./../../bussiness/notify/notifyHandler") const rtcCount = require("./../rtcCount/count"); const utils = require("./../../utils/utils"); const rtcConstant = require("../rtcConstant"); -const rtcClientEvent = rtcConstant.rtcClientEvent - +const rtcClientEvent = rtcConstant.rtcClientEvent; +const rtcLocalNetRoom = require("../rtcLocalNetRoom/localNetRoom"); /** * 退出房间 @@ -48,6 +48,9 @@ async function exit(io, socket, tables, dbClient, data){ rtcCount.count(io, socket, tables, dbClient, data); + //局域网房间变动通知 + rtcLocalNetRoom.localNetRoomForExit(io, socket, tables, dbClient, { room }); + } catch (e) { socket.emit(rtcClientEvent.tips, { room: data.room, diff --git a/svr/src/socket/rtcLocalNetRoom/localNetRoom.js b/svr/src/socket/rtcLocalNetRoom/localNetRoom.js index 3a1c844..a01c100 100644 --- a/svr/src/socket/rtcLocalNetRoom/localNetRoom.js +++ b/svr/src/socket/rtcLocalNetRoom/localNetRoom.js @@ -2,134 +2,46 @@ const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent const bussinessNotify = require("../../bussiness/notify/notifyHandler") const utils = require("../../../src/utils/utils"); +const os = require('os'); /** - * 局域网房间发现列表 - * - * @param {*} io socketio对象 - * @param {*} socket 单个socket连接 - * @param {*} tables 数据表对象 - * @param {*} dbClient sequelize-orm对象 - * @param {*} data event参数 + * 服务器网络列表 + */ +let serverNetworkList = null; +(() => { + if (!serverNetworkList) { + serverNetworkList = []; + let ifaces = os.networkInterfaces(); + for (let iface in ifaces) { + for (let i = 0, len = ifaces[iface].length; i < len; ++i) { + const item = ifaces[iface][i]; + if (item.family === 'IPv4') { + serverNetworkList.push(ifaces[iface][i]) + } + } + } + } +})() + +console.log(serverNetworkList) + + +/** + * 通过ip获取子网掩码 + * @param {*} ip * @returns */ -async function localNetRoom(io, socket, tables, dbClient, data){ - try{ - const { toCurrentSocket = false, toAll = false } = data; - - let { ip, address } = utils.getSocketClientInfo(socket); - - let roomList = []; - let rooms = io.sockets.adapter.rooms; - - for(let roomId in rooms){ - if(roomId.length > 15){ - continue; - } - - //最多返回10个房间 - if(roomList.length > 10){ - break; - } - - // 是否开启局域网房间 - const localNetRoom = rooms[roomId].localNetRoom || false; - if(!localNetRoom){ - continue; - } - - // 房间ip - const roomIp = rooms[roomId].ip || ""; - // 房间address/ip - const roomAddress = rooms[roomId].address || ""; - - if(roomIp){ - // 本地请求 - if( - (roomIp.indexOf("127.0.0.1") > -1 && ip.indexOf("127.0.0.1") > -1) - || - (roomIp.indexOf("localhost") > -1 && ip.indexOf("localhost") > -1) - ){ - roomList = addFilterRoomListData(roomList, { - room : roomId, - type : 'file', - ips : [roomIp], - count : rooms[roomId].length - }) - }else{ - // 在同一个网段 - if(utils.isSameSubnet(roomIp, ip, "255.255.255.255")){ - roomList = addFilterRoomListData(roomList, { - room : roomId, - type : 'file', - ips : [roomIp], - count : rooms[roomId].length - }) - } - } - } - - if(roomAddress){ - // 本地请求 - if( - (roomAddress.indexOf("127.0.0.1") > -1 && address.indexOf("127.0.0.1") > -1) - || - (roomAddress.indexOf("localhost") > -1 && address.indexOf("localhost") > -1) - ){ - roomList = addFilterRoomListData(roomList, { - room : roomId, - type : 'file', - ips : [roomAddress], - count : rooms[roomId].length - }) - }else{ - // 在同一个网段 - if(utils.isSameSubnet(roomAddress, address, "255.255.255.255")){ - roomList = addFilterRoomListData(roomList, { - room : roomId, - type : 'file', - ips : [roomAddress], - count : rooms[roomId].length - }) - } - } - } - } - - roomList.map(item=>{ - item.room = item.room.toString().substring(0,1) + "***"; - }) - - // 通知当前用户 - if(toCurrentSocket){ - socket.emit(rtcClientEvent.localNetRoom, { - list : roomList - }) - } - - // 通知全部用户 - if(toAll){ - io.sockets.emit(rtcClientEvent.localNetRoom, { - list : roomList - }); - } - - }catch(e){ - utils.tlConsole(e) - bussinessNotify.sendSystemErrorMsg({ - title: "socket-localNetRoom", - data: JSON.stringify(data), - room: "", - from : socket.id, - msg : JSON.stringify({ - message: e.message, - fileName: e.fileName, - lineNumber: e.lineNumber, - stack: e.stack, - name: e.name - }, null, '\t') - }) +function getNetMaskByIp(ip) { + if (!serverNetworkList) { + return "255.255.255.255"; } + const filterList = serverNetworkList.filter(item => { + return item.address === ip; + }) + if (!filterList || filterList.length === 0) { + return "255.255.255.255"; + } + return filterList[0].netmask; } @@ -138,15 +50,15 @@ async function localNetRoom(io, socket, tables, dbClient, data){ * @param {*} list * @returns */ -function addFilterRoomListData(list, obj){ +function addFilterRoomListData(list, obj) { let exist = list.filter(item => item.room === obj.room).length > 0; - if(!exist){ + if (!exist) { list.push(obj) return list } - for(let i = 0; i < list.length; i++){ - if(list[i].room === obj.room){ + for (let i = 0; i < list.length; i++) { + if (list[i].room === obj.room) { let oldIps = list[i].ips; oldIps.push(obj.ips[0]) list[i].ips = oldIps; @@ -156,6 +68,245 @@ function addFilterRoomListData(list, obj){ } +/** + * 局域网房间发现列表 + * 连接类型广播 + * + * @param {*} io socketio对象 + * @param {*} socket 单个socket连接 + * @param {*} tables 数据表对象 + * @param {*} dbClient sequelize-orm对象 + * @param {*} data event参数 + * @returns + */ +function localNetRoom(io, socket, tables, dbClient, data) { + const { ips : currentIps = [] } = data; + + let filterRoomList = []; + + //所有正常的房间列表ip统计 + let rooms = io.sockets.adapter.rooms; + let roomIpsList = []; + for (let roomId in rooms) { + let roomIps = rooms[roomId].ips; + if ( + roomId.length > 15 || // 非法房间号 + !rooms[roomId] || // 房间不存在 + !roomIps || // 房间没有上报ip + roomIps.length === 0 || // 房间没有上报ip + rooms[roomId].length === 0 || // 房间没有人 + !rooms[roomId].localNetRoom // 房间没有开启局域网 + ) { + continue; + } + + //最多处理返回10个局域网房间 + if (roomIpsList.length > 10) { + break; + } + + roomIpsList.push(...roomIps.map(item => { + item.room = roomId; + item.count = rooms[roomId] ? Object.keys(rooms[roomId].sockets).length : 0, + item.owner = rooms[roomId].owner; + item.roomType = rooms[roomId].type; + return item; + })) + } + + //根据当前socket连接的ip信息,筛选出和ip在同一个局域网的房间列表 + currentIps.forEach(currentIpInfo => { + const { ipType: currentIpType, address: currentAddress } = currentIpInfo; + + roomIpsList.forEach(otherIpInfo => { + const { ipType: otherIpType, address: otherAddress, room, count, owner, roomType } = otherIpInfo; + + if (otherIpType === "srflx" && currentIpType === 'srflx') { //公网ip + if (utils.isSameSubnet(currentAddress, otherAddress, getNetMaskByIp(currentAddress))) { + filterRoomList = addFilterRoomListData(filterRoomList, { + room, roomType, count, owner, ips: [otherAddress] + }) + } + } else if (otherIpType === 'host' && currentIpType === 'host') { //内网ip + if (utils.isSameSubnet(currentAddress, otherAddress, getNetMaskByIp(currentAddress))) { + filterRoomList = addFilterRoomListData(filterRoomList, { + room, roomType, count, owner, ips: [otherAddress] + }) + } + } + }) + }); + + // filterRoomList.map(item => { + // item.room = item.room.toString().substring(0, 1) + "***"; + // }) + + return filterRoomList; +} + + +/** + * 局域网房间发现列表 + * socket用户连接之后广播 + * @param {*} io socketio对象 + * @param {*} socket 单个socket连接 + * @param {*} tables 数据表对象 + * @param {*} dbClient sequelize-orm对象 + * @param {*} data event参数 + * @returns + */ +function localNetRoomForConnect(io, socket, tables, dbClient, data) { + try { + let filterRoomList = localNetRoom(io, socket, tables, dbClient, data); + + socket.emit(rtcClientEvent.localNetRoom, { + list: filterRoomList, + mode : 'connect' + }); + + } catch (e) { + utils.tlConsole(e) + bussinessNotify.sendSystemErrorMsg({ + title: "socket-localNetRoomForConnect", + data: JSON.stringify(data), + room: "", + from: socket.id, + msg: JSON.stringify({ + message: e.message, + fileName: e.fileName, + lineNumber: e.lineNumber, + stack: e.stack, + name: e.name + }, null, '\t') + }) + } +} + + + +/** + * 局域网房间发现列表 + * socket用户加入房间之后广播 + * @param {*} io socketio对象 + * @param {*} socket 单个socket连接 + * @param {*} tables 数据表对象 + * @param {*} dbClient sequelize-orm对象 + * @param {*} data event参数 + * @returns + */ +function localNetRoomForJoin(io, socket, tables, dbClient, data) { + try { + const { room } = data; + const socketRoomInfo = io.sockets.adapter.rooms[room]; + const ips = socketRoomInfo ? socketRoomInfo.ips : []; + const owner = socketRoomInfo ? socketRoomInfo.owner : socket.id; + const count = socketRoomInfo ? Object.keys(socketRoomInfo.sockets).length : 0; + const roomType = socketRoomInfo ? socketRoomInfo.type : "file"; + + io.sockets.emit(rtcClientEvent.localNetRoom, { + list : [{ room, roomType, count, owner, ips : ips.map(item => item.address) }], + mode : 'join' + }); + + } catch (e) { + utils.tlConsole(e) + bussinessNotify.sendSystemErrorMsg({ + title: "socket-localNetRoomForJoin", + data: JSON.stringify(data), + room: "", + from: socket.id, + msg: JSON.stringify({ + message: e.message, + fileName: e.fileName, + lineNumber: e.lineNumber, + stack: e.stack, + name: e.name + }, null, '\t') + }) + } +} + + + +/** + * 局域网房间发现列表 + * socket用户退出房间之后广播 + * @param {*} io socketio对象 + * @param {*} socket 单个socket连接 + * @param {*} tables 数据表对象 + * @param {*} dbClient sequelize-orm对象 + * @param {*} data event参数 + * @returns + */ +function localNetRoomForExit(io, socket, tables, dbClient, data) { + try { + const { room } = data; + const socketRoomInfo = io.sockets.adapter.rooms[room]; + const ips = socketRoomInfo ? socketRoomInfo.ips : []; + const owner = socketRoomInfo ? socketRoomInfo.owner : socket.id; + const count = socketRoomInfo ? Object.keys(socketRoomInfo.sockets).length : 0; + const roomType = socketRoomInfo ? socketRoomInfo.type : "file"; + + io.sockets.emit(rtcClientEvent.localNetRoom, { + list : [{ room, roomType, count, owner, ips: ips.map(item => item.address) }], + mode : 'exit' + }); + + } catch (e) { + utils.tlConsole(e) + bussinessNotify.sendSystemErrorMsg({ + title: "socket-localNetRoomForExit", + data: JSON.stringify(data), + room: "", + from: socket.id, + msg: JSON.stringify({ + message: e.message, + fileName: e.fileName, + lineNumber: e.lineNumber, + stack: e.stack, + name: e.name + }, null, '\t') + }) + } +} + + +/** + * 局域网房间发现列表 + * socket用户断开连接之后广播 + * @param {*} io socketio对象 + * @param {*} socket 单个socket连接 + * @param {*} tables 数据表对象 + * @param {*} dbClient sequelize-orm对象 + * @param {*} data event参数 + * @returns + */ +function localNetRoomForDisconnect(io, socket, tables, dbClient, data) { + try { + io.sockets.emit(rtcClientEvent.localNetRoom, { + list : [{ socketId : socket.id }], + mode : 'disconnect' + }); + } catch (e) { + utils.tlConsole(e) + bussinessNotify.sendSystemErrorMsg({ + title: "socket-localNetRoomForDisconnect", + data: JSON.stringify(data), + room: "", + from: socket.id, + msg: JSON.stringify({ + message: e.message, + fileName: e.fileName, + lineNumber: e.lineNumber, + stack: e.stack, + name: e.name + }, null, '\t') + }) + } +} + + module.exports = { - localNetRoom + localNetRoomForConnect, localNetRoomForJoin, + localNetRoomForExit, localNetRoomForDisconnect } \ No newline at end of file diff --git a/svr/src/socket/rtcSubscribe/subscribe.js b/svr/src/socket/rtcSubscribe/subscribe.js new file mode 100644 index 0000000..6aa4be0 --- /dev/null +++ b/svr/src/socket/rtcSubscribe/subscribe.js @@ -0,0 +1,57 @@ +const utils = require("./../../utils/utils"); +const daoDog = require("./../../dao/dog/dog") +const daoUser = require("./../../dao/user/user") +const rtcConstant = require("../rtcConstant"); +const rtcClientEvent = rtcConstant.rtcClientEvent +const daoRelation = require("../../dao/relation/relation"); + + +/** + * 订阅网站通知 + * @param {*} io socketio对象 + * @param {*} socket 单个socket连接 + * @param {*} tables 数据表对象 + * @param {*} dbClient sequelize-orm对象 + * @param {*} data event参数 + * @returns + */ +async function subscribeNofity(io, socket, tables, dbClient, data){ + let { roomId = '', email = '' } = data; + + let { handshake, userAgent, ip } = utils.getSocketClientInfo(socket); + + socket.emit(rtcClientEvent.subscribeNofity, data); + + //控制操作事件入库 + let recoderId = await daoDog.addDogData({ + name: "订阅网站通知", + roomId: roomId, + socketId: socket.id, + device: userAgent, + flag: 0, + content: JSON.stringify(data), + handshake: JSON.stringify(handshake), + ip: ip + }, tables, dbClient); + + //更新用户订阅标识 + const { userId, flag = 0 } = socket.userInfo; + if(userId){ + await daoUser.updateUserFlag({ + id : userId, + flag : utils.setBit(flag, tables.UserOther.Flag.IS_SUBSCRIBE_WEBSITE_NOTIFY) + }, tables, dbClient); + } + + //添加用户-操作关联记录 + if(socket.userId){ + daoRelation.addUserDogRelation({ + dogId : recoderId, + userId : socket.userId, + }, tables, dbClient); + } +} + +module.exports = { + subscribeNofity +} \ No newline at end of file diff --git a/svr/src/socket/rtcToken/token.js b/svr/src/socket/rtcToken/token.js index 34e8fb3..089e60d 100644 --- a/svr/src/socket/rtcToken/token.js +++ b/svr/src/socket/rtcToken/token.js @@ -29,7 +29,7 @@ async function token(io, socket, tables, dbClient, data){ "content-type": "application/json", }, qs: { - token, key : "iamtsm-socket" + token, key : cfg.login.token.key }, }, (err, res, body) => { if(err){ @@ -42,9 +42,9 @@ async function token(io, socket, tables, dbClient, data){ return; } - socket.userId = body.userId; + socket.userInfo = body.userInfo; - utils.tlConsole("同步token信息成功 : ", token, body.userId) + utils.tlConsole("同步token信息成功 : ", token, body.userInfo) }); } diff --git a/svr/src/tables/user.js b/svr/src/tables/user.js index 75e9040..a30fab2 100644 --- a/svr/src/tables/user.js +++ b/svr/src/tables/user.js @@ -1,6 +1,11 @@ // user module.exports = (sequelize, DataTypes) => { return { + UserOther : { + Flag : { + IS_SUBSCRIBE_WEBSITE_NOTIFY : 0x1, //是否已订阅网站通知 + } + }, User: sequelize.define('user', { id: { type: DataTypes.INTEGER, @@ -36,6 +41,11 @@ module.exports = (sequelize, DataTypes) => { role: { type: DataTypes.STRING(15), comment: '用户身份' + }, + flag: { + type: DataTypes.INTEGER, + comment: '标志位', + defaultValue: 0, } }, { timestamps: true, diff --git a/svr/src/utils/utils.js b/svr/src/utils/utils.js index 60b4968..4ddde91 100644 --- a/svr/src/utils/utils.js +++ b/svr/src/utils/utils.js @@ -49,7 +49,7 @@ function getLocalIP() { function isSameSubnet(ip1, ip2, subnetMask) { // 将IPv4或IPv6地址和子网掩码转换为数字形式 function ipToNumber(ip) { - if (ip.includes(':')) { // IPv6 + if (ip.indexOf(':') > -1) { // IPv6 const parts = ip.split(':'); return parts.map(part => parseInt(part, 16)).join(''); } else { // IPv4 @@ -374,6 +374,15 @@ function checkBit(flag, bit){ return (flag & bit) === bit; } +/** + * 根据flag和bit设置对应的值 + * @param {*} flag + * @param {*} bit + */ +function setBit(flag, bit){ + return flag | bit; +} + module.exports = { @@ -392,5 +401,6 @@ module.exports = { unescapeStr, escapeStr, isSameSubnet, - checkBit + checkBit, + setBit } \ No newline at end of file diff --git a/svr/static/layui/font-ext/demo_index.html b/svr/static/layui/font-ext/demo_index.html index 884fe69..2ddf670 100644 --- a/svr/static/layui/font-ext/demo_index.html +++ b/svr/static/layui/font-ext/demo_index.html @@ -54,6 +54,24 @@