express-wx
Version:
Express Router for building Wechat Offical Account Message Server easily, supporting loading request (message) handlers dynamically. 快速构建微信公众号消息后端,支持动态加载请求处理逻辑代码。
101 lines (100 loc) • 4.68 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MongoDBUserProvider = exports.WXAPIUserProvider = void 0;
const Logger_1 = require("./Logger");
const Mongoose = require("mongoose");
const SendRequest = require("request-promise");
const utils_1 = require("./utils");
/**
* 这是一个构造函数,它返回的是一个UserProvider。
*
* 被返回的UserProvider的作用即是根据openId,请求微信接口,获取用户信息。当然为了减小接口的压力可能会对用户信息做一个缓存。
*
* @param userInfoCacheTimeMs 用户信息的缓存时间,单位为ms,默认为2小时(7200000ms)。如果指定为0则是不缓存。缓存在本地的内存进行,不会持久化。
* @param toLogData 选填。可以传入函数用于把用户的数据对象变换为可日志记录的格式。默认为:对MongoDBLogger记录昵称、性别、省份、unionid、remark;其余种类的Logger的则只记录昵称字符串。
* @constructor
*/
function WXAPIUserProvider(userInfoCacheTimeMs = 7200000, toLogData) {
let resFunc;
// @ts-ignore
resFunc = async function (openId) {
let { user, date } = resFunc.cache[openId] || {};
// @ts-ignore
if (user && new Date() - date <= resFunc.cacheTime)
return user;
else {
user = await SendRequest.get("https://api.weixin.qq.com/cgi-bin/user/info", {
qs: {
access_token: this.accessToken,
openid: openId,
lang: "zh_CN"
},
json: true
});
(0, utils_1.assertWXAPISuccess)(user);
user.toLogData = toLogData || function (loggerInstance) {
if (loggerInstance instanceof Logger_1.MongoDBLogger) {
let { nickname, sex, province, unionid, remark } = this;
return { nickname, sex, province, unionid, remark: remark ? remark : undefined };
}
return this.nickname;
};
resFunc.cache[openId] = { user, date: new Date() };
return user;
}
};
resFunc.cacheTime = userInfoCacheTimeMs;
resFunc.cache = {};
return resFunc;
}
exports.WXAPIUserProvider = WXAPIUserProvider;
/**
* 这是一个构造函数,它返回的是一个UserProvider。
*
* 被返回的UserProvider的作用即是根据openId,在指定的MongoDB collection中查找出用户对应的数据对象(T类型)。
* 返回的对象类型是T & mongoose.Document,同时具有T指定的属性和mongoose提供的文档操作接口,因而对用户的数据的增删改也同样很方便。
*
* @constructor
* @param connection 可以传MongoDB的URI,形如mongodb://user:password@host:port/database,也可以传Mongoose的Connection。
* @param schema 用户数据对应的mongoose.Schema。
* @param toLogData 必填,指定如何把用户转换为日志格式。
* @param option 选项配置。其中dbName表示使用的database名字(不填则默认为uri中指定的那个database)。
* 而connectionOption的内容是直接原样传给mongoose.createConnection的。
*/
function MongoDBUserProvider(connection, schema, toLogData, option) {
// option处理
option = option || {};
if (option.dbName !== undefined) {
option.connectionOption = option.connectionOption || {};
option.connectionOption.dbName = option.dbName;
}
let openIdName = option.openIdFieldName || "openId";
// 最终要返回的Provider函数
let resFunc;
// 如果是string,则创建连接
if (typeof connection === "string")
connection = Mongoose.createConnection(connection, option.connectionOption);
const indexDefinition = {};
indexDefinition[openIdName] = 1;
schema.index(indexDefinition);
let model = connection.model(schema.get("collection"), schema);
// @ts-ignore
resFunc = async function (openId) {
if (resFunc.valid === false)
throw Error("MongoDB连接失败,故无法查询用户!");
let queryParam = {};
queryParam[openIdName] = openId;
let res = await resFunc.model.findOne(queryParam);
if (res)
res.toLogData = toLogData;
return res;
};
// 如果是pendingConnection,则then一下
if ((0, utils_1.isPromiseLike)(connection))
connection.then(() => resFunc.valid = true, () => resFunc.valid = false);
else
resFunc.valid = true; // 否则直接视为成功
resFunc.model = model;
return resFunc;
}
exports.MongoDBUserProvider = MongoDBUserProvider;