MCSManager/route/websocket.js

237 lines
7.1 KiB
JavaScript
Raw Normal View History

2017-11-13 12:26:31 +08:00
const router = require('express')();
2018-04-18 11:20:17 +08:00
const fs = require('fs');
2017-11-13 12:26:31 +08:00
2018-04-21 14:15:20 +08:00
const TokenManager = require('../helper/TokenManager');
2017-11-13 12:26:31 +08:00
const {
WebSocketObserver
} = require('../model/WebSocketModel');
const permssion = require('../helper/Permission');
const response = require('../helper/Response');
2018-04-20 10:04:22 +08:00
const loginedContainer = require('../helper/LoginedContainer');
2017-11-13 12:26:31 +08:00
const counter = require('../core/counter');
2018-04-18 11:20:17 +08:00
const expressWs = require('express-ws')(router);
//WebSocket 会话类
class WebsocketSession {
constructor(config = {}) {
this.login = config.login || false;
this.uid = config.uid || null;
this.ws = config.ws || null;
this.username = config.username || null;
this.token = config.token || null;
this.console = config.console || null;
2018-04-20 21:23:03 +08:00
this.sessionID = config.sessionID || null;
2018-04-18 11:20:17 +08:00
}
send(data) {
if (data)
response.wsSend(data.ws, data.resK, data.resV, data.body);
}
2018-04-20 11:35:27 +08:00
getWebsocket() {
return this.ws || null;
}
2018-04-18 11:20:17 +08:00
}
2017-11-13 12:26:31 +08:00
2018-04-20 21:07:29 +08:00
//判断当前令牌者是否在线
function isWsOnline(token) {
for (let k in MCSERVER.allSockets) {
let wsSession = MCSERVER.allSockets[k];
if (wsSession.token == token) {
return true;
}
}
return false;
}
2017-11-13 12:26:31 +08:00
//WebSocket 创建
router.ws('/ws', function (ws, req) {
2018-04-18 11:20:17 +08:00
let token = req.query[permssion.tokenName] || null;
2017-11-13 12:26:31 +08:00
2018-04-21 14:43:42 +08:00
//无令牌 或 未登录
if (!token || !req.session['login']) {
2017-11-13 12:26:31 +08:00
counter.plus('csrfCounter');
ws.close();
return;
}
2018-04-20 21:07:29 +08:00
token = token.trim();
2018-04-15 21:49:12 +08:00
let username = null;
2018-05-22 23:04:55 +08:00
let status = false;
let wsAliveHBCount = 5;
2017-11-13 12:26:31 +08:00
//临时的会话id 一般只用于内部验证是否是这个tcp链接
2018-04-20 21:07:29 +08:00
let uid = permssion.randomString(12) + Date.parse(new Date()).toString();
2018-04-20 11:35:27 +08:00
let session_id = req.sessionID;
2017-11-13 12:26:31 +08:00
2018-04-21 14:43:42 +08:00
MCSERVER.log('[ WS CREATE ] 新的 Ws 创建 会话ID: [', session_id, ']');
2017-11-13 12:26:31 +08:00
//从令牌管理器中 获取对应的用户
2018-04-21 14:15:20 +08:00
username = TokenManager.getToken(token);
2018-04-21 14:43:42 +08:00
//Token 任务完成 | 删除
2018-04-21 14:15:20 +08:00
TokenManager.delToken(token);
delete req.session['token'];
2018-04-21 14:43:42 +08:00
req.session.save();
2018-04-15 20:57:01 +08:00
2018-04-15 21:49:12 +08:00
//用户名检查
2018-04-15 20:57:01 +08:00
if (!username || typeof username != "string" || username.trim() == "") {
2018-04-21 14:43:42 +08:00
MCSERVER.warning('错误令牌的 WS 尝试建立链接 | 已经阻止', ['用户值:', username, ' 令牌值:', token].join(" "));
2017-11-13 12:26:31 +08:00
counter.plus('notPermssionCounter');
ws.close();
return;
}
2018-04-20 21:07:29 +08:00
//唯一性检查
if (isWsOnline(token)) {
2018-04-21 14:43:42 +08:00
MCSERVER.warning('此令牌正在使用 | 阻止重复使用 | isWsOnline', ['用户值:', username, ' 令牌值:', token].join(" "));
2018-04-20 21:07:29 +08:00
ws.close();
return;
}
2018-04-20 11:35:27 +08:00
username = username.trim();
2018-04-21 14:43:42 +08:00
//登录逻辑性缺陷检查
if (!loginedContainer.isLogined(session_id, username)) {
2018-04-21 14:43:42 +08:00
MCSERVER.warning('未经过登陆逻辑的用户尝试连接 | 已经阻止', ['用户值:', username, ' 令牌值:', token].join(" "));
counter.plus('notPermssionCounter');
2018-04-20 10:04:22 +08:00
ws.close();
return;
}
2018-04-21 14:43:42 +08:00
//WebsocketSession 类生成
2018-04-18 11:20:17 +08:00
let WsSession = new WebsocketSession({
//Ws 判断身份条件,必须在 token 管理器与 Session 中认证登录
login: (username && req.session['login']) ? true : false,
uid: uid,
2018-04-20 11:35:27 +08:00
sessionID: session_id,
2018-04-18 11:20:17 +08:00
ws: ws,
username: username,
token: token,
console: null
});
2017-11-13 12:26:31 +08:00
2018-04-21 14:43:42 +08:00
//Session 级别验证登录检查
2018-04-15 21:49:12 +08:00
if (!WsSession.login) {
MCSERVER.warning('不明身份者建立 ws 链接', '已经阻止 | 可能的用户值: ' + WsSession.username);
counter.plus('notPermssionCounter');
ws.close();
return;
}
2018-05-22 23:04:55 +08:00
//状态标识
status = true;
2018-04-21 14:43:42 +08:00
2017-11-13 12:26:31 +08:00
//放置全局在线列表
MCSERVER.allSockets[uid] = WsSession;
if (!MCSERVER.onlineUser[WsSession.username])
MCSERVER.onlineUser[WsSession.username] = WsSession;
2018-04-21 14:43:42 +08:00
//检查通过..
2017-11-13 12:26:31 +08:00
MCSERVER.log('[ WebSocket INIT ]', ' 用户:', username, "与服务器建立链接");
2018-04-21 14:43:42 +08:00
2018-05-22 23:04:55 +08:00
2018-04-21 14:43:42 +08:00
//数据到达事件
2017-11-13 12:26:31 +08:00
ws.on('message', function (data) {
2018-04-15 21:49:12 +08:00
try {
2017-11-13 12:26:31 +08:00
2018-04-21 14:43:42 +08:00
//是否合法用户检查
2018-04-15 21:49:12 +08:00
if (!WsSession.login) {
//触发这里代表极为有可能有人正在攻击你
MCSERVER.warning('没有登录的用户正在尝试发送 Ws 命令', '已经阻止 | 可能的用户值: ' + username);
counter.plus('notPermssionCounter');
ws.close();
return;
}
2017-11-13 12:26:31 +08:00
2018-04-21 14:43:42 +08:00
//在线用户容器检查
2017-11-13 12:26:31 +08:00
if (!MCSERVER.onlineUser[username]) {
counter.plus('userOnlineCounter');
MCSERVER.onlineUser[username] = WsSession;
}
2018-04-21 14:43:42 +08:00
//检查完毕 | 开始解析数据
2017-11-13 12:26:31 +08:00
//自定义协议数据解析
let loc = data.indexOf('\n\n');
let reqHeader = data.substr(0, loc);
let reqBody = data.substr(loc + 2);
let obj;
let reqs = req;
//Websocket 自定义协议解析
reqHeaderObj = JSON.parse(reqHeader);
if (!reqHeaderObj) return;
2018-05-22 23:04:55 +08:00
//Websocket 心跳包 | 前端 10 秒递增链接健康指数
//当网络延迟特别高时,也能很好的降低指数. 将来指数够低时,将自动优化数据的发送
if (reqHeaderObj['RequestValue'] == "HBPackage") {
status = true;
wsAliveHBCount < 10 && wsAliveHBCount++;
2018-05-22 23:08:27 +08:00
return;
2018-05-22 23:04:55 +08:00
}
2017-11-13 12:26:31 +08:00
WebSocketObserver().emit('ws/req', {
ws: ws,
req: req,
user: username,
header: reqHeaderObj,
body: reqBody,
RequestValue: reqHeaderObj['RequestValue'],
token: token,
WsSession: WsSession
});
} catch (err) {
2018-04-18 11:20:17 +08:00
MCSERVER.error('WebSocket 请求处理时异常:', err);
2017-11-13 12:26:31 +08:00
}
});
2018-05-22 23:04:55 +08:00
//关闭事件
2017-11-13 12:26:31 +08:00
ws.on('close', function () {
2018-05-22 23:04:55 +08:00
WebSocketClose();
});
2017-11-13 12:26:31 +08:00
2018-05-22 23:04:55 +08:00
//Websocket 心跳包检查 | 12 秒递减一个链接健康指数
var HBMask = setInterval(() => {
if (wsAliveHBCount <= 0) {
MCSERVER.log('[ WebSocket HBPackage ]', '用户', username, '长时间未响应心跳包 | 已自动断开');
WebSocketClose();
}
wsAliveHBCount--;
}, 1000 * 12)
//Websocket 关闭函数
function WebSocketClose() {
if (!status) return;
ws.close();
clearInterval(HBMask);
2017-11-13 12:26:31 +08:00
status = false;
2018-04-21 14:15:20 +08:00
//再删一次,保险
TokenManager.delToken(token);
delete req.session['token'];
2017-11-13 12:26:31 +08:00
delete WsSession;
2018-04-21 14:15:20 +08:00
req.session.save();
2017-11-13 12:26:31 +08:00
//释放全局变量
if (MCSERVER.onlineUser[username]) {
delete MCSERVER.onlineUser[username];
}
delete MCSERVER.allSockets[uid];
MCSERVER.log('[ WebSocket CLOSE ]', '用户', username, '已经断开链接');
2018-05-22 23:04:55 +08:00
}
2017-11-13 12:26:31 +08:00
});
2018-04-18 11:20:17 +08:00
//加载 ws 子路由
require("../core/tools").autoLoadModule('route/websocket/', 'websocket/', (path) => {
2017-11-13 12:26:31 +08:00
require(path);
});
//模块导出
module.exports = router;