@vielhuber/wahelper 1.8.7 → 1.8.8
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/README.md +6 -0
- package/package.json +1 -1
- package/wahelper-daemon.js +43 -21
- package/wahelper.js +51 -20
package/README.md
CHANGED
|
@@ -53,6 +53,9 @@ npx wahelper \
|
|
|
53
53
|
--device "xxxxxxxxxxxx" \
|
|
54
54
|
...
|
|
55
55
|
|
|
56
|
+
# check the live connection
|
|
57
|
+
--action "get_status"
|
|
58
|
+
|
|
56
59
|
# fetch messages
|
|
57
60
|
--action "fetch_messages" \
|
|
58
61
|
--filter '{"from":"491234567890","to":"491234567890","message":"meeting","date_from":"2026-01-01","date_until":"2026-12-31"}' \
|
|
@@ -85,6 +88,9 @@ use vielhuber\wahelper\wahelper;
|
|
|
85
88
|
|
|
86
89
|
$wahelper = new wahelper();
|
|
87
90
|
|
|
91
|
+
// success is true only when connected
|
|
92
|
+
$status = $wahelper->getStatus(device: 'xxxxxxxxxxxx');
|
|
93
|
+
|
|
88
94
|
// fetch messages
|
|
89
95
|
$wahelper->fetchMessages(
|
|
90
96
|
device: 'xxxxxxxxxxxx',
|
package/package.json
CHANGED
package/wahelper-daemon.js
CHANGED
|
@@ -36,6 +36,7 @@ export default class wahelperDaemon {
|
|
|
36
36
|
this.dbLock = false;
|
|
37
37
|
this.connected = false;
|
|
38
38
|
this.connecting = false;
|
|
39
|
+
this.loggedOut = false;
|
|
39
40
|
this.qr = null;
|
|
40
41
|
this.pairingCode = null;
|
|
41
42
|
this.pairingCodeRequested = false;
|
|
@@ -698,8 +699,8 @@ export default class wahelperDaemon {
|
|
|
698
699
|
}
|
|
699
700
|
|
|
700
701
|
async sendMessageToUser(number = null, message = null, attachments = null) {
|
|
701
|
-
if (!this.connected
|
|
702
|
-
throw new Error('not_connected');
|
|
702
|
+
if (!this.getStatus().connected) {
|
|
703
|
+
throw new Error(this.loggedOut ? 'logged_out' : 'not_connected');
|
|
703
704
|
}
|
|
704
705
|
// validate all attachments exist before sending anything
|
|
705
706
|
if (attachments !== null && attachments.length > 0) {
|
|
@@ -724,8 +725,8 @@ export default class wahelperDaemon {
|
|
|
724
725
|
}
|
|
725
726
|
|
|
726
727
|
async sendMessageToGroup(name = null, message = null, attachments = null) {
|
|
727
|
-
if (!this.connected
|
|
728
|
-
throw new Error('not_connected');
|
|
728
|
+
if (!this.getStatus().connected) {
|
|
729
|
+
throw new Error(this.loggedOut ? 'logged_out' : 'not_connected');
|
|
729
730
|
}
|
|
730
731
|
// validate all attachments exist before sending anything
|
|
731
732
|
if (attachments !== null && attachments.length > 0) {
|
|
@@ -756,7 +757,7 @@ export default class wahelperDaemon {
|
|
|
756
757
|
}
|
|
757
758
|
|
|
758
759
|
connect() {
|
|
759
|
-
if (this.connecting) {
|
|
760
|
+
if (this.connecting || this.loggedOut) {
|
|
760
761
|
return;
|
|
761
762
|
}
|
|
762
763
|
this.connecting = true;
|
|
@@ -885,10 +886,16 @@ export default class wahelperDaemon {
|
|
|
885
886
|
socket
|
|
886
887
|
.requestPairingCode(this.device)
|
|
887
888
|
.then(code => {
|
|
889
|
+
if (this.sock !== socket) {
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
888
892
|
this.pairingCode = code;
|
|
889
893
|
console.log('\nPairing code: ' + code);
|
|
890
894
|
})
|
|
891
895
|
.catch(err => {
|
|
896
|
+
if (this.sock !== socket) {
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
892
899
|
this.lastError = { source: 'pairing', message: err.message, at: Date.now() };
|
|
893
900
|
this.log('Pairing code request failed: ' + err.message);
|
|
894
901
|
});
|
|
@@ -917,16 +924,19 @@ export default class wahelperDaemon {
|
|
|
917
924
|
}
|
|
918
925
|
|
|
919
926
|
if (statusCode === DisconnectReason.loggedOut) {
|
|
920
|
-
|
|
927
|
+
this.loggedOut = true;
|
|
928
|
+
this.sock = null;
|
|
921
929
|
this.qr = null;
|
|
922
930
|
this.pairingCode = null;
|
|
923
931
|
this.pairingCodeRequested = false;
|
|
924
|
-
this.
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
932
|
+
this.lastError = {
|
|
933
|
+
source: 'disconnect',
|
|
934
|
+
message: 'Logged out. Automatic reconnect stopped; manual device linking required.',
|
|
935
|
+
statusCode,
|
|
936
|
+
at: Date.now()
|
|
937
|
+
};
|
|
938
|
+
this.log(this.lastError);
|
|
939
|
+
console.error(this.lastError.message);
|
|
930
940
|
return;
|
|
931
941
|
}
|
|
932
942
|
|
|
@@ -949,10 +959,16 @@ export default class wahelperDaemon {
|
|
|
949
959
|
source: 'disconnect',
|
|
950
960
|
message:
|
|
951
961
|
'connection closed' +
|
|
952
|
-
(reason
|
|
962
|
+
(reason
|
|
963
|
+
? ' (' + reason + ')'
|
|
964
|
+
: statusCode
|
|
965
|
+
? ' (statusCode=' + statusCode + ')'
|
|
966
|
+
: ''),
|
|
967
|
+
statusCode,
|
|
953
968
|
at: Date.now()
|
|
954
969
|
};
|
|
955
970
|
}
|
|
971
|
+
this.log(this.lastError);
|
|
956
972
|
this.consecutiveFailures++;
|
|
957
973
|
// first 3 attempts recover network blips fast (1s/2s/4s),
|
|
958
974
|
// after that back off to 15min so a persistent failure
|
|
@@ -1000,6 +1016,19 @@ export default class wahelperDaemon {
|
|
|
1000
1016
|
});
|
|
1001
1017
|
}
|
|
1002
1018
|
|
|
1019
|
+
getStatus() {
|
|
1020
|
+
return {
|
|
1021
|
+
success: true,
|
|
1022
|
+
connected: this.connected && this.sock?.ws?.isOpen === true,
|
|
1023
|
+
connecting: this.connecting,
|
|
1024
|
+
loggedOut: this.loggedOut,
|
|
1025
|
+
device: this.device,
|
|
1026
|
+
qr: this.qr,
|
|
1027
|
+
pairingCode: this.pairingCode,
|
|
1028
|
+
lastError: this.lastError
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1003
1032
|
startHttpServer() {
|
|
1004
1033
|
this.httpServer = http.createServer(async (req, res) => {
|
|
1005
1034
|
// bound to 127.0.0.1 below — every request additionally has to
|
|
@@ -1025,14 +1054,7 @@ export default class wahelperDaemon {
|
|
|
1025
1054
|
this.sendJsonResponse(res, 403, { success: false, message: 'forbidden' });
|
|
1026
1055
|
return;
|
|
1027
1056
|
}
|
|
1028
|
-
this.sendJsonResponse(res, 200,
|
|
1029
|
-
success: true,
|
|
1030
|
-
connected: this.connected,
|
|
1031
|
-
device: this.device,
|
|
1032
|
-
qr: this.qr,
|
|
1033
|
-
pairingCode: this.pairingCode,
|
|
1034
|
-
lastError: this.lastError
|
|
1035
|
-
});
|
|
1057
|
+
this.sendJsonResponse(res, 200, this.getStatus());
|
|
1036
1058
|
return;
|
|
1037
1059
|
}
|
|
1038
1060
|
|
package/wahelper.js
CHANGED
|
@@ -53,6 +53,28 @@ export default class wahelper {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
async init() {
|
|
56
|
+
if (this.args.action === 'get_status') {
|
|
57
|
+
let status = this.args.device
|
|
58
|
+
? await this.callDaemon('GET', '/status')
|
|
59
|
+
: { success: false, message: 'missing_device' };
|
|
60
|
+
let connected = status.connected === true;
|
|
61
|
+
let response = {
|
|
62
|
+
success: connected,
|
|
63
|
+
message: connected ? 'connected' : status.loggedOut ? 'logged_out' : status.message || 'not_connected',
|
|
64
|
+
public_message: status.lastError?.message ?? null,
|
|
65
|
+
data: {
|
|
66
|
+
connected,
|
|
67
|
+
connecting: status.connecting === true,
|
|
68
|
+
loggedOut: status.loggedOut === true,
|
|
69
|
+
pairingRequired: status.loggedOut === true || Boolean(status.pairingCode || status.qr),
|
|
70
|
+
lastError: status.lastError ?? null
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
this.write(response, false);
|
|
74
|
+
console.log(JSON.stringify(response));
|
|
75
|
+
process.exitCode = connected ? 0 : 1;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
56
78
|
await this.awaitLock('init', true);
|
|
57
79
|
this.setLock('init', true);
|
|
58
80
|
this.write({ success: false, message: 'loading_state', data: null }, false);
|
|
@@ -127,7 +149,11 @@ export default class wahelper {
|
|
|
127
149
|
console.log('\n⚠️ Pairing required. Scan the QR code with WhatsApp, then retry.\n');
|
|
128
150
|
console.log(daemonStatus.qrString);
|
|
129
151
|
}
|
|
130
|
-
if (
|
|
152
|
+
if (
|
|
153
|
+
daemonStatus.message === 'daemon_error' ||
|
|
154
|
+
daemonStatus.message === 'daemon_timeout' ||
|
|
155
|
+
daemonStatus.message === 'logged_out'
|
|
156
|
+
) {
|
|
131
157
|
console.log('⛔ ' + (daemonStatus.public_message || daemonStatus.message));
|
|
132
158
|
}
|
|
133
159
|
this.write(
|
|
@@ -316,26 +342,25 @@ export default class wahelper {
|
|
|
316
342
|
}
|
|
317
343
|
|
|
318
344
|
async ensureDaemon() {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
if (status.connected) {
|
|
328
|
-
return status;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// poll up to 30s — return immediately when pairing code appears
|
|
332
|
-
console.log('Waiting for daemon to connect...');
|
|
333
|
-
for (let i = 0; i < 30; i++) {
|
|
334
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
335
|
-
status = await this.callDaemon('GET', '/status');
|
|
345
|
+
for (let i = 0; i <= 30; i++) {
|
|
346
|
+
let status = await this.callDaemon('GET', '/status');
|
|
347
|
+
if (status.success === false) {
|
|
348
|
+
return {
|
|
349
|
+
connected: false,
|
|
350
|
+
message: status.message === 'daemon_not_reachable' ? 'daemon_not_running' : status.message
|
|
351
|
+
};
|
|
352
|
+
}
|
|
336
353
|
if (status.connected) {
|
|
337
354
|
return status;
|
|
338
355
|
}
|
|
356
|
+
if (status.loggedOut) {
|
|
357
|
+
return {
|
|
358
|
+
connected: false,
|
|
359
|
+
message: 'logged_out',
|
|
360
|
+
public_message: status.lastError?.message,
|
|
361
|
+
data: status.lastError
|
|
362
|
+
};
|
|
363
|
+
}
|
|
339
364
|
if (status.pairingCode) {
|
|
340
365
|
return { connected: false, message: 'pairing_required', pairingCode: status.pairingCode };
|
|
341
366
|
}
|
|
@@ -353,6 +378,12 @@ export default class wahelper {
|
|
|
353
378
|
data: status.lastError
|
|
354
379
|
};
|
|
355
380
|
}
|
|
381
|
+
if (i === 0) {
|
|
382
|
+
console.log('Waiting for daemon to connect...');
|
|
383
|
+
}
|
|
384
|
+
if (i < 30) {
|
|
385
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
386
|
+
}
|
|
356
387
|
}
|
|
357
388
|
return { connected: false, message: 'daemon_timeout' };
|
|
358
389
|
}
|
|
@@ -400,7 +431,7 @@ export default class wahelper {
|
|
|
400
431
|
}
|
|
401
432
|
});
|
|
402
433
|
});
|
|
403
|
-
req.setTimeout(30000, () => {
|
|
434
|
+
req.setTimeout(path === '/status' ? 5000 : 30000, () => {
|
|
404
435
|
req.destroy();
|
|
405
436
|
this.log('⛔ Daemon request timeout');
|
|
406
437
|
resolve({ success: false, message: 'daemon_timeout' });
|
|
@@ -642,6 +673,6 @@ if (
|
|
|
642
673
|
) {
|
|
643
674
|
let wa = new wahelper();
|
|
644
675
|
wa.init()
|
|
645
|
-
.then(() => process.exit(0))
|
|
676
|
+
.then(() => process.exit(process.exitCode ?? 0))
|
|
646
677
|
.catch(() => process.exit(1));
|
|
647
678
|
}
|