@dongdev/fca-unofficial 0.0.7 → 0.0.8
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.
- package/README.md +77 -64
- package/index.js +79 -19
- package/lib/database/models/index.js +47 -0
- package/lib/database/models/thread.js +31 -0
- package/lib/database/threadData.js +93 -0
- package/lib/logger.js +96 -0
- package/package.json +8 -3
- package/src/getThreadInfo.js +293 -223
- package/src/getUserInfo.js +1 -7
- package/src/listenMqtt.js +716 -647
- package/utils.js +1236 -1349
- package/.travis.yml +0 -6
package/src/listenMqtt.js
CHANGED
@@ -1,74 +1,125 @@
|
|
1
|
-
/* eslint-disable no-redeclare */
|
2
1
|
"use strict";
|
3
2
|
const utils = require("../utils");
|
4
3
|
const log = require("npmlog");
|
5
|
-
const mqtt = require(
|
6
|
-
const WebSocket = require(
|
7
|
-
const HttpsProxyAgent = require(
|
8
|
-
const EventEmitter = require(
|
9
|
-
const Duplexify = require(
|
10
|
-
const {
|
11
|
-
|
12
|
-
} = require('stream');
|
13
|
-
const debugSeq = false;
|
14
|
-
var identity = function() {};
|
4
|
+
const mqtt = require("mqtt");
|
5
|
+
const WebSocket = require("ws");
|
6
|
+
const HttpsProxyAgent = require("https-proxy-agent");
|
7
|
+
const EventEmitter = require("events");
|
8
|
+
const Duplexify = require("duplexify");
|
9
|
+
const { Transform } = require("stream");
|
10
|
+
var identity = function () {};
|
15
11
|
var form = {};
|
16
|
-
var
|
17
|
-
const
|
12
|
+
var getSeqID = function () {};
|
13
|
+
const logger = require("../lib/logger.js");
|
14
|
+
const topics = [
|
15
|
+
"/ls_req",
|
16
|
+
"/ls_resp",
|
17
|
+
"/legacy_web",
|
18
|
+
"/webrtc",
|
19
|
+
"/rtc_multi",
|
20
|
+
"/onevc",
|
21
|
+
"/br_sr",
|
22
|
+
"/sr_res",
|
23
|
+
"/t_ms",
|
24
|
+
"/thread_typing",
|
25
|
+
"/orca_typing_notifications",
|
26
|
+
"/notify_disconnect",
|
27
|
+
"/orca_presence",
|
28
|
+
"/inbox",
|
29
|
+
"/mercury",
|
30
|
+
"/messaging_events",
|
31
|
+
"/orca_message_notifications",
|
32
|
+
"/pp",
|
33
|
+
"/webrtc_response",
|
34
|
+
];
|
18
35
|
let WebSocket_Global;
|
19
36
|
function buildProxy() {
|
20
37
|
const Proxy = new Transform({
|
21
38
|
objectMode: false,
|
22
39
|
transform(chunk, enc, next) {
|
23
|
-
if (WebSocket_Global.readyState !==
|
40
|
+
if (WebSocket_Global.readyState !== WebSocket.OPEN) {
|
24
41
|
return next();
|
25
42
|
}
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
43
|
+
const data = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
|
44
|
+
try {
|
45
|
+
WebSocket_Global.send(data);
|
46
|
+
next();
|
47
|
+
} catch (err) {
|
48
|
+
console.error("WebSocket send error:", err);
|
49
|
+
next(err);
|
31
50
|
}
|
32
|
-
WebSocket_Global.send(data);
|
33
|
-
next();
|
34
51
|
},
|
35
52
|
flush(done) {
|
36
|
-
WebSocket_Global.
|
53
|
+
if (WebSocket_Global.readyState === WebSocket.OPEN) {
|
54
|
+
WebSocket_Global.close();
|
55
|
+
}
|
37
56
|
done();
|
38
57
|
},
|
39
58
|
writev(chunks, cb) {
|
40
|
-
|
41
|
-
|
42
|
-
|
59
|
+
try {
|
60
|
+
for (const { chunk } of chunks) {
|
61
|
+
this.push(
|
62
|
+
Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8")
|
63
|
+
);
|
43
64
|
}
|
44
|
-
|
45
|
-
})
|
46
|
-
|
65
|
+
cb();
|
66
|
+
} catch (err) {
|
67
|
+
console.error("Writev error:", err);
|
68
|
+
cb(err);
|
69
|
+
}
|
47
70
|
},
|
48
71
|
});
|
72
|
+
|
49
73
|
return Proxy;
|
50
74
|
}
|
51
75
|
function buildStream(options, WebSocket, Proxy) {
|
52
76
|
const Stream = Duplexify(undefined, undefined, options);
|
53
77
|
Stream.socket = WebSocket;
|
78
|
+
let pingInterval;
|
79
|
+
let reconnectTimeout;
|
80
|
+
const clearTimers = () => {
|
81
|
+
clearInterval(pingInterval);
|
82
|
+
clearTimeout(reconnectTimeout);
|
83
|
+
};
|
54
84
|
WebSocket.onclose = () => {
|
85
|
+
clearTimers();
|
55
86
|
Stream.end();
|
56
87
|
Stream.destroy();
|
57
88
|
};
|
58
89
|
WebSocket.onerror = (err) => {
|
90
|
+
clearTimers();
|
59
91
|
Stream.destroy(err);
|
60
92
|
};
|
61
93
|
WebSocket.onmessage = (event) => {
|
62
|
-
|
94
|
+
clearTimeout(reconnectTimeout);
|
95
|
+
const data =
|
96
|
+
event.data instanceof ArrayBuffer
|
97
|
+
? Buffer.from(event.data)
|
98
|
+
: Buffer.from(event.data, "utf8");
|
63
99
|
Stream.push(data);
|
64
100
|
};
|
65
101
|
WebSocket.onopen = () => {
|
66
102
|
Stream.setReadable(Proxy);
|
67
103
|
Stream.setWritable(Proxy);
|
68
|
-
Stream.emit(
|
104
|
+
Stream.emit("connect");
|
105
|
+
pingInterval = setInterval(() => {
|
106
|
+
if (WebSocket.readyState === WebSocket.OPEN) {
|
107
|
+
WebSocket.ping();
|
108
|
+
}
|
109
|
+
}, 30000);
|
110
|
+
reconnectTimeout = setTimeout(() => {
|
111
|
+
if (WebSocket.readyState === WebSocket.OPEN) {
|
112
|
+
WebSocket.close();
|
113
|
+
Stream.end();
|
114
|
+
Stream.destroy();
|
115
|
+
}
|
116
|
+
}, 60000);
|
69
117
|
};
|
70
118
|
WebSocket_Global = WebSocket;
|
71
|
-
Proxy.on(
|
119
|
+
Proxy.on("close", () => {
|
120
|
+
clearTimers();
|
121
|
+
WebSocket.close();
|
122
|
+
});
|
72
123
|
return Stream;
|
73
124
|
}
|
74
125
|
function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
@@ -82,22 +133,22 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
82
133
|
chat_on: chatOn,
|
83
134
|
fg: foreground,
|
84
135
|
d: GUID,
|
85
|
-
ct:
|
86
|
-
aid:
|
136
|
+
ct: "websocket",
|
137
|
+
aid: 219994525426954,
|
87
138
|
aids: null,
|
88
|
-
mqtt_sid:
|
139
|
+
mqtt_sid: "",
|
89
140
|
cp: 3,
|
90
141
|
ecp: 10,
|
91
142
|
st: [],
|
92
143
|
pm: [],
|
93
|
-
dc:
|
144
|
+
dc: "",
|
94
145
|
no_auto_fg: true,
|
95
146
|
gas: null,
|
96
147
|
pack: [],
|
97
148
|
p: null,
|
98
149
|
php_override: ""
|
99
150
|
};
|
100
|
-
const cookies = ctx.jar.getCookies(
|
151
|
+
const cookies = ctx.jar.getCookies("https://www.facebook.com").join("; ");
|
101
152
|
let host;
|
102
153
|
if (ctx.mqttEndpoint) {
|
103
154
|
host = `${ctx.mqttEndpoint}&sid=${sessionID}&cid=${GUID}`;
|
@@ -107,33 +158,52 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
107
158
|
host = `wss://edge-chat.facebook.com/chat?sid=${sessionID}&cid=${GUID}`;
|
108
159
|
}
|
109
160
|
const options = {
|
110
|
-
clientId:
|
111
|
-
protocolId:
|
161
|
+
clientId: "mqttwsclient",
|
162
|
+
protocolId: "MQIsdp",
|
112
163
|
protocolVersion: 3,
|
113
164
|
username: JSON.stringify(username),
|
114
165
|
clean: true,
|
115
166
|
wsOptions: {
|
116
167
|
headers: {
|
117
168
|
Cookie: cookies,
|
118
|
-
Origin:
|
119
|
-
|
120
|
-
|
121
|
-
|
169
|
+
Origin: "https://www.facebook.com",
|
170
|
+
"User-Agent":
|
171
|
+
ctx.globalOptions.userAgent ||
|
172
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
|
173
|
+
Referer: "https://www.facebook.com/",
|
174
|
+
Host: "edge-chat.facebook.com",
|
175
|
+
Connection: "Upgrade",
|
176
|
+
Pragma: "no-cache",
|
177
|
+
"Cache-Control": "no-cache",
|
178
|
+
Upgrade: "websocket",
|
179
|
+
"Sec-WebSocket-Version": "13",
|
180
|
+
"Accept-Encoding": "gzip, deflate, br",
|
181
|
+
"Accept-Language": "vi,en;q=0.9",
|
182
|
+
"Sec-WebSocket-Extensions":
|
183
|
+
"permessage-deflate; client_max_window_bits",
|
122
184
|
},
|
123
|
-
origin:
|
185
|
+
origin: "https://www.facebook.com",
|
124
186
|
protocolVersion: 13,
|
125
|
-
binaryType:
|
187
|
+
binaryType: "arraybuffer",
|
126
188
|
},
|
127
|
-
keepalive:
|
189
|
+
keepalive: 30,
|
128
190
|
reschedulePings: true,
|
129
|
-
reconnectPeriod:
|
130
|
-
connectTimeout:
|
191
|
+
reconnectPeriod: 1000,
|
192
|
+
connectTimeout: 5000,
|
131
193
|
};
|
132
|
-
if (
|
194
|
+
if (ctx.globalOptions.proxy !== undefined) {
|
133
195
|
const agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
|
134
196
|
options.wsOptions.agent = agent;
|
135
197
|
}
|
136
|
-
ctx.mqttClient = new mqtt.Client(
|
198
|
+
ctx.mqttClient = new mqtt.Client(
|
199
|
+
() =>
|
200
|
+
buildStream(
|
201
|
+
options,
|
202
|
+
new WebSocket(host, options.wsOptions),
|
203
|
+
buildProxy()
|
204
|
+
),
|
205
|
+
options
|
206
|
+
);
|
137
207
|
const mqttClient = ctx.mqttClient;
|
138
208
|
global.mqttClient = mqttClient;
|
139
209
|
mqttClient.on('error', function (err) {
|
@@ -157,25 +227,22 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
157
227
|
});
|
158
228
|
}
|
159
229
|
});
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
mqttClient.subscribe(topicsub);
|
168
|
-
});
|
169
|
-
|
170
|
-
let topic;
|
230
|
+
mqttClient.on("connect", function () {
|
231
|
+
if (process.env.OnStatus === undefined) {
|
232
|
+
logger("fca-unoffcial premium", "info");
|
233
|
+
process.env.OnStatus = true;
|
234
|
+
}
|
235
|
+
topics.forEach((topicsub) => mqttClient.subscribe(topicsub));
|
236
|
+
var topic;
|
171
237
|
const queue = {
|
172
|
-
sync_api_version:
|
173
|
-
max_deltas_able_to_process:
|
238
|
+
sync_api_version: 11,
|
239
|
+
max_deltas_able_to_process: 100,
|
174
240
|
delta_batch_size: 500,
|
175
241
|
encoding: "JSON",
|
176
|
-
entity_fbid: ctx.
|
242
|
+
entity_fbid: ctx.userID,
|
243
|
+
initial_titan_sequence_id: ctx.lastSeqId,
|
244
|
+
device_params: null,
|
177
245
|
};
|
178
|
-
|
179
246
|
if (ctx.syncToken) {
|
180
247
|
topic = "/messenger_sync_get_diffs";
|
181
248
|
queue.last_seq_id = ctx.lastSeqId;
|
@@ -185,294 +252,264 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
185
252
|
queue.initial_titan_sequence_id = ctx.lastSeqId;
|
186
253
|
queue.device_params = null;
|
187
254
|
}
|
188
|
-
|
189
|
-
mqttClient.publish(
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
});
|
200
|
-
mqttClient.publish("/set_client_settings", JSON.stringify({
|
201
|
-
make_user_available_when_in_foreground: true
|
202
|
-
}), {
|
203
|
-
qos: 1
|
204
|
-
});
|
205
|
-
|
255
|
+
mqttClient.publish(topic, JSON.stringify(queue), { qos: 1, retain: false });
|
256
|
+
mqttClient.publish(
|
257
|
+
"/foreground_state",
|
258
|
+
JSON.stringify({ foreground: chatOn }),
|
259
|
+
{ qos: 1 }
|
260
|
+
);
|
261
|
+
mqttClient.publish(
|
262
|
+
"/set_client_settings",
|
263
|
+
JSON.stringify({ make_user_available_when_in_foreground: true }),
|
264
|
+
{ qos: 1 }
|
265
|
+
);
|
206
266
|
const rTimeout = setTimeout(function () {
|
207
267
|
mqttClient.end();
|
208
268
|
listenMqtt(defaultFuncs, api, ctx, globalCallback);
|
209
269
|
}, 5000);
|
210
|
-
|
211
270
|
ctx.tmsWait = function () {
|
212
271
|
clearTimeout(rTimeout);
|
213
|
-
ctx.globalOptions.emitReady
|
214
|
-
|
215
|
-
|
216
|
-
|
272
|
+
ctx.globalOptions.emitReady
|
273
|
+
? globalCallback({
|
274
|
+
type: "ready",
|
275
|
+
error: null,
|
276
|
+
})
|
277
|
+
: "";
|
217
278
|
delete ctx.tmsWait;
|
218
279
|
};
|
219
|
-
|
220
280
|
});
|
221
|
-
|
222
|
-
mqttClient.on('message', function (topic, message, _packet) {
|
223
|
-
let jsonMessage = Buffer.isBuffer(message) ? Buffer.from(message).toString() : message;
|
281
|
+
mqttClient.on("message", function (topic, message, _packet) {
|
224
282
|
try {
|
225
|
-
jsonMessage =
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
type: "friend_request_received",
|
233
|
-
actorFbId: jsonMessage.from.toString(),
|
234
|
-
timestamp: Date.now().toString()
|
235
|
-
});
|
236
|
-
} else if (jsonMessage.type === "jewel_requests_remove_old") {
|
237
|
-
globalCallback(null, {
|
238
|
-
type: "friend_request_cancel",
|
239
|
-
actorFbId: jsonMessage.from.toString(),
|
240
|
-
timestamp: Date.now().toString()
|
241
|
-
});
|
242
|
-
} else if (topic === "/t_ms") {
|
243
|
-
if (ctx.tmsWait && typeof ctx.tmsWait == "function") {
|
244
|
-
ctx.tmsWait();
|
245
|
-
}
|
246
|
-
|
247
|
-
if (jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
|
248
|
-
ctx.lastSeqId = jsonMessage.firstDeltaSeqId;
|
249
|
-
ctx.syncToken = jsonMessage.syncToken;
|
250
|
-
}
|
251
|
-
|
252
|
-
if (jsonMessage.lastIssuedSeqId) {
|
253
|
-
ctx.lastSeqId = parseInt(jsonMessage.lastIssuedSeqId);
|
283
|
+
let jsonMessage = Buffer.isBuffer(message)
|
284
|
+
? Buffer.from(message).toString()
|
285
|
+
: message;
|
286
|
+
try {
|
287
|
+
jsonMessage = JSON.parse(jsonMessage);
|
288
|
+
} catch (e) {
|
289
|
+
jsonMessage = {};
|
254
290
|
}
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
"delta": delta
|
291
|
+
if (jsonMessage.type === "jewel_requests_add") {
|
292
|
+
globalCallback(null, {
|
293
|
+
type: "friend_request_received",
|
294
|
+
actorFbId: jsonMessage.from.toString(),
|
295
|
+
timestamp: Date.now().toString(),
|
261
296
|
});
|
262
|
-
}
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
297
|
+
} else if (jsonMessage.type === "jewel_requests_remove_old") {
|
298
|
+
globalCallback(null, {
|
299
|
+
type: "friend_request_cancel",
|
300
|
+
actorFbId: jsonMessage.from.toString(),
|
301
|
+
timestamp: Date.now().toString(),
|
302
|
+
});
|
303
|
+
} else if (topic === "/t_ms") {
|
304
|
+
if (ctx.tmsWait && typeof ctx.tmsWait == "function") {
|
305
|
+
ctx.tmsWait();
|
306
|
+
}
|
307
|
+
if (jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
|
308
|
+
ctx.lastSeqId = jsonMessage.firstDeltaSeqId;
|
309
|
+
ctx.syncToken = jsonMessage.syncToken;
|
310
|
+
}
|
311
|
+
if (jsonMessage.lastIssuedSeqId) {
|
312
|
+
ctx.lastSeqId = parseInt(jsonMessage.lastIssuedSeqId);
|
313
|
+
}
|
314
|
+
for (const i in jsonMessage.deltas) {
|
315
|
+
const delta = jsonMessage.deltas[i];
|
316
|
+
parseDelta(defaultFuncs, api, ctx, globalCallback, {
|
317
|
+
delta: delta,
|
318
|
+
});
|
319
|
+
}
|
320
|
+
} else if (
|
321
|
+
topic === "/thread_typing" ||
|
322
|
+
topic === "/orca_typing_notifications"
|
323
|
+
) {
|
324
|
+
const typ = {
|
325
|
+
type: "typ",
|
326
|
+
isTyping: !!jsonMessage.state,
|
327
|
+
from: jsonMessage.sender_fbid.toString(),
|
328
|
+
threadID: utils.formatID(
|
329
|
+
(jsonMessage.thread || jsonMessage.sender_fbid).toString()
|
330
|
+
),
|
331
|
+
};
|
332
|
+
(function () {
|
333
|
+
globalCallback(null, typ);
|
334
|
+
})();
|
335
|
+
} else if (topic === "/orca_presence") {
|
336
|
+
if (!ctx.globalOptions.updatePresence) {
|
337
|
+
for (const i in jsonMessage.list) {
|
338
|
+
const data = jsonMessage.list[i];
|
339
|
+
const userID = data["u"];
|
340
|
+
const presence = {
|
341
|
+
type: "presence",
|
342
|
+
userID: userID.toString(),
|
343
|
+
timestamp: data["l"] * 1000,
|
344
|
+
statuses: data["p"],
|
345
|
+
};
|
346
|
+
(function () {
|
347
|
+
globalCallback(null, presence);
|
348
|
+
})();
|
349
|
+
}
|
350
|
+
}
|
351
|
+
} else if (topic == "/ls_resp") {
|
352
|
+
const parsedPayload = JSON.parse(jsonMessage.payload);
|
353
|
+
const reqID = jsonMessage.request_id;
|
354
|
+
if (ctx["tasks"].has(reqID)) {
|
355
|
+
const taskData = ctx["tasks"].get(reqID);
|
356
|
+
const { type: taskType, callback: taskCallback } = taskData;
|
357
|
+
const taskRespData = getTaskResponseData(taskType, parsedPayload);
|
358
|
+
if (taskRespData == null) {
|
359
|
+
taskCallback("error", null);
|
360
|
+
} else {
|
361
|
+
taskCallback(null, {
|
362
|
+
type: taskType,
|
363
|
+
reqID: reqID,
|
364
|
+
...taskRespData,
|
365
|
+
});
|
366
|
+
}
|
289
367
|
}
|
290
368
|
}
|
369
|
+
} catch (ex) {
|
370
|
+
console.error("Message parsing error:", ex);
|
371
|
+
if (ex.stack) console.error(ex.stack);
|
372
|
+
return;
|
291
373
|
}
|
292
|
-
|
293
374
|
});
|
294
|
-
|
375
|
+
mqttClient.on("close", function () {});
|
376
|
+
mqttClient.on("disconnect", () => {});
|
295
377
|
}
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
378
|
+
function getTaskResponseData(taskType, payload) {
|
379
|
+
try {
|
380
|
+
switch (taskType) {
|
381
|
+
case "send_message_mqtt": {
|
382
|
+
return {
|
383
|
+
type: taskType,
|
384
|
+
threadID: payload.step[1][2][2][1][2],
|
385
|
+
messageID: payload.step[1][2][2][1][3],
|
386
|
+
payload: payload.step[1][2],
|
387
|
+
};
|
388
|
+
}
|
389
|
+
case "set_message_reaction": {
|
390
|
+
return {
|
391
|
+
mid: payload.step[1][2][2][1][4],
|
392
|
+
};
|
393
|
+
}
|
394
|
+
case "edit_message": {
|
395
|
+
return {
|
396
|
+
mid: payload.step[1][2][2][1][2],
|
397
|
+
};
|
398
|
+
}
|
399
|
+
}
|
400
|
+
} catch (error) {
|
401
|
+
return null;
|
402
|
+
}
|
403
|
+
}
|
404
|
+
function parseDelta(defaultFuncs, api, ctx, globalCallback, { delta }) {
|
405
|
+
if (delta.class === "NewMessage") {
|
406
|
+
if (ctx.globalOptions.pageID && ctx.globalOptions.pageID !== delta.queue)
|
303
407
|
return;
|
304
|
-
|
305
|
-
|
306
|
-
|
408
|
+
const resolveAttachmentUrl = (i) => {
|
409
|
+
if (
|
410
|
+
!delta.attachments ||
|
411
|
+
i === delta.attachments.length ||
|
412
|
+
utils.getType(delta.attachments) !== "Array"
|
413
|
+
) {
|
307
414
|
let fmtMsg;
|
308
415
|
try {
|
309
|
-
fmtMsg = utils.formatDeltaMessage(
|
416
|
+
fmtMsg = utils.formatDeltaMessage(delta);
|
310
417
|
} catch (err) {
|
311
|
-
return
|
312
|
-
error: "Problem parsing message object. Please open an issue at https://github.com/ntkhang03/fb-chat-api/issues.",
|
313
|
-
detail: err,
|
314
|
-
res: v,
|
315
|
-
type: "parse_error"
|
316
|
-
});
|
418
|
+
return log.error("Lỗi Nhẹ", err);
|
317
419
|
}
|
318
420
|
if (fmtMsg) {
|
319
421
|
if (ctx.globalOptions.autoMarkDelivery) {
|
320
422
|
markDelivery(ctx, api, fmtMsg.threadID, fmtMsg.messageID);
|
321
423
|
}
|
424
|
+
if (!ctx.globalOptions.selfListen && fmtMsg.senderID === ctx.userID)
|
425
|
+
return;
|
426
|
+
globalCallback(null, fmtMsg);
|
322
427
|
}
|
323
|
-
return !ctx.globalOptions.selfListen &&
|
324
|
-
(fmtMsg.senderID === ctx.i_userID || fmtMsg.senderID === ctx.userID) ?
|
325
|
-
undefined :
|
326
|
-
(function () {
|
327
|
-
globalCallback(null, fmtMsg);
|
328
|
-
})();
|
329
428
|
} else {
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
(err
|
334
|
-
|
335
|
-
|
336
|
-
i
|
337
|
-
].mercury.metadata.url = url;
|
338
|
-
return resolveAttachmentUrl(i + 1);
|
339
|
-
}
|
340
|
-
);
|
429
|
+
const attachment = delta.attachments[i];
|
430
|
+
if (attachment.mercury.attach_type === "photo") {
|
431
|
+
api.resolvePhotoUrl(attachment.fbid, (err, url) => {
|
432
|
+
if (!err) attachment.mercury.metadata.url = url;
|
433
|
+
resolveAttachmentUrl(i + 1);
|
434
|
+
});
|
341
435
|
} else {
|
342
|
-
|
436
|
+
resolveAttachmentUrl(i + 1);
|
343
437
|
}
|
344
438
|
}
|
345
|
-
}
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
const clientPayload = utils.decodeClientPayload(
|
350
|
-
v.delta.payload
|
351
|
-
);
|
352
|
-
|
439
|
+
};
|
440
|
+
resolveAttachmentUrl(0);
|
441
|
+
} else if (delta.class === "ClientPayload") {
|
442
|
+
const clientPayload = utils.decodeClientPayload(delta.payload);
|
353
443
|
if (clientPayload && clientPayload.deltas) {
|
354
|
-
for (const
|
355
|
-
const delta = clientPayload.deltas[i];
|
444
|
+
for (const delta of clientPayload.deltas) {
|
356
445
|
if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) {
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
(
|
385
|
-
globalCallback(null, {
|
386
|
-
type: "message_self_delete",
|
387
|
-
threadID: (delta.deltaRemoveMessage.threadKey.threadFbId ?
|
388
|
-
delta.deltaRemoveMessage.threadKey.threadFbId : delta.deltaRemoveMessage.threadKey
|
389
|
-
.otherUserFbId).toString(),
|
390
|
-
messageID: delta.deltaRemoveMessage.messageIds.length == 1 ? delta.deltaRemoveMessage.messageIds[0] : delta.deltaRemoveMessage.messageIds,
|
391
|
-
senderID: api.getCurrentUserID(),
|
392
|
-
deletionTimestamp: delta.deltaRemoveMessage.deletionTimestamp,
|
393
|
-
timestamp: delta.deltaRemoveMessage.timestamp
|
394
|
-
});
|
395
|
-
})();
|
446
|
+
const messageReaction = {
|
447
|
+
type: "message_reaction",
|
448
|
+
threadID: (delta.deltaMessageReaction.threadKey.threadFbId
|
449
|
+
? delta.deltaMessageReaction.threadKey.threadFbId
|
450
|
+
: delta.deltaMessageReaction.threadKey.otherUserFbId
|
451
|
+
).toString(),
|
452
|
+
messageID: delta.deltaMessageReaction.messageId,
|
453
|
+
reaction: delta.deltaMessageReaction.reaction,
|
454
|
+
senderID: delta.deltaMessageReaction.senderId.toString(),
|
455
|
+
userID: delta.deltaMessageReaction.userId.toString(),
|
456
|
+
};
|
457
|
+
globalCallback(null, messageReaction);
|
458
|
+
} else if (
|
459
|
+
delta.deltaRecallMessageData &&
|
460
|
+
!!ctx.globalOptions.listenEvents
|
461
|
+
) {
|
462
|
+
const messageUnsend = {
|
463
|
+
type: "message_unsend",
|
464
|
+
threadID: (delta.deltaRecallMessageData.threadKey.threadFbId
|
465
|
+
? delta.deltaRecallMessageData.threadKey.threadFbId
|
466
|
+
: delta.deltaRecallMessageData.threadKey.otherUserFbId
|
467
|
+
).toString(),
|
468
|
+
messageID: delta.deltaRecallMessageData.messageID,
|
469
|
+
senderID: delta.deltaRecallMessageData.senderID.toString(),
|
470
|
+
deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp,
|
471
|
+
timestamp: delta.deltaRecallMessageData.timestamp,
|
472
|
+
};
|
473
|
+
globalCallback(null, messageUnsend);
|
396
474
|
} else if (delta.deltaMessageReply) {
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
delta.deltaMessageReply.message.data === undefined
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
let m_length = mdata.map(u => u.l);
|
475
|
+
const mdata =
|
476
|
+
delta.deltaMessageReply.message === undefined
|
477
|
+
? []
|
478
|
+
: delta.deltaMessageReply.message.data === undefined
|
479
|
+
? []
|
480
|
+
: delta.deltaMessageReply.message.data.prng === undefined
|
481
|
+
? []
|
482
|
+
: JSON.parse(delta.deltaMessageReply.message.data.prng);
|
406
483
|
|
484
|
+
const m_id = mdata.map((u) => u.i);
|
485
|
+
const m_offset = mdata.map((u) => u.o);
|
486
|
+
const m_length = mdata.map((u) => u.l);
|
407
487
|
const mentions = {};
|
408
|
-
|
409
488
|
for (let i = 0; i < m_id.length; i++) {
|
410
|
-
mentions[m_id[i]] = (
|
411
|
-
|
412
|
-
|
413
|
-
);
|
489
|
+
mentions[m_id[i]] = (
|
490
|
+
delta.deltaMessageReply.message.body || ""
|
491
|
+
).substring(m_offset[i], m_offset[i] + m_length[i]);
|
414
492
|
}
|
415
|
-
//Mention block - 1#
|
416
493
|
const callbackToReturn = {
|
417
494
|
type: "message_reply",
|
418
|
-
threadID: (delta.deltaMessageReply.message.messageMetadata.threadKey
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
} catch (ex) {
|
432
|
-
x = att;
|
433
|
-
x.error = ex;
|
434
|
-
x.type = "unknown";
|
435
|
-
}
|
436
|
-
return x;
|
437
|
-
}),
|
438
|
-
body: delta.deltaMessageReply.message.body || "",
|
439
|
-
isGroup: !!delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId,
|
440
|
-
mentions: mentions,
|
441
|
-
timestamp: delta.deltaMessageReply.message.messageMetadata.timestamp,
|
442
|
-
participantIDs: (delta.deltaMessageReply.message.messageMetadata.cid.canonicalParticipantFbids || delta.deltaMessageReply.message.participants || []).map(e => e.toString())
|
443
|
-
};
|
444
|
-
|
445
|
-
if (delta.deltaMessageReply.repliedToMessage) {
|
446
|
-
//Mention block - #2
|
447
|
-
mdata =
|
448
|
-
delta.deltaMessageReply.repliedToMessage === undefined ? [] :
|
449
|
-
delta.deltaMessageReply.repliedToMessage.data === undefined ? [] :
|
450
|
-
delta.deltaMessageReply.repliedToMessage.data.prng === undefined ? [] :
|
451
|
-
JSON.parse(delta.deltaMessageReply.repliedToMessage.data.prng);
|
452
|
-
m_id = mdata.map(u => u.i);
|
453
|
-
m_offset = mdata.map(u => u.o);
|
454
|
-
m_length = mdata.map(u => u.l);
|
455
|
-
|
456
|
-
const rmentions = {};
|
457
|
-
|
458
|
-
for (let i = 0; i < m_id.length; i++) {
|
459
|
-
rmentions[m_id[i]] = (delta.deltaMessageReply.repliedToMessage.body || "").substring(
|
460
|
-
m_offset[i],
|
461
|
-
m_offset[i] + m_length[i]
|
462
|
-
);
|
463
|
-
}
|
464
|
-
//Mention block - 2#
|
465
|
-
callbackToReturn.messageReply = {
|
466
|
-
threadID: (delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId ?
|
467
|
-
delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey
|
468
|
-
.otherUserFbId).toString(),
|
469
|
-
messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId,
|
470
|
-
senderID: delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId.toString(),
|
471
|
-
attachments: delta.deltaMessageReply.repliedToMessage.attachments.map(function (att) {
|
495
|
+
threadID: (delta.deltaMessageReply.message.messageMetadata.threadKey
|
496
|
+
.threadFbId
|
497
|
+
? delta.deltaMessageReply.message.messageMetadata.threadKey
|
498
|
+
.threadFbId
|
499
|
+
: delta.deltaMessageReply.message.messageMetadata.threadKey
|
500
|
+
.otherUserFbId
|
501
|
+
).toString(),
|
502
|
+
messageID:
|
503
|
+
delta.deltaMessageReply.message.messageMetadata.messageId,
|
504
|
+
senderID:
|
505
|
+
delta.deltaMessageReply.message.messageMetadata.actorFbId.toString(),
|
506
|
+
attachments: (delta.deltaMessageReply.message.attachments || [])
|
507
|
+
.map((att) => {
|
472
508
|
const mercury = JSON.parse(att.mercuryJSON);
|
473
509
|
Object.assign(att, mercury);
|
474
510
|
return att;
|
475
|
-
})
|
511
|
+
})
|
512
|
+
.map((att) => {
|
476
513
|
let x;
|
477
514
|
try {
|
478
515
|
x = utils._formatAttachment(att);
|
@@ -483,130 +520,209 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
483
520
|
}
|
484
521
|
return x;
|
485
522
|
}),
|
523
|
+
args: (delta.deltaMessageReply.message.body || "")
|
524
|
+
.trim()
|
525
|
+
.split(/\s+/),
|
526
|
+
body: delta.deltaMessageReply.message.body || "",
|
527
|
+
isGroup:
|
528
|
+
!!delta.deltaMessageReply.message.messageMetadata.threadKey
|
529
|
+
.threadFbId,
|
530
|
+
mentions,
|
531
|
+
timestamp: parseInt(
|
532
|
+
delta.deltaMessageReply.message.messageMetadata.timestamp
|
533
|
+
),
|
534
|
+
participantIDs: (
|
535
|
+
delta.deltaMessageReply.message.participants || []
|
536
|
+
).map((e) => e.toString()),
|
537
|
+
};
|
538
|
+
if (delta.deltaMessageReply.repliedToMessage) {
|
539
|
+
const mdata =
|
540
|
+
delta.deltaMessageReply.repliedToMessage === undefined
|
541
|
+
? []
|
542
|
+
: delta.deltaMessageReply.repliedToMessage.data === undefined
|
543
|
+
? []
|
544
|
+
: delta.deltaMessageReply.repliedToMessage.data.prng ===
|
545
|
+
undefined
|
546
|
+
? []
|
547
|
+
: JSON.parse(
|
548
|
+
delta.deltaMessageReply.repliedToMessage.data.prng
|
549
|
+
);
|
550
|
+
const m_id = mdata.map((u) => u.i);
|
551
|
+
const m_offset = mdata.map((u) => u.o);
|
552
|
+
const m_length = mdata.map((u) => u.l);
|
553
|
+
const rmentions = {};
|
554
|
+
for (let i = 0; i < m_id.length; i++) {
|
555
|
+
rmentions[m_id[i]] = (
|
556
|
+
delta.deltaMessageReply.repliedToMessage.body || ""
|
557
|
+
).substring(m_offset[i], m_offset[i] + m_length[i]);
|
558
|
+
}
|
559
|
+
callbackToReturn.messageReply = {
|
560
|
+
threadID: (delta.deltaMessageReply.repliedToMessage
|
561
|
+
.messageMetadata.threadKey.threadFbId
|
562
|
+
? delta.deltaMessageReply.repliedToMessage.messageMetadata
|
563
|
+
.threadKey.threadFbId
|
564
|
+
: delta.deltaMessageReply.repliedToMessage.messageMetadata
|
565
|
+
.threadKey.otherUserFbId
|
566
|
+
).toString(),
|
567
|
+
messageID:
|
568
|
+
delta.deltaMessageReply.repliedToMessage.messageMetadata
|
569
|
+
.messageId,
|
570
|
+
senderID:
|
571
|
+
delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId.toString(),
|
572
|
+
attachments: delta.deltaMessageReply.repliedToMessage.attachments
|
573
|
+
.map((att) => {
|
574
|
+
let mercury;
|
575
|
+
try {
|
576
|
+
mercury = JSON.parse(att.mercuryJSON);
|
577
|
+
Object.assign(att, mercury);
|
578
|
+
} catch (ex) {
|
579
|
+
mercury = {};
|
580
|
+
}
|
581
|
+
return att;
|
582
|
+
})
|
583
|
+
.map((att) => {
|
584
|
+
let x;
|
585
|
+
try {
|
586
|
+
x = utils._formatAttachment(att);
|
587
|
+
} catch (ex) {
|
588
|
+
x = att;
|
589
|
+
x.error = ex;
|
590
|
+
x.type = "unknown";
|
591
|
+
}
|
592
|
+
return x;
|
593
|
+
}),
|
594
|
+
args: (delta.deltaMessageReply.repliedToMessage.body || "")
|
595
|
+
.trim()
|
596
|
+
.split(/\s+/),
|
486
597
|
body: delta.deltaMessageReply.repliedToMessage.body || "",
|
487
|
-
isGroup:
|
598
|
+
isGroup:
|
599
|
+
!!delta.deltaMessageReply.repliedToMessage.messageMetadata
|
600
|
+
.threadKey.threadFbId,
|
488
601
|
mentions: rmentions,
|
489
|
-
timestamp:
|
602
|
+
timestamp: parseInt(
|
603
|
+
delta.deltaMessageReply.repliedToMessage.messageMetadata
|
604
|
+
.timestamp
|
605
|
+
),
|
606
|
+
participantIDs: (
|
607
|
+
delta.deltaMessageReply.repliedToMessage.participants || []
|
608
|
+
).map((e) => e.toString()),
|
490
609
|
};
|
491
610
|
} else if (delta.deltaMessageReply.replyToMessageId) {
|
492
611
|
return defaultFuncs
|
493
612
|
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, {
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
})
|
613
|
+
av: ctx.globalOptions.pageID,
|
614
|
+
queries: JSON.stringify({
|
615
|
+
o0: {
|
616
|
+
doc_id: "2848441488556444",
|
617
|
+
query_params: {
|
618
|
+
thread_and_message_id: {
|
619
|
+
thread_id: callbackToReturn.threadID,
|
620
|
+
message_id: delta.deltaMessageReply.replyToMessageId.id,
|
621
|
+
},
|
622
|
+
},
|
623
|
+
},
|
624
|
+
}),
|
507
625
|
})
|
508
626
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
509
627
|
.then((resData) => {
|
510
|
-
if (resData[resData.length - 1].error_results > 0)
|
628
|
+
if (resData[resData.length - 1].error_results > 0)
|
511
629
|
throw resData[0].o0.errors;
|
512
|
-
|
513
|
-
|
514
|
-
if (resData[resData.length - 1].successful_results === 0) {
|
630
|
+
if (resData[resData.length - 1].successful_results === 0)
|
515
631
|
throw {
|
516
632
|
error: "forcedFetch: there was no successful_results",
|
517
|
-
res: resData
|
633
|
+
res: resData,
|
518
634
|
};
|
519
|
-
}
|
520
|
-
|
521
635
|
const fetchData = resData[0].o0.data.message;
|
522
|
-
|
523
636
|
const mobj = {};
|
524
637
|
for (const n in fetchData.message.ranges) {
|
525
|
-
mobj[fetchData.message.ranges[n].entity.id] = (
|
638
|
+
mobj[fetchData.message.ranges[n].entity.id] = (
|
639
|
+
fetchData.message.text || ""
|
640
|
+
).substr(
|
641
|
+
fetchData.message.ranges[n].offset,
|
642
|
+
fetchData.message.ranges[n].length
|
643
|
+
);
|
526
644
|
}
|
527
|
-
|
528
645
|
callbackToReturn.messageReply = {
|
646
|
+
type: "Message",
|
529
647
|
threadID: callbackToReturn.threadID,
|
530
648
|
messageID: fetchData.message_id,
|
531
649
|
senderID: fetchData.message_sender.id.toString(),
|
532
|
-
attachments: fetchData.message.blob_attachment.map(att =>
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
x = att;
|
540
|
-
x.error = ex;
|
541
|
-
x.type = "unknown";
|
542
|
-
}
|
543
|
-
return x;
|
544
|
-
}),
|
650
|
+
attachments: fetchData.message.blob_attachment.map((att) =>
|
651
|
+
utils._formatAttachment({
|
652
|
+
blob_attachment: att,
|
653
|
+
})
|
654
|
+
),
|
655
|
+
args:
|
656
|
+
(fetchData.message.text || "").trim().split(/\s+/) || [],
|
545
657
|
body: fetchData.message.text || "",
|
546
658
|
isGroup: callbackToReturn.isGroup,
|
547
659
|
mentions: mobj,
|
548
|
-
timestamp: parseInt(fetchData.timestamp_precise)
|
660
|
+
timestamp: parseInt(fetchData.timestamp_precise),
|
549
661
|
};
|
550
662
|
})
|
551
|
-
.catch((err) =>
|
552
|
-
|
553
|
-
})
|
554
|
-
.finally(function () {
|
663
|
+
.catch((err) => log.error("forcedFetch", err))
|
664
|
+
.finally(() => {
|
555
665
|
if (ctx.globalOptions.autoMarkDelivery) {
|
556
|
-
markDelivery(
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
666
|
+
markDelivery(
|
667
|
+
ctx,
|
668
|
+
api,
|
669
|
+
callbackToReturn.threadID,
|
670
|
+
callbackToReturn.messageID
|
671
|
+
);
|
672
|
+
}
|
673
|
+
if (
|
674
|
+
!ctx.globalOptions.selfListen &&
|
675
|
+
callbackToReturn.senderID === ctx.userID
|
676
|
+
)
|
677
|
+
return;
|
678
|
+
globalCallback(null, callbackToReturn);
|
563
679
|
});
|
564
680
|
} else {
|
565
681
|
callbackToReturn.delta = delta;
|
566
682
|
}
|
567
|
-
|
568
683
|
if (ctx.globalOptions.autoMarkDelivery) {
|
569
|
-
markDelivery(
|
684
|
+
markDelivery(
|
685
|
+
ctx,
|
686
|
+
api,
|
687
|
+
callbackToReturn.threadID,
|
688
|
+
callbackToReturn.messageID
|
689
|
+
);
|
570
690
|
}
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
})();
|
691
|
+
if (
|
692
|
+
!ctx.globalOptions.selfListen &&
|
693
|
+
callbackToReturn.senderID === ctx.userID
|
694
|
+
)
|
695
|
+
return;
|
696
|
+
globalCallback(null, callbackToReturn);
|
578
697
|
}
|
579
698
|
}
|
580
699
|
return;
|
581
700
|
}
|
582
701
|
}
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
)
|
587
|
-
return;
|
588
|
-
|
589
|
-
switch (v.delta.class) {
|
590
|
-
case "ReadReceipt":
|
591
|
-
var fmtMsg;
|
702
|
+
switch (delta.class) {
|
703
|
+
case "ReadReceipt": {
|
704
|
+
let fmtMsg;
|
592
705
|
try {
|
593
|
-
fmtMsg = utils.formatDeltaReadReceipt(
|
706
|
+
fmtMsg = utils.formatDeltaReadReceipt(delta);
|
594
707
|
} catch (err) {
|
595
|
-
return
|
596
|
-
error: "Problem parsing message object. Please open an issue at https://github.com/ntkhang03/fb-chat-api/issues.",
|
597
|
-
detail: err,
|
598
|
-
res: v.delta,
|
599
|
-
type: "parse_error"
|
600
|
-
});
|
708
|
+
return log.error("Lỗi Nhẹ", err);
|
601
709
|
}
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
case "AdminTextMessage":
|
606
|
-
switch (
|
710
|
+
globalCallback(null, fmtMsg);
|
711
|
+
break;
|
712
|
+
}
|
713
|
+
case "AdminTextMessage": {
|
714
|
+
switch (delta.type) {
|
715
|
+
case "instant_game_dynamic_custom_update":
|
716
|
+
case "accept_pending_thread":
|
717
|
+
case "confirm_friend_request":
|
718
|
+
case "shared_album_delete":
|
719
|
+
case "shared_album_addition":
|
720
|
+
case "pin_messages_v2":
|
721
|
+
case "unpin_messages_v2":
|
607
722
|
case "change_thread_theme":
|
608
723
|
case "change_thread_nickname":
|
609
724
|
case "change_thread_icon":
|
725
|
+
case "change_thread_quick_reaction":
|
610
726
|
case "change_thread_admins":
|
611
727
|
case "group_poll":
|
612
728
|
case "joinable_group_link_mode_change":
|
@@ -614,316 +730,258 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
614
730
|
case "change_thread_approval_mode":
|
615
731
|
case "messenger_call_log":
|
616
732
|
case "participant_joined_group_call":
|
617
|
-
|
733
|
+
case "rtc_call_log":
|
734
|
+
case "update_vote": {
|
735
|
+
let fmtMsg;
|
618
736
|
try {
|
619
|
-
fmtMsg = utils.formatDeltaEvent(
|
737
|
+
fmtMsg = utils.formatDeltaEvent(delta);
|
620
738
|
} catch (err) {
|
621
|
-
|
622
|
-
|
623
|
-
detail: err,
|
624
|
-
res: v.delta,
|
625
|
-
type: "parse_error"
|
626
|
-
});
|
739
|
+
console.log(delta);
|
740
|
+
return log.error("Lỗi Nhẹ", err);
|
627
741
|
}
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
default:
|
632
|
-
return;
|
742
|
+
globalCallback(null, fmtMsg);
|
743
|
+
break;
|
744
|
+
}
|
633
745
|
}
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
746
|
+
break;
|
747
|
+
}
|
748
|
+
case "ForcedFetch": {
|
749
|
+
if (!delta.threadKey) return;
|
750
|
+
const mid = delta.messageId;
|
751
|
+
const tid = delta.threadKey.threadFbId;
|
639
752
|
if (mid && tid) {
|
640
753
|
const form = {
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
})
|
754
|
+
av: ctx.globalOptions.pageID,
|
755
|
+
queries: JSON.stringify({
|
756
|
+
o0: {
|
757
|
+
doc_id: "2848441488556444",
|
758
|
+
query_params: {
|
759
|
+
thread_and_message_id: {
|
760
|
+
thread_id: tid.toString(),
|
761
|
+
message_id: mid,
|
762
|
+
},
|
763
|
+
},
|
764
|
+
},
|
765
|
+
}),
|
654
766
|
};
|
655
|
-
|
656
767
|
defaultFuncs
|
657
768
|
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
|
658
769
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
659
770
|
.then((resData) => {
|
660
|
-
if (resData[resData.length - 1].error_results > 0)
|
771
|
+
if (resData[resData.length - 1].error_results > 0)
|
661
772
|
throw resData[0].o0.errors;
|
662
|
-
|
663
|
-
|
664
|
-
if (resData[resData.length - 1].successful_results === 0) {
|
773
|
+
if (resData[resData.length - 1].successful_results === 0)
|
665
774
|
throw {
|
666
775
|
error: "forcedFetch: there was no successful_results",
|
667
|
-
res: resData
|
776
|
+
res: resData,
|
668
777
|
};
|
669
|
-
}
|
670
|
-
|
671
778
|
const fetchData = resData[0].o0.data.message;
|
672
|
-
|
673
|
-
if (utils.getType(fetchData) == "Object") {
|
779
|
+
if (utils.getType(fetchData) === "Object") {
|
674
780
|
log.info("forcedFetch", fetchData);
|
675
781
|
switch (fetchData.__typename) {
|
676
782
|
case "ThreadImageMessage":
|
677
|
-
(!ctx.globalOptions.
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
783
|
+
(!ctx.globalOptions.selfListen &&
|
784
|
+
fetchData.message_sender.id.toString() === ctx.userID) ||
|
785
|
+
!ctx.loggedIn
|
786
|
+
? undefined
|
787
|
+
: (function () {
|
788
|
+
globalCallback(null, {
|
789
|
+
type: "event",
|
790
|
+
threadID: utils.formatID(tid.toString()),
|
791
|
+
logMessageType: "log:thread-image",
|
792
|
+
logMessageData: {
|
793
|
+
image: {
|
794
|
+
attachmentID:
|
795
|
+
fetchData.image_with_metadata &&
|
796
|
+
fetchData.image_with_metadata
|
797
|
+
.legacy_attachment_id,
|
798
|
+
width:
|
799
|
+
fetchData.image_with_metadata &&
|
800
|
+
fetchData.image_with_metadata
|
801
|
+
.original_dimensions.x,
|
802
|
+
height:
|
803
|
+
fetchData.image_with_metadata &&
|
804
|
+
fetchData.image_with_metadata
|
805
|
+
.original_dimensions.y,
|
806
|
+
url:
|
807
|
+
fetchData.image_with_metadata &&
|
808
|
+
fetchData.image_with_metadata.preview.uri,
|
809
|
+
},
|
810
|
+
},
|
811
|
+
logMessageBody: fetchData.snippet,
|
812
|
+
timestamp: fetchData.timestamp_precise,
|
813
|
+
author: fetchData.message_sender.id,
|
814
|
+
});
|
815
|
+
})();
|
696
816
|
break;
|
697
|
-
case "UserMessage":
|
698
|
-
|
817
|
+
case "UserMessage": {
|
818
|
+
const event = {
|
699
819
|
type: "message",
|
700
820
|
senderID: utils.formatID(fetchData.message_sender.id),
|
701
821
|
body: fetchData.message.text || "",
|
702
822
|
threadID: utils.formatID(tid.toString()),
|
703
823
|
messageID: fetchData.message_id,
|
704
|
-
attachments: [
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
824
|
+
attachments: [
|
825
|
+
{
|
826
|
+
type: "share",
|
827
|
+
ID: fetchData.extensible_attachment
|
828
|
+
.legacy_attachment_id,
|
829
|
+
url: fetchData.extensible_attachment.story_attachment
|
830
|
+
.url,
|
831
|
+
title:
|
832
|
+
fetchData.extensible_attachment.story_attachment
|
833
|
+
.title_with_entities.text,
|
834
|
+
description:
|
835
|
+
fetchData.extensible_attachment.story_attachment
|
836
|
+
.description.text,
|
837
|
+
source:
|
838
|
+
fetchData.extensible_attachment.story_attachment
|
839
|
+
.source,
|
840
|
+
image: (
|
841
|
+
(
|
842
|
+
fetchData.extensible_attachment.story_attachment
|
843
|
+
.media || {}
|
844
|
+
).image || {}
|
845
|
+
).uri,
|
846
|
+
width: (
|
847
|
+
(
|
848
|
+
fetchData.extensible_attachment.story_attachment
|
849
|
+
.media || {}
|
850
|
+
).image || {}
|
851
|
+
).width,
|
852
|
+
height: (
|
853
|
+
(
|
854
|
+
fetchData.extensible_attachment.story_attachment
|
855
|
+
.media || {}
|
856
|
+
).image || {}
|
857
|
+
).height,
|
858
|
+
playable:
|
859
|
+
(
|
860
|
+
fetchData.extensible_attachment.story_attachment
|
861
|
+
.media || {}
|
862
|
+
).is_playable || false,
|
863
|
+
duration:
|
864
|
+
(
|
865
|
+
fetchData.extensible_attachment.story_attachment
|
866
|
+
.media || {}
|
867
|
+
).playable_duration_in_ms || 0,
|
868
|
+
subattachments:
|
869
|
+
fetchData.extensible_attachment.subattachments,
|
870
|
+
properties:
|
871
|
+
fetchData.extensible_attachment.story_attachment
|
872
|
+
.properties,
|
873
|
+
},
|
874
|
+
],
|
722
875
|
mentions: {},
|
723
876
|
timestamp: parseInt(fetchData.timestamp_precise),
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
globalCallback(null,
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
messageID: fetchData.message_id,
|
733
|
-
attachments: [{
|
734
|
-
type: "share",
|
735
|
-
ID: fetchData.extensible_attachment.legacy_attachment_id,
|
736
|
-
url: fetchData.extensible_attachment.story_attachment.url,
|
737
|
-
|
738
|
-
title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
|
739
|
-
description: fetchData.extensible_attachment.story_attachment.description.text,
|
740
|
-
source: fetchData.extensible_attachment.story_attachment.source,
|
741
|
-
|
742
|
-
image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
|
743
|
-
width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
|
744
|
-
height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
|
745
|
-
playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
|
746
|
-
duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
|
747
|
-
|
748
|
-
subattachments: fetchData.extensible_attachment.subattachments,
|
749
|
-
properties: fetchData.extensible_attachment.story_attachment.properties
|
750
|
-
}],
|
751
|
-
mentions: {},
|
752
|
-
timestamp: parseInt(fetchData.timestamp_precise),
|
753
|
-
participantIDs: (fetchData.participants || (fetchData.messageMetadata ? fetchData.messageMetadata.cid ? fetchData.messageMetadata.cid.canonicalParticipantFbids : fetchData.messageMetadata.participantIds : []) || []),
|
754
|
-
isGroup: (fetchData.message_sender.id != tid.toString())
|
755
|
-
});
|
877
|
+
isGroup: fetchData.message_sender.id !== tid.toString(),
|
878
|
+
};
|
879
|
+
log.info("ff-Return", event);
|
880
|
+
globalCallback(null, event);
|
881
|
+
break;
|
882
|
+
}
|
883
|
+
default:
|
884
|
+
log.error("forcedFetch", fetchData);
|
756
885
|
}
|
757
886
|
} else {
|
758
887
|
log.error("forcedFetch", fetchData);
|
759
888
|
}
|
760
889
|
})
|
761
|
-
.catch((err) =>
|
762
|
-
log.error("forcedFetch", err);
|
763
|
-
});
|
890
|
+
.catch((err) => log.error("forcedFetch", err));
|
764
891
|
}
|
765
892
|
break;
|
893
|
+
}
|
766
894
|
case "ThreadName":
|
767
895
|
case "ParticipantsAddedToGroupThread":
|
768
|
-
case "ParticipantLeftGroupThread":
|
769
|
-
|
770
|
-
var formattedEvent;
|
896
|
+
case "ParticipantLeftGroupThread": {
|
897
|
+
let formattedEvent;
|
771
898
|
try {
|
772
|
-
formattedEvent = utils.formatDeltaEvent(
|
899
|
+
formattedEvent = utils.formatDeltaEvent(delta);
|
773
900
|
} catch (err) {
|
774
|
-
|
775
|
-
|
776
|
-
detail: err,
|
777
|
-
res: v.delta,
|
778
|
-
type: "parse_error"
|
779
|
-
});
|
901
|
+
console.log(err);
|
902
|
+
return log.error("Lỗi Nhẹ", err);
|
780
903
|
}
|
781
|
-
|
782
|
-
|
783
|
-
(
|
784
|
-
|
785
|
-
|
904
|
+
if (
|
905
|
+
!ctx.globalOptions.selfListen &&
|
906
|
+
formattedEvent.author.toString() === ctx.userID
|
907
|
+
)
|
908
|
+
return;
|
909
|
+
if (!ctx.loggedIn) return;
|
910
|
+
globalCallback(null, formattedEvent);
|
911
|
+
break;
|
912
|
+
}
|
913
|
+
case "NewMessage": {
|
914
|
+
const hasLiveLocation = (delta) => {
|
915
|
+
const attachment =
|
916
|
+
delta.attachments?.[0]?.mercury?.extensible_attachment;
|
917
|
+
const storyAttachment = attachment?.story_attachment;
|
918
|
+
return storyAttachment?.style_list?.includes("message_live_location");
|
919
|
+
};
|
920
|
+
if (delta.attachments?.length === 1 && hasLiveLocation(delta)) {
|
921
|
+
delta.class = "UserLocation";
|
922
|
+
try {
|
923
|
+
const fmtMsg = utils.formatDeltaEvent(delta);
|
924
|
+
globalCallback(null, fmtMsg);
|
925
|
+
} catch (err) {
|
926
|
+
console.log(delta);
|
927
|
+
log.error("Lỗi Nhẹ", err);
|
928
|
+
}
|
929
|
+
}
|
930
|
+
break;
|
931
|
+
}
|
786
932
|
}
|
787
933
|
}
|
788
|
-
|
789
934
|
function markDelivery(ctx, api, threadID, messageID) {
|
790
935
|
if (threadID && messageID) {
|
791
936
|
api.markAsDelivered(threadID, messageID, (err) => {
|
792
|
-
if (err)
|
793
|
-
|
794
|
-
} else {
|
937
|
+
if (err) log.error("markAsDelivered", err);
|
938
|
+
else {
|
795
939
|
if (ctx.globalOptions.autoMarkRead) {
|
796
940
|
api.markAsRead(threadID, (err) => {
|
797
|
-
if (err)
|
798
|
-
log.error("markAsDelivered", err);
|
799
|
-
}
|
941
|
+
if (err) log.error("markAsDelivered", err);
|
800
942
|
});
|
801
943
|
}
|
802
944
|
}
|
803
945
|
});
|
804
946
|
}
|
805
947
|
}
|
806
|
-
|
807
948
|
module.exports = function (defaultFuncs, api, ctx) {
|
808
949
|
let globalCallback = identity;
|
809
|
-
|
810
|
-
getSeqId = function getSeqId() {
|
950
|
+
getSeqID = function getSeqID() {
|
811
951
|
ctx.t_mqttCalled = false;
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
return attemptRequest(retries - 1);
|
821
|
-
}
|
822
|
-
throw {
|
823
|
-
error: "Could not obtain fb_dtsg after multiple attempts"
|
824
|
-
};
|
825
|
-
}
|
826
|
-
ctx.fb_dtsg = dtsg;
|
827
|
-
}
|
828
|
-
const form = {
|
829
|
-
av: ctx.userID,
|
830
|
-
fb_dtsg: ctx.fb_dtsg,
|
831
|
-
queries: JSON.stringify({
|
832
|
-
o0: {
|
833
|
-
doc_id: '3336396659757871',
|
834
|
-
query_params: {
|
835
|
-
limit: 1,
|
836
|
-
before: null,
|
837
|
-
tags: ['INBOX'],
|
838
|
-
includeDeliveryReceipts: false,
|
839
|
-
includeSeqID: true
|
840
|
-
}
|
841
|
-
}
|
842
|
-
}),
|
843
|
-
__user: ctx.userID,
|
844
|
-
__a: '1',
|
845
|
-
__req: '8',
|
846
|
-
__hs: '19577.HYP:comet_pkg.2.1..2.1',
|
847
|
-
dpr: '1',
|
848
|
-
fb_api_caller_class: 'RelayModern',
|
849
|
-
fb_api_req_friendly_name: 'MessengerGraphQLThreadlistFetcher'
|
850
|
-
};
|
851
|
-
const headers = {
|
852
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
853
|
-
'Referer': 'https://www.facebook.com/',
|
854
|
-
'Origin': 'https://www.facebook.com',
|
855
|
-
'sec-fetch-site': 'same-origin',
|
856
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
857
|
-
'Cookie': ctx.jar.getCookieString('https://www.facebook.com'),
|
858
|
-
'accept': '*/*',
|
859
|
-
'accept-encoding': 'gzip, deflate, br'
|
860
|
-
};
|
861
|
-
|
862
|
-
const resData = await defaultFuncs
|
863
|
-
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form, {
|
864
|
-
headers
|
865
|
-
})
|
866
|
-
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
867
|
-
if (debugSeq) {
|
868
|
-
console.log('GraphQL SeqID Response:', JSON.stringify(resData, null, 2));
|
869
|
-
}
|
870
|
-
|
871
|
-
if (resData.error === 1357004 || resData.error === 1357001) {
|
872
|
-
if (retries > 0) {
|
873
|
-
console.log("Session error, refreshing token and retrying...");
|
874
|
-
ctx.fb_dtsg = null;
|
875
|
-
await sleep(2000);
|
876
|
-
return attemptRequest(retries - 1);
|
877
|
-
}
|
952
|
+
defaultFuncs
|
953
|
+
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
|
954
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
955
|
+
.then((resData) => {
|
956
|
+
if (utils.getType(resData) !== "Array") throw { error: "Not logged in", res: resData };
|
957
|
+
if (resData && resData[resData.length - 1].error_results > 0)
|
958
|
+
throw resData[0].o0.errors;
|
959
|
+
if (resData[resData.length - 1].successful_results === 0)
|
878
960
|
throw {
|
879
|
-
error: "
|
961
|
+
error: "getSeqId: there was no successful_results",
|
962
|
+
res: resData,
|
880
963
|
};
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
res: resData
|
887
|
-
};
|
888
|
-
}
|
889
|
-
|
890
|
-
const seqID = resData[0]?.o0?.data?.viewer?.message_threads?.sync_sequence_id;
|
891
|
-
if (!seqID) {
|
964
|
+
if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) {
|
965
|
+
ctx.lastSeqId =
|
966
|
+
resData[0].o0.data.viewer.message_threads.sync_sequence_id;
|
967
|
+
listenMqtt(defaultFuncs, api, ctx, globalCallback);
|
968
|
+
} else
|
892
969
|
throw {
|
893
|
-
error: "
|
894
|
-
res: resData
|
970
|
+
error: "getSeqId: no sync_sequence_id found.",
|
971
|
+
res: resData,
|
895
972
|
};
|
896
|
-
|
897
|
-
|
898
|
-
ctx.lastSeqId = seqID;
|
899
|
-
if (debugSeq) {
|
900
|
-
console.log('Got SeqID:', ctx.lastSeqId);
|
901
|
-
}
|
902
|
-
|
903
|
-
return listenMqtt(defaultFuncs, api, ctx, globalCallback);
|
904
|
-
|
905
|
-
} catch (err) {
|
906
|
-
if (retries > 0) {
|
907
|
-
console.log("Request failed, retrying...");
|
908
|
-
|
909
|
-
return attemptRequest(retries - 1);
|
910
|
-
}
|
911
|
-
throw err;
|
912
|
-
}
|
913
|
-
}
|
914
|
-
|
915
|
-
return attemptRequest()
|
973
|
+
})
|
916
974
|
.catch((err) => {
|
917
975
|
log.error("getSeqId", err);
|
918
|
-
if (utils.getType(err)
|
976
|
+
if (utils.getType(err) === "Object" && err.error === "Not logged in")
|
977
|
+
ctx.loggedIn = false;
|
919
978
|
return globalCallback(err);
|
920
979
|
});
|
921
|
-
}
|
980
|
+
};
|
922
981
|
return function (callback) {
|
923
982
|
class MessageEmitter extends EventEmitter {
|
924
983
|
stopListening(callback) {
|
925
|
-
|
926
|
-
callback = callback || (() => { });
|
984
|
+
callback = callback || (() => {});
|
927
985
|
globalCallback = identity;
|
928
986
|
if (ctx.mqttClient) {
|
929
987
|
ctx.mqttClient.unsubscribe("/webrtc");
|
@@ -936,33 +994,44 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
936
994
|
});
|
937
995
|
}
|
938
996
|
}
|
939
|
-
|
940
997
|
async stopListeningAsync() {
|
941
998
|
return new Promise((resolve) => {
|
942
999
|
this.stopListening(resolve);
|
943
1000
|
});
|
944
1001
|
}
|
945
1002
|
}
|
946
|
-
|
947
1003
|
const msgEmitter = new MessageEmitter();
|
948
|
-
globalCallback =
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
1004
|
+
globalCallback =
|
1005
|
+
callback ||
|
1006
|
+
function (error, message) {
|
1007
|
+
if (error) {
|
1008
|
+
return msgEmitter.emit("error", error);
|
1009
|
+
}
|
1010
|
+
msgEmitter.emit("message", message);
|
1011
|
+
};
|
1012
|
+
if (!ctx.firstListen) ctx.lastSeqId = null;
|
957
1013
|
ctx.syncToken = undefined;
|
958
1014
|
ctx.t_mqttCalled = false;
|
959
|
-
|
1015
|
+
form = {
|
1016
|
+
av: ctx.globalOptions.pageID,
|
1017
|
+
queries: JSON.stringify({
|
1018
|
+
o0: {
|
1019
|
+
doc_id: "3336396659757871",
|
1020
|
+
query_params: {
|
1021
|
+
limit: 1,
|
1022
|
+
before: null,
|
1023
|
+
tags: ["INBOX"],
|
1024
|
+
includeDeliveryReceipts: false,
|
1025
|
+
includeSeqID: true,
|
1026
|
+
},
|
1027
|
+
},
|
1028
|
+
}),
|
1029
|
+
};
|
960
1030
|
if (!ctx.firstListen || !ctx.lastSeqId) {
|
961
|
-
|
1031
|
+
getSeqID(defaultFuncs, api, ctx, globalCallback);
|
962
1032
|
} else {
|
963
1033
|
listenMqtt(defaultFuncs, api, ctx, globalCallback);
|
964
1034
|
}
|
965
|
-
|
966
1035
|
api.stopListening = msgEmitter.stopListening;
|
967
1036
|
api.stopListeningAsync = msgEmitter.stopListeningAsync;
|
968
1037
|
return msgEmitter;
|