UNPKG

10.9 kBJavaScriptView Raw
1"use strict";
2var __extends = (this && this.__extends) || (function () {
3 var extendStatics = Object.setPrototypeOf ||
4 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6 return function (d, b) {
7 extendStatics(d, b);
8 function __() { this.constructor = d; }
9 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
10 };
11})();
12Object.defineProperty(exports, "__esModule", { value: true });
13var path = require("path");
14var crypto = require("crypto");
15var request = require("request");
16var channel_1 = require("./channel");
17var logger_1 = require("./logger");
18var recime_keyvalue_store_1 = require("recime-keyvalue-store");
19var MaxDuration = 15;
20var WeChat = /** @class */ (function (_super) {
21 __extends(WeChat, _super);
22 function WeChat(bot) {
23 return _super.call(this, { bot: bot, log: new logger_1.WeChatLogger(bot) }) || this;
24 }
25 WeChat.prototype.execute = function (body, parameters, handler) {
26 var _this = this;
27 return new Promise(function (resolve) {
28 _this.context.log.incoming(body);
29 if (body.Event && (body.Event === 'unsubscribe' || body.Event.search(/LOCATION/ig) === 0))
30 return resolve();
31 if (body.Event && (body.Event === 'event' || body.Event.search(/VIEW/ig) === 0))
32 return resolve();
33 handler(_this.context.bot, body, 'wechat', function (messages) {
34 var response = (messages || []).map(function (message) { return function () {
35 return _this.sendMessage(body.FromUserName, message);
36 }; });
37 return response
38 .reduce(function (a, b) {
39 return a.then(function (messages) {
40 return b().then(function (message) {
41 return;
42 });
43 });
44 }, Promise.resolve()).then(function () {
45 resolve();
46 });
47 }, function (err) {
48 resolve(err.message);
49 });
50 });
51 };
52 WeChat.prototype.sendMessage = function (toUser, message) {
53 var _this = this;
54 return new Promise(function (resolve, reject) {
55 var reqData = {
56 touser: toUser,
57 msgtype: message.type,
58 };
59 switch (message.type) {
60 case "text": {
61 reqData.text = {
62 content: message.content
63 };
64 break;
65 }
66 case "audio":
67 case "image":
68 case "video": {
69 message.type = message.type === "audio" ? "voice" : message.type;
70 var media = function () {
71 if (message.media_id) {
72 return Promise.resolve({
73 media_id: message.media_id
74 });
75 }
76 return _this.uploadMedia(message.url, message.type).then(function (data) {
77 reqData.msgtype = data.type;
78 if (data.media_id) {
79 return {
80 media_id: data.media_id
81 };
82 }
83 });
84 };
85 return media().then(function (file) {
86 reqData[message.type] = file;
87 return _this.postMessage(reqData).then(function () {
88 return resolve();
89 });
90 });
91 }
92 case "news": {
93 reqData.news = {
94 "articles": ((message.news || []).articles || []).map(function (article) {
95 return {
96 title: article.title,
97 picurl: article.picurl,
98 url: article.url,
99 description: article.digest
100 // content : article.content
101 };
102 })
103 };
104 break;
105 }
106 case "typing": {
107 return _this.sendTypingMessage(toUser).then(function () {
108 var duration = parseInt(message.duration);
109 setTimeout(function () {
110 return resolve();
111 }, (duration === MaxDuration ? duration - 1 : duration) * 1000);
112 });
113 }
114 default: {
115 reqData.msgtype = "text";
116 reqData.text = {
117 content: message.text || "Message type not supported."
118 };
119 }
120 }
121 ;
122 return _this.postMessage(reqData).then(function () {
123 return resolve();
124 });
125 });
126 };
127 WeChat.prototype.postMessage = function (data) {
128 var _this = this;
129 return new Promise(function (resolve, reject) {
130 _this.accessToken().then(function (accessToken) {
131 var reqData = {
132 url: "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + accessToken,
133 json: true,
134 method: "POST",
135 body: data
136 };
137 request(reqData, function (err, response, body) {
138 if (err) {
139 console.error(err);
140 return resolve();
141 }
142 if (response.statusCode < 200 && response.statusCode > 299) {
143 console.error(body);
144 return resolve();
145 }
146 if (body.errcode) {
147 console.error(body);
148 return resolve();
149 }
150 _this.context.log.outgoing(reqData, body);
151 resolve();
152 });
153 })
154 .catch(function (err) {
155 console.error(err);
156 resolve();
157 });
158 });
159 };
160 WeChat.prototype.sendTypingMessage = function (toUser) {
161 var _this = this;
162 return new Promise(function (resolve) {
163 _this.accessToken().then(function (accessToken) {
164 var options = {
165 uri: "https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=" + accessToken,
166 method: 'POST',
167 json: {
168 command: 'Typing',
169 touser: toUser
170 }
171 };
172 request(options, function (err, response, body) {
173 resolve();
174 });
175 }).catch(function (err) {
176 console.error(err);
177 resolve();
178 });
179 });
180 };
181 WeChat.prototype.accessToken = function () {
182 var _this = this;
183 var db = recime_keyvalue_store_1.default.init(this.context.bot.id);
184 return new Promise(function (resolve, reject) {
185 db.get(_this.context.bot.config.RECIME_WECHAT_APP_ID).then(function (value) {
186 if (value && value.expires > new Date().getTime())
187 resolve(value.token);
188 else {
189 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), {
190 "Accept": "application/json"
191 }, function (err, response, body) {
192 var result = JSON.parse(body);
193 if (response.statusCode < 200 && response.statusCode > 299)
194 return reject(new Error("[Error] Invalid access token"));
195 if (result.errcode)
196 return reject(new Error(result.errmsg));
197 var accessToken = JSON.parse(response.body).access_token;
198 db.set(_this.context.bot.config.RECIME_WECHAT_APP_ID, {
199 expires: Date.now() + 7200,
200 token: accessToken
201 }).then(function () { return resolve(accessToken); });
202 resolve(accessToken);
203 });
204 }
205 });
206 });
207 };
208 WeChat.prototype.uploadMedia = function (mediaUrl, type) {
209 var _this = this;
210 var parsed = require("url").parse(mediaUrl).path;
211 return new Promise(function (resolve) {
212 _this.accessToken().then(function (accessToken) {
213 var readStream = request(mediaUrl);
214 request({
215 url: "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + accessToken + "&type=" + type,
216 json: true,
217 method: "POST",
218 formData: {
219 media: readStream,
220 filename: path.basename(parsed)
221 }
222 }, function (err, response, body) {
223 if (response.statusCode < 200 && response.statusCode > 299) {
224 return resolve({
225 msgtype: "text",
226 content: "[Error] Invalid media url."
227 });
228 }
229 if (body.errcode) {
230 return resolve({
231 msgtype: "text",
232 content: body.errmsg
233 });
234 }
235 return resolve(body);
236 });
237 }, function (err) {
238 return resolve({
239 msgtype: "text",
240 content: err.message
241 });
242 });
243 });
244 };
245 WeChat.prototype.verify = function (query) {
246 var accessToken = process.env.RECIME_WECHAT_ACCESS_TOKEN || this.context.bot.config.RECIME_WECHAT_ACCESS_TOKEN;
247 var token = [query['timestamp'], query['nonce'], accessToken].sort().join("");
248 var hash = crypto.createHash('sha1').update(token).digest('hex');
249 return hash === query['signature'];
250 };
251 return WeChat;
252}(channel_1.Channel));
253exports.WeChat = WeChat;