nazrul-core 1.1.9 → 1.2.9

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/listenMqtt.js +222 -753
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nazrul-core",
3
- "version": "1.1.9",
3
+ "version": "1.2.9",
4
4
  "description": "Facebook-chat-api made by Priyansh rajput",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/listenMqtt.js CHANGED
@@ -1,6 +1,8 @@
1
1
  /* eslint-disable linebreak-style */
2
2
  'use strict';
3
3
 
4
+ /* ================= REQUIRE ================= */
5
+
4
6
  const utils = require('../utils');
5
7
  const log = require('npmlog');
6
8
  const mqtt = require('mqtt');
@@ -8,857 +10,324 @@ const WebSocket = require('ws');
8
10
  const HttpsProxyAgent = require('https-proxy-agent');
9
11
  const EventEmitter = require('events');
10
12
  const Duplexify = require('duplexify');
11
- const {
12
- Transform
13
- } = require('stream');
14
- var identity = function() {};
13
+ const { Transform } = require('stream');
14
+
15
+ /* ================= GLOBAL ================= */
16
+
17
+ var identity = function () {};
15
18
  var form = {};
16
- var getSeqID = function() {};
19
+ var getSeqID = function () {};
20
+
21
+ global.Fca = global.Fca || {};
22
+ global.Fca.Data = global.Fca.Data || {};
17
23
  global.Fca.Data.MsgCount = new Map();
18
24
  global.Fca.Data.event = new Map();
19
25
 
