recime-bot-runtime
Version:
This runtime is intended to run inside a micro-service container with platform specific integration and module interpreter.
333 lines (309 loc) • 14.3 kB
JavaScript
// Copyright 2017 The Recime Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
;
const fs = require("fs");
const path = require("path");``
const query = require("querystring");
const HandleBars = require("handlebars");
const DB = require("recime-keyvalue-store").default;
const Dialog = require("./dist/dialog").Dialog;
const Script = require("./dist/chat-engine/script").Script;``
const BotFramework = require("./dist/bot-framework").BotFramework;
const Facebook = require("./dist/facebook").Facebook;
const Slack = require("./dist/slack").Slack;
const SendBird = require("./dist/sendbird").SendBird;
const Telegram = require("./dist/telegram").Telegram;
const Twilio = require("./dist/twilio").Twilio;
const WeChat = require("./dist/wechat").WeChat;
const Viber = require("./dist/viber").Viber;
const XML = require('./dist/xml').XML;
const SchemaValidator = require('./dist/schema-validator').SchemaValidator;
const MsgObject = require("./dist/msg-object").MsgObject;
const MessageProcessor = require("./dist/message-processor").MessageProcessor;
const WebLogger = require("./dist/logger").WebLogger;
const BotModel = require("./dist/bot-model").BotModel;
const Broadcast = require('./dist/broadcast').Broadcast;
const Message = require('./dist/message').Message;
module.exports = (dir)=> {
var env = process.env;
var host = "";
const handler = function(bot, data, platform, success, error){
const script = new Script(bot);
const converter = new MessageProcessor(bot.id, platform);
var options = {
homedir : dir,
uid : bot.id,
data : converter.convert(data),
env: env,
platform : platform,
host : host
};
script.execute(options).then(success).catch(error);
};
const res = (code, body, contentType)=>{
return {
"statusCode" : code || 200,
"headers": {
"Content-Type" : contentType || "application/json",
"Access-Control-Allow-Origin": "*"
},
"body": body || JSON.stringify({
result: 'alive',
timestamp: new Date()
})
}
};
const html = (body)=>{
return res(200, body, "text/html");
};
const bind = (event, context, callback) => {
if (event.httpMethod === 'GET' && (event.path || '').endsWith('/ping')) {
return callback(void 0, res());
}
const body = MsgObject.parse(event.body || '');
const query = event.queryStringParameters || {};
host = event.host;
const platform = 'web';
var params = {
uid: (() => {
console.log("PATH:", event.path);
const parts = event.path.split('/');
for (let i = 1; i < parts.length; i++) {
if (parts[i].length === 32) {
return parts[i];
}
}
return void 0;
})() || context.functionName,
homedir : dir
};
if (event.path.match(/\/v1\/broadcast/)) {
const model = new BotModel(params.uid);
return model.get().then(bot => {
const broadcast = new Broadcast(bot);
broadcast.send(body).then(result=>{
return callback(void 0, res(200, JSON.stringify(result)));
}).catch(err => {
console.log(err);
callback(void 0, res(200, JSON.stringify(err)));
});
}).catch(err =>{
console.log(err);
callback(void 0, res(err.code, JSON.stringify(err)));
});
}
if (event.path.match(/\/v1\/send/)){
const model = new BotModel(params.uid);
return model.get().then(bot => {
switch(body.platform){
case 'facebook':{
const facebook = new Facebook(bot);
return facebook.send({
sender : body.sender,
messages : [new Message(body.platform).eval(body.message)],
tag : body.tag
});
}
case 'viber' : {
const viber = new Viber(bot);
return viber.send({
sender : body.sender,
messages : [new Message(body.platform).eval(body.message)]
});
}
}
}).then (()=>{
return callback(void 0, res(200, JSON.stringify({ success : true})));
})
.catch(err =>{
console.log(err);
callback(void 0, res(err.code, JSON.stringify(err)));
});
}
if (event.httpMethod === 'GET') {
if (query['hub.mode'] && query['hub.mode'].match(/subscribe/ig)){
const model = new BotModel(params.uid);
return model.get().then(bot=>{
const facebook = new Facebook(bot);
facebook.verifyToken(query).then((result) => {
context.succeed(res(200, result, "text/plain"));
}, (err) => {
context.succeed(res(403, ""));
});
});
}
else if (query['signature'] && query['timestamp'] && query['nonce']){
const model = new BotModel(params.uid);
return model.get().then(bot => {
const wechat = new WeChat(bot);
if (wechat.verify(query)){
context.succeed(res(200, query['echostr'], "text/plain"));
} else {
context.succeed(res(403, "Invalid access token"));
}
});
}else {
if (query["ref"]){
return handler(context.functionName, {
sender : query["ref"]
}, "web", (result)=>{
return context.succeed(html(result));
}, (err)=>{
return context.succeed(res(500, JSON.stringify(err)));
});
}
else {
// warm up
DB.init(params.uid).set('timestamp', Date.now());
Dialog.html({
id: params.uid,
dir : __dirname
}).then ((result)=>{
context.succeed(html(result));
}, (err)=>{
console.log(err);
context.succeed(res(500, "Invalid bot."));
});
}
}
} else {
const model = new BotModel(params.uid);
model.get().then ((bot)=>{
// convert xml to json if necessary.
XML.ifConvert(body).then((body) => {
SchemaValidator.findOne(body).then((platform) => {
switch (platform) {
case "bot-framework": {
const botFramework = new BotFramework(bot);
botFramework.execute(body, query, handler).then(body=>{
context.succeed(res(200, JSON.stringify(body)));
}, (err)=>{
console.error(err);
context.fail(err);
});
break;
}
case "facebook": {
const facebook = new Facebook(bot);
facebook.execute(body, query, handler).then((body) => {
context.succeed(res(200, JSON.stringify(body)));
}, (err) => {
console.error(err);
context.fail(err);
});
break;
}
case "telegram": {
const telegram = new Telegram(bot);
telegram.execute(body, query, handler).then((body) => {
context.succeed(res(200, JSON.stringify(body)));
}, (err) => {
console.error(err);
context.fail(err);
});
break;
}
case "slack": {
const slack = new Slack(bot);
slack.verifyToken(body).then((result) => {
context.succeed(res(200, body.challenge, "text/plain"));
}, (err) => {
context.succeed(res(403, ""));
});
break;
}
case "slack-command": {
context.succeed(res(200, ""));
break;
}
case "slack-event": {
const slack = new Slack(bot);
slack.execute(body, query, handler).then((body) => {
context.succeed(res(200, JSON.stringify(body)));
}, (err) => {
console.error(err);
context.fail(err);
});
break;
}
case "sendbird": {
const sendbird = new SendBird(bot);
sendbird.execute(body, query, handler).then((body) => {
context.succeed(res(200, JSON.stringify(body)));
}, (err) => {
console.error(err);
context.fail(err);
});
break;
}
case "twilio": {
const twilio = new Twilio(bot);
twilio.execute(body, query, handler).then((body) => {
context.succeed(res(200, "<Response/>", "application/xml"));
}, (err) => {
console.error(err);
context.fail(err);
});
break;
}
case "wechat": {
const wechat = new WeChat(bot);
wechat.execute(body, query, handler).then((body) => {
context.succeed(res(200, "", "text/plain"));
}, (err) => {
console.error(err);
context.succeed(res(200, "", "text/plain"));
});
// context.succeed("");
break;
}
case "viber": {
if (body.event === "message" || body.event === "conversation_started") {
const viber = new Viber(bot);
viber.execute(body, query, handler).then((body) => {
context.succeed(res(200, JSON.stringify(body)));
}, (err) => {
context.succeed(res(200, err.message));
});
} else {
context.succeed(res(200, JSON.stringify({
success: true
})));
}
break;
}
default: {
const log = new WebLogger(bot);
return handler(bot, body, platform, (result) => {
log.outgoing(body, result);
return context.succeed(res(200, JSON.stringify(result)));
}, (err) => {
return context.succeed(res(200, JSON.stringify(err)))
});
}
}
}).catch((err) => {
console.error(err);
context.fail(err);
});
});
}).catch((err)=>{
console.error(err);
context.fail(err);
}) // bot
}
};
return {
bind : bind
};
};