UNPKG

@broid/flowdock

Version:

Convert Flowdock messages into Activity Streams 2 with Broid Integration

185 lines (184 loc) 7.68 kB
"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 flowdock = require("flowdock"); const R = require("ramda"); const Rx_1 = require("rxjs/Rx"); const uuid = require("uuid"); const Parser_1 = require("./Parser"); const makeRequest = (session, method, ...args) => new Promise((resolve, reject) => session[method](...args, (err, body) => err ? reject(err) : resolve(body))); class Adapter { constructor(obj) { this.serviceID = obj && obj.serviceID || uuid.v4(); this.logLevel = obj && obj.logLevel || 'info'; this.token = obj && obj.token || null; this.parser = new Parser_1.Parser(this.serviceName(), this.serviceID, this.logLevel); this.logger = new utils_1.Logger('adapter', this.logLevel); this.storeUsers = new Map(); this.storeFlows = new Map(); } users() { return Promise.resolve(this.storeUsers); } channels() { return Promise.resolve(this.storeFlows); } serviceId() { return this.serviceID; } serviceName() { return 'flowdock'; } getRouter() { return null; } connect() { if (!this.token) { return Rx_1.Observable.throw(new Error('Credentials should exist.')); } if (this.connected) { return Rx_1.Observable.of({ type: 'connected', serviceID: this.serviceId() }); } this.connected = true; this.session = new flowdock.Session(this.token); return Rx_1.Observable.of({ type: 'connected', serviceID: this.serviceId() }); } disconnect() { this.connected = false; return Promise.resolve(null); } listen() { const getFlows = new Promise((resolve, reject) => { this.session.flows((err, flows) => { if (err) { return reject(err); } return resolve(flows); }); }); return Rx_1.Observable.fromPromise(getFlows) .switchMap((value) => { return Rx_1.Observable.of(value) .mergeMap((flows) => { const users = R.flatten(R.map((flow) => flow.users, flows)); R.forEach((user) => this.storeUsers.set(user.id.toString(), user), users); R.forEach((flow) => this.storeFlows.set(flow.id.toString(), R.dissoc('users', flow)), flows); return Promise.resolve(R.map((flow) => flow.id.toString(), flows)); }) .mergeMap((flowIDs) => { const streams = R.map((flowID) => this.session.stream(flowID, { user: 1 }), flowIDs); const obs = R.map((stream) => Rx_1.Observable.fromEvent(stream, 'message'), streams); return Rx_1.Observable.merge(...obs); }) .mergeMap((event) => { this.logger.debug('Event received', event); if (event.event !== 'message' && event.event !== 'message-edit') { return Rx_1.Observable.empty(); } if (!event.flow) { return this.userByID(event.user) .then((userFrom) => { event.flow = userFrom; event.user = userFrom; event._isPrivate = true; return event; }); } return this.flowByID(event.flow) .then((flow) => { return this.userByID(event.user) .then((user) => { event.flow = flow; event.user = user; return 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(() => { if (R.path(['object', 'type'], data) !== 'Note') { return Promise.reject(new Error('Only Note is supported.')); } return Promise.resolve(data) .then((result) => { const dataType = data.type; const flowID = R.path(['to', 'id'], result); const toType = R.path(['to', 'type'], result); const content = R.path(['object', 'content'], result); const contentID = R.path(['object', 'id'], result); const tags = R.map((tag) => tag.name, R.path(['object', 'tag'], result) || []); const context = R.path(['object', 'context'], result); if (context && context.content) { return Promise.fromCallback((cb) => this.session .threadMessage(flowID, context.content, content, tags, cb)); } else if (toType === 'Group' && (dataType === 'Update' || dataType === 'Delete')) { return this.flowByID(flowID) .then((flow) => Promise.fromCallback((cb) => this.session .editMessage(flow.parameterized_name, R.path(['organization', 'parameterized_name'], flow), Number(contentID), { content, tags }, cb))); } else if (toType === 'Person') { return this.userByID(flowID) .tap(console.log) .then((user) => Promise.fromCallback((cb) => this.session .privateMessage(user.id, content, tags, cb))); } return Promise.fromCallback((cb) => this.session .message(flowID, content, tags, cb)); }); }) .then(({ type: 'sent', serviceID: this.serviceId() })); } userByID(userID) { return Promise.resolve(this.storeUsers.get(userID)) .then((user) => { if (!user) { return makeRequest(this.session, 'users', { id: userID }) .then((body) => { this.storeUsers.set(body.id.toString(), body); return body; }); } return user; }); } flowByID(flowID) { return Promise.resolve(this.storeFlows.get(flowID)) .then((flow) => { if (!flow) { return makeRequest(this.session, '/flows/find', { id: flowID }) .then((body) => { R.forEach((user) => this.storeUsers.set(user.id.toString(), user), body.users); this.storeFlows.set(body.id.toString(), R.dissoc('users', body)); return body; }); } return flow; }); } } exports.Adapter = Adapter;