comet-messenger
Version:
Yet another way to interact with Facebook Messenger in Node-JS
82 lines (65 loc) • 3 kB
JavaScript
const debug = require('debug')('Comet:Worker');
const facebook = require('./lib/facebook-api');
const messageFactory = require('./lib/messages');
module.exports = function createWorker({ pages, schema }) {
const pages_lookup = {};
pages.forEach(page => {
if (!page || !page.id || !page.token) throw new Error('Invalid page passed to worker');
pages_lookup[`${page.id}`] = page;
});
return {
async process(payload) {
if (!payload || !payload.type || !payload.page_id || !payload.user_id) {
throw new Error(`Invalid payload: ${JSON.stringify(payload)}`);
}
const page = pages_lookup[`${payload.page_id}`];
if (!page) throw new Error(`Unknown page for payload: ${JSON.stringify(payload)}`);
const { type, user_id } = payload;
// If this is a postback item, format it for consistency
if (type === 'postback' && typeof payload.postback === 'string') {
payload.postback = { trigger: `${payload.postback}` };
}
// If postback, do we have a relevant function?
let fn = null;
switch (type) {
case 'postback':
fn = schema._getFunction(`postback.${payload.postback.trigger}`);
if (typeof fn !== 'function') throw new Error(`Missing postback function for "${payload.postback.trigger}"`);
break;
case 'input':
fn = schema._getFunction('input._catch') || function () { /* NOOP */ };
break;
}
if (typeof fn !== 'function') throw new Error(`Unknown type for payload: ${JSON.stringify(payload)}`);
const req = {
page, payload, // eslint-disable-line object-property-newline
meta: {}, // Create a meta object, which will be returned at the end, for logging etc.
send: createSend({ page, user_id }), // Create a simplified send function to make this easy
};
// Run the before functions in parallel
const beforeFns = schema._getFunction('before');
if (beforeFns) await Promise.all(beforeFns.map(bfn => bfn(req)));
debug(JSON.stringify(req));
if (req.pointer && payload.type === 'input') {
fn = schema._getFunction(`input.${req.pointer}`);
if (typeof fn !== 'function') throw new Error(`Missing input function for state "${req.pointer}"`);
}
// run relevant function
await fn(req);
// Run the after functions in parallel
const afterFns = schema._getFunction('after');
if (afterFns) await Promise.all(afterFns.map(afn => afn(req)));
return req.meta;
},
};
};
function createSend({ page, user_id }) {
const { token } = page;
if (!token || !user_id) throw new Error('Missing page.token/user_id');
return async function (messages) {
messages = (Array.isArray(messages) ? messages : [ messages ]).map(messageFactory.toMessage);
for (const message of messages) {
await facebook.send({ access_token: token, message, user_id }); // eslint-disable-line no-await-in-loop
}
};
}