forked from Konard/vk-bot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoutgoing-messages.js
168 lines (151 loc) · 5.47 KB
/
outgoing-messages.js
1
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
const queue = [];
const tickSize = 1000; // ms
const typingSpeedInCharactersPerMinute = 400;
const typingSpeedInCharactersPerSecond = typingSpeedInCharactersPerMinute / 60;
const typingInterval = 5;
const minTicksToRead = 2;
const maxTicksToRead = 4;
const minTicksToTyping = 6;
const maxTicksToTyping = 8;
const minTicksToSticker = 6;
const maxTicksToSticker = 8;
const minTicksToReply = 10;
const maxTicksToReply = 14;
if (maxTicksToRead > minTicksToTyping)
{
throw new Error('maxTicksToRead > minTicksToTyping')
}
if (maxTicksToRead > minTicksToSticker)
{
throw new Error('maxTicksToRead > minTicksToSticker')
}
if (maxTicksToTyping > minTicksToReply)
{
throw new Error('maxTicksToTyping > minTicksToReply')
}
const calculateMinimumSecondsToType = (text, speed = typingSpeedInCharactersPerSecond) => {
return Math.floor(text.length / speed);
};
function randomInRange(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min) + min);
}
function randomInteger() {
return randomInRange(Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
}
async function activateTyping(context) {
const peerId = context?.request?.peerId;
if (peerId && context.vk) {
console.log('Activating typing status...');
await context.vk.api.messages.setActivity({
peer_id: peerId,
type: 'typing'
});
console.log('Typing status is activated.');
}
}
function markMessagesAsRead(options) {
if (!options?.vk || !options?.request) {
return;
}
const timeout = randomInRange(minTicksToRead * tickSize, maxTicksToRead * tickSize);
console.log(`Messages before ${options.request.id} for user ${options.request.senderId} will be marked as read in ${timeout}ms.`);
setTimeout(async () => {
await options.vk.api.messages.markAsRead({
peer_id: options.request.senderId,
start_message_id: options.request.id
}).catch(console.error);
console.log(`Messages before ${options.request.id} for user ${options.request.senderId} are marked as read.`);
}, timeout);
}
function disableTypingIndication(options) {
options.ticksToTyping = Number.MAX_SAFE_INTEGER;
}
function enqueueMessage(options) {
let defaultOptions = {
ticksToTyping: randomInRange(minTicksToTyping, maxTicksToTyping),
waitTicks: randomInRange(minTicksToReply, maxTicksToReply),
};
if (options?.response?.sticker_id) {
disableTypingIndication(options);
defaultOptions.waitTicks = randomInRange(minTicksToSticker, maxTicksToSticker);
} else if (options?.response?.message) {
defaultOptions.waitTicks += calculateMinimumSecondsToType(options?.response?.message);
}
const combinedOptions = {
...defaultOptions,
...options
};
if (!combinedOptions?.response?.random_id) {
combinedOptions.response.random_id = randomInteger();
console.log('combinedOptions.response.random_id', options.response.random_id)
}
if (!combinedOptions.waitTicksLeft) {
combinedOptions.waitTicksLeft = combinedOptions.waitTicks;
}
queue.push(combinedOptions);
markMessagesAsRead(options);
}
const handleOutgoingMessage = async () => {
const context = queue[0];
if (!context) { // no messages to send - to nothing
return;
}
if (context.waitTicksLeft > 0) // we have a message to send - wait for the set interval
{
const ticksPassed = context.waitTicks - context.waitTicksLeft;
// console.log('context.ticksToTyping', context.ticksToTyping);
console.log('ticksPassed', ticksPassed);
// console.log('context.ticksToTyping >= ticksPassed', ticksPassed >= context.ticksToTyping);
// console.log('((ticksPassed - context.ticksToTyping) % typingInterval == 0)', ((ticksPassed - context.ticksToTyping) % typingInterval == 0));
if (ticksPassed >= context.ticksToTyping && ((ticksPassed - context.ticksToTyping) % typingInterval == 0)) {
await activateTyping(context);
}
// console.log('context.waitTicksLeft', context.waitTicksLeft);
context.waitTicksLeft--;
return;
}
queue.shift(); // dequeue message
console.log('context.request', context.response);
console.log('context.response', context.response);
try {
if (context.request) {
await context.request.send(context.response);
} else if (context.vk) {
await context.vk.api.messages.send({
random_id: Math.random(),
...context.response
});
}
} catch (e) {
if (e.code === 900) { // Can't send messages for users from blacklist
const peerId = context?.request?.peerId;
console.log(`${peerId} peer is blocked from sending messages to him.`);
return; // This error requires to do nothing.
} else if (e.code === 902) { // Can't send messages to this user due to their privacy settings
const peerId = context?.request?.peerId;
console.log(`${peerId} peer does not allow to send messages to him.`);
return; // This error requires to do nothing.
// TODO: unfriend or block user
// TODO: or make a script that check all such users, and unfriends them or blocks them
} else if (e.code === 7) { // Permission to perform this action is denied
const peerId = context?.request?.peerId;
console.log(`${peerId} peer is deactivated (blocked or deleted).`);
return; // This error requires to do nothing.
// TODO: unfriend
} else {
throw e;
}
}
};
module.exports = {
queue,
tickSize,
typingSpeedInCharactersPerMinute,
typingSpeedInCharactersPerSecond,
calculateMinimumSecondsToType,
randomInRange,
handleOutgoingMessage,
enqueueMessage
};