Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ If you reply with a string, the response will be packaged in a bot-specific form

Individual bots support more complex responses, such as buttons, attachments and so on. You can send all those responses by replying with an object, instead of a string. In that case, _Claudia Bot Builder_ does not transform the response at all, and just passes it back to the sender. It's then your responsibility to ensure that the resulting object is in the correct format for the bot engine. Use `request.type` to discover the bot engine sending the requests.

If you reply with an array multiple messages will be sent in sequence. Each array item can be text or already formatted object and it'll follow the same rules explained above. At the moment, this is supported for Facebook Messenger only.
If you reply with an array multiple messages will be sent in sequence. Each array item can be text or already formatted object and it'll follow the same rules explained above. At the moment, this is supported for Facebook Messenger, GroupMe, Telegram, and Viber only.

Additionally, _Claudia Bot Builder_ exports message generators for for generating more complex responses including buttons and attachments for Facebook and Slack and function for sending delayed/multiple replies.

Expand Down
10 changes: 2 additions & 8 deletions lib/facebook/reply.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const rp = require('minimal-request-promise'),
promiseEach = require('../promise-each'),
breakText = require('../breaktext');

module.exports = function fbReply(recipient, message, fbAccessToken) {
Expand Down Expand Up @@ -30,13 +31,6 @@ module.exports = function fbReply(recipient, message, fbAccessToken) {
};
return rp.post(`https://graph.facebook.com/v2.6/me/messages?access_token=${fbAccessToken}`, options);
},
sendAll = function () {
if (!messages.length) {
return Promise.resolve();
} else {
return sendSingle(messages.shift()).then(sendAll);
}
},
messages = [];

function breakTextAndReturnFormatted(message) {
Expand All @@ -58,5 +52,5 @@ module.exports = function fbReply(recipient, message, fbAccessToken) {
} else {
messages = [message];
}
return sendAll();
return promiseEach(sendSingle)(messages);
};
9 changes: 7 additions & 2 deletions lib/groupme/reply.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
'use strict';
const rp = require('minimal-request-promise');
const promiseEach = require('../promise-each');

function gmReply(message, botId) {
function sendSingle(message, botId) {
var data = {
bot_id: botId,
text: typeof message === 'string' ? message : message.text
Expand All @@ -17,4 +18,8 @@ function gmReply(message, botId) {
return rp.post('https://api.groupme.com/v3/bots/post', options);
}

module.exports = gmReply;
function gmReply(message, botId) {
return promiseEach(m => sendSingle(m, botId))(message);
}

module.exports = gmReply;
16 changes: 16 additions & 0 deletions lib/promise-each.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// adapted from https://raw.githubusercontent.com/yoshuawuyts/promise-each/4d4397e52bea67cd94b0e13010e95ca68fd625f0/index.js

module.exports = each;

// apply a function to all values
// should only be used for side effects
// (fn) -> prom
function each (fn) {
return (arr) => {
arr = Array.isArray(arr) ? arr : [arr];

return arr.reduce((prev, curr, i) => {
return prev.then(() => fn(curr, i, arr.length));
}, Promise.resolve()).then(() => arr);
};
}
30 changes: 9 additions & 21 deletions lib/telegram/reply.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const rp = require('minimal-request-promise');
const promiseEach = require('../promise-each');
const REQUEST_THROTTLE = 1000/30;
const RETRIABLE_ERRORS = ['ECONNRESET', 'ENOTFOUND', 'ESOCKETTIMEDOUT', 'ETIMEDOUT', 'ECONNREFUSED', 'EHOSTUNREACH', 'EPIPE', 'EAI_AGAIN'];
const NUMBER_OF_RETRIES = 20;
Expand Down Expand Up @@ -59,26 +60,13 @@ module.exports = function tlReply(messageObject, message, tlAccessToken) {
};

return sendHttpRequest(tlAccessToken, method, options, numberOfRetries);
},

sendAll = function () {
if (!messages.length) {
return Promise.resolve();
} else {
return sendSingle(messages.shift())
.then(() => {
return new Promise((resolve) => {
if (!messages.length)
resolve();
else
setTimeout(resolve, REQUEST_THROTTLE);
});
})
.then(sendAll);
}
},

messages = Array.isArray(message) ? message : [message];
};

return sendAll();
return promiseEach(m =>
sendSingle(m).then(() =>
new Promise(resolve =>
setTimeout(resolve, REQUEST_THROTTLE)
)
)
)(message);
};
15 changes: 2 additions & 13 deletions lib/viber/reply.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';
const rp = require('minimal-request-promise');
const promiseEach = require('../promise-each');

function sendSingle(receiver, authToken, messageObj) {
let message;
Expand Down Expand Up @@ -30,20 +31,8 @@ function sendSingle(receiver, authToken, messageObj) {
return rp.post('https://chatapi.viber.com/pa/send_message', options);
}

function sendAll(receiver, authToken, messages) {
if (!messages.length) {
return Promise.resolve();
} else {
return sendSingle(receiver, authToken, messages.shift())
.then(() => sendAll(receiver, authToken, messages));
}
}

function sendReply(receiver, messages, authToken) {
if (!Array.isArray(messages))
messages = [messages];

return sendAll(receiver, authToken, messages);
return promiseEach(m => sendSingle(receiver, authToken, m))(messages);
}

module.exports = sendReply;
25 changes: 25 additions & 0 deletions spec/groupme/groupme-reply-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,29 @@ describe('GroupMe Reply', () => {
reply({ sender: 1, text: 'hello groupme', originalRequest: {}, type: 'groupme'}, 123123).then(done, done.fail);
});

describe('when an array is passed', () => {
it('does not send the second request until the first one completes', done => {
let answers = ['foo', 'bar'];
https.request.pipe(() => {
Promise.resolve().then(() => {
expect(https.request.calls.length).toEqual(1);
}).then(done);
});
reply(answers, 123123);
});
it('sends the requests in sequence', done => {
let answers = ['foo', 'bar'];
https.request.pipe(function () {
this.respond('200', 'OK');
if (https.request.calls.length === 2) {
expect(JSON.parse(https.request.calls[0].body[0])).toEqual({bot_id: 123123, text:'foo'});
expect(JSON.parse(https.request.calls[1].body[0])).toEqual({bot_id: 123123, text:'bar'});
done();
}
});
reply(answers, 123123);

});

});
});