@cexy/hoonfca 1.0.3 → 1.0.5
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/CHANGELOG.md +181 -0
- package/DOCS.md +2636 -0
- package/LICENSE-MIT +21 -21
- package/README.md +632 -0
- package/func/checkUpdate.js +222 -0
- package/func/logger.js +48 -0
- package/index.d.ts +731 -605
- package/index.js +6 -777
- package/module/config.js +34 -0
- package/module/login.js +136 -0
- package/module/loginHelper.js +1034 -0
- package/module/options.js +45 -0
- package/package.json +53 -22
- package/src/api/action/addExternalModule.js +25 -0
- package/src/api/action/changeAvatar.js +137 -0
- package/src/{changeBio.js → api/action/changeBio.js} +75 -76
- package/src/api/action/enableAutoSaveAppState.js +73 -0
- package/src/{getCurrentUserID.js → api/action/getCurrentUserID.js} +7 -7
- package/src/{handleFriendRequest.js → api/action/handleFriendRequest.js} +57 -57
- package/src/api/action/logout.js +76 -0
- package/src/api/action/refreshFb_dtsg.js +48 -0
- package/src/api/action/setPostReaction.js +106 -0
- package/src/api/action/unfriend.js +54 -0
- package/src/api/http/httpGet.js +46 -0
- package/src/api/http/httpPost.js +52 -0
- package/src/api/http/postFormData.js +47 -0
- package/src/api/messaging/addUserToGroup.js +68 -0
- package/src/api/messaging/changeAdminStatus.js +122 -0
- package/src/api/messaging/changeArchivedStatus.js +55 -0
- package/src/api/messaging/changeBlockedStatus.js +48 -0
- package/src/api/messaging/changeGroupImage.js +90 -0
- package/src/api/messaging/changeNickname.js +70 -0
- package/src/api/messaging/changeThreadColor.js +79 -0
- package/src/api/messaging/changeThreadEmoji.js +106 -0
- package/src/{createNewGroup.js → api/messaging/createNewGroup.js} +88 -88
- package/src/api/messaging/createPoll.js +43 -0
- package/src/api/messaging/createThemeAI.js +98 -0
- package/src/{deleteMessage.js → api/messaging/deleteMessage.js} +56 -56
- package/src/{deleteThread.js → api/messaging/deleteThread.js} +56 -56
- package/src/api/messaging/editMessage.js +68 -0
- package/src/api/messaging/forwardAttachment.js +51 -0
- package/src/{getEmojiUrl.js → api/messaging/getEmojiUrl.js} +8 -8
- package/src/{getFriendsList.js → api/messaging/getFriendsList.js} +82 -84
- package/src/api/messaging/getMessage.js +829 -0
- package/src/api/messaging/getThemePictures.js +62 -0
- package/src/api/messaging/handleMessageRequest.js +65 -0
- package/src/{markAsDelivered.js → api/messaging/markAsDelivered.js} +57 -58
- package/src/{markAsRead.js → api/messaging/markAsRead.js} +88 -88
- package/src/{markAsReadAll.js → api/messaging/markAsReadAll.js} +49 -50
- package/src/api/messaging/markAsSeen.js +61 -0
- package/src/{muteThread.js → api/messaging/muteThread.js} +50 -52
- package/src/api/messaging/removeUserFromGroup.js +106 -0
- package/src/{resolvePhotoUrl.js → api/messaging/resolvePhotoUrl.js} +43 -45
- package/src/api/messaging/scheduler.js +264 -0
- package/src/{searchForThread.js → api/messaging/searchForThread.js} +52 -53
- package/src/api/messaging/sendMessage.js +272 -0
- package/src/api/messaging/sendTypingIndicator.js +67 -0
- package/src/api/messaging/setMessageReaction.js +76 -0
- package/src/api/messaging/setTitle.js +119 -0
- package/src/{shareContact.js → api/messaging/shareContact.js} +49 -53
- package/src/api/messaging/threadColors.js +128 -0
- package/src/api/messaging/unsendMessage.js +81 -0
- package/src/api/messaging/uploadAttachment.js +94 -0
- package/src/api/socket/core/connectMqtt.js +255 -0
- package/src/api/socket/core/emitAuth.js +106 -0
- package/src/api/socket/core/getSeqID.js +40 -0
- package/src/api/socket/core/getTaskResponseData.js +22 -0
- package/src/api/socket/core/markDelivery.js +12 -0
- package/src/api/socket/core/parseDelta.js +391 -0
- package/src/api/socket/detail/buildStream.js +208 -0
- package/src/api/socket/detail/constants.js +24 -0
- package/src/api/socket/listenMqtt.js +364 -0
- package/src/api/socket/middleware/index.js +216 -0
- package/src/{getThreadHistory.js → api/threads/getThreadHistory.js} +664 -647
- package/src/api/threads/getThreadInfo.js +438 -0
- package/src/{getThreadList.js → api/threads/getThreadList.js} +293 -292
- package/src/{getThreadPictures.js → api/threads/getThreadPictures.js} +78 -79
- package/src/{getUserID.js → api/users/getUserID.js} +65 -66
- package/src/api/users/getUserInfo.js +327 -0
- package/src/api/users/getUserInfoV2.js +134 -0
- package/src/core/sendReqMqtt.js +96 -0
- package/src/database/models/index.js +87 -0
- package/src/database/models/thread.js +45 -0
- package/src/database/models/user.js +46 -0
- package/src/database/threadData.js +98 -0
- package/src/database/userData.js +89 -0
- package/src/utils/client.js +320 -0
- package/src/utils/constants.js +23 -0
- package/{utils.js → src/utils/format.js} +1115 -1447
- package/src/utils/headers.js +115 -0
- package/src/utils/request.js +305 -0
- package/.travis.yml +0 -6
- package/src/addExternalModule.js +0 -23
- package/src/addUserToGroup.js +0 -113
- package/src/changeAdminStatus.js +0 -95
- package/src/changeApprovalMode.js +0 -79
- package/src/changeArchivedStatus.js +0 -55
- package/src/changeBlockedStatus.js +0 -47
- package/src/changeBlockedStatusMqtt.js +0 -86
- package/src/changeGroupImage.js +0 -133
- package/src/changeNickname.js +0 -59
- package/src/changeThreadColor.js +0 -71
- package/src/changeThreadEmoji.js +0 -55
- package/src/createPoll.js +0 -130
- package/src/editMessage.js +0 -63
- package/src/forwardAttachment.js +0 -60
- package/src/forwardMessage.js +0 -63
- package/src/getGroupsList.js +0 -83
- package/src/getMarketplace.js +0 -84
- package/src/getNotifications.js +0 -86
- package/src/getPagesList.js +0 -83
- package/src/getStories.js +0 -88
- package/src/getThreadInfo.js +0 -222
- package/src/getUserInfo.js +0 -128
- package/src/handleMessageRequest.js +0 -65
- package/src/httpGet.js +0 -58
- package/src/httpPost.js +0 -58
- package/src/listenMqtt.js +0 -1018
- package/src/logout.js +0 -75
- package/src/markAsSeen.js +0 -61
- package/src/pinMessage.js +0 -61
- package/src/removeUserFromGroup.js +0 -79
- package/src/searchUsers.js +0 -89
- package/src/sendComment.js +0 -161
- package/src/sendMessage.js +0 -457
- package/src/sendTypingIndicator.js +0 -179
- package/src/setBio.js +0 -86
- package/src/setMessageReaction.js +0 -186
- package/src/setPostReaction.js +0 -71
- package/src/setTheme.js +0 -313
- package/src/setTitle.js +0 -90
- package/src/shareLink.js +0 -62
- package/src/threadColors.js +0 -57
- package/src/unfriend.js +0 -53
- package/src/unsendMessage.js +0 -104
|
@@ -1,52 +1,50 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)
|
|
36
|
-
.then(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
};
|
|
52
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
const log = require("npmlog");
|
|
3
|
+
const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
|
|
4
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
5
|
+
// muteSecond: -1=permanent mute, 0=unmute, 60=one minute, 3600=one hour, etc.
|
|
6
|
+
return function muteThread(threadID, muteSeconds, callback) {
|
|
7
|
+
let resolveFunc = function() {};
|
|
8
|
+
let rejectFunc = function() {};
|
|
9
|
+
const returnPromise = new Promise(function(resolve, reject) {
|
|
10
|
+
resolveFunc = resolve;
|
|
11
|
+
rejectFunc = reject;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
if (!callback) {
|
|
15
|
+
callback = function(err, friendList) {
|
|
16
|
+
if (err) {
|
|
17
|
+
return rejectFunc(err);
|
|
18
|
+
}
|
|
19
|
+
resolveFunc(friendList);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const form = {
|
|
24
|
+
thread_fbid: threadID,
|
|
25
|
+
mute_settings: muteSeconds
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
defaultFuncs
|
|
29
|
+
.post(
|
|
30
|
+
"https://www.facebook.com/ajax/mercury/change_mute_thread.php",
|
|
31
|
+
ctx.jar,
|
|
32
|
+
form
|
|
33
|
+
)
|
|
34
|
+
.then(saveCookies(ctx.jar))
|
|
35
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs))
|
|
36
|
+
.then(function(resData) {
|
|
37
|
+
if (resData.error) {
|
|
38
|
+
throw resData;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return callback();
|
|
42
|
+
})
|
|
43
|
+
.catch(function(err) {
|
|
44
|
+
log.error("muteThread", err);
|
|
45
|
+
return callback(err);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return returnPromise;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { getType } = require("../../utils/format");
|
|
4
|
+
const { parseAndCheckLogin } = require("../../utils/client");
|
|
5
|
+
const log = require("npmlog");
|
|
6
|
+
|
|
7
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
8
|
+
function removeUserFromGroupNoMqtt(userID, threadID, callback) {
|
|
9
|
+
if (!callback && (getType(threadID) === "Function" || getType(threadID) === "AsyncFunction")) throw { error: "please pass a threadID as a second argument." };
|
|
10
|
+
if (getType(threadID) !== "Number" && getType(threadID) !== "String") throw { error: "threadID should be of type Number or String and not " + getType(threadID) + "." };
|
|
11
|
+
if (getType(userID) !== "Number" && getType(userID) !== "String") throw { error: "userID should be of type Number or String and not " + getType(userID) + "." };
|
|
12
|
+
var resolveFunc = function () { };
|
|
13
|
+
var rejectFunc = function () { };
|
|
14
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
|
15
|
+
resolveFunc = resolve;
|
|
16
|
+
rejectFunc = reject;
|
|
17
|
+
});
|
|
18
|
+
if (!callback) {
|
|
19
|
+
callback = function (err, data) {
|
|
20
|
+
if (err) return rejectFunc(err);
|
|
21
|
+
resolveFunc(data);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
var form = {
|
|
25
|
+
uid: userID,
|
|
26
|
+
tid: threadID
|
|
27
|
+
};
|
|
28
|
+
defaultFuncs
|
|
29
|
+
.post("https://www.facebook.com/chat/remove_participants", ctx.jar, form)
|
|
30
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs))
|
|
31
|
+
.then(function (resData) {
|
|
32
|
+
if (!resData) throw { error: "Remove from group failed." };
|
|
33
|
+
if (resData.error) throw resData;
|
|
34
|
+
return callback();
|
|
35
|
+
})
|
|
36
|
+
.catch(function (err) {
|
|
37
|
+
log.error("removeUserFromGroup", err);
|
|
38
|
+
return callback(err);
|
|
39
|
+
});
|
|
40
|
+
return returnPromise;
|
|
41
|
+
};
|
|
42
|
+
function removeUserFromGroupMqtt(userID, threadID, callback) {
|
|
43
|
+
if (!ctx.mqttClient) {
|
|
44
|
+
throw new Error("Not connected to MQTT");
|
|
45
|
+
}
|
|
46
|
+
if (!callback && (getType(threadID) === "Function" || getType(threadID) === "AsyncFunction")) throw { error: "please pass a threadID as a second argument." };
|
|
47
|
+
if (getType(threadID) !== "Number" && getType(threadID) !== "String") throw { error: "threadID should be of type Number or String and not " + getType(threadID) + "." };
|
|
48
|
+
if (getType(userID) !== "Number" && getType(userID) !== "String") throw { error: "userID should be of type Number or String and not " + getType(userID) + "." };
|
|
49
|
+
var resolveFunc = function () { };
|
|
50
|
+
var rejectFunc = function () { };
|
|
51
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
|
52
|
+
resolveFunc = resolve;
|
|
53
|
+
rejectFunc = reject;
|
|
54
|
+
});
|
|
55
|
+
if (!callback) {
|
|
56
|
+
callback = function (err, data) {
|
|
57
|
+
if (err) return rejectFunc(err);
|
|
58
|
+
resolveFunc(data);
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
let count_req = 0;
|
|
62
|
+
var form = JSON.stringify({
|
|
63
|
+
"app_id": "2220391788200892",
|
|
64
|
+
"payload": JSON.stringify({
|
|
65
|
+
epoch_id: generateOfflineThreadingID(),
|
|
66
|
+
tasks: [
|
|
67
|
+
{
|
|
68
|
+
failure_count: null,
|
|
69
|
+
label: '140',
|
|
70
|
+
payload: JSON.stringify({
|
|
71
|
+
"thread_id": threadID,
|
|
72
|
+
"contact_id": userID,
|
|
73
|
+
"sync_group": 1
|
|
74
|
+
}),
|
|
75
|
+
queue_name: 'remove_participant_v2',
|
|
76
|
+
task_id: Math.random() * 1001 << 0
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
version_id: '8798795233522156'
|
|
80
|
+
}),
|
|
81
|
+
"request_id": ++count_req,
|
|
82
|
+
"type": 3
|
|
83
|
+
});
|
|
84
|
+
mqttClient.publish('/ls_req', form, (err, data) => {
|
|
85
|
+
if (err) {
|
|
86
|
+
callback(err, null);
|
|
87
|
+
rejectFunc(false);
|
|
88
|
+
} else {
|
|
89
|
+
callback(null, true);
|
|
90
|
+
resolveFunc(true);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return returnPromise;
|
|
94
|
+
};
|
|
95
|
+
return function removeUserFromGroup(userID, threadID, callback) {
|
|
96
|
+
if (ctx.mqttClient) {
|
|
97
|
+
try {
|
|
98
|
+
removeUserFromGroupMqtt(userID, threadID, callback);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
removeUserFromGroupNoMqtt(userID, threadID, callback);
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
removeUserFromGroupNoMqtt(userID, threadID, callback);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
};
|
|
@@ -1,45 +1,43 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
};
|
|
45
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
const log = require("npmlog");
|
|
3
|
+
const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
|
|
4
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
5
|
+
return function resolvePhotoUrl(photoID, callback) {
|
|
6
|
+
let resolveFunc = function() {};
|
|
7
|
+
let rejectFunc = function() {};
|
|
8
|
+
const returnPromise = new Promise(function(resolve, reject) {
|
|
9
|
+
resolveFunc = resolve;
|
|
10
|
+
rejectFunc = reject;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
if (!callback) {
|
|
14
|
+
callback = function(err, friendList) {
|
|
15
|
+
if (err) {
|
|
16
|
+
return rejectFunc(err);
|
|
17
|
+
}
|
|
18
|
+
resolveFunc(friendList);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
defaultFuncs
|
|
23
|
+
.get("https://www.facebook.com/mercury/attachments/photo", ctx.jar, {
|
|
24
|
+
photo_id: photoID
|
|
25
|
+
})
|
|
26
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs))
|
|
27
|
+
.then(resData => {
|
|
28
|
+
if (resData.error) {
|
|
29
|
+
throw resData;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const photoUrl = resData.jsmods.require[0][3][0];
|
|
33
|
+
|
|
34
|
+
return callback(null, photoUrl);
|
|
35
|
+
})
|
|
36
|
+
.catch(err => {
|
|
37
|
+
log.error("resolvePhotoUrl", err);
|
|
38
|
+
return callback(err);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return returnPromise;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const logger = require("../../../func/logger");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Message Scheduler System
|
|
6
|
+
* Allows scheduling messages to be sent at a specific time in the future
|
|
7
|
+
*/
|
|
8
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
9
|
+
// Initialize scheduler on first call
|
|
10
|
+
if (!ctx._scheduler) {
|
|
11
|
+
ctx._scheduler = createSchedulerInstance(api);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return ctx._scheduler;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function createSchedulerInstance(api) {
|
|
18
|
+
const scheduledMessages = new Map(); // Map<id, ScheduledMessage>
|
|
19
|
+
let nextId = 1;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Scheduled Message Object
|
|
23
|
+
* @typedef {Object} ScheduledMessage
|
|
24
|
+
* @property {string} id - Unique identifier
|
|
25
|
+
* @property {string|Object} message - Message content
|
|
26
|
+
* @property {string|string[]} threadID - Target thread ID(s)
|
|
27
|
+
* @property {number} timestamp - When to send (Unix timestamp in ms)
|
|
28
|
+
* @property {number} createdAt - When scheduled (Unix timestamp in ms)
|
|
29
|
+
* @property {Object} options - Additional options (replyMessageID, isGroup, etc.)
|
|
30
|
+
* @property {Function} callback - Optional callback when sent
|
|
31
|
+
* @property {NodeJS.Timeout} timeout - Timeout reference
|
|
32
|
+
* @property {boolean} cancelled - Whether cancelled
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Schedule a message to be sent at a specific time
|
|
37
|
+
* @param {string|Object} message - Message content
|
|
38
|
+
* @param {string|string[]} threadID - Target thread ID(s)
|
|
39
|
+
* @param {Date|number|string} when - When to send (Date, timestamp, or ISO string)
|
|
40
|
+
* @param {Object} [options] - Additional options
|
|
41
|
+
* @param {string} [options.replyMessageID] - Message ID to reply to
|
|
42
|
+
* @param {boolean} [options.isGroup] - Whether it's a group chat
|
|
43
|
+
* @param {Function} [options.callback] - Callback when sent
|
|
44
|
+
* @returns {string} Scheduled message ID
|
|
45
|
+
*/
|
|
46
|
+
function scheduleMessage(message, threadID, when, options = {}) {
|
|
47
|
+
let timestamp;
|
|
48
|
+
|
|
49
|
+
// Parse when parameter
|
|
50
|
+
if (when instanceof Date) {
|
|
51
|
+
timestamp = when.getTime();
|
|
52
|
+
} else if (typeof when === "number") {
|
|
53
|
+
timestamp = when;
|
|
54
|
+
} else if (typeof when === "string") {
|
|
55
|
+
timestamp = new Date(when).getTime();
|
|
56
|
+
} else {
|
|
57
|
+
throw new Error("Invalid 'when' parameter. Must be Date, number (timestamp), or ISO string");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Validate timestamp
|
|
61
|
+
if (isNaN(timestamp)) {
|
|
62
|
+
throw new Error("Invalid date/time");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const now = Date.now();
|
|
66
|
+
if (timestamp <= now) {
|
|
67
|
+
throw new Error("Scheduled time must be in the future");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const id = `scheduled_${nextId++}_${Date.now()}`;
|
|
71
|
+
const delay = timestamp - now;
|
|
72
|
+
|
|
73
|
+
// Create scheduled message object
|
|
74
|
+
const scheduled = {
|
|
75
|
+
id,
|
|
76
|
+
message,
|
|
77
|
+
threadID,
|
|
78
|
+
timestamp,
|
|
79
|
+
createdAt: now,
|
|
80
|
+
options: {
|
|
81
|
+
replyMessageID: options.replyMessageID,
|
|
82
|
+
isGroup: options.isGroup,
|
|
83
|
+
callback: options.callback
|
|
84
|
+
},
|
|
85
|
+
cancelled: false
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Set timeout to send message
|
|
89
|
+
scheduled.timeout = setTimeout(() => {
|
|
90
|
+
if (scheduled.cancelled) return;
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
logger(`Sending scheduled message ${id}`, "info");
|
|
94
|
+
|
|
95
|
+
// Send message
|
|
96
|
+
api.sendMessage(
|
|
97
|
+
message,
|
|
98
|
+
threadID,
|
|
99
|
+
scheduled.options.callback || (() => {}),
|
|
100
|
+
scheduled.options.replyMessageID,
|
|
101
|
+
scheduled.options.isGroup
|
|
102
|
+
).then(() => {
|
|
103
|
+
logger(`Scheduled message ${id} sent successfully`, "info");
|
|
104
|
+
scheduledMessages.delete(id);
|
|
105
|
+
}).catch(err => {
|
|
106
|
+
logger(`Error sending scheduled message ${id}: ${err && err.message ? err.message : String(err)}`, "error");
|
|
107
|
+
if (scheduled.options.callback) {
|
|
108
|
+
scheduled.options.callback(err);
|
|
109
|
+
}
|
|
110
|
+
scheduledMessages.delete(id);
|
|
111
|
+
});
|
|
112
|
+
} catch (err) {
|
|
113
|
+
logger(`Error in scheduled message ${id}: ${err && err.message ? err.message : String(err)}`, "error");
|
|
114
|
+
scheduledMessages.delete(id);
|
|
115
|
+
}
|
|
116
|
+
}, delay);
|
|
117
|
+
|
|
118
|
+
scheduledMessages.set(id, scheduled);
|
|
119
|
+
logger(`Message scheduled: ${id} (in ${Math.round(delay / 1000)}s)`, "info");
|
|
120
|
+
|
|
121
|
+
return id;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Cancel a scheduled message
|
|
126
|
+
* @param {string} id - Scheduled message ID
|
|
127
|
+
* @returns {boolean} True if cancelled, false if not found
|
|
128
|
+
*/
|
|
129
|
+
function cancelScheduledMessage(id) {
|
|
130
|
+
const scheduled = scheduledMessages.get(id);
|
|
131
|
+
if (!scheduled) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (scheduled.cancelled) {
|
|
136
|
+
return false; // Already cancelled
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
clearTimeout(scheduled.timeout);
|
|
140
|
+
scheduled.cancelled = true;
|
|
141
|
+
scheduledMessages.delete(id);
|
|
142
|
+
logger(`Scheduled message ${id} cancelled`, "info");
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get scheduled message info
|
|
148
|
+
* @param {string} id - Scheduled message ID
|
|
149
|
+
* @returns {ScheduledMessage|null} Scheduled message or null if not found
|
|
150
|
+
*/
|
|
151
|
+
function getScheduledMessage(id) {
|
|
152
|
+
const scheduled = scheduledMessages.get(id);
|
|
153
|
+
if (!scheduled || scheduled.cancelled) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Return a copy without internal properties
|
|
158
|
+
return {
|
|
159
|
+
id: scheduled.id,
|
|
160
|
+
message: scheduled.message,
|
|
161
|
+
threadID: scheduled.threadID,
|
|
162
|
+
timestamp: scheduled.timestamp,
|
|
163
|
+
createdAt: scheduled.createdAt,
|
|
164
|
+
options: { ...scheduled.options },
|
|
165
|
+
timeUntilSend: scheduled.timestamp - Date.now()
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* List all scheduled messages
|
|
171
|
+
* @returns {ScheduledMessage[]} Array of scheduled messages
|
|
172
|
+
*/
|
|
173
|
+
function listScheduledMessages() {
|
|
174
|
+
const now = Date.now();
|
|
175
|
+
const list = [];
|
|
176
|
+
|
|
177
|
+
for (const scheduled of scheduledMessages.values()) {
|
|
178
|
+
if (scheduled.cancelled) continue;
|
|
179
|
+
|
|
180
|
+
list.push({
|
|
181
|
+
id: scheduled.id,
|
|
182
|
+
message: scheduled.message,
|
|
183
|
+
threadID: scheduled.threadID,
|
|
184
|
+
timestamp: scheduled.timestamp,
|
|
185
|
+
createdAt: scheduled.createdAt,
|
|
186
|
+
options: { ...scheduled.options },
|
|
187
|
+
timeUntilSend: scheduled.timestamp - now
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Sort by timestamp
|
|
192
|
+
return list.sort((a, b) => a.timestamp - b.timestamp);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Cancel all scheduled messages
|
|
197
|
+
* @returns {number} Number of cancelled messages
|
|
198
|
+
*/
|
|
199
|
+
function cancelAllScheduledMessages() {
|
|
200
|
+
let count = 0;
|
|
201
|
+
for (const id of scheduledMessages.keys()) {
|
|
202
|
+
if (cancelScheduledMessage(id)) {
|
|
203
|
+
count++;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
logger(`Cancelled ${count} scheduled messages`, "info");
|
|
207
|
+
return count;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Get count of scheduled messages
|
|
212
|
+
* @returns {number} Count
|
|
213
|
+
*/
|
|
214
|
+
function getScheduledCount() {
|
|
215
|
+
return scheduledMessages.size;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Clear expired/cancelled messages from memory
|
|
220
|
+
*/
|
|
221
|
+
function cleanup() {
|
|
222
|
+
const now = Date.now();
|
|
223
|
+
let cleaned = 0;
|
|
224
|
+
|
|
225
|
+
for (const [id, scheduled] of scheduledMessages.entries()) {
|
|
226
|
+
if (scheduled.cancelled || scheduled.timestamp < now) {
|
|
227
|
+
scheduledMessages.delete(id);
|
|
228
|
+
cleaned++;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (cleaned > 0) {
|
|
233
|
+
logger(`Cleaned up ${cleaned} scheduled messages`, "info");
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Auto cleanup every 5 minutes
|
|
238
|
+
const cleanupInterval = setInterval(cleanup, 5 * 60 * 1000);
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Destroy scheduler and cleanup all resources
|
|
242
|
+
* @returns {number} Number of cancelled messages
|
|
243
|
+
*/
|
|
244
|
+
function destroy() {
|
|
245
|
+
clearInterval(cleanupInterval);
|
|
246
|
+
const count = cancelAllScheduledMessages();
|
|
247
|
+
logger("Scheduler destroyed and all resources cleaned up", "info");
|
|
248
|
+
return count;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Return scheduler API
|
|
252
|
+
return {
|
|
253
|
+
scheduleMessage,
|
|
254
|
+
cancelScheduledMessage,
|
|
255
|
+
getScheduledMessage,
|
|
256
|
+
listScheduledMessages,
|
|
257
|
+
cancelAllScheduledMessages,
|
|
258
|
+
getScheduledCount,
|
|
259
|
+
cleanup,
|
|
260
|
+
destroy,
|
|
261
|
+
// Cleanup interval reference for manual cleanup if needed
|
|
262
|
+
_cleanupInterval: cleanupInterval
|
|
263
|
+
};
|
|
264
|
+
}
|
|
@@ -1,53 +1,52 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
)
|
|
37
|
-
.then(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { parseAndCheckLogin } = require("../../utils/client");
|
|
4
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
5
|
+
return function searchForThread(name, callback) {
|
|
6
|
+
let resolveFunc = function() {};
|
|
7
|
+
let rejectFunc = function() {};
|
|
8
|
+
const returnPromise = new Promise(function(resolve, reject) {
|
|
9
|
+
resolveFunc = resolve;
|
|
10
|
+
rejectFunc = reject;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
if (!callback) {
|
|
14
|
+
callback = function(err, friendList) {
|
|
15
|
+
if (err) {
|
|
16
|
+
return rejectFunc(err);
|
|
17
|
+
}
|
|
18
|
+
resolveFunc(friendList);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const tmpForm = {
|
|
23
|
+
client: "web_messenger",
|
|
24
|
+
query: name,
|
|
25
|
+
offset: 0,
|
|
26
|
+
limit: 21,
|
|
27
|
+
index: "fbid"
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
defaultFuncs
|
|
31
|
+
.post(
|
|
32
|
+
"https://www.facebook.com/ajax/mercury/search_threads.php",
|
|
33
|
+
ctx.jar,
|
|
34
|
+
tmpForm
|
|
35
|
+
)
|
|
36
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs))
|
|
37
|
+
.then(function(resData) {
|
|
38
|
+
if (resData.error) {
|
|
39
|
+
throw resData;
|
|
40
|
+
}
|
|
41
|
+
if (!resData.payload.mercury_payload.threads) {
|
|
42
|
+
return callback({ error: "Could not find thread `" + name + "`." });
|
|
43
|
+
}
|
|
44
|
+
return callback(
|
|
45
|
+
null,
|
|
46
|
+
resData.payload.mercury_payload.threads.map(utils.formatThread)
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return returnPromise;
|
|
51
|
+
};
|
|
52
|
+
};
|