mm_os
Version:
这是超级美眉服务端框架,用于快速构建应用程序。
513 lines (486 loc) • 11.8 kB
JavaScript
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;