@vielhuber/wahelper 1.6.0 → 1.6.2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/wahelper-daemon.js +55 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielhuber/wahelper",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "Lightweight whatsapp integration layer.",
5
5
  "main": "wahelper.js",
6
6
  "files": [
@@ -36,6 +36,7 @@ export default class wahelperDaemon {
36
36
  this.lastError = null;
37
37
  this.isFirstRun = false;
38
38
  this.reconnectDelay = 1000;
39
+ this.consecutiveFailures = 0;
39
40
  this.httpServer = null;
40
41
 
41
42
  if (this.args.device) {
@@ -213,7 +214,9 @@ export default class wahelperDaemon {
213
214
  async storeDataToDatabase(data) {
214
215
  this.log('storeDataToDatabase');
215
216
 
216
- if (!data.messages || data.messages.length === 0) {
217
+ let messages = Array.isArray(data?.messages) ? data.messages : [];
218
+ let chats = Array.isArray(data?.chats) ? data.chats : [];
219
+ if (messages.length === 0 && chats.length === 0) {
217
220
  return;
218
221
  }
219
222
 
@@ -223,9 +226,8 @@ export default class wahelperDaemon {
223
226
  }
224
227
  this.dbLock = true;
225
228
 
226
- //this.log(data.messages);
227
229
  let count = 0,
228
- length = data.messages.length;
230
+ length = messages.length;
229
231
 
230
232
  // if db is closed in the meantime
231
233
  if (this.dbIsOpen === false) {
@@ -241,7 +243,7 @@ export default class wahelperDaemon {
241
243
  VALUES (?, ?, ?, ?, ?, ?, ?)
242
244
  `);
243
245
 
244
- for (let messages__value of data.messages) {
246
+ for (let messages__value of messages) {
245
247
  let id = messages__value.key?.id,
246
248
  chatId = messages__value.key?.remoteJid,
247
249
  fromMe = messages__value.key?.fromMe ? 1 : 0,
@@ -372,6 +374,8 @@ export default class wahelperDaemon {
372
374
  }
373
375
  }
374
376
 
377
+ this.applyReadFlags(messages, chats);
378
+
375
379
  this.db.exec('COMMIT');
376
380
  this.log('END TRANSACTION');
377
381
  if (count > 0) {
@@ -400,6 +404,43 @@ export default class wahelperDaemon {
400
404
  this.dbLock = false;
401
405
  }
402
406
 
407
+ // mark messages as read based on two signals that baileys ships with
408
+ // history-sync and chats.upsert payloads:
409
+ // 1. message.status === READ (=4, sometimes serialised as "READ") —
410
+ // the WA server already knows this message was seen on some device
411
+ // 2. chat.unreadCount === 0 — the user has opened that chat on the
412
+ // phone, so every incoming message there is implicitly seen
413
+ applyReadFlags(messages, chats) {
414
+ let device = this.args.device || 'me';
415
+ let byStatus = this.db.prepare('UPDATE messages SET `read` = 1 WHERE id = ? AND `read` = 0');
416
+ let byChat = this.db.prepare(
417
+ 'UPDATE messages SET `read` = 1 WHERE `read` = 0 AND ((`from` = ? AND `to` = ?) OR (`to` = ? AND `from` != ?))'
418
+ );
419
+
420
+ let touchedStatus = 0;
421
+ for (let m of messages) {
422
+ let s = m?.status;
423
+ if (s !== 4 && s !== '4' && s !== 'READ') continue;
424
+ let id = m?.key?.id;
425
+ if (!id) continue;
426
+ let r = byStatus.run(id);
427
+ if (r?.changes) touchedStatus += r.changes;
428
+ }
429
+
430
+ let touchedChat = 0;
431
+ for (let c of chats) {
432
+ if (c?.unreadCount !== 0) continue;
433
+ let cid = (c?.id ?? '').replace(/@.*$/, '');
434
+ if (!cid) continue;
435
+ let r = byChat.run(cid, device, cid, device);
436
+ if (r?.changes) touchedChat += r.changes;
437
+ }
438
+
439
+ if (touchedStatus > 0 || touchedChat > 0) {
440
+ this.log('marked read: ' + touchedStatus + ' via status, ' + touchedChat + ' via chat.unreadCount=0');
441
+ }
442
+ }
443
+
403
444
  async markMessagesRead(updates) {
404
445
  if (!Array.isArray(updates) || updates.length === 0) {
405
446
  return;
@@ -622,11 +663,16 @@ export default class wahelperDaemon {
622
663
  (reason ? ' (' + reason + ')' : statusCode ? ' (statusCode=' + statusCode + ')' : ''),
623
664
  at: Date.now()
624
665
  };
666
+ this.consecutiveFailures++;
667
+ // first 3 attempts recover network blips fast (1s/2s/4s),
668
+ // after that back off to 15min so a persistent failure
669
+ // (rate-overlimit, bad auth) doesn't keep hammering whatsapp
670
+ let cap = this.consecutiveFailures > 3 ? 15 * 60 * 1000 : 30000;
625
671
  let delay = this.reconnectDelay;
626
- this.log('Reconnecting in ' + delay + 'ms');
627
- console.log('Reconnecting in ' + delay + 'ms...');
672
+ this.log('Reconnecting in ' + delay + 'ms (attempt ' + this.consecutiveFailures + ')');
673
+ console.log('Reconnecting in ' + delay + 'ms (attempt ' + this.consecutiveFailures + ')...');
628
674
  setTimeout(() => {
629
- this.reconnectDelay = Math.min(this.reconnectDelay * 2, 30000);
675
+ this.reconnectDelay = Math.min(this.reconnectDelay * 2, cap);
630
676
  this.connect();
631
677
  }, delay);
632
678
  }
@@ -639,6 +685,7 @@ export default class wahelperDaemon {
639
685
  this.pairingCodeRequested = false;
640
686
  this.lastError = null;
641
687
  this.reconnectDelay = 1000;
688
+ this.consecutiveFailures = 0;
642
689
  this.log('✅ Connected');
643
690
  console.log('✅ Connected (device: ' + this.device + ')');
644
691
  }
@@ -674,10 +721,6 @@ export default class wahelperDaemon {
674
721
 
675
722
  try {
676
723
  if (req.method === 'GET' && url === '/status') {
677
- // trigger connect on first request
678
- if (!this.connected && !this.connecting) {
679
- this.connect();
680
- }
681
724
  this.sendJsonResponse(res, 200, {
682
725
  success: true,
683
726
  connected: this.connected,
@@ -821,7 +864,7 @@ export default class wahelperDaemon {
821
864
  this.initDatabase();
822
865
  this.initExitHooks();
823
866
  this.startHttpServer();
824
- // connect lazily on first incoming request
867
+ this.connect();
825
868
  }
826
869
  }
827
870