nodejs-insta-private-api-mqt 1.4.1 → 1.4.3
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.
|
@@ -5,6 +5,58 @@ const constants_1 = require("../../constants");
|
|
|
5
5
|
const shared_1 = require("../../shared");
|
|
6
6
|
const Chance = require("chance");
|
|
7
7
|
const thrift_1 = require("../../thrift");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* SerialQueue — Coadă strict serială cu retry și exponential backoff.
|
|
11
|
+
* Folosită per-thread pentru a serializa operațiile MQTT și a preveni
|
|
12
|
+
* race conditions și mesaje pierdute la reconectare.
|
|
13
|
+
*/
|
|
14
|
+
class SerialQueue {
|
|
15
|
+
constructor(name) {
|
|
16
|
+
this.name = name;
|
|
17
|
+
this.queue = [];
|
|
18
|
+
this.running = false;
|
|
19
|
+
}
|
|
20
|
+
enqueue(label, fn) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
this.queue.push({ label, fn, resolve, reject, retries: 0 });
|
|
23
|
+
this._tick();
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
_tick() {
|
|
27
|
+
if (this.running || this.queue.length === 0) return;
|
|
28
|
+
this.running = true;
|
|
29
|
+
this._processNext();
|
|
30
|
+
}
|
|
31
|
+
async _processNext() {
|
|
32
|
+
const MAX_RETRIES = 3;
|
|
33
|
+
const BASE_DELAY_MS = 500;
|
|
34
|
+
const item = this.queue[0];
|
|
35
|
+
if (!item) { this.running = false; return; }
|
|
36
|
+
try {
|
|
37
|
+
const result = await item.fn();
|
|
38
|
+
this.queue.shift();
|
|
39
|
+
item.resolve(result);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
if (item.retries < MAX_RETRIES) {
|
|
42
|
+
item.retries++;
|
|
43
|
+
const delay = BASE_DELAY_MS * Math.pow(2, item.retries - 1);
|
|
44
|
+
console.warn(`[Queue:${this.name}] "${item.label}" failed (try ${item.retries}/${MAX_RETRIES}), retry in ${delay}ms:`, err && err.message || err);
|
|
45
|
+
await new Promise(r => setTimeout(r, delay));
|
|
46
|
+
} else {
|
|
47
|
+
console.error(`[Queue:${this.name}] "${item.label}" failed after ${MAX_RETRIES} retries:`, err && err.message || err);
|
|
48
|
+
this.queue.shift();
|
|
49
|
+
item.reject(err);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (this.queue.length > 0) {
|
|
53
|
+
this._processNext();
|
|
54
|
+
} else {
|
|
55
|
+
this.running = false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
8
60
|
class DirectCommands {
|
|
9
61
|
constructor(client) {
|
|
10
62
|
this.directDebug = (0, shared_1.debugChannel)('realtime', 'direct');
|
|
@@ -20,23 +72,38 @@ class DirectCommands {
|
|
|
20
72
|
];
|
|
21
73
|
this.client = client;
|
|
22
74
|
this.chance = new Chance();
|
|
75
|
+
// Coadă per-thread pentru operații MQTT
|
|
76
|
+
this._threadQueues = new Map();
|
|
77
|
+
// Coadă globală pentru operații non-thread (ex: foreground state)
|
|
78
|
+
this._globalQueue = new SerialQueue('direct:global');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Returnează (sau creează) coada pentru un threadId specific */
|
|
82
|
+
_getThreadQueue(threadId) {
|
|
83
|
+
if (!this._threadQueues.has(threadId)) {
|
|
84
|
+
this._threadQueues.set(threadId, new SerialQueue(`direct:${threadId}`));
|
|
85
|
+
}
|
|
86
|
+
return this._threadQueues.get(threadId);
|
|
23
87
|
}
|
|
88
|
+
|
|
24
89
|
async sendForegroundState(state) {
|
|
25
90
|
this.directDebug(`Updated foreground state: ${JSON.stringify(state)}`);
|
|
26
|
-
return this.
|
|
27
|
-
.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
91
|
+
return this._globalQueue.enqueue('sendForegroundState', async () => {
|
|
92
|
+
return this.client
|
|
93
|
+
.publish({
|
|
94
|
+
topic: constants_1.Topics.FOREGROUND_STATE.id,
|
|
95
|
+
payload: await (0, shared_1.compressDeflate)(Buffer.concat([Buffer.alloc(1, 0), (0, thrift_1.thriftWriteFromObject)(state, this.foregroundStateConfig)])),
|
|
96
|
+
qosLevel: 1,
|
|
97
|
+
})
|
|
98
|
+
.then(res => {
|
|
99
|
+
if ((0, shared_1.notUndefined)(state.keepAliveTimeout)) {
|
|
100
|
+
this.client.keepAlive = state.keepAliveTimeout;
|
|
101
|
+
}
|
|
102
|
+
return res;
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
40
107
|
async sendCommand({ action, data, threadId, clientContext, }) {
|
|
41
108
|
if (clientContext) {
|
|
42
109
|
data.client_context = clientContext;
|
|
@@ -46,12 +113,16 @@ class DirectCommands {
|
|
|
46
113
|
thread_id: threadId,
|
|
47
114
|
...data,
|
|
48
115
|
});
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
116
|
+
const q = this._getThreadQueue(threadId);
|
|
117
|
+
return q.enqueue(action, async () => {
|
|
118
|
+
return this.client.publish({
|
|
119
|
+
topic: constants_1.Topics.SEND_MESSAGE.id,
|
|
120
|
+
qosLevel: 1,
|
|
121
|
+
payload: await (0, shared_1.compressDeflate)(json),
|
|
122
|
+
});
|
|
53
123
|
});
|
|
54
124
|
}
|
|
125
|
+
|
|
55
126
|
async sendItem({ threadId, itemType, data, clientContext }) {
|
|
56
127
|
return this.sendCommand({
|
|
57
128
|
action: 'send_item',
|
|
@@ -155,13 +226,26 @@ class DirectCommands {
|
|
|
155
226
|
},
|
|
156
227
|
});
|
|
157
228
|
}
|
|
158
|
-
async
|
|
159
|
-
|
|
229
|
+
async sendText({ text, clientContext, threadId }) {
|
|
230
|
+
const timestamp = Date.now() * 1000;
|
|
231
|
+
const messageId = `${timestamp}-${Math.random().toString(36).substr(2, 9)}`;
|
|
232
|
+
|
|
233
|
+
const result = await this.sendItem({
|
|
234
|
+
itemType: 'text',
|
|
235
|
+
threadId,
|
|
236
|
+
clientContext: messageId,
|
|
237
|
+
timestamp,
|
|
238
|
+
offline_threading_id: messageId,
|
|
239
|
+
data: {
|
|
160
240
|
text,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
241
|
+
},
|
|
242
|
+
ttl: 0,
|
|
243
|
+
shh_mode: false,
|
|
244
|
+
send_attribution: 'direct_thread',
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
165
249
|
async markAsSeen({ threadId, itemId }) {
|
|
166
250
|
return this.sendCommand({
|
|
167
251
|
action: 'mark_seen',
|
|
@@ -5,6 +5,57 @@ const shared_1 = require("../../shared");
|
|
|
5
5
|
const uuid_1 = require("uuid");
|
|
6
6
|
const constants_1 = require("../../constants");
|
|
7
7
|
const thrift_1 = require("../../thrift");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* SerialQueue — Coadă strict serială cu retry și exponential backoff.
|
|
11
|
+
* Folosită per-thread pentru a serializa operațiile MQTT și a preveni
|
|
12
|
+
* race conditions și mesaje pierdute la reconectare.
|
|
13
|
+
*/
|
|
14
|
+
class SerialQueue {
|
|
15
|
+
constructor(name) {
|
|
16
|
+
this.name = name;
|
|
17
|
+
this.queue = [];
|
|
18
|
+
this.running = false;
|
|
19
|
+
}
|
|
20
|
+
enqueue(label, fn) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
this.queue.push({ label, fn, resolve, reject, retries: 0 });
|
|
23
|
+
this._tick();
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
_tick() {
|
|
27
|
+
if (this.running || this.queue.length === 0) return;
|
|
28
|
+
this.running = true;
|
|
29
|
+
this._processNext();
|
|
30
|
+
}
|
|
31
|
+
async _processNext() {
|
|
32
|
+
const MAX_RETRIES = 3;
|
|
33
|
+
const BASE_DELAY_MS = 500;
|
|
34
|
+
const item = this.queue[0];
|
|
35
|
+
if (!item) { this.running = false; return; }
|
|
36
|
+
try {
|
|
37
|
+
const result = await item.fn();
|
|
38
|
+
this.queue.shift();
|
|
39
|
+
item.resolve(result);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
if (item.retries < MAX_RETRIES) {
|
|
42
|
+
item.retries++;
|
|
43
|
+
const delay = BASE_DELAY_MS * Math.pow(2, item.retries - 1);
|
|
44
|
+
console.warn(`[Queue:${this.name}] "${item.label}" failed (try ${item.retries}/${MAX_RETRIES}), retry in ${delay}ms:`, err && err.message || err);
|
|
45
|
+
await new Promise(r => setTimeout(r, delay));
|
|
46
|
+
} else {
|
|
47
|
+
console.error(`[Queue:${this.name}] "${item.label}" failed after ${MAX_RETRIES} retries:`, err && err.message || err);
|
|
48
|
+
this.queue.shift();
|
|
49
|
+
item.reject(err);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (this.queue.length > 0) {
|
|
53
|
+
this._processNext();
|
|
54
|
+
} else {
|
|
55
|
+
this.running = false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
8
59
|
/**
|
|
9
60
|
* EnhancedDirectCommands
|
|
10
61
|
*
|
|
@@ -32,6 +83,17 @@ class EnhancedDirectCommands {
|
|
|
32
83
|
thrift_1.ThriftDescriptors.listOfBinary('unsubscribeGenericTopics', 7),
|
|
33
84
|
thrift_1.ThriftDescriptors.int64('requestId', 8),
|
|
34
85
|
];
|
|
86
|
+
// Coadă per-thread pentru operații MQTT
|
|
87
|
+
this._threadQueues = new Map();
|
|
88
|
+
// Coadă globală pentru operații non-thread (ex: foreground state)
|
|
89
|
+
this._globalQueue = new SerialQueue('enhanced:global');
|
|
90
|
+
}
|
|
91
|
+
/** Returnează (sau creează) coada pentru un threadId specific */
|
|
92
|
+
_getThreadQueue(threadId) {
|
|
93
|
+
if (!this._threadQueues.has(threadId)) {
|
|
94
|
+
this._threadQueues.set(threadId, new SerialQueue(`enhanced:${threadId}`));
|
|
95
|
+
}
|
|
96
|
+
return this._threadQueues.get(threadId);
|
|
35
97
|
}
|
|
36
98
|
/**
|
|
37
99
|
* Attempt to locate the MQTT client object on the realtime client.
|
|
@@ -132,62 +194,66 @@ class EnhancedDirectCommands {
|
|
|
132
194
|
}
|
|
133
195
|
/**
|
|
134
196
|
* Send foreground state via MQTT with Thrift encoding (matching instagram_mqtt)
|
|
197
|
+
* Folosește coada globală — nu depinde de un thread specific.
|
|
135
198
|
*/
|
|
136
199
|
async sendForegroundState(state) {
|
|
137
200
|
this.enhancedDebug(`Updated foreground state: ${JSON.stringify(state)}`);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
Buffer.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
201
|
+
return this._globalQueue.enqueue('sendForegroundState', async () => {
|
|
202
|
+
try {
|
|
203
|
+
const mqtt = this.getMqtt();
|
|
204
|
+
const thriftBuffer = (0, thrift_1.thriftWriteFromObject)(state, this.foregroundStateConfig);
|
|
205
|
+
const concat = Buffer.concat([
|
|
206
|
+
Buffer.alloc(1, 0),
|
|
207
|
+
thriftBuffer
|
|
208
|
+
]);
|
|
209
|
+
const payload = await (0, shared_1.compressDeflate)(concat);
|
|
210
|
+
const result = await this.publishToMqtt(mqtt, {
|
|
211
|
+
topic: constants_1.Topics.FOREGROUND_STATE.id,
|
|
212
|
+
payload: payload,
|
|
213
|
+
qosLevel: 1,
|
|
214
|
+
});
|
|
215
|
+
if ((0, shared_1.notUndefined)(state.keepAliveTimeout)) {
|
|
216
|
+
mqtt.keepAlive = state.keepAliveTimeout;
|
|
217
|
+
}
|
|
218
|
+
this.enhancedDebug(`✅ Foreground state updated via MQTT!`);
|
|
219
|
+
return result;
|
|
155
220
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
throw err;
|
|
162
|
-
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
this.enhancedDebug(`Foreground state failed: ${err && err.message ? err.message : String(err)}`);
|
|
223
|
+
throw err;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
163
226
|
}
|
|
164
227
|
/**
|
|
165
228
|
* Base command sender (matching instagram_mqtt format)
|
|
166
229
|
* It encodes the command as JSON, compresses, and publishes to SEND_MESSAGE topic.
|
|
230
|
+
* All operations are serialized per-thread via SerialQueue.
|
|
167
231
|
*/
|
|
168
232
|
async sendCommand({ action, data, threadId, clientContext }) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (clientContext) {
|
|
172
|
-
data.client_context = clientContext;
|
|
173
|
-
}
|
|
174
|
-
const json = JSON.stringify({
|
|
175
|
-
action,
|
|
176
|
-
thread_id: threadId,
|
|
177
|
-
...data,
|
|
178
|
-
});
|
|
179
|
-
// ensure Buffer (some compress implementations expect Buffer)
|
|
180
|
-
const payload = await (0, shared_1.compressDeflate)(Buffer.from(json));
|
|
181
|
-
return this.publishToMqtt(mqtt, {
|
|
182
|
-
topic: constants_1.Topics.SEND_MESSAGE.id,
|
|
183
|
-
qosLevel: 1,
|
|
184
|
-
payload: payload,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
catch (err) {
|
|
188
|
-
this.enhancedDebug(`sendCommand failed: ${err && err.message ? err.message : String(err)}`);
|
|
189
|
-
throw err;
|
|
233
|
+
if (clientContext) {
|
|
234
|
+
data.client_context = clientContext;
|
|
190
235
|
}
|
|
236
|
+
const json = JSON.stringify({
|
|
237
|
+
action,
|
|
238
|
+
thread_id: threadId,
|
|
239
|
+
...data,
|
|
240
|
+
});
|
|
241
|
+
const q = this._getThreadQueue(threadId);
|
|
242
|
+
return q.enqueue(action, async () => {
|
|
243
|
+
try {
|
|
244
|
+
const mqtt = this.getMqtt();
|
|
245
|
+
const payload = await (0, shared_1.compressDeflate)(Buffer.from(json));
|
|
246
|
+
return this.publishToMqtt(mqtt, {
|
|
247
|
+
topic: constants_1.Topics.SEND_MESSAGE.id,
|
|
248
|
+
qosLevel: 1,
|
|
249
|
+
payload: payload,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
this.enhancedDebug(`sendCommand failed: ${err && err.message ? err.message : String(err)}`);
|
|
254
|
+
throw err;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
191
257
|
}
|
|
192
258
|
/**
|
|
193
259
|
* Base item sender (matching instagram_mqtt format)
|
|
@@ -206,19 +272,26 @@ class EnhancedDirectCommands {
|
|
|
206
272
|
/**
|
|
207
273
|
* Send text via MQTT
|
|
208
274
|
*/
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
275
|
+
async sendText({ text, clientContext, threadId }) {
|
|
276
|
+
const timestamp = Date.now() * 1000;
|
|
277
|
+
const messageId = `${timestamp}-${Math.random().toString(36).substr(2, 9)}`;
|
|
278
|
+
|
|
279
|
+
const result = await this.sendItem({
|
|
280
|
+
itemType: 'text',
|
|
281
|
+
threadId,
|
|
282
|
+
clientContext: messageId,
|
|
283
|
+
timestamp,
|
|
284
|
+
offline_threading_id: messageId,
|
|
285
|
+
data: {
|
|
286
|
+
text,
|
|
287
|
+
},
|
|
288
|
+
ttl: 0,
|
|
289
|
+
shh_mode: false,
|
|
290
|
+
send_attribution: 'direct_thread',
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
222
295
|
/**
|
|
223
296
|
* Alias for sendText
|
|
224
297
|
*/
|
|
@@ -3,14 +3,78 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DMSender = void 0;
|
|
4
4
|
const shared_1 = require("../../shared");
|
|
5
5
|
const uuid_1 = require("uuid");
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
*SerialQueue — Strictly serial queue with retry and exponential backoff.
|
|
9
|
+
* Used per-thread to serialize MQTT operations and prevent
|
|
10
|
+
* Race conditions and messages lost when reconnecting.
|
|
11
|
+
*/
|
|
12
|
+
class SerialQueue {
|
|
13
|
+
constructor(name) {
|
|
14
|
+
this.name = name;
|
|
15
|
+
this.queue = [];
|
|
16
|
+
this.running = false;
|
|
17
|
+
}
|
|
18
|
+
enqueue(label, fn) {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
this.queue.push({ label, fn, resolve, reject, retries: 0 });
|
|
21
|
+
this._tick();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
_tick() {
|
|
25
|
+
if (this.running || this.queue.length === 0) return;
|
|
26
|
+
this.running = true;
|
|
27
|
+
this._processNext();
|
|
28
|
+
}
|
|
29
|
+
async _processNext() {
|
|
30
|
+
const MAX_RETRIES = 3;
|
|
31
|
+
const BASE_DELAY_MS = 500;
|
|
32
|
+
const item = this.queue[0];
|
|
33
|
+
if (!item) { this.running = false; return; }
|
|
34
|
+
try {
|
|
35
|
+
const result = await item.fn();
|
|
36
|
+
this.queue.shift();
|
|
37
|
+
item.resolve(result);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
if (item.retries < MAX_RETRIES) {
|
|
40
|
+
item.retries++;
|
|
41
|
+
const delay = BASE_DELAY_MS * Math.pow(2, item.retries - 1);
|
|
42
|
+
console.warn(`[Queue:${this.name}] "${item.label}" failed (try ${item.retries}/${MAX_RETRIES}), retry in ${delay}ms:`, err && err.message || err);
|
|
43
|
+
await new Promise(r => setTimeout(r, delay));
|
|
44
|
+
} else {
|
|
45
|
+
console.error(`[Queue:${this.name}] "${item.label}" failed after ${MAX_RETRIES} retries:`, err && err.message || err);
|
|
46
|
+
this.queue.shift();
|
|
47
|
+
item.reject(err);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (this.queue.length > 0) {
|
|
51
|
+
this._processNext();
|
|
52
|
+
} else {
|
|
53
|
+
this.running = false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
6
58
|
/**
|
|
7
59
|
* Direct Message Sender via MQTT
|
|
60
|
+
* All operations are serialized per-thread via SerialQueue.
|
|
8
61
|
*/
|
|
9
62
|
class DMSender {
|
|
10
63
|
constructor(client) {
|
|
11
64
|
this.dmDebug = (0, shared_1.debugChannel)('realtime', 'dm-sender');
|
|
12
65
|
this.client = client;
|
|
66
|
+
//Per-thread queue for DM operations
|
|
67
|
+
this._threadQueues = new Map();
|
|
13
68
|
}
|
|
69
|
+
|
|
70
|
+
/** Returns (or creates) the queue for a specific threadId */
|
|
71
|
+
_getThreadQueue(threadId) {
|
|
72
|
+
if (!this._threadQueues.has(threadId)) {
|
|
73
|
+
this._threadQueues.set(threadId, new SerialQueue(`dm-sender:${threadId}`));
|
|
74
|
+
}
|
|
75
|
+
return this._threadQueues.get(threadId);
|
|
76
|
+
}
|
|
77
|
+
|
|
14
78
|
/**
|
|
15
79
|
* Send text message via MQTT
|
|
16
80
|
*/
|
|
@@ -24,18 +88,22 @@ class DMSender {
|
|
|
24
88
|
timestamp: Date.now(),
|
|
25
89
|
client_context: clientContext || (0, uuid_1.v4)(),
|
|
26
90
|
};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
91
|
+
const q = this._getThreadQueue(threadId);
|
|
92
|
+
return q.enqueue('sendTextMessage', async () => {
|
|
93
|
+
try {
|
|
94
|
+
return await this.client.directCommands?.sendCommand({
|
|
95
|
+
action: 'send_item',
|
|
96
|
+
data: command,
|
|
97
|
+
threadId,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
this.dmDebug(`Failed to send message: ${err.message}`);
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
38
105
|
}
|
|
106
|
+
|
|
39
107
|
/**
|
|
40
108
|
* Send media message via MQTT (photo/video)
|
|
41
109
|
*/
|
|
@@ -49,18 +117,22 @@ class DMSender {
|
|
|
49
117
|
timestamp: Date.now(),
|
|
50
118
|
client_context: clientContext || (0, uuid_1.v4)(),
|
|
51
119
|
};
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
120
|
+
const q = this._getThreadQueue(threadId);
|
|
121
|
+
return q.enqueue('sendMediaMessage', async () => {
|
|
122
|
+
try {
|
|
123
|
+
return await this.client.directCommands?.sendCommand({
|
|
124
|
+
action: 'send_item',
|
|
125
|
+
data: command,
|
|
126
|
+
threadId,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
this.dmDebug(`Failed to send media: ${err.message}`);
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
63
134
|
}
|
|
135
|
+
|
|
64
136
|
/**
|
|
65
137
|
* Send link message
|
|
66
138
|
*/
|
|
@@ -75,17 +147,20 @@ class DMSender {
|
|
|
75
147
|
timestamp: Date.now(),
|
|
76
148
|
client_context: clientContext || (0, uuid_1.v4)(),
|
|
77
149
|
};
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
150
|
+
const q = this._getThreadQueue(threadId);
|
|
151
|
+
return q.enqueue('sendLinkMessage', async () => {
|
|
152
|
+
try {
|
|
153
|
+
return await this.client.directCommands?.sendCommand({
|
|
154
|
+
action: 'send_item',
|
|
155
|
+
data: command,
|
|
156
|
+
threadId,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
this.dmDebug(`Failed to send link: ${err.message}`);
|
|
161
|
+
throw err;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
89
164
|
}
|
|
90
165
|
}
|
|
91
166
|
exports.DMSender = DMSender;
|