express-wx
Version:
Express Router for building Wechat Offical Account Message Server easily, supporting loading request (message) handlers dynamically. 快速构建微信公众号消息后端,支持动态加载请求处理逻辑代码。
460 lines (459 loc) • 17.2 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var TextWXMessage_1, EventWXMessage_1, ImageWXMessage_1, VoiceWXMessage_1, VideoWXMessage_1, ShortVideoWXMessage_1, LocationWXMessage_1, LinkWXMessage_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseMessageXml = exports.MiniProgramPageWXMessage = exports.WXCardWXMessage = exports.MsgMenuWXMessage = exports.MPNewsWXMessage = exports.NoResponseWXMessage = exports.NewsWXMessage = exports.MusicWXMessage = exports.LinkWXMessage = exports.LocationWXMessage = exports.ShortVideoWXMessage = exports.VideoWXMessage = exports.VoiceWXMessage = exports.ImageWXMessage = exports.EventWXMessage = exports.TextWXMessage = exports.WXMessageBasicPart = exports.WXMessageReceiveClass = void 0;
const utils_1 = require("./utils");
const request = require("request-promise");
const naming_style_1 = require("naming-style");
let _registeredWXTypes = {};
/** @decorator */
function WXMessageReceiveClass(typeName, cannotToXML = false) {
return (target) => {
if (target.hasOwnProperty("fromXML")) {
_registeredWXTypes[typeName] = target;
}
else {
target["fromXML"] = function () {
throw Error("微信API未定义此种消息类型为可能接收到的消息类型!您很可能是收到了一个不是一个来自微信官方的请求。");
};
}
if (!target.prototype.hasOwnProperty("toJson"))
target.prototype.toJson = function () {
throw Error("微信API未提供向用户发送此类型的消息的方法!");
};
if (cannotToXML)
target.prototype.toXML = function () {
throw Error("该类型的消息不能被回复给用户,只能通过客服消息发送!");
};
};
}
exports.WXMessageReceiveClass = WXMessageReceiveClass;
let _wxJsonToXmlKeyAdapter = {
musicurl: "MusicUrl",
hqmusicurl: "HQMusicUrl",
picurl: "PicUrl"
};
function addJSONtoXML(xml, json) {
for (let k in json) {
if (k === "touser" || k === "msgtype")
continue;
let v = json[k];
let type = typeof v;
let parsedKey = _wxJsonToXmlKeyAdapter[k] || (0, naming_style_1.pascal)(k);
if (type === "string" || type === "boolean" || type === "number")
(0, utils_1.xmlSetText)(xml, parsedKey, v, true);
else if (type === "object") {
if (v instanceof Array) {
xml[parsedKey] = { item: v.map((o) => addJSONtoXML({}, o)) };
}
else
xml[parsedKey] = addJSONtoXML({}, v);
}
}
return xml;
}
class WXMessageBasicPart {
constructor(type, openId) {
if (!type)
return;
this.type = type;
this.openId = openId;
this.CreateTime = new Date();
}
addBasicPartToXML(xml) {
this.type = (0, utils_1.xmlGetKey)(xml, "MsgType");
this.openId = (0, utils_1.xmlGetKey)(xml, "FromUserName");
this.CreateTime = new Date(Number((0, utils_1.xmlGetKey)(xml, "CreateTime")) * 1000);
this.MsgId = (0, utils_1.xmlGetKey)(xml, "MsgId");
return this;
}
static fromXML(xml) {
return new WXMessageBasicPart(null).addBasicPartToXML(xml);
}
toJson() {
return {
touser: this.openId,
msgtype: this.type
};
}
toXML() {
// 在消息转xml阶段,是不加入FromUserName信息的,由内置中间件在之后根据req中提供的信息加入进来。
// 而如果openId已经指定,则会自动填入ToUserName;否则会留空ToUserName,之后由WXRouter上的逻辑手动填入。
let xml = {};
(0, utils_1.xmlSetText)(xml, "MsgType", this.type, true);
(0, utils_1.xmlSetText)(xml, "CreateTime", String(Math.round(this.CreateTime.getTime() / 1000)));
(0, utils_1.xmlSetText)(xml, "ToUserName", this.openId, true);
addJSONtoXML(xml, this.toJson());
return xml;
}
toLog() {
let o = Object.assign({}, this);
delete o.openId;
delete o.CreateTime;
delete o.MsgId;
return o;
}
}
exports.WXMessageBasicPart = WXMessageBasicPart;
let TextWXMessage = TextWXMessage_1 = class TextWXMessage extends WXMessageBasicPart {
constructor(text) {
super("text");
this.type = "text";
this.text = text;
}
static fromXML(xml) {
let ins = new TextWXMessage_1((0, utils_1.xmlGetKey)(xml, "Content")).addBasicPartToXML(xml);
ins.bizmsgmenuid = (0, utils_1.xmlGetKey)(xml, "bizmsgmenuid");
return ins;
}
toJson() {
let s = super.toJson();
s.text = { content: this.text };
return s;
}
toXML() {
let xml = super.toXML();
xml.Content = xml.Text.Content;
delete xml.Text;
return xml;
}
toLog() {
if (!this.bizmsgmenuid)
return this.text;
else
return super.toLog();
}
};
TextWXMessage = TextWXMessage_1 = __decorate([
WXMessageReceiveClass("text")
], TextWXMessage);
exports.TextWXMessage = TextWXMessage;
let EventWXMessage = EventWXMessage_1 = class EventWXMessage extends WXMessageBasicPart {
constructor() {
super("event");
this.type = "event";
}
static fromXML(xml) {
let ins = new EventWXMessage_1().addBasicPartToXML(xml);
ins.event = (0, utils_1.xmlGetKey)(xml, "Event");
ins.EventKey = (0, utils_1.xmlGetKey)(xml, "EventKey");
if (ins.event === "subscribe" || ins.event === "SCAN")
ins.Ticket = (0, utils_1.xmlGetKey)(xml, "Ticket");
if (ins.event === "LOCATION")
ins.positionInfo = {
Latitude: (0, utils_1.xmlGetKey)(xml, "Latitude"),
Longitude: (0, utils_1.xmlGetKey)(xml, "Longitude"),
Precision: (0, utils_1.xmlGetKey)(xml, "Precision")
};
if (ins.event === "TEMPLATESENDJOBFINISH")
ins.Status = (0, utils_1.xmlGetKey)(xml, "Status");
return ins;
}
};
EventWXMessage = EventWXMessage_1 = __decorate([
WXMessageReceiveClass("event")
], EventWXMessage);
exports.EventWXMessage = EventWXMessage;
let ImageWXMessage = ImageWXMessage_1 = class ImageWXMessage extends WXMessageBasicPart {
constructor(MediaId) {
super("image");
this.type = "image";
this.MediaId = MediaId;
}
static fromXML(xml) {
let ins = new ImageWXMessage_1((0, utils_1.xmlGetKey)(xml, "MediaId")).addBasicPartToXML(xml);
ins.PicUrl = (0, utils_1.xmlGetKey)(xml, "PicUrl");
return ins;
}
toJson() {
let s = super.toJson();
s.image = { "media_id": this.MediaId };
return s;
}
async requestBytes() {
if (!this.PicUrl)
return null;
return request(this.PicUrl, {
method: "GET",
timeout: 3000,
encoding: null,
gzip: true
});
}
};
ImageWXMessage = ImageWXMessage_1 = __decorate([
WXMessageReceiveClass("image")
], ImageWXMessage);
exports.ImageWXMessage = ImageWXMessage;
let VoiceWXMessage = VoiceWXMessage_1 = class VoiceWXMessage extends WXMessageBasicPart {
constructor(MediaId) {
super("voice");
this.type = "voice";
this.MediaId = MediaId;
}
static fromXML(xml) {
let ins = new VoiceWXMessage_1((0, utils_1.xmlGetKey)(xml, "MediaId")).addBasicPartToXML(xml);
ins.Format = (0, utils_1.xmlGetKey)(xml, "Format");
ins.Recognition = (0, utils_1.xmlGetKey)(xml, "Recognition");
return ins;
}
toJson() {
let s = super.toJson();
s.voice = { media_id: this.MediaId };
return s;
}
async requestBytes() {
throw Error("利用素材接口获取该Media的方法暂未实现!");
}
};
VoiceWXMessage = VoiceWXMessage_1 = __decorate([
WXMessageReceiveClass("voice")
], VoiceWXMessage);
exports.VoiceWXMessage = VoiceWXMessage;
let VideoWXMessage = VideoWXMessage_1 = class VideoWXMessage extends WXMessageBasicPart {
constructor(MediaId, title, description) {
super("video");
this.type = "video";
this.MediaId = MediaId;
this.title = title;
this.description = description;
}
static fromXML(xml) {
let ins = new VideoWXMessage_1((0, utils_1.xmlGetKey)(xml, "MediaId")).addBasicPartToXML(xml);
ins.ThumbMediaId = (0, utils_1.xmlGetKey)(xml, "ThumbMediaId");
return ins;
}
toJson() {
let s = super.toJson();
s.video = {
media_id: this.MediaId,
thumb_media_id: this.ThumbMediaId,
title: this.title,
description: this.description
};
return s;
}
async requestBytes() {
throw Error("利用素材接口获取该Media的方法暂未实现!");
}
async requestThumbBytes() {
throw Error("利用素材接口获取该Media的方法暂未实现!");
}
};
VideoWXMessage = VideoWXMessage_1 = __decorate([
WXMessageReceiveClass("video")
], VideoWXMessage);
exports.VideoWXMessage = VideoWXMessage;
let ShortVideoWXMessage = ShortVideoWXMessage_1 = class ShortVideoWXMessage extends WXMessageBasicPart {
constructor() {
super("shortvideo");
this.type = "shortvideo";
}
static fromXML(xml) {
let ins = new ShortVideoWXMessage_1().addBasicPartToXML(xml);
ins.MediaId = (0, utils_1.xmlGetKey)(xml, "MediaId");
ins.ThumbMediaId = (0, utils_1.xmlGetKey)(xml, "ThumbMediaId");
return ins;
}
async requestBytes() {
throw Error("利用素材接口获取该Media的方法暂未实现!");
}
async requestThumbBytes() {
throw Error("利用素材接口获取该Media的方法暂未实现!");
}
};
ShortVideoWXMessage = ShortVideoWXMessage_1 = __decorate([
WXMessageReceiveClass("shortvideo")
], ShortVideoWXMessage);
exports.ShortVideoWXMessage = ShortVideoWXMessage;
let LocationWXMessage = LocationWXMessage_1 = class LocationWXMessage extends WXMessageBasicPart {
constructor() {
super("location");
this.type = "location";
}
static fromXML(xml) {
let ins = new LocationWXMessage_1().addBasicPartToXML(xml);
ins.x = (0, utils_1.xmlGetKey)(xml, "Location_X");
ins.y = (0, utils_1.xmlGetKey)(xml, "Location_Y");
ins.scale = (0, utils_1.xmlGetKey)(xml, "Scale");
ins.label = (0, utils_1.xmlGetKey)(xml, "Label");
return ins;
}
};
LocationWXMessage = LocationWXMessage_1 = __decorate([
WXMessageReceiveClass("location")
], LocationWXMessage);
exports.LocationWXMessage = LocationWXMessage;
let LinkWXMessage = LinkWXMessage_1 = class LinkWXMessage extends WXMessageBasicPart {
constructor() {
super("link");
this.type = "link";
}
static fromXML(xml) {
let ins = new LinkWXMessage_1().addBasicPartToXML(xml);
ins.url = (0, utils_1.xmlGetKey)(xml, "Url");
ins.title = (0, utils_1.xmlGetKey)(xml, "Title");
ins.description = (0, utils_1.xmlGetKey)(xml, "Description");
return ins;
}
};
LinkWXMessage = LinkWXMessage_1 = __decorate([
WXMessageReceiveClass("link")
], LinkWXMessage);
exports.LinkWXMessage = LinkWXMessage;
/** 此消息类型只会作为回复类型,不会出现在收到的消息中。 */
let MusicWXMessage = class MusicWXMessage extends WXMessageBasicPart {
constructor(ThumbMediaId, MusicURL, HQMusicURL, title, description) {
super("music");
this.type = "music";
this.ThumbMediaId = ThumbMediaId;
this.MusicURL = MusicURL;
this.HQMusicURL = HQMusicURL;
this.title = title;
this.description = description;
}
toJson() {
let s = super.toJson();
s.music = {
title: this.title,
description: this.description,
musicurl: this.MusicURL,
hqmusicurl: this.HQMusicURL,
thumb_media_id: this.ThumbMediaId
};
return s;
}
};
MusicWXMessage = __decorate([
WXMessageReceiveClass("music")
], MusicWXMessage);
exports.MusicWXMessage = MusicWXMessage;
/** 图文消息类型。此消息类型只会作为回复类型,不会出现在收到的消息中。 */
let NewsWXMessage = class NewsWXMessage extends WXMessageBasicPart {
constructor(articles) {
super("news");
this.type = "news";
this.articles = articles;
}
toJson() {
let s = super.toJson();
s.news = {
articles: this.articles
};
return s;
}
};
NewsWXMessage = __decorate([
WXMessageReceiveClass("news")
], NewsWXMessage);
exports.NewsWXMessage = NewsWXMessage;
/** 表示希望对客户端不予回复任何消息(即接口返回"success")。此消息类型只会作为回复类型,不会出现在收到的消息中。 */
class NoResponseWXMessage extends WXMessageBasicPart {
constructor() {
super("noresponse");
this.type = "noresponse";
}
toXML(xml) {
return null;
}
toLog() {
return null;
}
}
exports.NoResponseWXMessage = NoResponseWXMessage;
/** 图文消息类型。此消息类型只会作为**客服消息**的回复类型,不会出现在收到的消息中、也不能通过被动回复返回给用户。 */
let MPNewsWXMessage = class MPNewsWXMessage extends WXMessageBasicPart {
constructor(MediaId) {
super("mpnews");
this.type = "mpnews";
this.MediaId = MediaId;
}
toJson() {
let s = super.toJson();
s.mpnews = { media_id: this.MediaId };
return s;
}
};
MPNewsWXMessage = __decorate([
WXMessageReceiveClass("mpnews", true)
], MPNewsWXMessage);
exports.MPNewsWXMessage = MPNewsWXMessage;
/** 图文消息类型。此消息类型只会作为**客服消息**的回复类型,不会出现在收到的消息中、也不能通过被动回复返回给用户。 */
let MsgMenuWXMessage = class MsgMenuWXMessage extends WXMessageBasicPart {
constructor(head_content, list, tail_content) {
super("msgmenu");
this.type = "msgmenu";
this.head_content = head_content;
this.list = list;
this.tail_content = tail_content;
}
toJson() {
let s = super.toJson();
s.msgmenu = {
head_content: this.head_content,
list: this.list,
tail_content: this.tail_content
};
return s;
}
};
MsgMenuWXMessage = __decorate([
WXMessageReceiveClass("msgmenu", true)
], MsgMenuWXMessage);
exports.MsgMenuWXMessage = MsgMenuWXMessage;
/** 图文消息类型。此消息类型只会作为**客服消息**的回复类型,不会出现在收到的消息中、也不能通过被动回复返回给用户。 */
let WXCardWXMessage = class WXCardWXMessage extends WXMessageBasicPart {
constructor(card_id) {
super("wxcard");
this.type = "wxcard";
this.card_id = card_id;
}
toJson() {
let s = super.toJson();
s.wxcard = { card_id: this.card_id };
return s;
}
};
WXCardWXMessage = __decorate([
WXMessageReceiveClass("wxcard", true)
], WXCardWXMessage);
exports.WXCardWXMessage = WXCardWXMessage;
/** 图文消息类型。此消息类型只会作为**客服消息**的回复类型,不会出现在收到的消息中、也不能通过被动回复返回给用户。 */
let MiniProgramPageWXMessage = class MiniProgramPageWXMessage extends WXMessageBasicPart {
constructor(titie, appid, pagepath, thumb_media_id) {
super("mpnews");
this.type = "mpnews";
this.title = titie;
this.appid = appid;
this.pagepath = pagepath;
this.thumb_media_id = thumb_media_id;
}
toJson() {
let s = super.toJson();
s.miniprogrampage = {
title: this.title,
appid: this.appid,
pagepath: this.pagepath,
thumb_media_id: this.thumb_media_id
};
return s;
}
};
MiniProgramPageWXMessage = __decorate([
WXMessageReceiveClass("miniprogrampage", true)
], MiniProgramPageWXMessage);
exports.MiniProgramPageWXMessage = MiniProgramPageWXMessage;
function parseMessageXml(xml) {
let type = (0, utils_1.xmlGetKey)(xml, "MsgType");
let cls = _registeredWXTypes[type];
if (!cls)
throw Error("收到了不支持的消息类型!");
return cls.fromXML(xml);
}
exports.parseMessageXml = parseMessageXml;