alicezetion 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/.cache/replit/__replit_disk_meta.json +1 -1
  2. package/.cache/replit/nix/env.json +1 -1
  3. package/alice/addExternalModule.js +19 -0
  4. package/alice/{add.js → addUserToGroup.js} +16 -2
  5. package/alice/{admin.js → changeAdminStatus.js} +17 -3
  6. package/alice/{archive.js → changeArchivedStatus.js} +16 -2
  7. package/alice/changeBio.js +77 -0
  8. package/alice/changeBlockedStatus.js +47 -0
  9. package/alice/{gcimage.js → changeGroupImage.js} +16 -2
  10. package/alice/{nickname.js → changeNickname.js} +17 -2
  11. package/alice/changeThreadColor.js +71 -0
  12. package/alice/{emoji.js → changeThreadEmoji.js} +16 -2
  13. package/alice/createNewGroup.js +86 -0
  14. package/alice/{poll.js → createPoll.js} +18 -2
  15. package/alice/{deletemsg.js → deleteMessage.js} +15 -2
  16. package/alice/{deletegc.js → deleteThread.js} +15 -2
  17. package/alice/{forward.js → forwardAttachment.js} +16 -3
  18. package/alice/{id.js → getCurrentUserID.js} +1 -1
  19. package/alice/{friend.js → getFriendsList.js} +17 -3
  20. package/alice/{history.js → getThreadHistory.js} +19 -6
  21. package/alice/{gchistorydeprecated.js → getThreadHistoryDeprecated.js} +18 -1
  22. package/alice/{gcinfo.js → getThreadInfo.js} +49 -13
  23. package/alice/{gcinfodeprecated.js → getThreadInfoDeprecated.js} +17 -2
  24. package/alice/{gclist.js → getThreadList.js} +27 -9
  25. package/alice/{gclistdeprecated.js → getThreadListDeprecated.js} +1 -1
  26. package/alice/{gcimg.js → getThreadPictures.js} +15 -2
  27. package/alice/{userid.js → getUserID.js} +16 -2
  28. package/alice/{userinfo.js → getUserInfo.js} +18 -3
  29. package/alice/handleFriendRequest.js +61 -0
  30. package/alice/{msgrequest.js → handleMessageRequest.js} +16 -2
  31. package/alice/httpGet.js +52 -0
  32. package/alice/httpPost.js +52 -0
  33. package/alice/listenMqtt.js +363 -134
  34. package/alice/logout.js +18 -2
  35. package/alice/{delivered.js → markAsDelivered.js} +19 -2
  36. package/alice/markAsRead.js +80 -0
  37. package/alice/{seen.js → markAsReadAll.js} +16 -2
  38. package/alice/markAsSeen.js +59 -0
  39. package/alice/{mute.js → muteThread.js} +16 -2
  40. package/alice/{kick.js → removeUserFromGroup.js} +16 -2
  41. package/alice/{resolveimgurl.js → resolvePhotoUrl.js} +16 -2
  42. package/alice/{gcsearch.js → searchForThread.js} +16 -2
  43. package/alice/{chat.js → sendMessage.js} +78 -34
  44. package/alice/sendTypingIndicator.js +103 -0
  45. package/alice/{react.js → setMessageReaction.js} +39 -4
  46. package/alice/setPostReaction.js +76 -0
  47. package/alice/{title.js → setTitle.js} +16 -3
  48. package/alice/threadColors.js +57 -0
  49. package/alice/unfriend.js +52 -0
  50. package/alice/{unsend.js → unsendMessage.js} +16 -2
  51. package/index.js +324 -143
  52. package/package.json +27 -18
  53. package/utils.js +137 -61
  54. package/.cache/replit/modules.stamp +0 -0
  55. package/README.md +0 -40
  56. package/alice/block.js +0 -72
  57. package/alice/color.js +0 -53
  58. package/alice/gcolor.js +0 -22
  59. package/alice/listen.js +0 -553
  60. package/alice/read.js +0 -52
  61. package/alice/typeindicator.js +0 -77
  62. /package/alice/{emojiurl.js → getEmojiUrl.js} +0 -0
@@ -4,34 +4,43 @@ var utils = require("../utils");
4
4
  var log = require("npmlog");
5
5
  var mqtt = require('mqtt');
6
6
  var websocket = require('websocket-stream');
7
+ var HttpsProxyAgent = require('https-proxy-agent');
8
+ const EventEmitter = require('events');
7
9
 
