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.4 kB
JavaScript
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();