recime-bot-runtime
Version:
This runtime is intended to run inside a micro-service container with platform specific integration and module interpreter.
254 lines (253 loc) • 10.9 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var path = require("path");
var crypto = require("crypto");
var request = require("request");
var channel_1 = require("./channel");
var logger_1 = require("./logger");
var recime_keyvalue_store_1 = require("recime-keyvalue-store");
var MaxDuration = 15;
var WeChat = /** @class */ (function (_super) {
__extends(WeChat, _super);
function WeChat(bot) {
return _super.call(this, { bot: bot, log: new logger_1.WeChatLogger(bot) }) || this;
}
WeChat.prototype.execute = function (body, parameters, handler) {
var _this = this;
return new Promise(function (resolve) {
_this.context.log.incoming(body);
if (body.Event && (body.Event === 'unsubscribe' || body.Event.search(/LOCATION/ig) === 0))
return resolve();
if (body.Event && (body.Event === 'event' || body.Event.search(/VIEW/ig) === 0))
return resolve();
handler(_this.context.bot, body, 'wechat', function (messages) {
var response = (messages || []).map(function (message) { return function () {
return _this.sendMessage(body.FromUserName, message);
}; });
return response
.reduce(function (a, b) {
return a.then(function (messages) {
return b().then(function (message) {
return;
});
});
}, Promise.resolve()).then(function () {
resolve();
});
}, function (err) {
resolve(err.message);
});
});
};
WeChat.prototype.sendMessage = function (toUser, message) {
var _this = this;
return new Promise(function (resolve, reject) {
var reqData = {
touser: toUser,
msgtype: message.type,
};
switch (message.type) {
case "text": {
reqData.text = {
content: message.content
};
break;
}
case "audio":
case "image":
case "video": {
message.type = message.type === "audio" ? "voice" : message.type;
var media = function () {
if (message.media_id) {
return Promise.resolve({
media_id: message.media_id
});
}
return _this.uploadMedia(message.url, message.type).then(function (data) {
reqData.msgtype = data.type;
if (data.media_id) {
return {
media_id: data.media_id
};
}
});
};
return media().then(function (file) {
reqData[message.type] = file;
return _this.postMessage(reqData).then(function () {
return resolve();
});
});
}
case "news": {
reqData.news = {
"articles": ((message.news || []).articles || []).map(function (article) {
return {
title: article.title,
picurl: article.picurl,
url: article.url,
description: article.digest
// content : article.content
};
})
};
break;
}
case "typing": {
return _this.sendTypingMessage(toUser).then(function () {
var duration = parseInt(message.duration);
setTimeout(function () {
return resolve();
}, (duration === MaxDuration ? duration - 1 : duration) * 1000);
});
}
default: {
reqData.msgtype = "text";
reqData.text = {
content: message.text || "Message type not supported."
};
}
}
;
return _this.postMessage(reqData).then(function () {
return resolve();
});
});
};
WeChat.prototype.postMessage = function (data) {
var _this = this;
return new Promise(function (resolve, reject) {
_this.accessToken().then(function (accessToken) {
var reqData = {
url: "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + accessToken,
json: true,
method: "POST",
body: data
};
request(reqData, function (err, response, body) {
if (err) {
console.error(err);
return resolve();
}
if (response.statusCode < 200 && response.statusCode > 299) {
console.error(body);
return resolve();
}
if (body.errcode) {
console.error(body);
return resolve();
}
_this.context.log.outgoing(reqData, body);
resolve();
});
})
.catch(function (err) {
console.error(err);
resolve();
});
});
};
WeChat.prototype.sendTypingMessage = function (toUser) {
var _this = this;
return new Promise(function (resolve) {
_this.accessToken().then(function (accessToken) {
var options = {
uri: "https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=" + accessToken,
method: 'POST',
json: {
command: 'Typing',
touser: toUser
}
};
request(options, function (err, response, body) {
resolve();
});
}).catch(function (err) {
console.error(err);
resolve();
});
});
};
WeChat.prototype.accessToken = function () {
var _this = this;
var db = recime_keyvalue_store_1.default.init(this.context.bot.id);
return new Promise(function (resolve, reject) {
db.get(_this.context.bot.config.RECIME_WECHAT_APP_ID).then(function (value) {
if (value && value.expires > new Date().getTime())
resolve(value.token);
else {
request.get("https://proxy.recime.io/wechat/token?grant_type=client_credential&appid=" + (process.env.RECIME_WECHAT_APP_ID || _this.context.bot.config.RECIME_WECHAT_APP_ID) + "&secret=" + (process.env.RECIME_WECHAT_APP_SECRET || _this.context.bot.config.RECIME_WECHAT_APP_SECRET), {
"Accept": "application/json"
}, function (err, response, body) {
var result = JSON.parse(body);
if (response.statusCode < 200 && response.statusCode > 299)
return reject(new Error("[Error] Invalid access token"));
if (result.errcode)
return reject(new Error(result.errmsg));
var accessToken = JSON.parse(response.body).access_token;
db.set(_this.context.bot.config.RECIME_WECHAT_APP_ID, {
expires: Date.now() + 7200,
token: accessToken
}).then(function () { return resolve(accessToken); });
resolve(accessToken);
});
}
});
});
};
WeChat.prototype.uploadMedia = function (mediaUrl, type) {
var _this = this;
var parsed = require("url").parse(mediaUrl).path;
return new Promise(function (resolve) {
_this.accessToken().then(function (accessToken) {
var readStream = request(mediaUrl);
request({
url: "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + accessToken + "&type=" + type,
json: true,
method: "POST",
formData: {
media: readStream,
filename: path.basename(parsed)
}
}, function (err, response, body) {
if (response.statusCode < 200 && response.statusCode > 299) {
return resolve({
msgtype: "text",
content: "[Error] Invalid media url."
});
}
if (body.errcode) {
return resolve({
msgtype: "text",
content: body.errmsg
});
}
return resolve(body);
});
}, function (err) {
return resolve({
msgtype: "text",
content: err.message
});
});
});
};
WeChat.prototype.verify = function (query) {
var accessToken = process.env.RECIME_WECHAT_ACCESS_TOKEN || this.context.bot.config.RECIME_WECHAT_ACCESS_TOKEN;
var token = [query['timestamp'], query['nonce'], accessToken].sort().join("");
var hash = crypto.createHash('sha1').update(token).digest('hex');
return hash === query['signature'];
};
return WeChat;
}(channel_1.Channel));
exports.WeChat = WeChat;