UNPKG

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
"use strict"; 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;