20
- const topics = ['/ls_req', '/ls_resp', '/legacy_web', '/webrtc', '/rtc_multi', '/onevc', '/br_sr', '/sr_res', '/t_ms', '/thread_typing', '/orca_typing_notifications', '/notify_disconnect', '/orca_presence', '/inbox', '/mercury', '/messaging_events', '/orca_message_notifications', '/pp', '/webrtc_response'];
21
-
22
- let WebSocket_Global;
23
-
24
- function buildProxy() {
25
- const Proxy = new Transform({
26
- objectMode: false,
26
+ /* ================= TOPICS ================= */
27
+
28
+ const topics = [
29
+ '/ls_req',
30
+ '/ls_resp',
31
+ '/legacy_web',
32
+ '/webrtc',
33
+ '/rtc_multi',
34
+ '/onevc',
35
+ '/br_sr',
36
+ '/sr_res',
37
+ '/t_ms',
38
+ '/thread_typing',
39
+ '/orca_typing_notifications',
40
+ '/notify_disconnect',
41
+ '/orca_presence',
42
+ '/inbox',
43
+ '/mercury',
44
+ '/messaging_events',
45
+ '/orca_message_notifications',
46
+ '/pp',
47
+ '/webrtc_response'
48
+ ];
49
+
50
+ /* ================= WEBSOCKET STREAM ================= */
51
+
52
+ function buildProxy(ws) {
53
+ return new Transform({
27
54
  transform(chunk, enc, next) {
28
- if (WebSocket_Global.readyState !== WebSocket_Global.OPEN) {
29
- return next();
30
- }
31
-
32
- let data;
33
- if (typeof chunk === 'string') {
34
- data = Buffer.from(chunk, 'utf8');
35
- } else {
36
- data = chunk;
55
+ if (ws.readyState === ws.OPEN) {
56
+ ws.send(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
37
57
  }
38
-
39
- WebSocket_Global.send(data);
40
58
  next();
41
59
  },
42
60
  flush(done) {
43
- WebSocket_Global.close();
61
+ try { ws.close(); } catch {}
44
62
  done();
45
- },
46
- writev(chunks, cb) {
47
- const buffers = chunks.map(({ chunk }) => {
48
- if (typeof chunk === 'string') {
49
- return Buffer.from(chunk, 'utf8');
50
- }
51
- return chunk;
52
- });
53
- this._write(Buffer.concat(buffers), 'binary', cb);
54
- },
63
+ }
55
64
  });
56
- return Proxy;
57
65
  }
58
66
 
59
- function buildStream(options, WebSocket, Proxy) {
60
- const Stream = Duplexify(undefined, undefined, options);
61
- Stream.socket = WebSocket;
67
+ function buildStream(ws, options) {
68
+ const proxy = buildProxy(ws);
69
+ const stream = Duplexify(undefined, undefined, options);
62
70
 
63
- WebSocket.onclose = () => {
64
- Stream.end();
65
- Stream.destroy();
66
- };
71
+ ws.binaryType = 'arraybuffer';
67
72
 
68
- WebSocket.onerror = (err) => {
69
- Stream.destroy(err);
73
+ ws.onopen = () => {
74
+ stream.setReadable(proxy);
75
+ stream.setWritable(proxy);
76
+ stream.emit('connect');
70
77
  };
71
78
 
72
- WebSocket.onmessage = (event) => {
73
- const data = event.data instanceof ArrayBuffer ? Buffer.from(event.data) : Buffer.from(event.data, 'utf8');
74
- Stream.push(data);
79
+ ws.onmessage = evt => {
80
+ const data = evt.data instanceof ArrayBuffer
81
+ ? Buffer.from(evt.data)
82
+ : Buffer.from(evt.data);
83
+ stream.push(data);
75
84
  };
76
85
 
77
- WebSocket.onopen = () => {
78
- Stream.setReadable(Proxy);
79
- Stream.setWritable(Proxy);
80
- Stream.emit('connect');
81
- };
86
+ ws.onerror = err => stream.destroy(err);
87
+ ws.onclose = () => stream.destroy();
82
88
 
83
- WebSocket_Global = WebSocket;
84
- Proxy.on('close', () => WebSocket.close());
85
-
86
- return Stream;
89
+ return stream;
87
90
  }
88
91
 
92
+ /* ================= MQTT LISTENER ================= */
93
+
89
94
  function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
90
- const chatOn = ctx.globalOptions.online;
91
- const foreground = false;
92
95
 
93
- const sessionID = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1;
94
- const GUID = utils.getGUID()
96
+ const sessionID = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
97
+ const GUID = utils.getGUID();
98
+
95
99
  const username = {
96
100
  u: ctx.userID,
97
101
  s: sessionID,
98
- chat_on: chatOn,
99
- fg: foreground,
102
+ chat_on: ctx.globalOptions.online,
103
+ fg: false,
100
104
  d: GUID,
101
105
  ct: 'websocket',
102
- aid: '219994525426954',
103
- aids: null,
104
- mqtt_sid: '',
105
- cp: 3,
106
- ecp: 10,
107
- st: [],
108
- pm: [],
109
- dc: '',
110
- no_auto_fg: true,
111
- gas: null,
112
- pack: [],
113
- p: null,
114
- php_override: ""
106
+ aid: '219994525426954'
115
107
  };
116
108
 
117
- const cookies = ctx.jar.getCookies('https://www.facebook.com').join('; ');
109
+ const cookies = ctx.jar
110
+ .getCookies('https://www.facebook.com')
111
+ .join('; ');
118
112
 
119
- let host;
120
- if (ctx.mqttEndpoint) {
121
- host = `${ctx.mqttEndpoint}&sid=${sessionID}&cid=${GUID}`;
122
- } else if (ctx.region) {
123
- host = `wss://edge-chat.facebook.com/chat?region=${ctx.region.toLowerCase()}&sid=${sessionID}&cid=${GUID}`;
124
- } else {
125
- host = `wss://edge-chat.facebook.com/chat?sid=${sessionID}&cid=${GUID}`;
126
- }
113
+ const host = ctx.region
114
+ ? `wss://edge-chat.facebook.com/chat?region=${ctx.region}&sid=${sessionID}&cid=${GUID}`
115
+ : `wss://edge-chat.facebook.com/chat?sid=${sessionID}&cid=${GUID}`;
127
116
 
128
- const options = {
129
- clientId: 'mqttwsclient',
130
- protocolId: 'MQIsdp',
131
- protocolVersion: 3,
132
- username: JSON.stringify(username),
133
- clean: true,
134
- wsOptions: {
135
- headers: {
136
- Cookie: cookies,
137
- Origin: 'https://www.facebook.com',
138
- 'User-Agent': ctx.globalOptions.userAgent,
139
- Referer: 'https://www.facebook.com/',
140
- Host: new URL(host).hostname,
141
- },
142
- origin: 'https://www.facebook.com',
143
- protocolVersion: 13,
144
- binaryType: 'arraybuffer',
145
- },
146
- keepalive: 60,
147
- reschedulePings: true,
148
- reconnectPeriod: 3,
117
+ const wsOptions = {
118
+ headers: {
119
+ Cookie: cookies,
120
+ Origin: 'https://www.facebook.com',
121
+ Referer: 'https://www.facebook.com/',
122
+ 'User-Agent': ctx.globalOptions.userAgent
123
+ }
149
124
  };
150
125
 
151
- if (ctx.globalOptions.proxy !== undefined) {
152
- const agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
153
- options.wsOptions.agent = agent;
126
+ if (ctx.globalOptions.proxy) {
127
+ wsOptions.agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
154
128
  }
155
129
 
156
- ctx.mqttClient = new mqtt.Client(() => buildStream(options, new WebSocket(host, options.wsOptions), buildProxy()), options);
157
- global.mqttClient = ctx.mqttClient;
158
-
159
- global.mqttClient.on('error', (err) => {
160
- log.error('listenMqtt', err);
161
- global.mqttClient.end();
162
-
163
- if (ctx.globalOptions.autoReconnect) {
164
- getSeqID();
165
- } else {
166
- globalCallback({
167
- type: 'stop_listen',
168
- error: 'Server Đã Sập - Auto Restart'
169
- }, null);
170
- return process.exit(1);
130
+ const client = mqtt.connect(host, {
131
+ protocol: 'ws',
132
+ clientId: 'mqttwsclient',
133
+ protocolVersion: 4,
134
+ clean: true,
135
+ keepalive: 60,
136
+ reconnectPeriod: 5000,
137
+ username: JSON.stringify(username),
138
+ wsOptions,
139
+ transformWsUrl: () => host,
140
+ createWebsocket: () => {
141
+ const ws = new WebSocket(host, wsOptions);
142
+ return buildStream(ws);
171
143
  }
172
144
  });
173
145
 
174
- global.mqttClient.on('connect', () => {
175
- if (!global.Fca.Data.Setup || global.Fca.Data.Setup === undefined) {
176
- if (global.Fca.Require.Nazrul.RestartMQTT_Minutes !== 0 && global.Fca.Data.StopListening !== true) {
177
- global.Fca.Data.Setup = true;
178
- setTimeout(() => {
179
- global.Fca.Require.logger.Warning('Closing MQTT Client...');
180
- ctx.mqttClient.end();
181
- global.Fca.Require.logger.Warning('Reconnecting MQTT Client...');
182
- global.Fca.Data.Setup = false;
183
- getSeqID();
184
- }, Number(global.Fca.Require.Nazrul.RestartMQTT_Minutes) * 60 * 1000);
185
- }
186
- }
146
+ ctx.mqttClient = client;
147
+ global.mqttClient = client;
187
148
 
188
- if (process.env.OnStatus === undefined) {
189
- global.Fca.Require.logger.Normal('Nazrul Fca Premium Access');
190
-
191
- if (Number(global.Fca.Require.Nazrul.AutoRestartMinutes) === 0) {
192
- // something
193
- } else if (Number(global.Fca.Require.Nazrul.AutoRestartMinutes) < 10) {
194
- log.warn('AutoRestartMinutes', 'The number of minutes to automatically restart must be more than 10 minutes');
195
- } else if (Number(global.Fca.Require.Nazrul.AutoRestartMinutes) < 0) {
196
- log.warn('AutoRestartMinutes', 'Invalid auto-restart minutes!');
197
- } else {
198
- global.Fca.Require.logger.Normal(global.Fca.getText(global.Fca.Require.Language.Src.AutoRestart, global.Fca.Require.Nazrul.AutoRestartMinutes));
199
- global.Fca.Require.logger.Normal(`Auto Restart MQTT Client After: ${global.Fca.Require.Nazrul.RestartMQTT_Minutes} Minutes`);
200
- setTimeout(() => {
201
- global.Fca.Require.logger.Normal(global.Fca.Require.Language.Src.OnRestart);
202
- process.exit(1);
203
- }, Number(global.Fca.Require.Nazrul.AutoRestartMinutes) * 60000);
204
- }
205
- require('../broadcast').startBroadcasting();
206
- const MemoryManager = require('../Extra/Src/Release_Memory');
207
- const path = require('path');
208
-
209
- const SettingMemoryManager = {
210
- warningThreshold: 0.7,
211
- releaseThreshold: 0.8,
212
- maxThreshold: 0.9,
213
- interval: 300 * 1000,
214
- logLevel: 'warn',
215
- logFile: path.join(process.cwd(), 'Nazrul_Database' ,'memory.log'),
216
- smartReleaseEnabled: true,
217
- allowLog: (global.Fca.Require.Nazrul.AntiStuckAndMemoryLeak.LogFile.Use || false)
218
- };
219
-
220
- const memoryManager = new MemoryManager(SettingMemoryManager);
221
-
222
- memoryManager.autoStart(60 * 60 * 1000);
223
-
224
- if (global.Fca.Require.Nazrul.AntiStuckAndMemoryLeak.AutoRestart.Use) {
225
- memoryManager.onMaxMemory(function() {
226
- global.Fca.Require.logger.Warning('Memory Usage >= 90% - Auto Restart Avoid Crash');
227
- process.exit(1);
228
- });
229
- }
230
- process.env.OnStatus = true;
231
- }
149
+ /* ===== CONNECT ===== */
232
150
 
233
- topics.forEach((topicsub) => global.mqttClient.subscribe(topicsub));
151
+ client.on('connect', () => {
234
152
 
153
+ topics.forEach(t => client.subscribe(t));
235
154
 
236
- let topic;
237
155
  const queue = {
238
156
  sync_api_version: 11,
239
157
  max_deltas_able_to_process: 100,
240
158
  delta_batch_size: 500,
241
159
  encoding: 'JSON',
242
- entity_fbid: ctx.userID,
243
- };
244
-
245
- topic = "/messenger_sync_create_queue";
246
- queue.initial_titan_sequence_id = ctx.lastSeqId;
247
- queue.device_params = null;
248
-
249
- global.mqttClient.publish(topic, JSON.stringify(queue), {
250
- qos: 1,
251
- retain: false
252
- });
253
-
254
- var rTimeout = setTimeout(function() {
255
- global.mqttClient.end();
256
- getSeqID();
257
- }, 3000);
258
-
259
- ctx.tmsWait = function() {
260
- clearTimeout(rTimeout);
261
- ctx.globalOptions.emitReady ? globalCallback({
262
- type: "ready",
263
- error: null
264
- }) : '';
265
- delete ctx.tmsWait;
160
+ entity_fbid: ctx.userID
266
161
  };
267
- });
268
162
 
269
- const HandleMessage = function(topic, message, _packet) {
270
- const jsonMessage = JSON.parse(message.toString());
271
- if (topic === "/t_ms") {
272
- if (ctx.tmsWait && typeof ctx.tmsWait == "function") ctx.tmsWait();
273
-
274
- if (jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
275
- ctx.lastSeqId = jsonMessage.firstDeltaSeqId;
276
- ctx.syncToken = jsonMessage.syncToken;
277
- }
278
-
279
- if (jsonMessage.lastIssuedSeqId) ctx.lastSeqId = parseInt(jsonMessage.lastIssuedSeqId);
280
- //If it contains more than 1 delta
281
- for (var i in jsonMessage.deltas) {
282
- var delta = jsonMessage.deltas[i];
283
- parseDelta(defaultFuncs, api, ctx, globalCallback, {
284
- "delta": delta
285
- });
286
- }
287
- } else if (topic === "/ls_resp") {
288
- const payload = JSON.parse(jsonMessage.payload); //'{"name":null,"step":[1,[1,[4,0,1,[5,"taskExists",[19,"415"]]],[23,[2,0],[1,[5,"replaceOptimsiticMessage","7192532113093667880","mid.$gABfX5li9LA6VdUymnWPRAdlkiawo"]]]],[1,[4,0,1,[5,"taskExists",[19,"415"]]],[23,[2,0],[1,[5,"mailboxTaskCompletionApiOnTaskCompletion",[19,"415"],true]]]],[1,[4,0,1,[5,"taskExists",[19,"415"]]],[23,[2,0],[1,[5,"removeTask",[19,"415"],[9]]]]]]}'
289
- const request_ID = jsonMessage.request_id;
290
-
291
- if (ctx.callback_Task[request_ID] != undefined && ctx.callback_Task[request_ID].type != undefined) {
292
- const {
293
- callback,
294
- type
295
- } = ctx.callback_Task[request_ID];
296
- const Data = new getRespData(type, payload);
297
- if (!callback) {
298
- return;
299
- }
300
- else if (!Data) {
301
- callback("Something went wrong 🐳", null);
302
- } else {
303
- callback(null, Data);
304
- }
305
- }
306
- } else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") {
307
- var typ = {
308
- type: "typ",
309
- isTyping: !!jsonMessage.state,
310
- from: jsonMessage.sender_fbid.toString(),
311
- threadID: utils.formatID((jsonMessage.thread || jsonMessage.sender_fbid).toString())
312
- };
313
- (function() {
314
- globalCallback(null, typ);
315
- })();
316
- } else if (topic === "/orca_presence") {
317
- if (!ctx.globalOptions.updatePresence) {
318
- for (var i in jsonMessage.list) {
319
- var data = jsonMessage.list[i];
320
- var userID = data["u"];
321
-
322
- var presence = {
323
- type: "presence",
324
- userID: userID.toString(),
325
- //Convert to ms
326
- timestamp: data["l"] * 1000,
327
- statuses: data["p"]
328
- };
329
- (function() {
330
- globalCallback(null, presence);
331
- })();
332
- }
333
- }
163
+ if (ctx.lastSeqId) {
164
+ queue.initial_titan_sequence_id = ctx.lastSeqId;
334
165
  }
335
166
 
336
- };
337
-
338
- global.mqttClient.on('message', HandleMessage);
167
+ client.publish(
168
+ '/messenger_sync_create_queue',
169
+ JSON.stringify(queue),
170
+ { qos: 1 }
171
+ );
339
172
 
340
- process.on('SIGINT', () => {
341
- LogUptime();
342
- process.kill(process.pid);
173
+ globalCallback(null, { type: 'ready' });
343
174
  });
344
175
 
345
- process.on('exit', LogUptime);
346
-
176
+ /* ===== MESSAGE ===== */
347
177
 
348
- }
178
+ client.on('message', (topic, message) => {
179
+ let json;
180
+ try {
181
+ json = JSON.parse(message.toString());
182
+ } catch {
183
+ return;
184
+ }
349
185
 
350
- function getRespData(Type, payload) {
351
- try {
352
- switch (Type) {
353
- case "sendMqttMessage": {
354
- return {
355
- type: Type,
356
- threadID: payload.step[1][2][2][1][2], //this is sick bro
357
- messageID: payload.step[1][2][2][1][3],
358
- payload: payload.step[1][2]
359
- };
186
+ if (topic === '/t_ms') {
187
+ if (json.lastIssuedSeqId) {
188
+ ctx.lastSeqId = parseInt(json.lastIssuedSeqId);
360
189
  }
361
- default: { //!very LAZY :> cook yourself
362
- return {
363
- Data: payload.step[1][2][2][1],
364
- type: Type,
365
- payload: payload.step[1][2]
366
- };
190
+
191
+ if (Array.isArray(json.deltas)) {
192
+ json.deltas.forEach(delta => {
193
+ parseDelta(defaultFuncs, api, ctx, globalCallback, { delta });
194
+ });
367
195
  }
368
196
  }
369
- } catch (e) {
370
- return null;
371
- }
372
- }
373
197
 
374
- function LogUptime() {
375
- const uptime = process.uptime();
376
- const {
377
- join
378
- } = require('path');
379
- const filePath = join(__dirname, '../CountTime.json');
380
-
381
- let time1;
382
- if (global.Fca.Require.fs.existsSync(filePath)) {
383
- time1 = Number(global.Fca.Require.fs.readFileSync(filePath, 'utf8')) || 0;
384
- } else {
385
- time1 = 0;
386
- }
198
+ if (topic === '/thread_typing' || topic === '/orca_typing_notifications') {
199
+ globalCallback(null, {
200
+ type: 'typ',
201
+ from: json.sender_fbid?.toString(),
202
+ isTyping: !!json.state,
203
+ threadID: (json.thread || json.sender_fbid).toString()
204
+ });
205
+ }
387
206
 
388
- global.Fca.Require.fs.writeFileSync(filePath, String(Number(uptime) + time1), 'utf8');
389
- }
207
+ if (topic === '/orca_presence' && json.list) {
208
+ json.list.forEach(p => {
209
+ globalCallback(null, {
210
+ type: 'presence',
211
+ userID: p.u.toString(),
212
+ timestamp: p.l * 1000,
213
+ statuses: p.p
214
+ });
215
+ });
216
+ }
217
+ });
390
218
 
391
- if (global.Fca.Require.Nazrul.AntiGetInfo.AntiGetThreadInfo) {
392
- setInterval(() => {
393
- try {
394
- const { updateMessageCount, getData, hasData } = require('../Extra/ExtraGetThread');
395
- const Data = global.Fca.Data.MsgCount;
396
- const Arr = Array.from(Data.keys());
397
- for (let i of Arr) {
398
- const Count = parseInt(Data.get(i));
399
- if (hasData(i)) {
400
- let x = getData(i);
401
- x.messageCount += Count;
402
- updateMessageCount(i, x);
403
- Data.delete(i);
404
- }
405
- }
406
-
407
- } catch (e) {
408
- console.log(e);
409
- }
410
- }, 30 * 1000);
219
+ client.on('error', err => log.error('MQTT', err));
220
+ client.on('close', () => log.warn('MQTT', 'Disconnected'));
411
221
  }
412
222
 
413
- function parseDelta(defaultFuncs, api, ctx, globalCallback, {
414
- delta
415
- }) {
416
- if (delta.class === 'NewMessage') {
417
- if (ctx.globalOptions.pageID && ctx.globalOptions.pageID !== delta.queue) return;
418
-
419
- const resolveAttachmentUrl = (i) => {
420
- if (!delta.attachments || i === delta.attachments.length || utils.getType(delta.attachments) !== 'Array') {
421
- let fmtMsg;
422
- try {
423
- fmtMsg = utils.formatDeltaMessage(delta);
424
- } catch (err) {
425
- return log.error('Lỗi Nhẹ', err);
426
- }
427
-
428
- if (fmtMsg) {
429
- const isGroup = fmtMsg.isGroup;
430
- const threadID = fmtMsg.threadID;
431
- const messageID = fmtMsg.messageID;
432
-
433
- global.Fca.Data.event.set("Data", {
434
- isGroup,
435
- threadID,
436
- messageID
437
- });
438
-
439
- if (global.Fca.Require.Nazrul.AntiGetInfo.AntiGetThreadInfo) {
440
- global.Fca.Data.MsgCount.set(fmtMsg.threadID, ((global.Fca.Data.MsgCount.get(fmtMsg.threadID)) + 1 || 1));
441
- }
442
-
443
- if (ctx.globalOptions.autoMarkDelivery) {
444
- markDelivery(ctx, api, fmtMsg.threadID, fmtMsg.messageID);
445
- }
446
-
447
- if (!ctx.globalOptions.selfListen && fmtMsg.senderID === ctx.userID) return;
448
- globalCallback(null, fmtMsg);
449
- }
450
- } else {
451
- const attachment = delta.attachments[i];
452
- if (attachment.mercury.attach_type === 'photo') {
453
- api.resolvePhotoUrl(attachment.fbid, (err, url) => {
454
- if (!err) attachment.mercury.metadata.url = url;
455
- resolveAttachmentUrl(i + 1);
456
- });
457
- } else {
458
- resolveAttachmentUrl(i + 1);
459
- }
460
- }
461
- };
223
+ /* ================= DELTA PARSER ================= */
462
224
 
463
- resolveAttachmentUrl(0);
464
- } else if (delta.class === 'ClientPayload') {
465
- const clientPayload = utils.decodeClientPayload(delta.payload);
466
- if (clientPayload && clientPayload.deltas) {
467
- for (const delta of clientPayload.deltas) {
468
- if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) {
469
- const messageReaction = {
470
- type: 'message_reaction',
471
- threadID: (delta.deltaMessageReaction.threadKey.threadFbId ? delta.deltaMessageReaction.threadKey.threadFbId : delta.deltaMessageReaction.threadKey.otherUserFbId).toString(),
472
- messageID: delta.deltaMessageReaction.messageId,
473
- reaction: delta.deltaMessageReaction.reaction,
474
- senderID: delta.deltaMessageReaction.senderId.toString(),
475
- userID: delta.deltaMessageReaction.userId.toString(),
476
- };
477
- globalCallback(null, messageReaction);
478
- } else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
479
- const messageUnsend = {
480
- type: 'message_unsend',
481
- threadID: (delta.deltaRecallMessageData.threadKey.threadFbId ? delta.deltaRecallMessageData.threadKey.threadFbId : delta.deltaRecallMessageData.threadKey.otherUserFbId).toString(),
482
- messageID: delta.deltaRecallMessageData.messageID,
483
- senderID: delta.deltaRecallMessageData.senderID.toString(),
484
- deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp,
485
- timestamp: delta.deltaRecallMessageData.timestamp,
486
- };
487
- globalCallback(null, messageUnsend);
488
- } else if (delta.deltaMessageReply) {
489
- const msg = delta.deltaMessageReply.message || {};
490
- let mentions = {};
491
-
492
- try {
493
- const prng = msg?.data?.prng ? JSON.parse(msg.data.prng) : [];
494
- for (const m of prng) {
495
- if (m.i && m.o !== undefined && m.l !== undefined) {
496
- mentions[m.i] = (msg.body || "").substr(m.o, m.l);
497
- }
498
- }
499
- } catch {
500
- mentions = {};
501
- }
502
-
503
- const callbackToReturn = {
504
- type: "message_reply",
505
- threadID: (
506
- msg.messageMetadata.threadKey.threadFbId ||
507
- msg.messageMetadata.threadKey.otherUserFbId
508
- ).toString(),
509
- messageID: msg.messageMetadata.messageId,
510
- senderID: msg.messageMetadata.actorFbId.toString(),
511
- body: msg.body || "",
512
- args: (msg.body || "").trim().split(/\s+/),
513
- isGroup: !!msg.messageMetadata.threadKey.threadFbId,
514
- mentions,
515
- timestamp: parseInt(msg.messageMetadata.timestamp),
516
- participantIDs: (msg.participants || []).map(e => e.toString()),
517
- attachments: (msg.attachments || []).map(att => {
518
- try {
519
- const mercury = JSON.parse(att.mercuryJSON);
520
- Object.assign(att, mercury);
521
- return utils._formatAttachment(att);
522
- } catch {
523
- return att;
524
- }
525
- })
526
- };
527
-
528
- if (delta.deltaMessageReply.repliedToMessage) {
529
- const rmsg = delta.deltaMessageReply.repliedToMessage;
530
- let rmentions = {};
225
+ function parseDelta(defaultFuncs, api, ctx, globalCallback, { delta }) {
531
226
 
227
+ /* ===== NEW MESSAGE ===== */
228
+ if (delta.class === 'NewMessage') {
229
+ let msg;
532
230
  try {
533
- const rprng = rmsg?.data?.prng ? JSON.parse(rmsg.data.prng) : [];
534
- for (const m of rprng) {
535
- if (m.i && m.o !== undefined && m.l !== undefined) {
536
- rmentions[m.i] = (rmsg.body || "").substr(m.o, m.l);
537
- }
538
- }
231
+ msg = utils.formatDeltaMessage(delta);
539
232
  } catch {
540
- rmentions = {};
233
+ return;
541
234
  }
542
235
 
543
- callbackToReturn.messageReply = {
544
- senderID: rmsg.messageMetadata.actorFbId.toString(),
545
- body: rmsg.body || "",
546
- mentions: rmentions,
547
- messageID: rmsg.messageMetadata.messageId,
548
- threadID: callbackToReturn.threadID,
549
- isGroup: callbackToReturn.isGroup,
550
- timestamp: parseInt(rmsg.messageMetadata.timestamp)
551
- };
552
- }
236
+ if (!ctx.globalOptions.selfListen && msg.senderID === ctx.userID) return;
553
237
 
554
- if (ctx.globalOptions.autoMarkDelivery) {
555
- markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
556
- }
557
-
558
- if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
559
- globalCallback(null, callbackToReturn);
238
+ if (ctx.globalOptions.autoMarkDelivery) {
239
+ api.markAsDelivered(msg.threadID, msg.messageID, () => {
240
+ if (ctx.globalOptions.autoMarkRead) {
241
+ api.markAsRead(msg.threadID, () => {});
560
242
  }
561
- }
562
-
563
- return;
243
+ });
564
244
  }
245
+
246
+ return globalCallback(null, msg);
565
247
  }
566
- switch (delta.class) {
567
- case 'ReadReceipt': {
568
- let fmtMsg;
569
- try {
570
- fmtMsg = utils.formatDeltaReadReceipt(delta);
571
- } catch (err) {
572
- return log.error('Lỗi Nhẹ', err);
573
- }
574
- globalCallback(null, fmtMsg);
575
- break;
576
- }
577
- case 'AdminTextMessage': {
578
- switch (delta.type) {
579
- case 'joinable_group_link_mode_change':
580
- case 'magic_words':
581
- case 'pin_messages_v2':
582
- case 'change_thread_theme':
583
- case 'change_thread_icon':
584
- case 'change_thread_nickname':
585
- case 'change_thread_admins':
586
- case 'change_thread_approval_mode':
587
- case 'group_poll':
588
- case 'messenger_call_log':
589
- case 'participant_joined_group_call': {
590
- let fmtMsg;
591
- try {
592
- fmtMsg = utils.formatDeltaEvent(delta);
593
- } catch (err) {
594
- console.log(delta);
595
- return log.error('Lỗi Nhẹ', err);
596
- }
597
- globalCallback(null, fmtMsg);
598
- break;
599
- }
600
- }
601
- break;
602
- }
603
248
 
604
- //For group images
605
- case 'ForcedFetch': {
606
- if (!delta.threadKey) return;
607
- const mid = delta.messageId;
608
- const tid = delta.threadKey.threadFbId;
609
-
610
- if (mid && tid) {
611
- const form = {
612
- av: ctx.globalOptions.pageID,
613
- queries: JSON.stringify({
614
- o0: {
615
- doc_id: '2848441488556444',
616
- query_params: {
617
- thread_and_message_id: {
618
- thread_id: tid.toString(),
619
- message_id: mid,
620
- },
621
- },
622
- },
623
- }),
624
- };
625
- defaultFuncs
626
- .post('https://www.facebook.com/api/graphqlbatch/', ctx.jar, form)
627
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
628
- .then((resData) => {
629
- if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
630
-
631
- if (resData[resData.length - 1].successful_results === 0) throw {
632
- error: 'forcedFetch: there was no successful_results',
633
- res: resData
634
- };
635
-
636
- const fetchData = resData[0].o0.data.message;
637
-
638
- if (utils.getType(fetchData) === 'Object') {
639
- log.info('forcedFetch', fetchData);
640
- switch (fetchData.__typename) {
641
- case 'ThreadImageMessage':
642
- if (!ctx.globalOptions.selfListen && fetchData.message_sender.id.toString() === ctx.userID) return;
643
- if (!ctx.loggedIn) return;
644
-
645
- globalCallback(null, {
646
- type: 'change_thread_image',
647
- threadID: utils.formatID(tid.toString()),
648
- snippet: fetchData.snippet,
649
- timestamp: fetchData.timestamp_precise,
650
- author: fetchData.message_sender.id,
651
- image: {
652
- attachmentID: fetchData.image_with_metadata && fetchData.image_with_metadata.legacy_attachment_id,
653
- width: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.x,
654
- height: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.y,
655
- url: fetchData.image_with_metadata && fetchData.image_with_metadata.preview.uri,
656
- },
657
- });
658
- break;
659
- case 'UserMessage': {
660
- const event = {
661
- type: 'message',
662
- senderID: utils.formatID(fetchData.message_sender.id),
663
- body: fetchData.message.text || '',
664
- threadID: utils.formatID(tid.toString()),
665
- messageID: fetchData.message_id,
666
- attachments: [{
667
- type: 'share',
668
- ID: fetchData.extensible_attachment.legacy_attachment_id,
669
- url: fetchData.extensible_attachment.story_attachment.url,
670
- title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
671
- description: fetchData.extensible_attachment.story_attachment.description.text,
672
- source: fetchData.extensible_attachment.story_attachment.source,
673
- image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
674
- width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
675
- height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
676
- playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
677
- duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
678
- subattachments: fetchData.extensible_attachment.subattachments,
679
- properties: fetchData.extensible_attachment.story_attachment.properties,
680
- }],
681
- mentions: {},
682
- timestamp: parseInt(fetchData.timestamp_precise),
683
- isGroup: (fetchData.message_sender.id !== tid.toString()),
684
- };
685
-
686
- log.info('ff-Return', event);
687
- globalCallback(null, event);
688
- break;
689
- }
690
- default:
691
- log.error('forcedFetch', fetchData);
692
- }
693
- } else {
694
- log.error('forcedFetch', fetchData);
695
- }
696
- })
697
- .catch((err) => log.error('forcedFetch', err));
698
- }
699
- break;
700
- }
701
- case 'ThreadName':
702
- case 'ParticipantsAddedToGroupThread':
703
- case 'ParticipantLeftGroupThread': {
704
- let formattedEvent;
705
- try {
706
- formattedEvent = utils.formatDeltaEvent(delta);
707
- } catch (err) {
708
- console.log(err);
709
- return log.error('Lỗi Nhẹ', err);
249
+ /* ===== CLIENT PAYLOAD ===== */
250
+ if (delta.class === 'ClientPayload') {
251
+ const payload = utils.decodeClientPayload(delta.payload);
252
+ if (!payload || !payload.deltas) return;
253
+
254
+ for (const d of payload.deltas) {
255
+
256
+ if (d.deltaMessageReaction) {
257
+ globalCallback(null, {
258
+ type: 'message_reaction',
259
+ threadID: (
260
+ d.deltaMessageReaction.threadKey.threadFbId ||
261
+ d.deltaMessageReaction.threadKey.otherUserFbId
262
+ ).toString(),
263
+ messageID: d.deltaMessageReaction.messageId,
264
+ reaction: d.deltaMessageReaction.reaction,
265
+ senderID: d.deltaMessageReaction.senderId.toString(),
266
+ userID: d.deltaMessageReaction.userId.toString()
267
+ });
710
268
  }
711
269
 
712
- if (!ctx.globalOptions.selfListen && formattedEvent.author.toString() === ctx.userID) return;
713
- if (!ctx.loggedIn) return;
714
- globalCallback(null, formattedEvent);
715
- break;
716
- }
717
- case 'NewMessage': {
718
- const hasLiveLocation = delta => {
719
- const attachment = delta.attachments?.[0]?.mercury?.extensible_attachment;
720
- const storyAttachment = attachment?.story_attachment;
721
- return storyAttachment?.style_list?.includes('message_live_location');
722
- };
723
-
724
- if (delta.attachments?.length === 1 && hasLiveLocation(delta)) {
725
- delta.class = 'UserLocation';
726
-
727
- try {
728
- const fmtMsg = utils.formatDeltaEvent(delta);
729
- globalCallback(null, fmtMsg);
730
- } catch (err) {
731
- console.log(delta);
732
- log.error('Lỗi Nhẹ', err);
733
- }
270
+ if (d.deltaRecallMessageData) {
271
+ globalCallback(null, {
272
+ type: 'message_unsend',
273
+ threadID: (
274
+ d.deltaRecallMessageData.threadKey.threadFbId ||
275
+ d.deltaRecallMessageData.threadKey.otherUserFbId
276
+ ).toString(),
277
+ messageID: d.deltaRecallMessageData.messageID,
278
+ senderID: d.deltaRecallMessageData.senderID.toString(),
279
+ timestamp: d.deltaRecallMessageData.timestamp
280
+ });
734
281
  }
735
- break;
736
- }
737
- }
738
- }
739
282
 
740
- function markDelivery(ctx, api, threadID, messageID) {
741
- if (threadID && messageID) {
742
- api.markAsDelivered(threadID, messageID, (err) => {
743
- if (err) log.error('markAsDelivered', err);
744
- else {
745
- if (ctx.globalOptions.autoMarkRead) {
746
- api.markAsRead(threadID, (err) => {
747
- if (err) log.error('markAsDelivered', err);
748
- });
749
- }
283
+ if (d.deltaMessageReply) {
284
+ const msg = d.deltaMessageReply.message;
285
+ if (!msg) continue;
286
+
287
+ globalCallback(null, {
288
+ type: 'message_reply',
289
+ threadID: (
290
+ msg.messageMetadata.threadKey.threadFbId ||
291
+ msg.messageMetadata.threadKey.otherUserFbId
292
+ ).toString(),
293
+ messageID: msg.messageMetadata.messageId,
294
+ senderID: msg.messageMetadata.actorFbId.toString(),
295
+ body: msg.body || '',
296
+ timestamp: parseInt(msg.messageMetadata.timestamp),
297
+ isGroup: !!msg.messageMetadata.threadKey.threadFbId
298
+ });
750
299
  }
751
- });
300
+ }
752
301
  }
753
302
  }
754
303
 
304
+ /* ================= EXPORT ================= */
755
305
 
306
+ module.exports = function (defaultFuncs, api, ctx) {
756
307
 
757
- module.exports = function(defaultFuncs, api, ctx) {
758
- var globalCallback = identity;
759
- var okeoke;
760
- getSeqID = function getSeqID() {
761
- ctx.t_mqttCalled = false;
762
- defaultFuncs
763
- .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
764
- .then(res => {
765
- okeoke = res;
766
- return res;
767
- })
768
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
769
- .then((resData) => {
770
- if (utils.getType(resData) != "Array") {
771
- if (okeoke.request.uri && okeoke.request.uri.href.includes("https://www.facebook.com/checkpoint/")) {
772
- if (okeoke.request.uri.href.includes('601051028565049')) {
773
- return global.Fca.BypassAutomationNotification(undefined, ctx.jar, ctx.globalOptions, undefined ,process.env.UID)
774
- }
775
- }
776
- if (global.Fca.Require.Nazrul.AutoLogin) {
777
- return global.Fca.Require.logger.Warning(global.Fca.Require.Language.Index.AutoLogin, function() {
778
- return global.Fca.Action('AutoLogin');
779
- });
780
- } else if (!global.Fca.Require.Nazrul.AutoLogin) {
781
- return global.Fca.Require.logger.Error(global.Fca.Require.Language.Index.ErrAppState);
782
- }
783
- return;
784
- } else {
785
- if (resData && resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
786
- if (resData[resData.length - 1].successful_results === 0) throw {
787
- error: "getSeqId: there was no successful_results",
788
- res: resData
789
- };
790
- if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) {
791
- ctx.lastSeqId = resData[0].o0.data.viewer.message_threads.sync_sequence_id;
792
- listenMqtt(defaultFuncs, api, ctx, globalCallback);
793
- } else throw {
794
- error: "getSeqId: no sync_sequence_id found.",
795
- res: resData
796
- };
797
- }
798
- })
799
- .catch((err) => {
800
- log.error("getSeqId", err);
801
- if (okeoke.request.uri && okeoke.request.uri.href.includes("https://www.facebook.com/checkpoint/")) {
802
- if (okeoke.request.uri.href.includes('601051028565049')) {
803
- return global.Fca.BypassAutomationNotification(undefined, ctx.jar, ctx.globalOptions, undefined ,process.env.UID)
804
- }
805
- }
806
- if (utils.getType(err) == "Object" && err.error === global.Fca.Require.Language.Index.ErrAppState) ctx.loggedIn = false;
807
- return globalCallback(err);
808
- });
809
- };
308
+ return function (callback) {
810
309
 
811
- return function(callback) {
812
310
  class MessageEmitter extends EventEmitter {
813
- stopListening(callback) {
814
- callback = callback || (() => {});
815
- globalCallback = identity;
311
+ stopListening() {
816
312
  if (ctx.mqttClient) {
817
- ctx.mqttClient.unsubscribe("/webrtc");
818
- ctx.mqttClient.unsubscribe("/rtc_multi");
819
- ctx.mqttClient.unsubscribe("/onevc");
820
- ctx.mqttClient.publish("/browser_close", "{}");
821
- ctx.mqttClient.end(false, function(...data) {
822
- ctx.mqttClient = undefined;
823
- });
313
+ ctx.mqttClient.end(true);
314
+ ctx.mqttClient = null;
824
315
  }
825
- global.Fca.Data.StopListening = true;
826
316
  }
827
317
  }
828
318
 
829
- var msgEmitter = new MessageEmitter();
830
- globalCallback = (callback || function(error, message) {
831
- if (error) return msgEmitter.emit("error", error);
832
- msgEmitter.emit("message", message);
833
- });
319
+ const emitter = new MessageEmitter();
834
320
 
835
- //Reset some stuff
836
- if (!ctx.firstListen) ctx.lastSeqId = null;
837
- ctx.syncToken = undefined;
838
- ctx.t_mqttCalled = false;
839
-
840
- //Same request as getThreadList
841
- form = {
842
- av: ctx.globalOptions.pageID,
843
- queries: JSON.stringify({
844
- o0: {
845
- doc_id: '3336396659757871',
846
- query_params: {
847
- limit: 1,
848
- before: null,
849
- tags: ['INBOX'],
850
- includeDeliveryReceipts: false,
851
- includeSeqID: true,
852
- },
853
- },
854
- }),
321
+ const globalCallback = (err, data) => {
322
+ if (err) emitter.emit('error', err);
323
+ else emitter.emit('message', data);
855
324
  };
856
325
 
857
-
858
- if (!ctx.firstListen || !ctx.lastSeqId) getSeqID();
859
- else listenMqtt(defaultFuncs, api, ctx, globalCallback);
326
+ if (!ctx.firstListen) ctx.lastSeqId = null;
860
327
  ctx.firstListen = false;
861
328
 
862
- return msgEmitter;
329
+ listenMqtt(defaultFuncs, api, ctx, globalCallback);
330
+
331
+ return emitter;
863
332
  };
864
333
  };