UNPKG

mm_os

Version:

这是超级美眉服务端框架,用于快速构建应用程序。

513 lines (486 loc) 11.8 kB
const Item = require('mm_machine').Item; /** * 指令驱动类 * @extends {Item} * @class */ class Drive extends Item { /** * 构造函数 * @param {String} dir 当前目录 * @constructor */ constructor(dir) { super(dir, __dirname); this.default_file = "./cmd.json"; // 默认启用热更新 this.mode = 3; // 开关 true为开启, false为关闭 this.onOff = true; /* 通用项 */ // 配置参数 this.config = { // 标识名 "name": "demo", // 分组名 "title": "指令标题", // 描述, 用于描述该接口有什么用的 "description": "暂无描述", // 文件名 "func_file": "./index.js", // 时态, 分before之前、main主要、after之后三个时态, "tense": "main", // 加载顺序,数字越大越后面加载 "sort": 1000, // 结束会话 当值为1时,指令触发并返回了内容后不再执行其他指令。为0时,指令触发仍继续执行其他指令 "end": 1, // 分组 "group": "default", // 类型: query便民查询,action执行,game游戏,orther其他,为空表示未分类 "type": "", // 匹配关键词 "match": [], // 不含关键词 "not_match": [], // 去除关键词 "remove": [], // 摘取 "extract": [], // 阶段 "stage": [ // 第一阶段 { // 方式 "mode": "fill", // 验证参数集 "param": [ // { // // 参数名 // "name": "name", // // 参数介绍名 // "title": "名称", // // 参数格式 // "format": "", // // 缺少参数提示语,传键值对,例如:{ number: "快递单号多少?" } // "not_tip": "", // // 错误提示 // "error_tip": "", // // 监听语法 // "listen": "", // // 校验函数明 // "func_name": "" // }, ] }, // 第二阶段 { // 方式 "mode": "update", // 验证参数集 "param": [] }, // 第三阶段 { // 方式 "mode": "fill", // 验证参数集 "param": [] } ] } } }; /** * 创建一个参数模型 */ Drive.prototype.model = function() { return { // 参数名 "name": "name", // 参数介绍名 "title": "名称", // 排序 "sort": 10, // 监听语法 "listen": "", // 参数格式 "format": "", // 缺少参数提示语 "not_tip": "", // 更新提示 "update_tip": "", // 错误提示 "error_tip": "" }; }; /** * 校验是否匹配指令 * @param {Object} content 请求的正文 * @param {Object} db 数据管理器 * @return {Boolean} 匹配返回true,不匹配返回false */ Drive.prototype.match = function(content, db) { var word; var arr = this.config.match; for (var i = 0; i < arr.length; i++) { var format = arr[i]; var str = content.matchs(format); if (str) { word = str; break; } } return word; }; /** * 校验是否不含关键词 * @param {Object} content 请求的正文 * @param {Object} db 数据管理器 * @return {Boolean} 不含返回true,含有返回false */ Drive.prototype.not_match = function(content, db) { var bl = true; var arr = this.config.not_match; for (var i = 0; i < arr.length; i++) { var format = arr[i]; if (content.matchs(format)) { bl = false; break; } } return bl; }; /** * 抽取主要内容 * @param {String} content 正文 * @param {Object} db 数据管理器 * @return {Object} 返回过滤后的参数 */ Drive.prototype.extract = async function(content, db) { var list = this.config.extract; if (!list.length) { return content } for (var i = 0; i < list.length; i++) { var format = list[i]; var ret = content.matchs(format); if (ret) { content = ret; } } return content; }; /** * 移除关键词 * @param {Array} content 内容 * @param {Object} db 数据管理器 * @return {Object} 返回过滤后的参数 */ Drive.prototype.remove = async function(content, db) { var list = this.config.remove; for (var i = 0; i < list.length; i++) { var format = list[i]; if (format.indexOf("/") === 0) { var fmt = format.replace(/\//g, '\\/').replace(/\r/g, '\\r').replace(/\n/g, '\\n') .replace(/\*/g, '.*').replace( /\{[a-zA-Z\u4e00-\u9fa5_]+\}/g, '[\\s\\S]*'); var rx = eval(fmt); content = content.replace(rx, "").trim(); } else { content = content.replace(format, "").trim(); } } return content; }; /** * 修改提示 * @param {Object} msg 消息上下文 * @param {Object} db 数据管理器 * @return {Object} 返回过滤后的参数 */ Drive.prototype.view_tip = async function(msg, db, tip) { var form = this.view(msg, db); tip = tip.replace("{form}", form); return tip; }; /** * 1. 检验阶段, 判断条件是否满足 * @param {Object} msg 消息上下文 * @param {Object} db 数据管理器 * @return {String} 验证失败返回错误提示 */ Drive.prototype.check = async function(msg, db) { // 校验是否匹配指令 var word = await this.match(msg.content, db); if (word) { var bl = await this.not_match(msg.content, db); if (!bl) { return } } return word; }; /** * 2. 过滤阶段, 抽出主要的内容 * @param {Object} msg 消息上下文 * @param {Object} db 数据管理器 * @return {Object} 返回过滤后的参数 */ Drive.prototype.filter = async function(msg, db) { var content = await this.extract(msg.content); content = await this.remove(content); if (content) { msg.keyword = content; } return content; }; /** * 3.1 信息补全阶段 用于通知用户补全执行的必要条件 * @param {Object} msg 消息上下文 * @param {Object} db 数据管理器 * @param {Object} stage 阶段参数 * @return {Object} 返回参数表单 */ Drive.prototype.fill = async function(msg, db, stage) { if (!stage) { return ""; } var list = stage.param; if (!list || list.length === 0) { return ""; } var keyword = ""; var tip = ""; // 获取已有参数 var form = {}; if (msg.form) { form = msg.form.toJson(); } // 补全内容 var ct = msg.content_last || ""; var len = list.length; for (var i = 0; i < len; i++) { var o = list[i]; var k = o.name; if (!form[k]) { if (ct) { var value = ct; if (o.format) { value = value.matchs(o.format); } if (value) { form[k] = value; } else if (o.error_tip) { tip = await this.view_tip(msg, db, o.error_tip); break; } else if (o.not_tip) { tip = await this.view_tip(msg, db, o.not_tip); break; } ct = ""; } else { keyword = k; tip = await this.view_tip(msg, db, o.not_tip); break; } } } msg.form = JSON.stringify(form); db.form = form; return tip; }; /** * 3.2 更新信息 用于用户更改完善 * @param {Object} msg 消息上下文 * @param {Object} db 数据管理器 * @param {Object} stage 阶段参数 * @return {Object} 返回参数表单 */ Drive.prototype.update = async function(msg, db, stage) { if (!stage) { return ""; } var list = stage.param; if (!list || list.length === 0) { return ""; } var tip = ""; // 获取已有参数 var form = {}; if (msg.form) { form = msg.form.toJson(); } // 补全内容 var ct = msg.content_last || ""; var form = msg.form.toJson(); for (var i = 0; i < list.length; i++) { var o = list[i]; var k = o.name; if (form[k]) { var value = ct.matchs(o.listen); if (value) { if (o.update_tip) { tip = o.update_tip; } else { tip = "那" + value.replace(value.matchs("{不对}"), '是?'); } msg.note = k; break; } else if (msg.note == k && o.format) { value = ct.matchs(o.format); if (value) { form[k] = value; ct = ct.replace(value, ''); break; } } } } msg.form = JSON.stringify(form); db.form = form; return tip; }; /** * 4. 执行阶段 * @param {Object} msg 消息上下文 * @param {Object} db 数据管理器 * @return {Object} 返回执行结果 */ Drive.prototype.main = async function(msg, db) { return "你好"; }; /** * 5. 结束阶段 用来判断是否结束会话 * @param {Object} msg 消息上下文 * @param {Object} db 数据管理器 * @param {Object} ret 执行结果 * @return {Boolean} 返回会话结果 */ Drive.prototype.end = async function(msg, db, ret) { if (ret) { var txt = ""; if (typeof(ret) == "object") { txt = JSON.stringify(ret); } else { txt = ret; } if (this.config.tense == "main") { if (txt.indexOf('?') === -1 && txt.indexOf('?') === -1) { msg.end = 0; } } } return ret; }; /** * 执行前 用于有历史信息时,直接获取,不重复询问 * @param {Object} msg 消息上下文 * @param {Object} db 数据管理器 * @return {Object} 执行结果, 如果有结果则直接跳过其他步骤,并返回 */ Drive.prototype.run_before = async function(msg, db) { return null; }; /** * 执行后, 用于特殊情况下的不结束会话 * @param {Object} msg 消息上下文 * @param {Object} db 数据管理器 * @param {Object} ret 执行结果 * @return {Object} */ Drive.prototype.run_after = async function(msg, db, ret) { return ret; }; /** * 执行 * @param {Object} param 状态参数 * @param {Object} db 数据管理器 * @return {Object} 返回执行结果 */ Drive.prototype.run = async function(msg, db) { var ret; try { // 第一步, 验证阶段 var match = await this.check(msg, db); if (!match) { return } msg.match = match.substring(0, 255); // 第二步, 过滤阶段 await this.filter(msg, db); // 执行前 ret = await this.run_before(msg, db); if (!ret) { // 第三步, 信息补全或更新阶段 var stages = this.config.stage; if (stages.length >= msg.stage) { var stage = stages[msg.stage - 1]; if (stage) { var mode = stage.mode ? stage.mode : "fill"; if (this[mode]) { ret = await this[mode](msg, db, stage); } } } if (!ret) { // 第五步, 执行阶段 ret = await this.main(msg, db); // 第六步, 结束会话阶段 ret = this.end(msg, db, ret); } } // 执行后 ret = await this.run_after(msg, db, ret); } catch (error) { $.log.error("指令执行失败!", this.config.name, error); } return ret; }; /** * 查看参数 * @param {Object} param 状态参数 * @param {Object} db 数据管理器 * @return {Object} 返回结构化参数 */ Drive.prototype.view = function(msg, db) { var ret = ""; if (msg.form) { var json = msg.form.toJson(); var stage = this.config.stage; if (stage && stage.length >= msg.stage) { var list = stage[msg.stage - 1].param; if (list) { for (var i = 0; i < list.length; i++) { var o = list[i]; var value = json[o.name]; if (value) { ret += o.title + ": " + value + "\r\n"; } } } } } return ret.trim(); }; /** * 获取插件 * @param {String} app 应用名称 * @param {String} name 插件名称 * @returns {Object} 返回获取到的插件 */ Drive.prototype.plugin = function(app, name) { var plus; var l = $.slash; if (!app) { app = this.filename.between("app" + l, l); } if (!name) { name = this.filename.between("plugin" + l, l); } var plugins = $.pool.plugin[app]; if (plugins) { plus = plugins.get(name); } return plus } module.exports = Drive;