8
- var identity = function () {};
9
-
10
- //Don't really know what this does but I think it's for the active state
11
- //TODO: Move to ctx when implemented
12
- var chatOn = true;
13
- var foreground = false;
10
+ var identity = function () { };
11
+ var form = {};
12
+ var getSeqID = function () { };
14
13
 
15
14
  var topics = [
16
- "/t_ms",
17
- "/thread_typing",
18
- "/orca_typing_notifications",
19
- "/orca_presence",
20
15
  "/legacy_web",
21
- "/br_sr",
22
- "/sr_res",
23
16
  "/webrtc",
17
+ "/rtc_multi",
24
18
  "/onevc",
19
+ "/br_sr", //Notification
20
+ //Need to publish /br_sr right after this
21
+ "/sr_res",
22
+ "/t_ms",
23
+ "/thread_typing",
24
+ "/orca_typing_notifications",
25
25
  "/notify_disconnect",
26
- "/inbox",
27
- "/mercury",
28
- "/messaging_events",
29
- "/orca_message_notifications",
30
- "/pp",
31
- "/webrtc_response",
26
+ //Need to publish /messenger_sync_create_queue right after this
27
+ "/orca_presence",
28
+ //Will receive /sr_res right here.
29
+
30
+ //"/inbox",
31
+ //"/mercury",
32
+ //"/messaging_events",
33
+ //"/orca_message_notifications",
34
+ //"/pp",
35
+ //"/webrtc_response",
32
36
  ];
33
37
 
34
- function listenMqtt(defaultFuncs, bot, ctx, globalCallback) {
38
+ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
39
+ //Don't really know what this does but I think it's for the active state?
40
+ //TODO: Move to ctx when implemented
41
+ var chatOn = ctx.globalOptions.online;
42
+ var foreground = false;
43
+
35
44
  var sessionID = Math.floor(Math.random() * 9007199254740991) + 1;
36
45
  var username = {
37
46
  u: ctx.userID,
@@ -45,17 +54,23 @@ function listenMqtt(defaultFuncs, bot, ctx, globalCallback) {
45
54
  mqtt_sid: "",
46
55
  cp: 3,
47
56
  ecp: 10,
48
- st: topics,
57
+ st: [],
49
58
  pm: [],
50
59
  dc: "",
51
60
  no_auto_fg: true,
52
- gas: null
61
+ gas: null,
62
+ pack: []
53
63
  };
54
64
  var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; ");
55
65
 
56
- //Region could be changed for better ping. (Region atn: Southeast Asia, region ash: West US, prob) (Don't really know if we need it).
57
- //// var host = 'wss://edge-chat.facebook.com/chat?region=atn&sid=' + sessionID;
58
- var host = 'wss://edge-chat.facebook.com/chat?sid=' + sessionID;
66
+ var host;
67
+ if (ctx.mqttEndpoint) {
68
+ host = `${ctx.mqttEndpoint}&sid=${sessionID}`;
69
+ } else if (ctx.region) {
70
+ host = `wss://edge-chat.facebook.com/chat?region=${ctx.region.toLocaleLowerCase()}&sid=${sessionID}`;
71
+ } else {
72
+ host = `wss://edge-chat.facebook.com/chat?sid=${sessionID}`;
73
+ }
59
74
 
60
75
  var options = {
61
76
  clientId: "mqttwsclient",
@@ -68,25 +83,43 @@ function listenMqtt(defaultFuncs, bot, ctx, globalCallback) {
68
83
  'Cookie': cookies,
69
84
  'Origin': 'https://www.facebook.com',
70
85
  'User-Agent': ctx.globalOptions.userAgent,
71
- 'Referer': 'https://www.facebook.com',
72
- 'Host': 'edge-chat.facebook.com'
86
+ 'Referer': 'https://www.facebook.com/',
87
+ 'Host': new URL(host).hostname //'edge-chat.facebook.com'
73
88
  },
74
89
  origin: 'https://www.facebook.com',
75
90
  protocolVersion: 13
76
- }
91
+ },
92
+ keepalive: 10,
93
+ reschedulePings: false
77
94
  };
78
95
 
96
+ if (typeof ctx.globalOptions.proxy != "undefined") {
97
+ var agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
98
+ options.wsOptions.agent = agent;
99
+ }
100
+
79
101
  ctx.mqttClient = new mqtt.Client(_ => websocket(host, options.wsOptions), options);
