@broid/twilio
Version:
Convert Twilio messages into Activity Streams 2 with Broid Integration
144 lines (143 loc) • 5.31 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const schemas_1 = require("@broid/schemas");
const utils_1 = require("@broid/utils");
const Promise = require("bluebird");
const events_1 = require("events");
const express_1 = require("express");
const R = require("ramda");
const Rx_1 = require("rxjs/Rx");
const twilio = require("twilio");
const uuid = require("uuid");
const Parser_1 = require("./Parser");
const WebHookServer_1 = require("./WebHookServer");
class Adapter {
constructor(obj) {
this.serviceID = obj && obj.serviceID || uuid.v4();
this.logLevel = obj && obj.logLevel || 'info';
this.token = obj && obj.token || null;
this.tokenSecret = obj && obj.tokenSecret || null;
this.username = obj && obj.username || 'SMS';
this.parser = new Parser_1.Parser(this.serviceName(), this.serviceID, this.logLevel);
this.logger = new utils_1.Logger('adapter', this.logLevel);
this.emitter = new events_1.EventEmitter();
this.router = this.setupRouter();
if (obj.http) {
this.webhookServer = new WebHookServer_1.WebHookServer(obj.http, this.router, this.logLevel);
}
}
users() {
return Promise.reject(new Error('Not supported'));
}
channels() {
return Promise.reject(new Error('Not supported'));
}
serviceId() {
return this.serviceID;
}
serviceName() {
return 'twilio';
}
getRouter() {
if (this.webhookServer) {
return null;
}
return this.router;
}
connect() {
if (this.connected) {
return Rx_1.Observable.of({ type: 'connected', serviceID: this.serviceId() });
}
if (!this.token || !this.tokenSecret) {
return Rx_1.Observable.throw(new Error('Credentials should exist.'));
}
this.session = new twilio.RestClient(this.token, this.tokenSecret);
if (this.webhookServer) {
this.webhookServer.listen();
}
this.connected = true;
return Rx_1.Observable.of({ type: 'connected', serviceID: this.serviceId() });
}
disconnect() {
this.connected = false;
if (this.webhookServer) {
return this.webhookServer.close();
}
return Promise.resolve(null);
}
listen() {
if (!this.session) {
return Rx_1.Observable.throw(new Error('No session found.'));
}
return Rx_1.Observable.fromEvent(this.emitter, 'message')
.switchMap((value) => {
return Rx_1.Observable.of(value)
.mergeMap((event) => this.parser.normalize(event))
.mergeMap((normalized) => this.parser.parse(normalized))
.mergeMap((parsed) => this.parser.validate(parsed))
.mergeMap((validated) => {
if (!validated) {
return Rx_1.Observable.empty();
}
return Promise.resolve(validated);
})
.catch((err) => {
this.logger.error('Caught Error, continuing', err);
return Rx_1.Observable.of(err);
});
})
.mergeMap((value) => {
if (value instanceof Error) {
return Rx_1.Observable.empty();
}
return Promise.resolve(value);
});
}
send(data) {
this.logger.debug('sending', { message: data });
return schemas_1.default(data, 'send')
.then(() => {
const toNumber = R.path(['to', 'id'], data)
|| R.path(['to', 'name'], data);
const objectType = R.path(['object', 'type'], data);
let content = R.path(['object', 'content'], data)
|| R.path(['object', 'name'], data);
if (objectType === 'Image' || objectType === 'Video') {
content = R.path(['object', 'url'], data)
|| R.path(['object', 'content'], data)
|| R.path(['object', 'name'], data);
}
if (objectType === 'Note' || objectType === 'Image' || objectType === 'Video') {
const sms = {
body: content,
from: this.username,
to: toNumber,
};
return new Promise((resolve, reject) => {
return this.session.messages.create(sms, (err) => {
if (err) {
return reject(err);
}
return resolve({ type: 'sent', serviceID: this.serviceId() });
});
});
}
return Promise.reject(new Error('Only Note, Image, and Video are supported.'));
});
}
setupRouter() {
const router = express_1.Router();
router.post('/', (req, res) => {
const event = {
request: req,
response: res,
};
this.emitter.emit('message', event);
const twiml = new twilio.TwimlResponse();
res.type('text/xml');
res.send(twiml.toString());
});
return router;
}
}
exports.Adapter = Adapter;