UNPKG

14 kBJavaScriptView Raw
1// Copyright 2017 The Recime Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14'use strict';
15
16const fs = require("fs");
17const path = require("path");
18const query = require("querystring");
19const HandleBars = require("handlebars");
20
21const DB = require("recime-keyvalue-store").default;
22
23const Dialog = require("./dist/dialog").Dialog;
24const Script = require("./dist/chat-engine/script").Script;
25const BotFramework = require("./dist/bot-framework").BotFramework;
26const Facebook = require("./dist/facebook").Facebook;
27const Slack = require("./dist/slack").Slack;
28const SendBird = require("./dist/sendbird").SendBird;
29const Telegram = require("./dist/telegram").Telegram;
30const Twilio = require("./dist/twilio").Twilio;
31const WeChat = require("./dist/wechat").WeChat;
32const Viber = require("./dist/viber").Viber;
33const XML = require('./dist/xml').XML;
34const SchemaValidator = require('./dist/schema-validator').SchemaValidator;
35const MsgObject = require("./dist/msg-object").MsgObject;
36const MessageProcessor = require("./dist/message-processor").MessageProcessor;
37
38const WebLogger = require("./dist/logger").WebLogger;
39
40const BotModel = require("./dist/bot-model").BotModel;
41const Broadcast = require('./dist/broadcast').Broadcast;
42
43const Message = require('./dist/message').Message;
44
45module.exports = (dir)=> {
46 var env = process.env;
47 var host = "";
48
49 const handler = function(bot, data, platform, success, error){
50 const script = new Script(bot);
51 const converter = new MessageProcessor(bot.id, platform);
52
53 var options = {
54 homedir : dir,
55 uid : bot.id,
56 data : converter.convert(data),
57 env: env,
58 platform : platform,
59 host : host
60 };
61
62 script.execute(options).then(success).catch(error);
63 };
64
65 const res = (code, body, contentType)=>{
66 return {
67 "statusCode" : code || 200,
68 "headers": {
69 "Content-Type" : contentType || "application/json",
70 "Access-Control-Allow-Origin": "*"
71 },
72 "body": body || JSON.stringify({
73 result: 'alive',
74 timestamp: new Date()
75 })
76 }
77 };
78
79 const html = (body)=>{
80 return res(200, body, "text/html");
81 };
82
83 const bind = (event, context, callback) => {
84 if (event.httpMethod === 'GET' && (event.path || '').endsWith('/ping')) {
85 return callback(void 0, res());
86 }
87 const body = MsgObject.parse(event.body || '');
88 const query = event.queryStringParameters || {};
89
90 host = event.host;
91 const platform = 'web';
92
93 var params = {
94 uid: (() => {
95 console.log("PATH:", event.path);
96
97 const parts = event.path.split('/');
98
99 for (let i = 1; i < parts.length; i++) {
100 if (parts[i].length === 32) {
101 return parts[i];
102 }
103 }
104 return void 0;
105 })() || context.functionName,
106 homedir : dir
107 };
108
109 if (event.path.match(/\/v1\/broadcast/)) {
110 const model = new BotModel(params.uid);
111 return model.get().then(bot => {
112 const broadcast = new Broadcast(bot);
113 broadcast.send(body).then(result=>{
114 return callback(void 0, res(200, JSON.stringify(result)));
115 }).catch(err => {
116 console.log(err);
117 callback(void 0, res(200, JSON.stringify(err)));
118 });
119 }).catch(err =>{
120 console.log(err);
121 callback(void 0, res(err.code, JSON.stringify(err)));
122 });
123 }
124 if (event.path.match(/\/v1\/send/)){
125 const model = new BotModel(params.uid);
126 return model.get().then(bot => {
127 switch(body.platform){
128 case 'facebook':{
129 const facebook = new Facebook(bot);
130 return facebook.send({
131 sender : body.sender,
132 messages : [new Message(body.platform).eval(body.message)],
133 tag : body.tag
134 });
135 }
136 }
137 }).then (()=>{
138 return callback(void 0, res(200, JSON.stringify({ success : true})));
139 })
140 .catch(err =>{
141 console.log(err);
142 callback(void 0, res(err.code, JSON.stringify(err)));
143 });
144 }
145 if (event.httpMethod === 'GET') {
146 if (query['hub.mode'] && query['hub.mode'].match(/subscribe/ig)){
147 const model = new BotModel(params.uid);
148 return model.get().then(bot=>{
149 const facebook = new Facebook(bot);
150
151 facebook.verifyToken(query).then((result) => {
152 context.succeed(res(200, result, "text/plain"));
153 }, (err) => {
154 context.succeed(res(403, ""));
155 });
156 });
157 }
158 else if (query['signature'] && query['timestamp'] && query['nonce']){
159 const model = new BotModel(params.uid);
160 return model.get().then(bot => {
161 const wechat = new WeChat(bot);
162 if (wechat.verify(query)){
163 context.succeed(res(200, query['echostr'], "text/plain"));
164 } else {
165 context.succeed(res(403, "Invalid access token"));
166 }
167 });
168 }else {
169 if (query["ref"]){
170 return handler(context.functionName, {
171 sender : query["ref"]
172 }, "web", (result)=>{
173 return context.succeed(html(result));
174 }, (err)=>{
175 return context.succeed(res(500, JSON.stringify(err)));
176 });
177 }
178 else {
179 // warm up
180 DB.init(params.uid).set('timestamp', Date.now());
181
182 Dialog.html({
183 id: params.uid,
184 dir : __dirname
185 }).then ((result)=>{
186 context.succeed(html(result));
187 }, (err)=>{
188 console.log(err);
189 context.succeed(res(500, "Invalid bot."));
190 });
191 }
192 }
193 } else {
194 const model = new BotModel(params.uid);
195 model.get().then ((bot)=>{
196 // convert xml to json if necessary.
197 XML.ifConvert(body).then((body) => {
198 SchemaValidator.findOne(body).then((platform) => {
199 switch (platform) {
200 case "bot-framework": {
201 const botFramework = new BotFramework(bot);
202 botFramework.execute(body, query, handler).then(body=>{
203 context.succeed(res(200, JSON.stringify(body)));
204 }, (err)=>{
205 console.error(err);
206 context.fail(err);
207 });
208 break;
209 }
210 case "facebook": {
211 const facebook = new Facebook(bot);
212 facebook.execute(body, query, handler).then((body) => {
213 context.succeed(res(200, JSON.stringify(body)));
214 }, (err) => {
215 console.error(err);
216 context.fail(err);
217 });
218 break;
219 }
220 case "telegram": {
221 const telegram = new Telegram(bot);
222 telegram.execute(body, query, handler).then((body) => {
223 context.succeed(res(200, JSON.stringify(body)));
224 }, (err) => {
225 console.error(err);
226 context.fail(err);
227 });
228 break;
229 }
230 case "slack": {
231 const slack = new Slack(bot);
232 slack.verifyToken(body).then((result) => {
233 context.succeed(res(200, body.challenge, "text/plain"));
234 }, (err) => {
235 context.succeed(res(403, ""));
236 });
237 break;
238 }
239 case "slack-command": {
240 context.succeed(res(200, ""));
241 break;
242 }
243 case "slack-event": {
244 const slack = new Slack(bot);
245 slack.execute(body, query, handler).then((body) => {
246 context.succeed(res(200, JSON.stringify(body)));
247 }, (err) => {
248 console.error(err);
249 context.fail(err);
250 });
251 break;
252 }
253 case "sendbird": {
254 const sendbird = new SendBird(bot);
255 sendbird.execute(body, query, handler).then((body) => {
256 context.succeed(res(200, JSON.stringify(body)));
257 }, (err) => {
258 console.error(err);
259 context.fail(err);
260 });
261 break;
262 }
263 case "twilio": {
264 const twilio = new Twilio(bot);
265
266 twilio.execute(body, query, handler).then((body) => {
267 context.succeed(res(200, "<Response/>", "application/xml"));
268 }, (err) => {
269 console.error(err);
270 context.fail(err);
271 });
272 break;
273 }
274 case "wechat": {
275 const wechat = new WeChat(bot);
276 wechat.execute(body, query, handler).then((body) => {
277 context.succeed(res(200, "", "text/plain"));
278 }, (err) => {
279 console.error(err);
280 context.succeed(res(200, "", "text/plain"));
281 });
282 // context.succeed("");
283 break;
284 }
285 case "viber": {
286 if (body.event === "message" || body.event === "conversation_started") {
287 const viber = new Viber(bot);
288 viber.execute(body, query, handler).then((body) => {
289 context.succeed(res(200, JSON.stringify(body)));
290 }, (err) => {
291 context.succeed(res(200, err.message));
292 });
293 } else {
294 context.succeed(res(200, JSON.stringify({
295 success: true
296 })));
297 }
298 break;
299 }
300 default: {
301 const log = new WebLogger(bot);
302 return handler(bot, body, platform, (result) => {
303 log.outgoing(body, result);
304 return context.succeed(res(200, JSON.stringify(result)));
305 }, (err) => {
306 return context.succeed(res(200, JSON.stringify(err)))
307 });
308 }
309 }
310 }).catch((err) => {
311 console.error(err);
312 context.fail(err);
313 });
314 });
315 }).catch((err)=>{
316 console.error(err);
317 context.fail(err);
318 }) // bot
319 }
320 };
321
322 return {
323 bind : bind
324 };
325};