80
102
 
81
103
  var mqttClient = ctx.mqttClient;
82
104
 
83
- mqttClient.on('error', function(err) {
84
- log.error(err);
105
+ mqttClient.on('error', function (err) {
106
+ console.error("listenMqtt", err);
85
107
  mqttClient.end();
86
- globalCallback("Connection refused: Server unavailable", null);
108
+ if (ctx.globalOptions.autoReconnect) {
109
+ getSeqID();
110
+ } else {
111
+ globalCallback({
112
+ type: "stop_listen",
113
+ error: "Connection refused: Server unavailable"
114
+ }, null);
115
+ }
87
116
  });
88
117
 
89
- mqttClient.on('connect', function() {
118
+ mqttClient.on('connect', function () {
119
+ topics.forEach(function (topicsub) {
120
+ mqttClient.subscribe(topicsub);
121
+ });
122
+
90
123
  var topic;
91
124
  var queue = {
92
125
  sync_api_version: 10,
@@ -96,11 +129,7 @@ function listenMqtt(defaultFuncs, bot, ctx, globalCallback) {
96
129
  entity_fbid: ctx.userID,
97
130
  };
98
131
 
99
- if(ctx.globalOptions.pageID) {
100
- queue.entity_fbid = ctx.globalOptions.pageID;
101
- }
102
-
103
- if(ctx.syncToken) {
132
+ if (ctx.syncToken) {
104
133
  topic = "/messenger_sync_get_diffs";
105
134
  queue.last_seq_id = ctx.lastSeqId;
106
135
  queue.sync_token = ctx.syncToken;
@@ -109,27 +138,45 @@ function listenMqtt(defaultFuncs, bot, ctx, globalCallback) {
109
138
  queue.initial_titan_sequence_id = ctx.lastSeqId;
110
139
  queue.device_params = null;
111
140
  }
112
-
113
- mqttClient.publish(topic, JSON.stringify(queue), {qos: 1, retain: false});
141
+
142
+ mqttClient.publish(topic, JSON.stringify(queue), { qos: 1, retain: false });
143
+
144
+ var rTimeout = setTimeout(function () {
145
+ mqttClient.end();
146
+ getSeqID();
147
+ }, 5000);
148
+
149
+ ctx.tmsWait = function () {
150
+ clearTimeout(rTimeout);
151
+ ctx.globalOptions.emitReady ? globalCallback({
152
+ type: "ready",
153
+ error: null
154
+ }) : "";
155
+ delete ctx.tmsWait;
156
+ };
114
157
  });
115
158
 
116
- mqttClient.on('message', function(topic, message, packet) {
117
- var jsonMessage = JSON.parse(message);
118
- if(topic === "/t_ms") {
119
- if(jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
159
+ mqttClient.on('message', function (topic, message, _packet) {
160
+ try {
161
+ var jsonMessage = JSON.parse(message);
162
+ } catch (ex) {
163
+ return;
164
+ //console.error("listenMqtt", "JSON conversion failed");
165
+ }
166
+ if (topic === "/t_ms") {
167
+ if (ctx.tmsWait && typeof ctx.tmsWait == "function") {
168
+ ctx.tmsWait();
169
+ }
170
+
171
+ if (jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
120
172
  ctx.lastSeqId = jsonMessage.firstDeltaSeqId;
121
173
  ctx.syncToken = jsonMessage.syncToken;
122
174
  }
123
175
 
124
- if(jsonMessage.lastIssuedSeqId) {
176
+ if (jsonMessage.lastIssuedSeqId) {
125
177
  ctx.lastSeqId = parseInt(jsonMessage.lastIssuedSeqId);
126
178
  }
127
179
 
128
- if(jsonMessage.queueEntityId && ctx.globalOptions.pageID &&
129
- ctx.globalOptions.pageID != jsonMessage.queueEntityId) {
130
- return;
131
- }
132
-
133
180
  //If it contains more than 1 delta
134
181
  for (var i in jsonMessage.deltas) {
135
182
  var delta = jsonMessage.deltas[i];
@@ -163,16 +210,22 @@ function listenMqtt(defaultFuncs, bot, ctx, globalCallback) {
163
210
 
164
211
  });
165
212
 
166
- mqttClient.on('close', function() {
213
+ mqttClient.on('close', function () {
214
+ //(function () { globalCallback("Connection closed."); })();
167
215
  // client.end();
168
216
  });
169
217
  }
170
218
 
171
219
  function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
172
- if(v.delta.class == "NewMessage") {
220
+ if (v.delta.class == "NewMessage") {
221
+ //Not tested for pages
222
+ if (ctx.globalOptions.pageID &&
223
+ ctx.globalOptions.pageID != v.queue
224
+ )
225
+ return;
226
+
173
227
  (function resolveAttachmentUrl(i) {
174
- // sometimes, with sticker message in group, delta does not contain 'attachments' property.
175
- if (v.delta.attachments && (i == v.delta.attachments.length)) {
228
+ if (i == v.delta.attachments.length) {
176
229
  var fmtMsg;
177
230
  try {
178
231
  fmtMsg = utils.formatDeltaMessage(v);
@@ -195,7 +248,7 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
195
248
  (function () { globalCallback(null, fmtMsg); })();
196
249
  } else {
197
250
  if (
198
- v.delta.attachments && (v.delta.attachments[i].mercury.attach_type == "photo")
251
+ v.delta.attachments[i].mercury.attach_type == "photo"
199
252
  ) {
200
253
  api.resolvePhotoUrl(
201
254
  v.delta.attachments[i].fbid,
@@ -222,28 +275,32 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
222
275
  for (var i in clientPayload.deltas) {
223
276
  var delta = clientPayload.deltas[i];
224
277
  if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) {
225
- (function () { globalCallback(null, {
226
- type: "message_reaction",
227
- threadID: (delta.deltaMessageReaction.threadKey
228
- .threadFbId ?
229
- delta.deltaMessageReaction.threadKey.threadFbId : delta.deltaMessageReaction.threadKey
230
- .otherUserFbId).toString(),
231
- messageID: delta.deltaMessageReaction.messageId,
232
- reaction: delta.deltaMessageReaction.reaction,
233
- senderID: delta.deltaMessageReaction.senderId.toString(),
234
- userID: delta.deltaMessageReaction.userId.toString()
235
- }); })();
278
+ (function () {
279
+ globalCallback(null, {
280
+ type: "message_reaction",
281
+ threadID: (delta.deltaMessageReaction.threadKey
282
+ .threadFbId ?
283
+ delta.deltaMessageReaction.threadKey.threadFbId : delta.deltaMessageReaction.threadKey
284
+ .otherUserFbId).toString(),
285
+ messageID: delta.deltaMessageReaction.messageId,
286
+ reaction: delta.deltaMessageReaction.reaction,
287
+ senderID: delta.deltaMessageReaction.senderId.toString(),
288
+ userID: delta.deltaMessageReaction.userId.toString()
289
+ });
290
+ })();
236
291
  } else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
237
- (function () { globalCallback(null, {
238
- type: "message_unsend",
239
- threadID: (delta.deltaRecallMessageData.threadKey.threadFbId ?
240
- delta.deltaRecallMessageData.threadKey.threadFbId : delta.deltaRecallMessageData.threadKey
241
- .otherUserFbId).toString(),
242
- messageID: delta.deltaRecallMessageData.messageID,
243
- senderID: delta.deltaRecallMessageData.senderID.toString(),
244
- deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp,
245
- timestamp: delta.deltaRecallMessageData.timestamp
246
- }); })();
292
+ (function () {
293
+ globalCallback(null, {
294
+ type: "message_unsend",
295
+ threadID: (delta.deltaRecallMessageData.threadKey.threadFbId ?
296
+ delta.deltaRecallMessageData.threadKey.threadFbId : delta.deltaRecallMessageData.threadKey
297
+ .otherUserFbId).toString(),
298
+ messageID: delta.deltaRecallMessageData.messageID,
299
+ senderID: delta.deltaRecallMessageData.senderID.toString(),
300
+ deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp,
301
+ timestamp: delta.deltaRecallMessageData.timestamp
302
+ });
303
+ })();
247
304
  } else if (delta.deltaMessageReply) {
248
305
  //Mention block - #1
249
306
  var mdata =
@@ -336,8 +393,79 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
336
393
  body: delta.deltaMessageReply.repliedToMessage.body || "",
337
394
  isGroup: !!delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId,
338
395
  mentions: rmentions,
339
- timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp,
396
+ timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp
340
397
  };
398
+ } else if (delta.deltaMessageReply.replyToMessageId) {
399
+ return defaultFuncs
400
+ .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, {
401
+ "av": ctx.globalOptions.pageID,
402
+ "queries": JSON.stringify({
403
+ "o0": {
404
+ //Using the same doc_id as forcedFetch
405
+ "doc_id": "2848441488556444",
406
+ "query_params": {
407
+ "thread_and_message_id": {
408
+ "thread_id": callbackToReturn.threadID,
409
+ "message_id": delta.deltaMessageReply.replyToMessageId.id,
410
+ }
411
+ }
412
+ }
413
+ })
414
+ })
415
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
416
+ .then((resData) => {
417
+ if (resData[resData.length - 1].error_results > 0) {
418
+ throw resData[0].o0.errors;
419
+ }
420
+
421
+ if (resData[resData.length - 1].successful_results === 0) {
422
+ throw { error: "forcedFetch: there was no successful_results", res: resData };
423
+ }
424
+
425
+ var fetchData = resData[0].o0.data.message;
426
+
427
+ var mobj = {};
428
+ for (var n in fetchData.message.ranges) {
429
+ mobj[fetchData.message.ranges[n].entity.id] = (fetchData.message.text || "").substr(fetchData.message.ranges[n].offset, fetchData.message.ranges[n].length);
430
+ }
431
+
432
+ callbackToReturn.messageReply = {
433
+ threadID: callbackToReturn.threadID,
434
+ messageID: fetchData.message_id,
435
+ senderID: fetchData.message_sender.id.toString(),
436
+ attachments: fetchData.message.blob_attachment.map(att => {
437
+ var x;
438
+ try {
439
+ x = utils._formatAttachment({
440
+ blob_attachment: att
441
+ });
442
+ } catch (ex) {
443
+ x = att;
444
+ x.error = ex;
445
+ x.type = "unknown";
446
+ }
447
+ return x;
448
+ }),
449
+ body: fetchData.message.text || "",
450
+ isGroup: callbackToReturn.isGroup,
451
+ mentions: mobj,
452
+ timestamp: parseInt(fetchData.timestamp_precise)
453
+ };
454
+ })
455
+ .catch((err) => {
456
+ console.error("forcedFetch", err);
457
+ })
458
+ .finally(function () {
459
+ if (ctx.globalOptions.autoMarkDelivery) {
460
+ markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
461
+ }
462
+ !ctx.globalOptions.selfListen &&
463
+ callbackToReturn.senderID === ctx.userID ?
464
+ undefined :
465
+ (function () { globalCallback(null, callbackToReturn); })();
466
+ });
467
+ } else {
468
+ callbackToReturn.delta = delta;
341
469
  }
342
470
 
343
471
  if (ctx.globalOptions.autoMarkDelivery) {
@@ -406,12 +534,12 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
406
534
  "av": ctx.globalOptions.pageID,
407
535
  "queries": JSON.stringify({
408
536
  "o0": {
409
- //This doc_id is valid as of ? (prob January 18, 2020)
410
- "doc_id": "1768656253222505",
537
+ //This doc_id is valid as of March 25, 2020
538
+ "doc_id": "2848441488556444",
411
539
  "query_params": {
412
540
  "thread_and_message_id": {
413
541
  "thread_id": tid.toString(),
414
- "message_id": mid.toString(),
542
+ "message_id": mid,
415
543
  }
416
544
  }
417
545
  }
@@ -431,28 +559,95 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
431
559
  }
432
560
 
433
561
  var fetchData = resData[0].o0.data.message;
434
- if (fetchData && fetchData.__typename === "ThreadImageMessage") {
435
- (!ctx.globalOptions.selfListen &&
436
- fetchData.message_sender.id.toString() === ctx.userID) ||
437
- !ctx.loggedIn ?
438
- undefined :
439
- (function () { globalCallback(null, {
440
- type: "change_thread_image",
441
- threadID: utils.formatID(tid.toString()),
442
- snippet: fetchData.snippet,
443
- timestamp: fetchData.timestamp_precise,
444
- author: fetchData.message_sender.id,
445
- image: {
446
- attachmentID: fetchData.image_with_metadata && fetchData.image_with_metadata.legacy_attachment_id,
447
- width: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.x,
448
- height: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.y,
449
- url: fetchData.image_with_metadata && fetchData.image_with_metadata.preview.uri
450
- }
451
- }); })();
562
+
563
+ if (utils.getType(fetchData) == "Object") {
564
+ log.info("forcedFetch", fetchData);
565
+ switch (fetchData.__typename) {
566
+ case "ThreadImageMessage":
567
+ (!ctx.globalOptions.selfListen &&
568
+ fetchData.message_sender.id.toString() === ctx.userID) ||
569
+ !ctx.loggedIn ?
570
+ undefined :
571
+ (function () {
572
+ globalCallback(null, {
573
+ type: "change_thread_image",
574
+ threadID: utils.formatID(tid.toString()),
575
+ snippet: fetchData.snippet,
576
+ timestamp: fetchData.timestamp_precise,
577
+ author: fetchData.message_sender.id,
578
+ image: {
579
+ attachmentID: fetchData.image_with_metadata && fetchData.image_with_metadata.legacy_attachment_id,
580
+ width: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.x,
581
+ height: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.y,
582
+ url: fetchData.image_with_metadata && fetchData.image_with_metadata.preview.uri
583
+ }
584
+ });
585
+ })();
586
+ break;
587
+ case "UserMessage":
588
+ log.info("ff-Return", {
589
+ type: "message",
590
+ senderID: utils.formatID(fetchData.message_sender.id),
591
+ body: fetchData.message.text || "",
592
+ threadID: utils.formatID(tid.toString()),
593
+ messageID: fetchData.message_id,
594
+ attachments: [{
595
+ type: "share",
596
+ ID: fetchData.extensible_attachment.legacy_attachment_id,
597
+ url: fetchData.extensible_attachment.story_attachment.url,
598
+
599
+ title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
600
+ description: fetchData.extensible_attachment.story_attachment.description.text,
601
+ source: fetchData.extensible_attachment.story_attachment.source,
602
+
603
+ image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
604
+ width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
605
+ height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
606
+ playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
607
+ duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
608
+
609
+ subattachments: fetchData.extensible_attachment.subattachments,
610
+ properties: fetchData.extensible_attachment.story_attachment.properties,
611
+ }],
612
+ mentions: {},
613
+ timestamp: parseInt(fetchData.timestamp_precise),
614
+ isGroup: (fetchData.message_sender.id != tid.toString())
615
+ });
616
+ globalCallback(null, {
617
+ type: "message",
618
+ senderID: utils.formatID(fetchData.message_sender.id),
619
+ body: fetchData.message.text || "",
620
+ threadID: utils.formatID(tid.toString()),
621
+ messageID: fetchData.message_id,
622
+ attachments: [{
623
+ type: "share",
624
+ ID: fetchData.extensible_attachment.legacy_attachment_id,
625
+ url: fetchData.extensible_attachment.story_attachment.url,
626
+
627
+ title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
628
+ description: fetchData.extensible_attachment.story_attachment.description.text,
629
+ source: fetchData.extensible_attachment.story_attachment.source,
630
+
631
+ image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
632
+ width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
633
+ height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
634
+ playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
635
+ duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
636
+
637
+ subattachments: fetchData.extensible_attachment.subattachments,
638
+ properties: fetchData.extensible_attachment.story_attachment.properties,
639
+ }],
640
+ mentions: {},
641
+ timestamp: parseInt(fetchData.timestamp_precise),
642
+ isGroup: (fetchData.message_sender.id != tid.toString())
643
+ });
644
+ }
645
+ } else {
646
+ console.error("forcedFetch", fetchData);
452
647
  }
453
648
  })
454
649
  .catch((err) => {
455
- log.error("forcedFetch", err);
650
+ console.error("forcedFetch", err);
456
651
  });
457
652
  }
458
653
  break;
@@ -482,12 +677,12 @@ function markDelivery(ctx, api, threadID, messageID) {
482
677
  if (threadID && messageID) {
483
678
  api.markAsDelivered(threadID, messageID, (err) => {
484
679
  if (err) {
485
- log.error(err);
680
+ console.error("markAsDelivered", err);
486
681
  } else {
487
682
  if (ctx.globalOptions.autoMarkRead) {
488
683
  api.markAsRead(threadID, (err) => {
489
684
  if (err) {
490
- log.error(err);
685
+ console.error("markAsDelivered", err);
491
686
  }
492
687
  });
493
688
  }
@@ -498,35 +693,20 @@ function markDelivery(ctx, api, threadID, messageID) {
498
693
 
499
694
  module.exports = function (defaultFuncs, api, ctx) {
500
695
  var globalCallback = identity;
501
- return function (callback) {
502
- globalCallback = callback;
503
-
504
- //Reset some stuff
505
- ctx.lastSeqId = 0;
506
- ctx.syncToken = undefined;
507
-
508
- //Same request as getThreadList
509
- const form = {
510
- "av": ctx.globalOptions.pageID,
511
- "queries": JSON.stringify({
512
- "o0": {
513
- "doc_id": "1349387578499440",
514
- "query_params": {
515
- "limit": 1,
516
- "before": null,
517
- "tags": ["INBOX"],
518
- "includeDeliveryReceipts": false,
519
- "includeSeqID": true
520
- }
521
- }
522
- })
523
- };
524
-
696
+ getSeqID = function getSeqID() {
697
+ ctx.t_mqttCalled = false;
525
698
  defaultFuncs
526
699
  .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
527
700
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
528
701
  .then((resData) => {
529
- if (resData && resData.length > 0 && resData[resData.length - 1].error_results > 0) {
702
+ if (utils.getType(resData) != "Array") {
703
+ throw {
704
+ error: "Not logged in",
705
+ res: resData
706
+ };
707
+ }
708
+
709
+ if (resData && resData[resData.length - 1].error_results > 0) {
530
710
  throw resData[0].o0.errors;
531
711
  }
532
712
 
@@ -537,24 +717,73 @@ module.exports = function (defaultFuncs, api, ctx) {
537
717
  if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) {
538
718
  ctx.lastSeqId = resData[0].o0.data.viewer.message_threads.sync_sequence_id;
539
719
  listenMqtt(defaultFuncs, api, ctx, globalCallback);
720
+ } else {
721
+ throw { error: "getSeqId: no sync_sequence_id found.", res: resData };
540
722
  }
541
-
542
723
  })
543
724
  .catch((err) => {
544
- log.error("getSeqId", err);
545
- return callback(err);
725
+ console.error("getSeqId", err);
726
+ if (utils.getType(err) == "Object" && err.error === "Not logged in") {
727
+ ctx.loggedIn = false;
728
+ }
729
+ return globalCallback(err);
546
730
  });
731
+ };
547
732
 
548
- var stopListening = function () {
549
- globalCallback = identity;
733
+ return function (callback) {
734
+ class MessageEmitter extends EventEmitter {
735
+ stopListening(callback) {
736
+ callback = callback || (() => { });
737
+ globalCallback = identity;
738
+ if (ctx.mqttClient) {
739
+ ctx.mqttClient.unsubscribe("/webrtc");
740
+ ctx.mqttClient.unsubscribe("/rtc_multi");
741
+ ctx.mqttClient.unsubscribe("/onevc");
742
+ ctx.mqttClient.publish("/browser_close", "{}");
743
+ ctx.mqttClient.end(false, function (...data) {
744
+ callback(data);
745
+ ctx.mqttClient = undefined;
746
+ });
747
+ }
748
+ }
749
+ }
550
750
 
551
- if(ctx.mqttClient)
552
- {
553
- ctx.mqttClient.end();
554
- ctx.mqttClient = undefined;
751
+ var msgEmitter = new MessageEmitter();
752
+ globalCallback = (callback || function (error, message) {
753
+ if (error) {
754
+ return msgEmitter.emit("error", error);
555
755
  }
756
+ msgEmitter.emit("message", message);
757
+ });
758
+
759
+ //Reset some stuff
760
+ if (!ctx.firstListen) ctx.lastSeqId = null;
761
+ ctx.syncToken = undefined;
762
+ ctx.t_mqttCalled = false;
763
+
764
+ //Same request as getThreadList
765
+ form = {
766
+ "av": ctx.globalOptions.pageID,
767
+ "queries": JSON.stringify({
768
+ "o0": {
769
+ "doc_id": "3336396659757871",
770
+ "query_params": {
771
+ "limit": 1,
772
+ "before": null,
773
+ "tags": ["INBOX"],
774
+ "includeDeliveryReceipts": false,
775
+ "includeSeqID": true
776
+ }
777
+ }
778
+ })
556
779
  };
557
780
 
558
- return stopListening;
781
+ if (!ctx.firstListen || !ctx.lastSeqId) {
782
+ getSeqID();
783
+ } else {
784
+ listenMqtt(defaultFuncs, api, ctx, globalCallback);
785
+ }
786
+ ctx.firstListen = false;
787
+ return msgEmitter;
559
788
  };
560
789
  };