Skip to content

Commit 71ccb46

Browse files
committed
fix: dont dispatch delivery notifications to catchAll as it may cause an infinite loop :O
1 parent a285fb7 commit 71ccb46

File tree

3 files changed

+105
-46
lines changed

3 files changed

+105
-46
lines changed

src/facebook/bot.ts

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ export class FacebookBot {
4141
}
4242

4343
public receiveMessage(fbMessage: IFbCallback) {
44+
var promises: any = [];
4445
// console.log('received message ..', JSON.stringify(fbMessage, null, 2));
45-
if (fbMessage.object !== FB_MESSAGE_TYPE.PAGE) return false;
46+
if (fbMessage.object !== FB_MESSAGE_TYPE.PAGE) return Promise.reject('invalid message type');
4647
for (var entry of fbMessage.entry) {
4748
// skip messages for other page_id
4849
if (entry.id.toString() !== this.settings.fb.page_id) {
@@ -51,38 +52,41 @@ export class FacebookBot {
5152
}
5253
// console.log('messaging ..', JSON.stringify(entry.messaging, null, 2));
5354
for (var messaging of entry.messaging) {
54-
this.dispatchSingleMessage(messaging);
55+
let p = this.getUserFromMessage(messaging)
56+
.then(this.dispatchSingleMessage.bind(this, messaging))
57+
.catch( err => {
58+
console.log(`error retrieving user ${JSON.stringify(err)}`);
59+
throw err;
60+
});
61+
promises.push(p);
5562
}
5663
}
57-
return true;
64+
return Promise.all(promises);
5865
}
5966

60-
public dispatchSingleMessage(messaging: IFbMessaging) {
67+
public dispatchSingleMessage(messaging: IFbMessaging, user: IBotUser) {
6168
let reply: FacebookReply = new FacebookReply(messaging.sender.id, this.fbApi);
69+
if (messaging.delivery) {
70+
return (this.botController.delivered) ? this.botController.delivered(user, messaging.delivery, reply) : null;
71+
}
6272
// console.log('dispatching..');
6373
if (messaging.optin) {
64-
return this.getUserFromMessage(messaging)
65-
.then( (user: IBotUser) => {
66-
return this.botController.newUser({user, ref: messaging.optin.ref}, reply);
67-
});
74+
return (this.botController.newUser) ? this.botController.newUser({user, ref: messaging.optin.ref}, reply) : null;
6875
}
69-
return this.getUserFromMessage(messaging)
70-
.then( (user: IBotUser) => {
71-
if (messaging.message) {
72-
if (messaging.message.text) {
73-
let textMessage: ITextMessage = {
74-
user,
75-
text: messaging.message.text
76-
}
77-
console.log(JSON.stringify(textMessage));
78-
return (this.botController.textMessage) ? this.botController.textMessage(textMessage, reply) : null;
79-
}
80-
if (messaging.message.attachments) {
81-
return this.dispatchAttachmentMessage(messaging, user);
76+
if (messaging.message) {
77+
if (messaging.message.text) {
78+
let textMessage: ITextMessage = {
79+
user,
80+
text: messaging.message.text
8281
}
82+
console.log(JSON.stringify(textMessage));
83+
return (this.botController.textMessage) ? this.botController.textMessage(textMessage, reply) : null;
8384
}
84-
return (this.botController.catchAll) ? this.botController.catchAll(user, messaging, reply) : null;
85-
});
85+
if (messaging.message.attachments) {
86+
return this.dispatchAttachmentMessage(messaging, user);
87+
}
88+
}
89+
return (this.botController.catchAll) ? this.botController.catchAll(user, messaging, reply) : null;
8690
}
8791

8892

src/interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export interface IBotController {
8888
imageMessage?(imageMessage: IImageMessage, reply: IBotReply): void;
8989
linkMessage?(linkMessage: ILinkMessage, reply: IBotReply): void;
9090
locationMessage?(locationMessage: ILocationMessage, reply: IBotReply): void;
91+
delivered?(user: IBotUser, delivery: Object, reply: IBotReply): void;
9192
catchAll?(user: IBotUser, msg: Object, reply: IBotReply): void;
9293
}
9394

tests/bot.spec.ts

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11

22
import {expect} from 'chai';
33
import * as sinon from 'sinon';
4-
import {FacebookBot} from '../src/facebook';
4+
import {FacebookBot, IFbMessaging} from '../src/facebook';
55
import {IBotSettings, INewUserMessage, IBotUser, IBotController} from '../src/interfaces';
66

77
class DummyController implements IBotController {
8-
newUser(msg: INewUserMessage) {console.log('got new user');}
9-
textMessage(textMessage: any) {console.log('got new textMessage');}
10-
imageMessage(image: any) {console.log('got new imageMessage');}
11-
linkMessage(link: any) {console.log('got linkMessage');}
12-
locationMessage(link: any) {console.log('got locationMessage');}
13-
catchAll(anything: any) {console.log('got catchAll');}
8+
cc = {
9+
newUser: 0,
10+
textMessage: 0,
11+
imageMessage: 0,
12+
linkMessage: 0,
13+
locationMessage: 0,
14+
delivered: 0,
15+
catchAll: 0,
16+
}
17+
newUser(msg: INewUserMessage) {console.log('got new user'); this.cc.newUser++;}
18+
textMessage(textMessage: any) {console.log('got new textMessage'); this.cc.textMessage++;}
19+
imageMessage(image: any) {console.log('got new imageMessage'); this.cc.imageMessage++;}
20+
linkMessage(link: any) {console.log('got linkMessage'); this.cc.linkMessage++;}
21+
locationMessage(link: any) {console.log('got locationMessage'); this.cc.locationMessage++;}
22+
delivered(link: any) {console.log('got delivered'); this.cc.delivered++;}
23+
catchAll(anything: any) {console.log('got catchAll'); this.cc.catchAll++;}
1424
}
1525

1626

@@ -22,29 +32,57 @@ describe('FacebookBot', () => {
2232
beforeEach(function () {
2333
ctrl = new DummyController();
2434
bot = new FacebookBot(fbSettings(), ctrl);
35+
bot.profiles [123] = {
36+
id: 123,
37+
firstname: 'Foo',
38+
lastname: 'Bar'
39+
};
2540
});
2641

2742
describe('receiveMessage', () => {
28-
it('return false if message type != page', () => {
29-
expect(bot.receiveMessage({object: 'foo', entry: []})).to.eql(false);
43+
it('return false if message type != page', (done) => {
44+
let expected = 'invalid message type';
45+
bot.receiveMessage({object: 'foo', entry: []})
46+
.catch( err => {
47+
expect(err).to.eql(expected);
48+
done();
49+
})
3050
});
31-
it('return true if message has been processed', () => {
32-
expect(bot.receiveMessage({object: 'page', entry: []})).to.eql(true);
33-
});
34-
it('should dispatch each message', () => {
35-
bot.receiveMessage(fakeMessageMixed());
51+
// it('return true if message has been processed', () => {
52+
// expect(bot.receiveMessage({object: 'page', entry: []})).to.eql(true);
53+
// });
54+
it('should dispatch each message', (done) => {
55+
bot.receiveMessage(fakeMessageMixed())
56+
.then( dispatchResults => {
57+
expect(dispatchResults.length).to.eql(4);
58+
expect(ctrl.cc.delivered).to.eql(1);
59+
expect(ctrl.cc.textMessage).to.eql(1);
60+
expect(ctrl.cc.imageMessage).to.eql(1);
61+
expect(ctrl.cc.locationMessage).to.eql(1);
62+
done();
63+
})
3664
// just console.log testing for now :(
3765
// if anyone knows a good mocking library for typescript youre welcome :)
38-
expect(true).to.eql(true);
66+
3967
});
68+
69+
});
70+
describe('dispatchSingleMessage', () => {
71+
it('should not dispatch delivery messages to catchAll', () => {
72+
let fakeMsgs = fakeMessageMixed(),
73+
message: IFbMessaging = fakeMsgs.entry[0].messaging[0];
74+
let result = bot.dispatchSingleMessage(message, {id: '1', firstname: 'foo', lastname: 'bar'} );
75+
expect(ctrl.cc.delivered).to.eql(1);
76+
expect(ctrl.cc.catchAll).to.eql(0);
4077
});
78+
})
4179
});
4280

4381

4482
function fbSettings(): IBotSettings {
4583
return {
4684
fb: {
47-
page_id: '1442484699367623',
85+
page_id: '234',
4886
access_token: 'at1',
4987
verify_token: 'vt1',
5088
callback_path: '/facebook/receive',
@@ -58,15 +96,31 @@ function fakeMessageMixed() {
5896
"object": "page",
5997
"entry": [
6098
{
61-
"id": 1442484699367623,
99+
"id": 234,
62100
"time": 1462967781419,
63101
"messaging": [
102+
{
103+
"sender":{
104+
"id":123
105+
},
106+
"recipient":{
107+
"id":234
108+
},
109+
"timestamp":1460245672080,
110+
"delivery":{
111+
"mids":[
112+
"mid.1458668856218:ed81099e15d3f4f233"
113+
],
114+
"watermark":1458668856253,
115+
"seq":37
116+
}
117+
},
64118
{
65119
"sender":{
66-
"id":10208007577165870
120+
"id":123
67121
},
68122
"recipient":{
69-
"id": 1442484699367623
123+
"id": 234
70124
},
71125
"timestamp":1460245672080,
72126
"message":{
@@ -77,10 +131,10 @@ function fakeMessageMixed() {
77131
},
78132
{
79133
"sender":{
80-
"id":10208007577165870
134+
"id":123
81135
},
82136
"recipient":{
83-
"id": 1442484699367623
137+
"id": 234
84138
},
85139
"timestamp":1458696618268,
86140
"message":{
@@ -98,10 +152,10 @@ function fakeMessageMixed() {
98152
},
99153
{
100154
"sender": {
101-
"id": 10208007577165870
155+
"id": 123
102156
},
103157
"recipient": {
104-
"id": 1442484699367623
158+
"id": 234
105159
},
106160
"timestamp": 1462967781299,
107161
"message": {

0 commit comments

Comments
 (0)