@dongdev/fca-unofficial 1.0.20 → 2.0.1
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/.gitattributes +1 -0
- package/CHANGELOG.md +32 -29
- package/DOCS.md +727 -592
- package/README.md +94 -97
- package/func/logger.js +112 -0
- package/html.html +474 -0
- package/index.js +1 -379
- package/module/config.js +26 -0
- package/module/login.js +45 -0
- package/module/loginHelper.js +634 -0
- package/module/options.js +49 -0
- package/package.json +6 -39
- package/src/api/action/addExternalModule.js +25 -0
- package/src/api/action/changeAvatar.js +136 -0
- package/src/api/action/changeBio.js +76 -0
- package/src/api/action/getCurrentUserID.js +7 -0
- package/src/api/action/handleFriendRequest.js +57 -0
- package/src/api/action/logout.js +75 -0
- package/src/{refreshFb_dtsg.js → api/action/refreshFb_dtsg.js} +8 -8
- package/src/api/action/setPostReaction.js +107 -0
- package/src/api/action/unfriend.js +55 -0
- package/src/api/http/httpGet.js +65 -0
- package/src/api/http/httpPost.js +65 -0
- package/src/{postFormData.js → api/http/postFormData.js} +10 -10
- package/src/api/messaging/addUserToGroup.js +69 -0
- package/src/api/messaging/changeAdminStatus.js +103 -0
- package/src/api/messaging/changeArchivedStatus.js +55 -0
- package/src/api/messaging/changeBlockedStatus.js +49 -0
- package/src/api/messaging/changeGroupImage.js +135 -0
- package/src/api/messaging/changeNickname.js +59 -0
- package/src/api/messaging/changeThreadColor.js +65 -0
- package/src/api/messaging/createNewGroup.js +88 -0
- package/src/api/messaging/createPoll.js +70 -0
- package/src/api/messaging/deleteMessage.js +56 -0
- package/src/api/messaging/deleteThread.js +56 -0
- package/src/api/messaging/forwardAttachment.js +60 -0
- package/src/api/messaging/getEmojiUrl.js +29 -0
- package/src/api/messaging/getFriendsList.js +83 -0
- package/src/api/messaging/getMessage.js +834 -0
- package/src/api/messaging/getThreadHistory.js +681 -0
- package/src/api/messaging/handleMessageRequest.js +65 -0
- package/src/api/messaging/markAsDelivered.js +57 -0
- package/src/api/messaging/markAsRead.js +88 -0
- package/src/api/messaging/markAsReadAll.js +50 -0
- package/src/api/messaging/markAsSeen.js +61 -0
- package/src/api/messaging/muteThread.js +51 -0
- package/src/api/messaging/removeUserFromGroup.js +79 -0
- package/src/api/messaging/resolvePhotoUrl.js +44 -0
- package/src/api/messaging/searchForThread.js +53 -0
- package/src/api/messaging/sendMessage.js +306 -0
- package/src/api/messaging/sendMessageMqtt.js +321 -0
- package/src/api/messaging/sendTypingIndicator.js +110 -0
- package/src/{setMessageReaction.js → api/messaging/setMessageReaction.js} +20 -20
- package/src/api/messaging/setTitle.js +90 -0
- package/src/api/messaging/shareContact.js +51 -0
- package/src/api/messaging/threadColors.js +131 -0
- package/src/api/messaging/unsendMessage.js +44 -0
- package/src/api/messaging/uploadAttachment.js +93 -0
- package/src/api/socket/detail/buildStream.js +100 -0
- package/src/{listenMqtt.js → api/socket/listenMqtt.js} +122 -206
- package/src/api/threads/changeThreadEmoji.js +55 -0
- package/src/api/threads/getThreadInfo.js +572 -0
- package/src/{getThreadList.js → api/threads/getThreadList.js} +110 -54
- package/src/api/threads/getThreadPictures.js +79 -0
- package/src/api/users/getUserID.js +66 -0
- package/src/api/users/getUserInfo.js +88 -0
- package/src/core/sendReqMqtt.js +63 -0
- package/{lib → src}/database/models/index.js +12 -10
- package/{lib → src}/database/models/thread.js +5 -5
- package/{lib → src}/database/threadData.js +19 -14
- package/src/utils/client.js +159 -0
- package/src/utils/constants.js +13 -0
- package/src/utils/format.js +60 -0
- package/src/utils/headers.js +41 -0
- package/src/utils/index.js +1497 -0
- package/src/utils/request.js +147 -0
- package/lib/logger.js +0 -96
- package/src/addExternalModule.js +0 -19
- package/src/addUserToGroup.js +0 -113
- package/src/changeAdminStatus.js +0 -79
- package/src/changeArchivedStatus.js +0 -55
- package/src/changeAvatar.js +0 -126
- package/src/changeBio.js +0 -77
- package/src/changeBlockedStatus.js +0 -47
- package/src/changeGroupImage.js +0 -132
- package/src/changeNickname.js +0 -59
- package/src/changeThreadColor.js +0 -65
- package/src/changeThreadEmoji.js +0 -55
- package/src/createNewGroup.js +0 -86
- package/src/createPoll.js +0 -71
- package/src/deleteMessage.js +0 -56
- package/src/deleteThread.js +0 -56
- package/src/forwardAttachment.js +0 -60
- package/src/getCurrentUserID.js +0 -7
- package/src/getEmojiUrl.js +0 -29
- package/src/getFriendsList.js +0 -83
- package/src/getMessage.js +0 -796
- package/src/getThreadHistory.js +0 -666
- package/src/getThreadInfo.js +0 -535
- package/src/getThreadPictures.js +0 -79
- package/src/getUserID.js +0 -66
- package/src/getUserInfo.js +0 -80
- package/src/handleFriendRequest.js +0 -61
- package/src/handleMessageRequest.js +0 -65
- package/src/httpGet.js +0 -57
- package/src/httpPost.js +0 -57
- package/src/httpPostFormData.js +0 -63
- package/src/logout.js +0 -75
- package/src/markAsDelivered.js +0 -58
- package/src/markAsRead.js +0 -80
- package/src/markAsReadAll.js +0 -50
- package/src/markAsSeen.js +0 -59
- package/src/muteThread.js +0 -52
- package/src/removeUserFromGroup.js +0 -79
- package/src/resolvePhotoUrl.js +0 -45
- package/src/searchForThread.js +0 -53
- package/src/sendMessage.js +0 -328
- package/src/sendMessageMqtt.js +0 -316
- package/src/sendTypingIndicator.js +0 -103
- package/src/setPostReaction.js +0 -109
- package/src/setTitle.js +0 -86
- package/src/shareContact.js +0 -49
- package/src/threadColors.js +0 -131
- package/src/unfriend.js +0 -52
- package/src/unsendMessage.js +0 -49
- package/src/uploadAttachment.js +0 -95
- package/utils.js +0 -1387
- /package/{lib → func}/login.js +0 -0
@@ -1,15 +1,17 @@
|
|
1
1
|
"use strict";
|
2
2
|
|
3
|
-
const utils = require("
|
3
|
+
const utils = require("../../utils");
|
4
4
|
const log = require("npmlog");
|
5
5
|
|
6
6
|
function createProfileUrl(url, username, id) {
|
7
7
|
if (url) return url;
|
8
|
-
return
|
8
|
+
return (
|
9
|
+
"https://www.facebook.com/" + (username || utils.formatID(id.toString()))
|
10
|
+
);
|
9
11
|
}
|
10
12
|
|
11
13
|
function formatParticipants(participants) {
|
12
|
-
return participants.edges.map(
|
14
|
+
return participants.edges.map(p => {
|
13
15
|
p = p.node.messaging_actor;
|
14
16
|
switch (p["__typename"]) {
|
15
17
|
case "User":
|
@@ -21,7 +23,7 @@ function formatParticipants(participants) {
|
|
21
23
|
gender: p.gender,
|
22
24
|
url: p.url, // how about making it profileURL
|
23
25
|
profilePicture: p.big_image_src.uri,
|
24
|
-
username:
|
26
|
+
username: p.username || null,
|
25
27
|
// TODO: maybe better names for these?
|
26
28
|
isViewerFriend: p.is_viewer_friend, // true/false
|
27
29
|
isMessengerUser: p.is_messenger_user, // true/false
|
@@ -37,13 +39,13 @@ function formatParticipants(participants) {
|
|
37
39
|
name: p.name,
|
38
40
|
url: p.url,
|
39
41
|
profilePicture: p.big_image_src.uri,
|
40
|
-
username:
|
42
|
+
username: p.username || null,
|
41
43
|
// uhm... better names maybe?
|
42
44
|
acceptsMessengerUserFeedback: p.accepts_messenger_user_feedback, // true/false
|
43
45
|
isMessengerUser: p.is_messenger_user, // true/false
|
44
46
|
isVerified: p.is_verified, // true/false
|
45
47
|
isMessengerPlatformBot: p.is_messenger_platform_bot, // true/false
|
46
|
-
isMessageBlockedByViewer: p.is_message_blocked_by_viewer
|
48
|
+
isMessageBlockedByViewer: p.is_message_blocked_by_viewer // true/false
|
47
49
|
};
|
48
50
|
case "ReducedMessagingActor":
|
49
51
|
case "UnavailableMessagingActor":
|
@@ -53,15 +55,19 @@ function formatParticipants(participants) {
|
|
53
55
|
name: p.name,
|
54
56
|
url: createProfileUrl(p.url, p.username, p.id), // in this case p.url is null all the time
|
55
57
|
profilePicture: p.big_image_src.uri, // in this case it is default facebook photo, we could determine gender using it
|
56
|
-
username:
|
57
|
-
isMessageBlockedByViewer: p.is_message_blocked_by_viewer
|
58
|
+
username: p.username || null, // maybe we could use it to generate profile URL?
|
59
|
+
isMessageBlockedByViewer: p.is_message_blocked_by_viewer // true/false
|
58
60
|
};
|
59
61
|
default:
|
60
|
-
log.warn(
|
62
|
+
log.warn(
|
63
|
+
"getThreadList",
|
64
|
+
"Found participant with unsupported typename. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues\n" +
|
65
|
+
JSON.stringify(p, null, 2)
|
66
|
+
);
|
61
67
|
return {
|
62
68
|
accountType: p["__typename"],
|
63
69
|
userID: utils.formatID(p.id.toString()),
|
64
|
-
name: p.name || `[unknown ${p["__typename"]}]
|
70
|
+
name: p.name || `[unknown ${p["__typename"]}]` // probably it will always be something... but fallback to [unknown], just in case
|
65
71
|
};
|
66
72
|
}
|
67
73
|
});
|
@@ -78,30 +84,40 @@ function getThreadName(t) {
|
|
78
84
|
|
79
85
|
for (let po of t.all_participants.edges) {
|
80
86
|
let p = po.node;
|
81
|
-
if (p.messaging_actor.id === t.thread_key.other_user_id)
|
87
|
+
if (p.messaging_actor.id === t.thread_key.other_user_id)
|
88
|
+
return p.messaging_actor.name;
|
82
89
|
}
|
83
90
|
}
|
84
91
|
|
85
92
|
function mapNicknames(customizationInfo) {
|
86
|
-
return
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
93
|
+
return customizationInfo && customizationInfo.participant_customizations
|
94
|
+
? customizationInfo.participant_customizations.map(u => {
|
95
|
+
return {
|
96
|
+
userID: u.participant_id,
|
97
|
+
nickname: u.nickname
|
98
|
+
};
|
99
|
+
})
|
100
|
+
: [];
|
92
101
|
}
|
93
102
|
|
94
103
|
function formatThreadList(data) {
|
95
104
|
return data.map(t => {
|
96
|
-
let lastMessageNode =
|
105
|
+
let lastMessageNode =
|
106
|
+
t.last_message && t.last_message.nodes && t.last_message.nodes.length > 0
|
107
|
+
? t.last_message.nodes[0]
|
108
|
+
: null;
|
97
109
|
return {
|
98
|
-
threadID: t.thread_key
|
110
|
+
threadID: t.thread_key
|
111
|
+
? utils.formatID(t.thread_key.thread_fbid || t.thread_key.other_user_id)
|
112
|
+
: null, // shall never be null
|
99
113
|
name: getThreadName(t),
|
100
114
|
unreadCount: t.unread_count,
|
101
115
|
messageCount: t.messages_count,
|
102
116
|
imageSrc: t.image ? t.image.uri : null,
|
103
117
|
emoji: t.customization_info ? t.customization_info.emoji : null,
|
104
|
-
color: formatColor(
|
118
|
+
color: formatColor(
|
119
|
+
t.customization_info ? t.customization_info.outgoing_bubble_color : null
|
120
|
+
),
|
105
121
|
threadTheme: t.thread_theme,
|
106
122
|
nicknames: mapNicknames(t.customization_info),
|
107
123
|
muteUntil: t.mute_until,
|
@@ -111,22 +127,37 @@ function formatThreadList(data) {
|
|
111
127
|
isGroup: t.thread_type === "GROUP",
|
112
128
|
customizationEnabled: t.customization_enabled, // false for ONE_TO_ONE with Page or ReducedMessagingActor
|
113
129
|
participantAddMode: t.participant_add_mode_as_string, // "ADD" if "GROUP" and null if "ONE_TO_ONE"
|
114
|
-
montageThread: t.montage_thread
|
130
|
+
montageThread: t.montage_thread
|
131
|
+
? Buffer.from(t.montage_thread.id, "base64").toString()
|
132
|
+
: null, // base64 encoded string "message_thread:0000000000000000"
|
115
133
|
reactionsMuteMode: t.reactions_mute_mode,
|
116
134
|
mentionsMuteMode: t.mentions_mute_mode,
|
117
135
|
isArchived: t.has_viewer_archived,
|
118
136
|
isSubscribed: t.is_viewer_subscribed,
|
119
137
|
timestamp: t.updated_time_precise, // in miliseconds
|
120
138
|
snippet: lastMessageNode ? lastMessageNode.snippet : null,
|
121
|
-
snippetAttachments: lastMessageNode
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
? (
|
139
|
+
snippetAttachments: lastMessageNode
|
140
|
+
? lastMessageNode.extensible_attachment
|
141
|
+
: null, // TODO: not sure if it works
|
142
|
+
snippetSender: lastMessageNode
|
143
|
+
? utils.formatID(
|
144
|
+
(lastMessageNode.message_sender.messaging_actor.id || "").toString()
|
145
|
+
)
|
126
146
|
: null,
|
147
|
+
lastMessageTimestamp: lastMessageNode
|
148
|
+
? lastMessageNode.timestamp_precise
|
149
|
+
: null, // timestamp in miliseconds
|
150
|
+
lastReadTimestamp:
|
151
|
+
t.last_read_receipt && t.last_read_receipt.nodes.length > 0
|
152
|
+
? t.last_read_receipt.nodes[0]
|
153
|
+
? t.last_read_receipt.nodes[0].timestamp_precise
|
154
|
+
: null
|
155
|
+
: null,
|
127
156
|
cannotReplyReason: t.cannot_reply_reason,
|
128
157
|
approvalMode: Boolean(t.approval_mode),
|
129
|
-
participantIDs: formatParticipants(t.all_participants).map(
|
158
|
+
participantIDs: formatParticipants(t.all_participants).map(
|
159
|
+
participant => participant.userID
|
160
|
+
),
|
130
161
|
threadType: t.thread_type === "GROUP" ? 2 : 1, // "GROUP" or "ONE_TO_ONE"
|
131
162
|
inviteLink: {
|
132
163
|
enable: t.joinable_mode ? t.joinable_mode.mode == 1 : false,
|
@@ -136,57 +167,82 @@ function formatThreadList(data) {
|
|
136
167
|
});
|
137
168
|
}
|
138
169
|
|
139
|
-
module.exports = function
|
170
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
140
171
|
return function getThreadList(limit, timestamp, tags, callback) {
|
141
|
-
if (
|
172
|
+
if (
|
173
|
+
!callback &&
|
174
|
+
(utils.getType(tags) === "Function" ||
|
175
|
+
utils.getType(tags) === "AsyncFunction")
|
176
|
+
) {
|
142
177
|
callback = tags;
|
143
178
|
tags = [""];
|
144
179
|
}
|
145
|
-
if (
|
146
|
-
|
180
|
+
if (
|
181
|
+
utils.getType(limit) !== "Number" ||
|
182
|
+
!Number.isInteger(limit) ||
|
183
|
+
limit <= 0
|
184
|
+
)
|
185
|
+
throw { error: "getThreadList: limit must be a positive integer" };
|
186
|
+
if (
|
187
|
+
utils.getType(timestamp) !== "Null" &&
|
188
|
+
(utils.getType(timestamp) !== "Number" || !Number.isInteger(timestamp))
|
189
|
+
)
|
190
|
+
throw { error: "getThreadList: timestamp must be an integer or null" };
|
147
191
|
if (utils.getType(tags) === "String") tags = [tags];
|
148
|
-
if (utils.getType(tags) !== "Array")
|
149
|
-
|
150
|
-
var
|
151
|
-
var
|
192
|
+
if (utils.getType(tags) !== "Array")
|
193
|
+
throw { error: "getThreadList: tags must be an array" };
|
194
|
+
var resolveFunc = function() {};
|
195
|
+
var rejectFunc = function() {};
|
196
|
+
var returnPromise = new Promise(function(resolve, reject) {
|
152
197
|
resolveFunc = resolve;
|
153
198
|
rejectFunc = reject;
|
154
199
|
});
|
155
|
-
if (
|
156
|
-
callback
|
200
|
+
if (
|
201
|
+
utils.getType(callback) !== "Function" &&
|
202
|
+
utils.getType(callback) !== "AsyncFunction"
|
203
|
+
) {
|
204
|
+
callback = function(err, data) {
|
157
205
|
if (err) return rejectFunc(err);
|
158
206
|
resolveFunc(data);
|
159
207
|
};
|
160
208
|
}
|
161
209
|
const form = {
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
210
|
+
av: ctx.globalOptions.pageID,
|
211
|
+
queries: JSON.stringify({
|
212
|
+
o0: {
|
213
|
+
doc_id: "3336396659757871",
|
214
|
+
query_params: {
|
215
|
+
limit: limit + (timestamp ? 1 : 0),
|
216
|
+
before: timestamp,
|
217
|
+
tags: tags,
|
218
|
+
includeDeliveryReceipts: true,
|
219
|
+
includeSeqID: false
|
172
220
|
}
|
173
221
|
}
|
174
222
|
}),
|
175
|
-
|
223
|
+
batch_name: "MessengerGraphQLThreadlistFetcher"
|
176
224
|
};
|
177
225
|
defaultFuncs
|
178
226
|
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
|
179
227
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
180
|
-
.then(
|
181
|
-
if (resData[resData.length - 1].error_results > 0)
|
182
|
-
|
228
|
+
.then(resData => {
|
229
|
+
if (resData[resData.length - 1].error_results > 0)
|
230
|
+
throw resData[0].o0.errors;
|
231
|
+
if (resData[resData.length - 1].successful_results === 0)
|
232
|
+
throw {
|
233
|
+
error: "getThreadList: there was no successful_results",
|
234
|
+
res: resData
|
235
|
+
};
|
183
236
|
if (timestamp) resData[0].o0.data.viewer.message_threads.nodes.shift();
|
184
|
-
callback(
|
237
|
+
callback(
|
238
|
+
null,
|
239
|
+
formatThreadList(resData[0].o0.data.viewer.message_threads.nodes)
|
240
|
+
);
|
185
241
|
})
|
186
|
-
.catch(
|
242
|
+
.catch(err => {
|
187
243
|
log.error("getThreadList", err);
|
188
244
|
return callback(err);
|
189
245
|
});
|
190
246
|
return returnPromise;
|
191
247
|
};
|
192
|
-
};
|
248
|
+
};
|
@@ -0,0 +1,79 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
const utils = require("../../utils");
|
4
|
+
const log = require("npmlog");
|
5
|
+
|
6
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
7
|
+
return function getThreadPictures(threadID, offset, limit, callback) {
|
8
|
+
let resolveFunc = function() {};
|
9
|
+
let rejectFunc = function() {};
|
10
|
+
const returnPromise = new Promise(function(resolve, reject) {
|
11
|
+
resolveFunc = resolve;
|
12
|
+
rejectFunc = reject;
|
13
|
+
});
|
14
|
+
|
15
|
+
if (!callback) {
|
16
|
+
callback = function(err, friendList) {
|
17
|
+
if (err) {
|
18
|
+
return rejectFunc(err);
|
19
|
+
}
|
20
|
+
resolveFunc(friendList);
|
21
|
+
};
|
22
|
+
}
|
23
|
+
|
24
|
+
let form = {
|
25
|
+
thread_id: threadID,
|
26
|
+
offset: offset,
|
27
|
+
limit: limit
|
28
|
+
};
|
29
|
+
|
30
|
+
defaultFuncs
|
31
|
+
.post(
|
32
|
+
"https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php",
|
33
|
+
ctx.jar,
|
34
|
+
form
|
35
|
+
)
|
36
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
37
|
+
.then(function(resData) {
|
38
|
+
if (resData.error) {
|
39
|
+
throw resData;
|
40
|
+
}
|
41
|
+
return Promise.all(
|
42
|
+
resData.payload.imagesData.map(function(image) {
|
43
|
+
form = {
|
44
|
+
thread_id: threadID,
|
45
|
+
image_id: image.fbid
|
46
|
+
};
|
47
|
+
return defaultFuncs
|
48
|
+
.post(
|
49
|
+
"https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php",
|
50
|
+
ctx.jar,
|
51
|
+
form
|
52
|
+
)
|
53
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
54
|
+
.then(function(resData) {
|
55
|
+
if (resData.error) {
|
56
|
+
throw resData;
|
57
|
+
}
|
58
|
+
// the response is pretty messy
|
59
|
+
const queryThreadID =
|
60
|
+
resData.jsmods.require[0][3][1].query_metadata.query_path[0]
|
61
|
+
.message_thread;
|
62
|
+
const imageData =
|
63
|
+
resData.jsmods.require[0][3][1].query_results[queryThreadID]
|
64
|
+
.message_images.edges[0].node.image2;
|
65
|
+
return imageData;
|
66
|
+
});
|
67
|
+
})
|
68
|
+
);
|
69
|
+
})
|
70
|
+
.then(function(resData) {
|
71
|
+
callback(null, resData);
|
72
|
+
})
|
73
|
+
.catch(function(err) {
|
74
|
+
log.error("Error in getThreadPictures", err);
|
75
|
+
callback(err);
|
76
|
+
});
|
77
|
+
return returnPromise;
|
78
|
+
};
|
79
|
+
};
|
@@ -0,0 +1,66 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
const utils = require("../../utils");
|
4
|
+
const log = require("npmlog");
|
5
|
+
|
6
|
+
function formatData(data) {
|
7
|
+
return {
|
8
|
+
userID: utils.formatID(data.uid.toString()),
|
9
|
+
photoUrl: data.photo,
|
10
|
+
indexRank: data.index_rank,
|
11
|
+
name: data.text,
|
12
|
+
isVerified: data.is_verified,
|
13
|
+
profileUrl: data.path,
|
14
|
+
category: data.category,
|
15
|
+
score: data.score,
|
16
|
+
type: data.type
|
17
|
+
};
|
18
|
+
}
|
19
|
+
|
20
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
21
|
+
return function getUserID(name, callback) {
|
22
|
+
let resolveFunc = function() {};
|
23
|
+
let rejectFunc = function() {};
|
24
|
+
const returnPromise = new Promise(function(resolve, reject) {
|
25
|
+
resolveFunc = resolve;
|
26
|
+
rejectFunc = reject;
|
27
|
+
});
|
28
|
+
|
29
|
+
if (!callback) {
|
30
|
+
callback = function(err, friendList) {
|
31
|
+
if (err) {
|
32
|
+
return rejectFunc(err);
|
33
|
+
}
|
34
|
+
resolveFunc(friendList);
|
35
|
+
};
|
36
|
+
}
|
37
|
+
|
38
|
+
const form = {
|
39
|
+
value: name.toLowerCase(),
|
40
|
+
viewer: ctx.i_userID || ctx.userID,
|
41
|
+
rsp: "search",
|
42
|
+
context: "search",
|
43
|
+
path: "/home.php",
|
44
|
+
request_id: utils.getGUID()
|
45
|
+
};
|
46
|
+
|
47
|
+
defaultFuncs
|
48
|
+
.get("https://www.facebook.com/ajax/typeahead/search.php", ctx.jar, form)
|
49
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
50
|
+
.then(function(resData) {
|
51
|
+
if (resData.error) {
|
52
|
+
throw resData;
|
53
|
+
}
|
54
|
+
|
55
|
+
const data = resData.payload.entries;
|
56
|
+
|
57
|
+
callback(null, data.map(formatData));
|
58
|
+
})
|
59
|
+
.catch(function(err) {
|
60
|
+
log.error("getUserID", err);
|
61
|
+
return callback(err);
|
62
|
+
});
|
63
|
+
|
64
|
+
return returnPromise;
|
65
|
+
};
|
66
|
+
};
|
@@ -0,0 +1,88 @@
|
|
1
|
+
"use strict";
|
2
|
+
const { parseAndCheckLogin } = require("../../utils/client");
|
3
|
+
var log = require("npmlog");
|
4
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
5
|
+
function formatData(data) {
|
6
|
+
const retObj = {};
|
7
|
+
for (const actor of data.messaging_actors || []) {
|
8
|
+
retObj[actor.id] = {
|
9
|
+
name: actor.name,
|
10
|
+
firstName: actor.short_name || null,
|
11
|
+
vanity: actor.username || null,
|
12
|
+
thumbSrc: actor.big_image_src?.uri || null,
|
13
|
+
profileUrl: actor.url || null,
|
14
|
+
gender: actor.gender || null,
|
15
|
+
type: actor.__typename || null,
|
16
|
+
isFriend: actor.is_viewer_friend || false,
|
17
|
+
isMessengerUser: actor.is_messenger_user || false,
|
18
|
+
isMessageBlockedByViewer: actor.is_message_blocked_by_viewer || false,
|
19
|
+
workInfo: actor.work_info || null,
|
20
|
+
messengerStatus: actor.messenger_account_status_category || null
|
21
|
+
};
|
22
|
+
}
|
23
|
+
return retObj;
|
24
|
+
}
|
25
|
+
return function getUserInfoGraphQL(id, callback) {
|
26
|
+
let resolveFunc, rejectFunc;
|
27
|
+
const returnPromise = new Promise((resolve, reject) => {
|
28
|
+
resolveFunc = resolve;
|
29
|
+
rejectFunc = reject;
|
30
|
+
});
|
31
|
+
if (typeof callback !== "function") {
|
32
|
+
callback = (err, data) => {
|
33
|
+
if (err) return rejectFunc(err);
|
34
|
+
resolveFunc(data);
|
35
|
+
};
|
36
|
+
}
|
37
|
+
const ids = Array.isArray(id) ? id : [id];
|
38
|
+
var form = {
|
39
|
+
queries: JSON.stringify({
|
40
|
+
o0: {
|
41
|
+
doc_id: "5009315269112105",
|
42
|
+
query_params: {
|
43
|
+
ids: ids
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}),
|
47
|
+
batch_name: "MessengerParticipantsFetcher"
|
48
|
+
};
|
49
|
+
defaultFuncs
|
50
|
+
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
|
51
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs))
|
52
|
+
.then(function(resData) {
|
53
|
+
if (!resData || resData.length === 0) {
|
54
|
+
throw new Error("Empty response from server");
|
55
|
+
}
|
56
|
+
if (resData.error) {
|
57
|
+
throw resData.error;
|
58
|
+
}
|
59
|
+
const response = resData[0];
|
60
|
+
console.log(response);
|
61
|
+
if (!response || !response.o0) {
|
62
|
+
throw new Error("Invalid response format");
|
63
|
+
}
|
64
|
+
if (response.o0.errors && response.o0.errors.length > 0) {
|
65
|
+
throw new Error(response.o0.errors[0].message || "GraphQL error");
|
66
|
+
}
|
67
|
+
const result = response.o0.data;
|
68
|
+
if (
|
69
|
+
!result ||
|
70
|
+
!result.messaging_actors ||
|
71
|
+
result.messaging_actors.length === 0
|
72
|
+
) {
|
73
|
+
log.warn("getUserInfo", "No user data found for the provided ID(s)");
|
74
|
+
return callback(null, {});
|
75
|
+
}
|
76
|
+
const formattedData = formatData(result);
|
77
|
+
return callback(null, formattedData);
|
78
|
+
})
|
79
|
+
.catch(err => {
|
80
|
+
log.error(
|
81
|
+
"getUserInfoGraphQL",
|
82
|
+
"Error: " + (err.message || "Unknown error occurred")
|
83
|
+
);
|
84
|
+
callback(err);
|
85
|
+
});
|
86
|
+
return returnPromise;
|
87
|
+
};
|
88
|
+
};
|
@@ -0,0 +1,63 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
function lsRequest(ctx, payload, options, callback) {
|
4
|
+
return new Promise((resolve, reject) => {
|
5
|
+
const cb = typeof options === "function" ? options : callback;
|
6
|
+
const opts = typeof options === "object" && options ? options : {};
|
7
|
+
if (!ctx || !ctx.mqttClient) {
|
8
|
+
const err = new Error("Not connected to MQTT");
|
9
|
+
if (cb) cb(err);
|
10
|
+
return reject(err);
|
11
|
+
}
|
12
|
+
if (typeof ctx.wsReqNumber !== "number") ctx.wsReqNumber = 0;
|
13
|
+
const reqID = typeof opts.request_id === "number" ? opts.request_id : ++ctx.wsReqNumber;
|
14
|
+
const timeoutMs = typeof opts.timeout === "number" ? opts.timeout : 20000;
|
15
|
+
const qos = typeof opts.qos === "number" ? opts.qos : 1;
|
16
|
+
const retain = !!opts.retain;
|
17
|
+
const reqTopic = "/ls_req";
|
18
|
+
const respTopic = opts.respTopic || "/ls_resp";
|
19
|
+
const form = JSON.stringify({
|
20
|
+
app_id: opts.app_id || "",
|
21
|
+
payload: typeof payload === "string" ? payload : JSON.stringify(payload),
|
22
|
+
request_id: reqID,
|
23
|
+
type: opts.type == null ? 3 : opts.type
|
24
|
+
});
|
25
|
+
let timer = null;
|
26
|
+
const handleRes = (topic, message) => {
|
27
|
+
if (topic !== respTopic) return;
|
28
|
+
let msg;
|
29
|
+
try {
|
30
|
+
msg = JSON.parse(message.toString());
|
31
|
+
} catch {
|
32
|
+
return;
|
33
|
+
}
|
34
|
+
if (msg.request_id !== reqID) return;
|
35
|
+
if (typeof opts.filter === "function" && !opts.filter(msg)) return;
|
36
|
+
ctx.mqttClient.removeListener("message", handleRes);
|
37
|
+
if (timer) clearTimeout(timer);
|
38
|
+
try {
|
39
|
+
msg.payload = typeof msg.payload === "string" ? JSON.parse(msg.payload) : msg.payload;
|
40
|
+
} catch { }
|
41
|
+
const out = { success: true, response: msg.payload, raw: msg };
|
42
|
+
if (cb) cb(null, out);
|
43
|
+
resolve(out);
|
44
|
+
};
|
45
|
+
ctx.mqttClient.on("message", handleRes);
|
46
|
+
timer = setTimeout(() => {
|
47
|
+
ctx.mqttClient.removeListener("message", handleRes);
|
48
|
+
const err = new Error("MQTT response timeout");
|
49
|
+
if (cb) cb(err);
|
50
|
+
reject(err);
|
51
|
+
}, timeoutMs);
|
52
|
+
ctx.mqttClient.publish(reqTopic, form, { qos, retain }, (err) => {
|
53
|
+
if (err) {
|
54
|
+
if (timer) clearTimeout(timer);
|
55
|
+
ctx.mqttClient.removeListener("message", handleRes);
|
56
|
+
if (cb) cb(err);
|
57
|
+
reject(err);
|
58
|
+
}
|
59
|
+
});
|
60
|
+
});
|
61
|
+
};
|
62
|
+
|
63
|
+
module.exports = sendReqMqtt;
|
@@ -1,13 +1,13 @@
|
|
1
|
-
const { Sequelize } = require(
|
2
|
-
const fs = require(
|
3
|
-
const path = require(
|
4
|
-
const databasePath = path.join(process.cwd(),
|
1
|
+
const { Sequelize } = require("sequelize");
|
2
|
+
const fs = require("fs");
|
3
|
+
const path = require("path");
|
4
|
+
const databasePath = path.join(process.cwd(), "Fca_Database");
|
5
5
|
if (!fs.existsSync(databasePath)) {
|
6
6
|
fs.mkdirSync(databasePath, { recursive: true });
|
7
7
|
}
|
8
8
|
const sequelize = new Sequelize({
|
9
|
-
dialect:
|
10
|
-
storage: path.join(databasePath,
|
9
|
+
dialect: "sqlite",
|
10
|
+
storage: path.join(databasePath, "database.sqlite"),
|
11
11
|
logging: false,
|
12
12
|
pool: {
|
13
13
|
max: 5,
|
@@ -24,7 +24,9 @@ const sequelize = new Sequelize({
|
|
24
24
|
isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED
|
25
25
|
});
|
26
26
|
const models = {};
|
27
|
-
fs.readdirSync(__dirname)
|
27
|
+
fs.readdirSync(__dirname)
|
28
|
+
.filter(file => file.endsWith(".js") && file !== "index.js")
|
29
|
+
.forEach(file => {
|
28
30
|
const model = require(path.join(__dirname, file))(sequelize);
|
29
31
|
models[model.name] = model;
|
30
32
|
});
|
@@ -37,11 +39,11 @@ models.sequelize = sequelize;
|
|
37
39
|
models.Sequelize = Sequelize;
|
38
40
|
models.syncAll = async () => {
|
39
41
|
try {
|
40
|
-
await sequelize.sync({ force: false });
|
42
|
+
await sequelize.sync({ force: false });
|
41
43
|
} catch (error) {
|
42
|
-
console.error(
|
44
|
+
console.error("Failed to synchronize models:", error);
|
43
45
|
throw error;
|
44
46
|
}
|
45
47
|
};
|
46
48
|
|
47
|
-
module.exports = models;
|
49
|
+
module.exports = models;
|
@@ -9,23 +9,23 @@ module.exports = function(sequelize) {
|
|
9
9
|
type: DataTypes.INTEGER,
|
10
10
|
allowNull: false,
|
11
11
|
autoIncrement: true,
|
12
|
-
primaryKey: true
|
12
|
+
primaryKey: true
|
13
13
|
},
|
14
14
|
threadID: {
|
15
15
|
type: DataTypes.STRING,
|
16
16
|
allowNull: false,
|
17
|
-
unique: true
|
17
|
+
unique: true
|
18
18
|
},
|
19
19
|
data: {
|
20
20
|
type: DataTypes.JSONB,
|
21
|
-
allowNull: true
|
21
|
+
allowNull: true
|
22
22
|
}
|
23
23
|
},
|
24
24
|
{
|
25
25
|
sequelize,
|
26
26
|
modelName: "Thread",
|
27
|
-
timestamps: true
|
27
|
+
timestamps: true
|
28
28
|
}
|
29
29
|
);
|
30
30
|
return Thread;
|
31
|
-
};
|
31
|
+
};
|