UNPKG

mm_os

Version:

MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。

352 lines (328 loc) 8.24 kB
const Manager = require('mm_machine').Manager; const Drive = require('./drive'); /** * 任务类 * @augments {Manager} * @class */ class Socket extends Manager { /** * 配置参数 * @type {object} */ static config = { /** * 名称 * @type {string} */ name: '', /** * 标题 * @type {string} */ title: 'socket管理', /** * 描述 * @type {string} */ description: '这是socket管理器', /** * 检索文件名 * @type {string} */ filename: 'socket.json', /** * 模板目录 * @type {string} */ tpl_dir: __dirname, /** * 基础目录 * @type {string} */ base_dir: '../common/socket'.fullname(__dirname), /** * 自定义目录,加载项目自定义资源 * @type {string} */ dir: './app'.fullname(), /** * 搜索模式 dir按目录搜索 | file按文件名搜索 * @type {string} */ search_way: 'file', /** * 是否懒加载 * @type {boolean} */ lazy_load: true, /** * 模式 * 1.生产模式,改变文件不会重新加载 * 2.热更新模式,改变配置文件会重新加载配置,不重新加载脚本 * 3.热重载模式,改变配置文件都会加载配置和脚本 * 4.重载模式,执行完后重新加载脚本,避免变量污染 * 5.热更新+重载模式,改变配置文件重新加载配置和脚本,执行完后重新加载脚本 * @type {number} */ mode: 3 }; /** * 构造函数 * @param {object} config 配置参数 * @param {object} parent 父级模块 */ constructor(config, parent) { super({ ...Socket.config, ...config }, parent); this.dict = {}; /** * 消息队列 */ this.list_msg = [ /* { // 消息ID id: "", // 请求方法 method: "", // 消息参数 params: {}, // 回调函数 func: function(res){}, // 时间戳 timestamp: 0, // 超时时间 timeout: 0, // 定时器 timer: null } */ ]; } } /** * socket驱动类 * @type {Drive} */ Socket.prototype.Drive = Drive; /** * 处理socket请求 * @param {object} ctx 请求上下文 * @param {Function} next 跳过当前, 然后继续执行函数 */ Socket.prototype.run = async function (ctx, next) { await next(); let path = ctx.path.toLocaleLowerCase(); var infos = this.getInfos(); for (var i = 0, info; info = infos[i++];) { // console.log("监听webscoket路径是否正确", path === info.path); if (info.state === 1) { let mod = this.getMod(info.name); if (path === info.path) { if (mod) { mod.add(ctx); } break; } } } }; /** * 发送消息到指定客户端 * @param {string} client_id 客户端ID * @param {string} method 方法名称 * @param {object} params 请求参数 * @returns {boolean} 发送是否成功 */ Socket.prototype.send = function (client_id, method, params) { var mods = this.getMods(); for (var k in mods) { var o = mods[k]; if (o.config.state === 1 && o.send) { // 设置管理器引用,用于消息回复处理 o.manager = this; return o.send(client_id, method, params); } } return false; }; /** * 发送消息到所有连接的客户端 * @param {string} method 方法名称 * @param {object} params 请求参数 */ Socket.prototype.sendAll = function (method, params) { var mods = this.getMods(); for (var k in mods) { var o = mods[k]; if (o.config.state === 1 && o.sendAll) { // 设置管理器引用,用于消息回复处理 o.manager = this; o.sendAll(method, params); } } }; /** * 发送请求到指定客户端 * @param {string} client_id 客户端ID * @param {string} method 方法名称 * @param {object} params 请求参数 * @param {Function} func 回调函数 * @param {number} timeout 超时时间(毫秒) * @returns {boolean} 发送是否成功 */ Socket.prototype.req = function (client_id, method, params, func, timeout = 0) { var mods = this.getMods(); for (var k in mods) { var o = mods[k]; if (o.config.state === 1 && o.req) { // 设置管理器引用,用于消息回复处理 o.manager = this; return o.req(client_id, method, params, func, timeout); } } return false; }; /** * 发送请求到所有连接的客户端 * @param {string} method 方法名称 * @param {object} params 请求参数 * @param {Function} func 回调函数 * @param {number} timeout 超时时间(毫秒) */ Socket.prototype.reqAll = function (method, params, func, timeout = 0) { var mods = this.getMods(); for (var k in mods) { var o = mods[k]; if (o.config.state === 1 && o.reqAll) { // 设置管理器引用,用于消息回复处理 o.manager = this; o.reqAll(method, params, func, timeout); } } }; /** * 同步请求到指定客户端 - 可及时取回消息 * @param {string} client_id 客户端ID * @param {string} method 请求方法 * @param {object} params 传递参数 * @param {number} timeout 超时时间(毫秒) * @returns {Promise} 返回响应结果的Promise */ Socket.prototype.reqAsync = function (client_id, method, params, timeout = 0) { var _this = this; return new Promise((resolve, reject) => { _this.req(client_id, method, params, (res) => { resolve(res); }, timeout); }); }; /** * 同步请求到所有客户端 - 可及时取回消息 * @param {string} method 请求方法 * @param {object} params 传递参数 * @param {number} timeout 超时时间(毫秒) * @returns {Promise} 返回响应结果的Promise */ Socket.prototype.reqAsyncAll = function (method, params, timeout = 0) { var _this = this; return new Promise((resolve, reject) => { _this.reqAll(method, params, (res) => { resolve(res); }, timeout); }); }; /** * 生成消息ID * @returns {string} 消息ID * @private */ Socket.prototype._genId = function () { return 'socket_' + Date.parse(new Date()) + '_' + Math.random().toString(36).substr(2, 9); }; /** * 根据ID移除消息 * @param {string} msg_id 消息ID * @private */ Socket.prototype._delMsgById = function (msg_id) { for (var i = 0; i < this.list_msg.length; i++) { if (this.list_msg[i].id === msg_id) { // 清除定时器 if (this.list_msg[i].timer) { clearTimeout(this.list_msg[i].timer); } this.list_msg.splice(i, 1); break; } } }; /** * 处理消息回复 * @param {object} msg 回复消息 * @private */ Socket.prototype._handleResponse = function (msg) { if (!msg || !msg.id) { return; } for (var i = 0; i < this.list_msg.length; i++) { let o = this.list_msg[i]; if (o.id === msg.id && o.func) { try { // 执行回调函数 o.func(msg); } catch (error) { console.error('Socket回调函数执行错误:', error); } // 从列表中移除已处理的消息 this._delMsgById(o.id); break; } } }; /** * 更新加载插件 * @param {string} path 检索路径 */ Socket.prototype.updateConfigAll = async function (path) { var p = path || './app/'; // 获取所有应用路径 var list_scope = $.dir.getAll(p, 'socket'); // 遍历目录路径 for (var i = 0, f; f = list_scope[i++];) { var list_file = $.file.getAll(f, '*' + this.type + '.json'); await this.loadList(list_file); } }; exports.Socket = Socket; /** * Socket组件池 */ if (!$.pool.socket) { $.pool.socket = {}; } /** * Socket管理器,用于创建缓存 * @param {string} scope 作用域 * @param {string} title 标题 * @returns {object} 返回一个缓存类 */ function socketAdmin(scope, title) { var sc = scope || $.val.scope + ''; var obj = $.pool.socket[sc]; if (!obj) { $.pool.socket[sc] = new Socket({ name: sc, title: title }); obj = $.pool.socket[sc]; } return obj; } /** * @module 导出Socket管理器 */ if ($.admin) { $.admin.socket = socketAdmin; }