UNPKG

vesh

Version:

码农nodejs版本VESH框架,使用函数责任链模式 实现了 默认文件跳转,自定义错误页,空文件处理,URL解析,Querystring与Form参数解析,PostFiles解析,MVC自动映射,SQL自动服务化,可继承页面,静态文件,json,tjson,jsonp,tjsonp,string,void,xjson,xjosnp等等6种JSON格式,http与https等等操作

1,525 lines (1,446 loc) 38.5 kB
import V from "gcl"; import Z from "zlib"; import C from "gcl/com/coooders/io/config"; import CK from "gcl/com/coooders/net/cookie"; import { MIME, get } from "gcl/com/coooders/net/mime"; import N from "gcl/com/coooders/db/ni"; import Q from "querystring"; import xlsx from "node-xlsx"; import socket from "ws"; import { GUID, SNOWID } from "gcl/com/coooders/common/tool"; /** * session:VESH V层会话管理器删除会话信息 */ export const SessionData = class { constructor(id, name) { const { _, __ } = pri(this, { name, idic: {}, isClear: false, isClearCache: false, id, manager: null, }); } get SessionID() { const { _, __ } = pri(this); return __.id; } set SessionID(id) { const { _, __ } = pri(this); if (__.id && __.id != id) throw new Error("SessionID 只能设置一次"); __.id = id; } get Name() { const { _, __ } = pri(this); return __.name; } clear() { const { _, __ } = pri(this); __.isClear = true; __.idic = {}; } get IsClear() { const { _, __ } = pri(this); return __.isClear; } clearCache() { const { _, __ } = pri(this); __.isClearCache = true; } get IsClearCache() { const { _, __ } = pri(this); return __.isClearCache; } data(k, v) { const { _, __ } = pri(this); if (typeof v != "undefined") __.idic[k] = v; else return __.idic[k]; } remove(k) { const { _, __ } = pri(this); delete __.idic[k]; } serialize() { const { _, __ } = pri(this); return V.merge({}, __.idic); } toString() { return V.toJsonString(this.serialize()); } deserialize(data, clear) { const { _, __ } = pri(this); if (clear) __.idic = {}; if (data && data.split) { const _data = Q.parse(data); for (var i in _data) if (typeof _data[i] != "function") __.idic[i] = _data[i]; } else if (typeof data == "object") V.merge(__.idic, data, true); return; } get Manager() { const { _, __ } = pri(this); return __.manager; } set Manager(sdm) { const { _, __ } = pri(this); if (__.manager) throw new Error("manager 只能设置一次"); __.manager = sdm; } dispose() { clear(); } }; export const User = class extends SessionData { constructor() { super(null, ".User"); } get Login() { return super.data("lin") == 1; } set Login(v) { const { _, __ } = pri(this); if (v != this.Login) { super.data("lin", v ? 1 : 0); if (v) { _.LoginTime = new Date(); } else { super.clear(); _.Manager.EIDS.clear(); _.Manager.MEIDS.clear(); _.Manager.MENUS.clear(); _.Manager.Permission.clear(); } } } get UserID() { return super.data("UID"); } set UserID(v) { super.data("UID", v); } get SystemID() { return super.data("SID"); } set SystemID(v) { super.data("SID", v); } get EntityID() { return super.data("EID"); } set EntityID(v) { super.data("EID", v); } get LoginTime() { return super.data("LT"); } set LoginTime(v) { super.data("LT", v); } serialize() { const { _, __ } = pri(this), id = super.SessionID; if (!V.isValid(id)) throw new Error("必须定义SessionID"); if (_.Login) { if (!V.isValid(_.UserID)) throw new Error("必须定义UserID"); this.LoginTime = new Date(); } const ret = super.serialize(); if (this.LoginTime) ret["LT"] = this.LoginTime.getTime(); ret[".ID"] = id; return ret; } deserialize(data, clear) { const { _, __ } = pri(this); super.deserialize(data, clear); if (this.LoginTime) this.LoginTime = new Date(parseInt(this.LoginTime)); if (super.data(".ID") && _.SessionID && _.SessionID != _.data(".ID")) throw new Error("SessionID 不同!不能重复设置!"); else _.SessionID = super.data(".ID"); _.remove(".ID"); } async toString() { const { _, __ } = pri(this); const ret = this.serialize(); delete ret[".ID"]; delete ret["UID"]; delete ret["SID"]; delete ret["EID"]; delete ret["LT"]; delete ret["lin"]; ret.UserID = this.UserID; ret.SessionID = this.SessionID; ret.EntityID = this.EntityID; ret.SystemID = this.SystemID; ret.LoginTime = this.LoginTime; ret.Login = this.Login; if (_.Manager) { ret.EIDS = await _.Manager.EIDS.get(); ret.MEIDS = await _.Manager.MEIDS.get(); ret.PIDS = await _.Manager.Permission.get(); ret.MENUS = await _.Manager.MENUS.get(); } return V.toJsonString(ret); } }; export const CreateID = () => GUID(); export const SessionDataManagerFactory = class { constructor(adapter, security, language) { pri(this, { adapter, security, language }); } getValue() { const { _, __ } = pri(this); return new SessionDataManager(__.adapter, __.security, __.language); } setValue(sdm) { if (sdm && sdm.dispose) sdm.dispose(); } }; /** * SessionDataManager:会话管理 每次请求都会新建一个会话管理用于管理这个会话上下文,改造为prototype模式以方面快速new */ export const SessionDataManager = class { constructor(adapter, passtime, language) { const { _, __ } = pri(this, { adapter: adapter, passtime: passtime || 8, lang: language, idic: {}, user: new User(), wxuser: null, end: false, sb: V.sb(), streams: [], }); __.user.Manager = _; this.status = ""; this.encoding = "UTF-8"; } /** * 最重要的属性 用于决定是否结束moduler链的处理 */ end(statusCode, desc) { const { _, __ } = pri(this); __.end = true; if (__.interrupt) { desc && (this.status = desc); return; } this.Response.statusCode = statusCode; if (desc) _.write(desc, null, true); } get IsEnd() { const { __ } = pri(this); return __.end; } /** * @param {重定向URL} url */ redirect(url) { const { _, __ } = pri(this); __.end = true; if (__.interrupt) return; this.Response.statusCode = 302; this.Response.setHeader("Location", url); } /** * * @param {gcl config对象} config * @param {gcl middler对象} middler * @param {gcl log对象} log * @param {gcl ni对象} ni * @param {node req对象} req * @param {node rep对象} rep */ init(config, middler, log, ni, req, rep, wsSessionIdic) { const { _, __ } = pri(this, { config, middler, log, ni, req, rep }); _.WSSessionMap = wsSessionIdic; } /** * 重新初始化会话纤细 * @param {会话ID} sessionID */ reInit(sessionID) { let { _, __ } = pri(this); for (let k in __) switch (k) { case "adapter": case "config": case "middler": case "log": case "ni": case "req": case "rep": case "lang": case "passtime": break; default: delete __[k]; break; } const user = new User(); user.SessionID = sessionID; user.Manager = _; __.user = user; __.idic = {}; __.end = false; __.sb = V.sb(); __.streams = []; } /** * 不能和init一起运行,因为init运行时没有Cookie等信息 */ async initSession(ID) { const { _, __ } = pri(this); await __.adapter.fillSessionData(__.user); if (!__.user.SessionID) __.user.SessionID = ID || CreateID(); if ( __.user.Login && (!__.user.LoginTime || new Date().sub("h", __.user.LoginTime) >= __.passtime) ) __.user.Login = false; } /** * * @param {文件路径} file */ map(file) { //需要知道__dirname; } write(data, encoding, clear = false) { const { _, __ } = pri(this); _.encoding = encoding || _.encoding; if (clear) __.sb.clear(); __.sb.append(data); } clearWrite() { const { _, __ } = pri(this); __.sb.clear(); } writeStream(stream) { const { _, __ } = pri(this); __.streams.push(stream); } /** * 用于生成符合结构的dbresult; * @param {Object/Array} obj */ async exportDBResult(obj = {}) { var dbresult = obj; var _obj = obj, level = 0; while (V.isArray(_obj || {})) { //开始剥葱 _obj = _obj[0]; level++; } while (level++ < 3) dbresult = [dbresult]; this.dbresult = dbresult; } /** * 用于生成返回的string * @param {Object/Array/Error} obj */ async exportString(obj = {}) { var iserror = obj.toString().startsWith("Error"); this.status = typeof obj == "string" ? obj : V.toJsonString([ [ [ iserror ? { success: false, error: obj.message || obj.err_msg || obj.errmsg, } : { success: true, data: V.isArray(obj) ? obj : [obj], }, ], ], ]); } /** * 导出文件 * @param {流或者Buffer} obj * @param {附件文件名} name */ async exportFile(obj, name) { const { _, __ } = pri(this); if (__.interrupt) return; this.Response.setHeader("content-type", get(name)); this.Response.setHeader( "Content-Disposition", encodeURI("attachment;filename=" + name), ); if (typeof obj == "string") _.write(obj, "utf-8"); else if (obj.on) _.writeStream(obj); else { //_.getResponseStream.write(obj); const stream = new V.ArrayStream(); stream.write(obj); _.writeStream(stream); } } /** * 导出文件 * @param {[[name,name],[value,value],[value,value]]} obj * @param {附件文件名} name */ async exportExcel(db, name) { var count = 0, _db = db, i = 0; while (V.isArray(_db[0])) { _db = _db[0]; count++; } count == 1 && (db = [db]); //1维要升级成2维 count == 0 && (db = [[]]); i = 0; const buffer = xlsx.build( db.map((v) => { return { name: "sheet" + ++i, data: v, }; }), ); // console.log(350,name); await this.exportFile(buffer, name); } clearStream() { const { _, __ } = pri(this); const ret = __.streams; __.streams = []; return ret; } getResponseStream() { const { _, __ } = pri(this); if (__.interrupt) return; return ( __.stream || (function () { let encodings = ( __.req.headers["vesh-encoding"] || __.req.headers["accept-encoding-vesh"] || __.req.headers["accept-encoding"] || "text/plain" ) .replace(/\s/g, "") .split(",") .filter((v) => V.isValid(v)), stream = null; for (let i = 0; i < encodings.length; i++) { const v = encodings[i]; //todo 因为gzip和deflate导致发送压缩计算 影响速度 switch (v.toLowerCase()) { case "gzip": _.Response.setHeader("content-encoding", "gzip"); stream = Z.createGzip(); stream.pipe(_.Response); __.stream = stream; return __.stream; case "deflate": _.Response.setHeader("content-encoding", "deflate"); stream = Z.Deflate(); stream.pipe(_.Response); __.stream = stream; return __.stream; case "ws": case "mqtt": return _.Response; } } //_.Response.setHeader("content-encoding", "text/plain"); __.stream = _.Response; return __.stream; })() ); } async flush() { const { _, __ } = pri(this); if (__.interrupt) return false; if (__.sb && __.sb.length > 0) { const st = _.getResponseStream(); //console.log(394, __.interrupt, __.sb && __.sb.toString(), __.streams && __.streams.length); await V.callback((call) => st.end(__.sb.clear(), _.encoding, call)); //console.log(396, '发送完成'); return false; } else if (__.streams && __.streams.length > 0) { const stream = _.getResponseStream(); await V.each(__.streams, (v, next) => { v.on("error", (err) => { __.log.error("VESH:" + err.stack); next(); }); v.on("end", next); //写入文件 v.pipe(stream, { end: false }); }).then(() => V.callback((call) => { _.Response.on("finish", (err) => { if (err) call(err); _.Response.removeAllListeners("finish"); _.Response.end(); call(null, true); }); __.stream.end(); __.streams = []; }), ); return false; } else if (__.stream) { await V.callback((call) => { _.Response.on("finish", () => { _.Response.removeAllListeners("finish"); _.Response.end(); call(); }); __.stream.end(); }); return false; } else return true; } /** * 中止后续session操作 ,MSocket方法专用 */ async interrupt() { pri(this, { interrupt: true }); } isInterrupt() { return !!pri(this).__.interrupt; } /** * 从QueryString和Form中获取数据 * @param {从QueryString和Form中获取数据} k */ param(k) { const { _, __ } = pri(this); return k ? (_.querystring ? _.querystring[k] : null) || (_.form ? _.form[k] : null) : null; } get Config() { const { _, __ } = pri(this); return __.config; } get Middler() { const { _, __ } = pri(this); return __.middler; } get Log() { const { _, __ } = pri(this); return __.log; } get Ni() { const { _, __ } = pri(this); return __.ni; } get Request() { const { _, __ } = pri(this); return __.req; } get Response() { const { _, __ } = pri(this); return __.rep; } get WebSocket() { const { _, __ } = pri(this); return __.req.webSocket; } get Message() { const { _, __ } = pri(this); return __.req.message; } /** * 主动下行其它SessionID 并返回下行成功的sessionID * @param {*} sessionIDs */ send(sessionIDs, data = {}) { const { _, __ } = pri(this); sessionIDs = V.isArray(sessionIDs) ? sessionIDs : typeof sessionIDs == "string" ? sessionIDs.split(",") : null; var rets = []; // console.log(623, sessionIDs, data); if (sessionIDs && _.WSSessionMap) { sessionIDs.map(function (id) { var client = _.WSSessionMap[id]; if (client && client.readyState == socket.OPEN) { client.send( V.toJsonString( V.merge( { event: "send", ID: V.SNOWID(), data: "", }, data, ), ), ); rets.push(id); } }); } else throw Error("不是webSocket会话!"); return rets; } closeWS(id) { const { _, __ } = pri(this); if (id && _.WSSessionMap) { var client = _.WSSessionMap[id]; try { client.close(); } catch (e) {} delete _.WSSessionMap[id]; } } AppSettings(k) { const { _, __ } = pri(this); return C.AppSettings(__.config, k); } /** * 用户信息 */ get User() { const { _, __ } = pri(this); return __.user; } /** * 用户信息 */ get WXUser() { const { _, __ } = pri(this); return __.wxuser; } set WXUser(v) { const { _, __ } = pri(this); __.wxuser = v; } /** * 角色串 */ get EIDS() { const { _, __ } = pri(this); __.eids = __.eids || new (class { async get() { var eids = await _.data(".EIDS"); var value = eids.data("values") || ""; eids.data("values", value); return value; } async clear() { (await _.data(".EIDS")).clear(); } async set(v = null) { const { __ } = pri(this); if (v) { (await _.data(".EIDS")).data("values", v); } } })(); return __.eids; } /** * 管理角色串 */ get MEIDS() { const { _, __ } = pri(this); __.meids = __.meids || new (class { async get() { var meids = await _.data(".MEIDS"); var value = meids.data("values") || ""; meids.data("values", value); return value; } async clear() { (await _.data(".MEIDS")).clear(); } async set(v = null) { const { __ } = pri(this); if (v) { (await _.data(".MEIDS")).data("values", v); } } })(); return __.meids; } /** * 菜单数组 */ get MENUS() { const { _, __ } = pri(this); __.menus = __.menus || new (class { async get() { let menus = await _.data(".MENUS"); let ret = menus.data("values") || ""; menus.data("values", ret); if (V.isValid(ret) && ret.length > 0) ret = V.json(ret); return ret; } async clear() { (await _.data(".MENUS")).clear(); } async set(v = null) { const { __ } = pri(this); if (v) { (await _.data(".MENUS")).data("values", V.toJsonString(v)); } } })(); return __.menus; } /** * 权限串 */ get Permission() { const { _, __ } = pri(this); __.pers = __.pers || new (class { constructor() { const that = this; pri(that, { params: {}, hasLoad: false }); } async hasRight(v) { const { __ } = pri(this); if (!__.hasLoad) { const config = await _.data(".PIDS"); const vals = config.data("values") || ""; config.data("values", vals); const charset = vals.indexOf(",") >= 0 ? "," : ";"; vals .split(charset) .forEach((v) => v.length > 0 && (__.params[v] = true)); __.hasLoad = true; } return __.params[v] || false; } async set(v = null) { const { __ } = pri(this); if (v) { (await _.data(".PIDS")).data("values", v); const charset = v.indexOf(",") >= 0 ? "," : ";"; v.split(charset).forEach( (v) => v.length > 0 && (__.params[v] = true), ); __.hasLoad = true; } } async clear() { (await _.data(".PIDS")).clear(); } async get() { const { __ } = pri(this); return ((await _.data(".PIDS")).data("values") || "").replace( /;/g, ",", ); } })(); return __.pers; } async hasRight(key) { const value = await this.data(".Permissions"); if (V.isArray(value.data(key))) throw new Error(`${key}的权限值重复!`); return V.isValid(value) && value.data(key) ? await this.Permission.hasRight(value.data(key)) : false; } async data(k) { const { _, __ } = pri(this); if (k.toLowerCase() == _.User.Name.toLowerCase()) return _.User; else if (__.idic[k]) return __.idic[k]; else { const data = await __.adapter.getSessionData(this, _.User.SessionID, k); __.idic[k] = data; return __.idic[k]; } } async update() { const { _, __ } = pri(this); if (!_.isStatic) { await V.forC(__.idic, async (k, v) => { v.IsClear ? await __.adapter.clearSessionData(v) : await __.adapter.saveSessionData(v); return false; }); __.user.IsClear ? await __.adapter.clearSessionData(__.user) : await __.adapter.saveSessionData(__.user); } return; } dispose() { const { _, __ } = pri(this); __.user.dispose(); for (let k in __.idic) __.idic[k].dispose(); } /** * 根据键值进行正则判断 * @param {*} key * @param {*} regex * @param {*} error * @param {*} isRequire */ testRegex(key, regex, error, isRequire) { V.testRegex(this.param(key), regex, error, key, isRequire); return this.param(key); } /** * 限制参数满足是数字 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} isRequire */ testNumber(key, error, isRequire) { V.testNumber(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是数字 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testInt(key, error, isRequire) { V.testInt(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是字母 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testLetter(key, error, isRequire) { V.testLetter(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是数字 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testPassword(key, error, isRequire) { V.testPassword(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是非空必填 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testRequired = (key, error) => { V.testRequired(this.param(key), error || `限制${key}要求为必填`); return this.param(key); }; /** * 限制参数满足是身份证 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testCard(key, error, isRequire) { V.testCard(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是手机号 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testMobile(key, error, isRequire) { V.testMobile(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是座机 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testPhone(key, error, isRequire) { V.testPhone(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是网络地址 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testUrl(key, error, isRequire) { V.testUrl(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是电子邮箱 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testEmail(key, error, isRequire) { V.testEmail(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是中文 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testChinese(key, error, isRequire) { V.testChinese(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是QQ * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testQQ(key, error, isRequire) { V.testQQ(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是邮政编码 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testZipCode(key, error, isRequire) { V.testZipCode(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是IP * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testIP(key, error, isRequire) { V.testIP(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是金额(2位小数) * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testCurreny(key, error, isRequire) { V.testCurreny(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是数字 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} isRequire */ testNumberOrNull(key, error, isRequire) { V.testNumberOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是数字 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testIntOrNull(key, error, isRequire) { V.testIntOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是字母 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testLetterOrNull(key, error, isRequire) { V.testLetterOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是数字 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testPasswordOrNull(key, error, isRequire) { V.testPasswordOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是非空必填 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testRequired = (key, error) => { V.testRequired(this.param(key), error || `限制${key}要求为必填`); return this.param(key); }; /** * 限制参数满足是身份证 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testCardOrNull(key, error, isRequire) { V.testCardOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是手机号 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testMobileOrNull(key, error, isRequire) { V.testMobileOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是座机 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testPhoneOrNull(key, error, isRequire) { V.testPhoneOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是网络地址 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testUrlOrNull(key, error, isRequire) { V.testUrlOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是电子邮箱 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testEmailOrNull(key, error, isRequire) { V.testEmailOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是中文 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testChineseOrNull(key, error, isRequire) { V.testChineseOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是QQ * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testQQOrNull(key, error, isRequire) { V.testQQOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是邮政编码 * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testZipCodeOrNull(key, error, isRequire) { V.testZipCodeOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是IP * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testIPOrNull(key, error, isRequire) { V.testIPOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 限制参数满足是金额(2位小数) * @param {要判断的值} value * @param {错误说明} error * @param {是否必填} testRequire */ testCurrenyOrNull(key, error, isRequire) { V.testCurrenyOrNull(this.param(key), error, key, isRequire); return this.param(key); } /** * 测试访问方法 多个为;号隔开 */ testMethod(methods = "GET") { const method = {}; methods = methods.toUpperCase(); methods.split(";").forEach((v) => (method[v] = true)); if (!method[this.Request.method]) { const e = new Error("限制的Method为" + methods); e.status = 401; throw e; } return true; } /** * 测试访问方法为GET */ testGet() { return this.testMethod("get"); } /** * 测试访问方法为POST */ testPost() { return this.testMethod("post"); } /** * 限制Restful几个方法 */ testRestful() { return this.testMethod("get;post;put;delete"); } /** * * @param {权限名,号隔开} key * @param {错误说明} error */ async testPermission(key, error) { const { _, __ } = pri(this); let val = false; await V.each( key.split(","), async (v) => { val = val || (await _.hasRight(v)); return false; }, true, ); if (!val) { const e = new Error(`该操作需要${key}权限`); e.status = 401; throw e; } return true; } /** * * @param {限制键} key * @param {错误提示} error * @param {限制有效期内单进程只能访问200次} count * @param {限制有效期,时长不能小于1s} time * @param {限制键的最大个数,默认一千万} limit */ testLimit(key = "testLimit", error = "单位时间内请求超过上限", count = 200) { //借用全局对象 sessionDataAdapter 进行数据缓存!和定时清理 const { __ } = pri(this), name = "____limit"; const lim = __.adapter[name] || (function () { var _limit = { cache: {}, checker: new (class { constructor() { const { _, __ } = pri(this, { go: false, run: function () { if (__.go) { setTimeout(function () { _.check(); __.run(); }, 1000); } }, }); } check() { delete _limit.cache; _limit.cache = {}; } start() { const { __ } = pri(this); __.go = true; __.run(); } stop() { pri(this).__.go = false; } })(), }; __.adapter[name] = _limit; _limit.checker.start(); return _limit; })(); lim.cache[key] = lim.cache[key] + 1 || 1; if (lim.cache[key] >= count) throw new Error(error || `键值${key}在1秒内已经到达了上限${count}!`); return true; } }; /** * ASessionSource:数据源基类,定义load,save,clear三个方法 */ export const ASessionSource = class { constructor() { pri(this); } async load(sdm, id, name) { return ""; } async save(sd, data) {} async clear(sd) {} }; /** * 测试用常量会话源 */ export const ConstSessionSource = class extends ASessionSource { constructor(value) { super(); const { _, __ } = pri(this, { value }); } load(sdm, id, name) { const { _, __ } = pri(this); return __.value; } }; /** * 数据源集合 借助CookieModuler完成Cookie会话处理 */ export const CookieSessionSource = class extends ASessionSource { constructor(config = {}) { super(); typeof config == "string" && (config = { domain: config }); const { _, __ } = pri(this, { config }); } async load(sdm, id, name) { if (sdm && sdm.Cookies && (sdm.Cookies[name] || sdm.SetCookies[name])) return Q.stringify((sdm.SetCookies[name] || sdm.Cookies[name]).value); else return null; } async clear(sd) { const { __ } = pri(this); if (sd && sd.Name && sd.Manager && sd.Manager.SetCookies) { let domain = ""; if ( sd.Manager.url.hostname && sd.Manager.url.hostname.match(/[a-zA-Z]/g) ) { domain = sd.Manager.url.hostname.split("."); domain = "." + domain.slice(domain.length - 2).join("."); } sd.Manager.SetCookies[sd.Name] = new CK.Cookie( V.merge({ domain }, __.config, { name: sd.Name, expires: new Date() }), ); } return true; } save(sd, data) { const { __ } = pri(this); if (sd && sd.Name && sd.Manager && sd.Manager.SetCookies) { let domain = ""; if ( sd.Manager.url.hostname && sd.Manager.url.hostname.match(/[a-zA-Z]/g) ) { domain = sd.Manager.url.hostname.split("."); domain = "." + domain.slice(domain.length - 2).join("."); } if (sd.Manager.SetCookies[sd.Name]) { if (V.toJsonString(__.config).length > 2) V.merge({ domain }, sd.Manager.SetCookies[sd.Name], __.config, true); } else { sd.Manager.SetCookies[sd.Name] = new CK.Cookie( V.merge({ domain }, __.config, { name: sd.Name }), ); } sd.Manager.SetCookies[sd.Name].value = data; } return true; } }; /** * SecuritySessionSourceDecorator:借助crypter完成加密会话处理 */ export const SecuritySessionSourceDecorator = class extends ASessionSource { constructor(resource, crypter) { super(); pri(this, { res: resource, crypter }); } async load(sdm, id, name) { const { _, __ } = pri(this); let data = await __.res.load(sdm, id, name); data = data ? (data.split ? Q.parse(data) : data) : ""; if (data["se"]) data = V.json(__.crypter.decrypt(data["se"])); return data; } async save(sd, data) { const { _, __ } = pri(this); for (let k in data) { await __.res.save(sd, { se: __.crypter.encrypt(data.split ? data : V.toJsonString(data)), }); return true; } return false; } async clear(sd) { const { __ } = pri(this); await __.res.clear(sd); } }; /** * NiSessionSource:使用Ni保持和获取会话信息,参数使用key:(sessionID;name)[id,name,value:(any)] * sql必须返回values字段作为结果 */ export const NiSessionSource = class extends ASessionSource { constructor( middler, appname = "Ni", templatename, savename, loadname, clearname, ) { super(); pri(this, { middler, appname, templatename, loadname, savename, clearname, ni: new N.NiTemplateManager(middler, appname), }); } async load(sdm, id = "", name = "") { const { _, __ } = pri(this); const res = await __.ni.excute(__.templatename, __.loadname, { key: (id || "") + ":" + name, id, name, }); if (res.hasData()) { //兼容各种神奇的数据库字段 value与permission.npcf中的字段对应 return (res.last()[0][0] || res.last()[0]).value || ""; } return ""; } async save(sd, data) { const { _, __ } = pri(this); await __.ni.excute(__.templatename, __.savename, { key: `${sd.SessionID}:${sd.Name}`, id: sd.SessionID || "", name: sd.Name || "", value: Q.stringify(data), }); return ""; } async clear(sd) { const { _, __ } = pri(this); const data = sd.serialize(); await __.ni.excute(__.templatename, __.clearname, { key: `${sd.SessionID}:${sd.Name}`, id: sd.SessionID || "", name: sd.Name || "", value: Q.stringify(data), }); return ""; } }; /** * 仅用于一次请求处理期间的数据保持,无法存留 */ export const NoStoreSessionSource = class extends ASessionSource { constructor() { super(); } }; export const SessionDataAdapter = class { constructor(res) { pri(this, { res, idic: {} }); if (!res) throw new Error("默认数据源不能为空!"); } setResource(k, res) { const { _, __ } = pri(this); __.idic[k] = res; } getResource(k) { const { _, __ } = pri(this); return __.idic[k] ? __.idic[k] : __.res; } async fillSessionData(data) { if (data && data.Name) { const source = this.getResource(data.Name); const text = await source.load(data.Manager, data.SessionID, data.Name); if (text) { data.deserialize(text, true); } return data; } else throw new Error("必须拥有name值"); } async getSessionData(manager, id, name) { const sessionData = new SessionData(id, name); sessionData.Manager = manager; return await this.fillSessionData(sessionData); } async saveSessionData(data) { if (data && data.Name) { const source = this.getResource(data.Name); await source.save(data, data.serialize()); } else throw new Error("必须拥有name值"); } async clearSessionData(data) { if (data && data.Name) { const source = this.getResource(data.Name); await source.clear(data); } else throw new Error("必须拥有name值"); } }; export default { SessionData, User, CreateID, SessionDataManagerFactory, SessionDataManager, SessionDataAdapter, ASessionSource, ConstSessionSource, CookieSessionSource, SecuritySessionSourceDecorator, NiSessionSource, NoStoreSessionSource, }; const pri = V.pris();