zklib-ts 1.0.6 → 1.0.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/dist/helper/command.d.ts +11 -5
- package/dist/helper/terminal.d.ts +541 -0
- package/dist/helper/utils.d.ts +42 -5
- package/dist/index.cjs.js +1593 -873
- package/dist/index.d.ts +7 -6
- package/dist/index.es.js +1593 -873
- package/dist/models/Attendance.d.ts +3 -0
- package/dist/models/Finger.d.ts +2 -1
- package/dist/services/options.service.d.ts +49 -0
- package/dist/services/transaction.service.d.ts +1 -1
- package/dist/services/user.service.d.ts +4 -4
- package/dist/ztcp.cjs.js +802 -0
- package/dist/ztcp.d.ts +16 -37
- package/dist/ztcp.js +800 -0
- package/dist/zudp.cjs.js +531 -0
- package/dist/zudp.d.ts +2 -2
- package/dist/zudp.js +510 -0
- package/package.json +87 -69
package/dist/index.cjs.js
CHANGED
|
@@ -43,7 +43,7 @@ var COMMANDS;
|
|
|
43
43
|
COMMANDS[COMMANDS["CMD_ATTLOG_RRQ"] = 13] = "CMD_ATTLOG_RRQ";
|
|
44
44
|
/** [0x4E, 0x04] Request to begin session using commkey. */
|
|
45
45
|
COMMANDS[COMMANDS["CMD_AUTH"] = 1102] = "CMD_AUTH";
|
|
46
|
-
/** Disable normal authentication of users. */
|
|
46
|
+
/** [0x3e, 0x00] Disable normal authentication of users. */
|
|
47
47
|
COMMANDS[COMMANDS["CMD_CANCELCAPTURE"] = 62] = "CMD_CANCELCAPTURE";
|
|
48
48
|
/** Capture fingerprint picture. */
|
|
49
49
|
COMMANDS[COMMANDS["CMD_CAPTUREFINGER"] = 1009] = "CMD_CAPTUREFINGER";
|
|
@@ -140,9 +140,9 @@ var COMMANDS;
|
|
|
140
140
|
COMMANDS[COMMANDS["CMD_SMS_RRQ"] = 71] = "CMD_SMS_RRQ";
|
|
141
141
|
/** Upload short message. */
|
|
142
142
|
COMMANDS[COMMANDS["CMD_SMS_WRQ"] = 70] = "CMD_SMS_WRQ";
|
|
143
|
-
/** Start enroll procedure. */
|
|
143
|
+
/** [0x3d, 0x00] Start enroll procedure. */
|
|
144
144
|
COMMANDS[COMMANDS["CMD_STARTENROLL"] = 61] = "CMD_STARTENROLL";
|
|
145
|
-
/** Set the machine to authentication state. */
|
|
145
|
+
/** [0x3c, 0x00] Set the machine to authentication state. */
|
|
146
146
|
COMMANDS[COMMANDS["CMD_STARTVERIFY"] = 60] = "CMD_STARTVERIFY";
|
|
147
147
|
/** Query state. */
|
|
148
148
|
COMMANDS[COMMANDS["CMD_STATE_RRQ"] = 64] = "CMD_STATE_RRQ";
|
|
@@ -186,29 +186,36 @@ var COMMANDS;
|
|
|
186
186
|
COMMANDS[COMMANDS["CMD_WRITE_LCD"] = 66] = "CMD_WRITE_LCD";
|
|
187
187
|
/** Write data to Mifare card. */
|
|
188
188
|
COMMANDS[COMMANDS["CMD_WRITE_MIFARE"] = 76] = "CMD_WRITE_MIFARE";
|
|
189
|
+
})(COMMANDS || (COMMANDS = {}));
|
|
190
|
+
var RTEvent;
|
|
191
|
+
(function (RTEvent) {
|
|
189
192
|
/** Triggered alarm. */
|
|
190
|
-
|
|
193
|
+
RTEvent[RTEvent["EF_ALARM"] = 512] = "EF_ALARM";
|
|
191
194
|
/** Attendance entry. */
|
|
192
|
-
|
|
195
|
+
RTEvent[RTEvent["EF_ATTLOG"] = 1] = "EF_ATTLOG";
|
|
193
196
|
/** Pressed keyboard key. */
|
|
194
|
-
|
|
197
|
+
RTEvent[RTEvent["EF_BUTTON"] = 16] = "EF_BUTTON";
|
|
195
198
|
/** Upload user data. */
|
|
196
|
-
|
|
199
|
+
RTEvent[RTEvent["EF_ENROLLFINGER"] = 8] = "EF_ENROLLFINGER";
|
|
197
200
|
/** Enrolled user. */
|
|
198
|
-
|
|
201
|
+
RTEvent[RTEvent["EF_ENROLLUSER"] = 4] = "EF_ENROLLUSER";
|
|
199
202
|
/** Pressed finger. */
|
|
200
|
-
|
|
203
|
+
RTEvent[RTEvent["EF_FINGER"] = 2] = "EF_FINGER";
|
|
201
204
|
/** Fingerprint score in enroll procedure. */
|
|
202
|
-
|
|
205
|
+
RTEvent[RTEvent["EF_FPFTR"] = 256] = "EF_FPFTR";
|
|
203
206
|
/** Restore access control to default. */
|
|
204
|
-
|
|
207
|
+
RTEvent[RTEvent["EF_UNLOCK"] = 32] = "EF_UNLOCK";
|
|
205
208
|
/** Registered user placed finger. */
|
|
206
|
-
|
|
207
|
-
})(
|
|
209
|
+
RTEvent[RTEvent["EF_VERIFY"] = 128] = "EF_VERIFY";
|
|
210
|
+
})(RTEvent || (RTEvent = {}));
|
|
208
211
|
var DISCOVERED_CMD;
|
|
209
212
|
(function (DISCOVERED_CMD) {
|
|
213
|
+
/** [0x7f, 0x13] */
|
|
214
|
+
DISCOVERED_CMD[DISCOVERED_CMD["UNKNOWN"] = 4991] = "UNKNOWN";
|
|
210
215
|
/** Returned when the Finger id not exists in the user uid, when attempting to download single finger template */
|
|
211
216
|
DISCOVERED_CMD[DISCOVERED_CMD["FID_NOT_FOUND"] = 4993] = "FID_NOT_FOUND";
|
|
217
|
+
/** [0x87, 0x13] i guess is an error reply code, is returned when attempint to read options ~isABCPinEnable and ~T9FunOn */
|
|
218
|
+
DISCOVERED_CMD[DISCOVERED_CMD["UNKNOWN_OR_NOT_SUPPORTED"] = 4999] = "UNKNOWN_OR_NOT_SUPPORTED";
|
|
212
219
|
})(DISCOVERED_CMD || (DISCOVERED_CMD = {}));
|
|
213
220
|
var Constants;
|
|
214
221
|
(function (Constants) {
|
|
@@ -227,33 +234,57 @@ const REQUEST_DATA = {
|
|
|
227
234
|
};
|
|
228
235
|
|
|
229
236
|
/**
|
|
230
|
-
*
|
|
231
|
-
* @param {number} time
|
|
237
|
+
* Error types for device communication
|
|
232
238
|
*/
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const minute = time % 60;
|
|
237
|
-
time = (time - minute) / 60;
|
|
238
|
-
const hour = time % 24;
|
|
239
|
-
time = (time - hour) / 24;
|
|
240
|
-
const day = time % 31 + 1;
|
|
241
|
-
time = (time - (day - 1)) / 31;
|
|
242
|
-
const month = time % 12;
|
|
243
|
-
time = (time - month) / 12;
|
|
244
|
-
const year = time + 2000;
|
|
245
|
-
return new Date(year, month, day, hour, minute, second);
|
|
246
|
-
};
|
|
239
|
+
const ERROR_TYPES = {
|
|
240
|
+
ECONNRESET: 'ECONNRESET',
|
|
241
|
+
ECONNREFUSED: 'ECONNREFUSED'};
|
|
247
242
|
/**
|
|
248
|
-
*
|
|
249
|
-
* @param {Date} date
|
|
243
|
+
* Custom error class for device communication errors
|
|
250
244
|
*/
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
245
|
+
class ZkError {
|
|
246
|
+
err;
|
|
247
|
+
ip;
|
|
248
|
+
command;
|
|
249
|
+
/**
|
|
250
|
+
* Creates a new ZkError instance
|
|
251
|
+
* @param err The error object
|
|
252
|
+
* @param command The command that caused the error
|
|
253
|
+
* @param ip The IP address of the device
|
|
254
|
+
*/
|
|
255
|
+
constructor(err, command, ip) {
|
|
256
|
+
this.err = err;
|
|
257
|
+
this.ip = ip;
|
|
258
|
+
this.command = command;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Gets a user-friendly error message
|
|
262
|
+
* @returns A formatted error message
|
|
263
|
+
*/
|
|
264
|
+
toast() {
|
|
265
|
+
if (this.err.code === ERROR_TYPES.ECONNRESET) {
|
|
266
|
+
return 'Another device is connecting to the device so the connection is interrupted';
|
|
267
|
+
}
|
|
268
|
+
else if (this.err.code === ERROR_TYPES.ECONNREFUSED) {
|
|
269
|
+
return 'IP of the device is refused';
|
|
270
|
+
}
|
|
271
|
+
return this.err.message;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Gets detailed error information
|
|
275
|
+
* @returns An object containing error details
|
|
276
|
+
*/
|
|
277
|
+
getError() {
|
|
278
|
+
return {
|
|
279
|
+
err: {
|
|
280
|
+
message: this.err.message,
|
|
281
|
+
code: this.err.code
|
|
282
|
+
},
|
|
283
|
+
ip: this.ip,
|
|
284
|
+
command: this.command
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
257
288
|
|
|
258
289
|
const parseCurrentTime = () => {
|
|
259
290
|
const currentTime = new Date();
|
|
@@ -295,7 +326,7 @@ class User {
|
|
|
295
326
|
* @param user_id Alternate user ID (default: "")
|
|
296
327
|
* @param card Card number (default: 0)
|
|
297
328
|
*/
|
|
298
|
-
constructor(uid, name, privilege, password =
|
|
329
|
+
constructor(uid, name, privilege, password = '', group_id = '', user_id = '', card = 0) {
|
|
299
330
|
this.uid = uid;
|
|
300
331
|
this.name = name;
|
|
301
332
|
this.privilege = privilege;
|
|
@@ -365,6 +396,9 @@ class User {
|
|
|
365
396
|
}
|
|
366
397
|
}
|
|
367
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Represents an Attendance Records
|
|
401
|
+
*/
|
|
368
402
|
class Attendance {
|
|
369
403
|
/** Internal serial number for the user */
|
|
370
404
|
sn;
|
|
@@ -393,7 +427,7 @@ const parseHexToTime = (hex) => {
|
|
|
393
427
|
date: hex.readUIntLE(2, 1),
|
|
394
428
|
hour: hex.readUIntLE(3, 1),
|
|
395
429
|
minute: hex.readUIntLE(4, 1),
|
|
396
|
-
second: hex.readUIntLE(5, 1)
|
|
430
|
+
second: hex.readUIntLE(5, 1),
|
|
397
431
|
};
|
|
398
432
|
return new Date(2000 + time.year, time.month - 1, time.date, time.hour, time.minute, time.second);
|
|
399
433
|
};
|
|
@@ -427,7 +461,9 @@ const createUDPHeader = (command, sessionId, replyId, data) => {
|
|
|
427
461
|
};
|
|
428
462
|
const createTCPHeader = (command, sessionId, replyId, data) => {
|
|
429
463
|
const buf = createUDPHeader(command, sessionId, replyId, data);
|
|
430
|
-
const prefixBuf = Buffer.from([
|
|
464
|
+
const prefixBuf = Buffer.from([
|
|
465
|
+
0x50, 0x50, 0x82, 0x7d, 0x13, 0x00, 0x00, 0x00,
|
|
466
|
+
]);
|
|
431
467
|
prefixBuf.writeUInt16LE(buf.length, 4);
|
|
432
468
|
return Buffer.concat([prefixBuf, buf]);
|
|
433
469
|
};
|
|
@@ -447,7 +483,7 @@ const parseTimeToDate = (time) => {
|
|
|
447
483
|
time = (time - minute) / 60;
|
|
448
484
|
const hour = time % 24;
|
|
449
485
|
time = (time - hour) / 24;
|
|
450
|
-
const day = time % 31 + 1;
|
|
486
|
+
const day = (time % 31) + 1;
|
|
451
487
|
time = (time - (day - 1)) / 31;
|
|
452
488
|
const month = time % 12;
|
|
453
489
|
time = (time - month) / 12;
|
|
@@ -460,38 +496,34 @@ const decodeUserData28 = (userData) => {
|
|
|
460
496
|
privilege: userData.readUIntLE(2, 1),
|
|
461
497
|
name: userData
|
|
462
498
|
.slice(8, 8 + 8)
|
|
463
|
-
.toString(
|
|
464
|
-
.split(
|
|
465
|
-
.shift() ||
|
|
499
|
+
.toString("ascii")
|
|
500
|
+
.split("\0")
|
|
501
|
+
.shift() || "",
|
|
466
502
|
user_id: userData.readUIntLE(24, 4).toString(),
|
|
467
503
|
};
|
|
468
504
|
};
|
|
469
505
|
const decodeUserData72 = (userData) => {
|
|
470
|
-
return new User(userData.readUIntLE(0, 2), userData
|
|
471
|
-
.slice(11)
|
|
472
|
-
.toString('ascii')
|
|
473
|
-
.split('\0')
|
|
474
|
-
.shift() || '', userData.readUIntLE(2, 1), userData
|
|
506
|
+
return new User(userData.readUIntLE(0, 2), userData.slice(11).toString("ascii").split("\0").shift() || "", userData.readUIntLE(2, 1), userData
|
|
475
507
|
.subarray(3, 3 + 8)
|
|
476
|
-
.toString(
|
|
477
|
-
.split(
|
|
478
|
-
.shift() ||
|
|
508
|
+
.toString("ascii")
|
|
509
|
+
.split("\0")
|
|
510
|
+
.shift() || "", userData.readUIntLE(39, 1), userData
|
|
479
511
|
.slice(48, 48 + 9)
|
|
480
|
-
.toString(
|
|
481
|
-
.split(
|
|
482
|
-
.shift() ||
|
|
512
|
+
.toString("ascii")
|
|
513
|
+
.split("\0")
|
|
514
|
+
.shift() || "", userData.readUIntLE(35, 4));
|
|
483
515
|
};
|
|
484
516
|
const decodeRecordData40 = (recordData) => {
|
|
485
517
|
return new Attendance(recordData.readUIntLE(0, 2), recordData
|
|
486
518
|
.slice(2, 2 + 9)
|
|
487
|
-
.toString(
|
|
488
|
-
.split(
|
|
489
|
-
.shift() ||
|
|
519
|
+
.toString("ascii")
|
|
520
|
+
.split("\0")
|
|
521
|
+
.shift() || "", recordData.readUIntLE(26, 1), parseTimeToDate(recordData.readUInt32LE(27)), recordData.readUIntLE(31, 1));
|
|
490
522
|
};
|
|
491
523
|
const decodeRecordData16 = (recordData) => {
|
|
492
524
|
return {
|
|
493
525
|
user_id: recordData.readUIntLE(0, 2).toString(),
|
|
494
|
-
record_time: parseTimeToDate(recordData.readUInt32LE(4))
|
|
526
|
+
record_time: parseTimeToDate(recordData.readUInt32LE(4)),
|
|
495
527
|
};
|
|
496
528
|
};
|
|
497
529
|
const decodeRecordRealTimeLog18 = (recordData) => {
|
|
@@ -499,22 +531,12 @@ const decodeRecordRealTimeLog18 = (recordData) => {
|
|
|
499
531
|
const record_time = parseHexToTime(recordData.subarray(12, 18));
|
|
500
532
|
return { user_id, record_time };
|
|
501
533
|
};
|
|
502
|
-
const decodeRecordRealTimeLog52 = (recordData) => {
|
|
503
|
-
const payload = removeTcpHeader(recordData);
|
|
504
|
-
const recvData = payload.subarray(8);
|
|
505
|
-
const user_id = recvData.slice(0, 9)
|
|
506
|
-
.toString('ascii')
|
|
507
|
-
.split('\0')
|
|
508
|
-
.shift() || '';
|
|
509
|
-
const record_time = parseHexToTime(recvData.subarray(26, 26 + 6));
|
|
510
|
-
return { user_id, record_time };
|
|
511
|
-
};
|
|
512
534
|
const decodeUDPHeader = (header) => {
|
|
513
535
|
return {
|
|
514
536
|
commandId: header.readUIntLE(0, 2),
|
|
515
537
|
checkSum: header.readUIntLE(2, 2),
|
|
516
538
|
sessionId: header.readUIntLE(4, 2),
|
|
517
|
-
replyId: header.readUIntLE(6, 2)
|
|
539
|
+
replyId: header.readUIntLE(6, 2),
|
|
518
540
|
};
|
|
519
541
|
};
|
|
520
542
|
const decodeTCPHeader = (header) => {
|
|
@@ -525,7 +547,7 @@ const decodeTCPHeader = (header) => {
|
|
|
525
547
|
checkSum: recvData.readUIntLE(2, 2),
|
|
526
548
|
sessionId: recvData.readUIntLE(4, 2),
|
|
527
549
|
replyId: recvData.readUIntLE(6, 2),
|
|
528
|
-
payloadSize
|
|
550
|
+
payloadSize,
|
|
529
551
|
};
|
|
530
552
|
};
|
|
531
553
|
const exportErrorMessage = (commandValue) => {
|
|
@@ -535,17 +557,18 @@ const exportErrorMessage = (commandValue) => {
|
|
|
535
557
|
return key.toString();
|
|
536
558
|
}
|
|
537
559
|
}
|
|
538
|
-
return
|
|
560
|
+
return "AN UNKNOWN ERROR";
|
|
539
561
|
};
|
|
562
|
+
const isRTEvent = (event) => Object.values(RTEvent).includes(event);
|
|
540
563
|
const checkNotEventTCP = (data) => {
|
|
541
564
|
try {
|
|
542
565
|
const cleanedData = removeTcpHeader(data);
|
|
543
566
|
const commandId = cleanedData.readUIntLE(0, 2);
|
|
544
567
|
const event = cleanedData.readUIntLE(4, 2);
|
|
545
|
-
return event
|
|
568
|
+
return isRTEvent(event) && commandId === COMMANDS.CMD_REG_EVENT;
|
|
546
569
|
}
|
|
547
570
|
catch (err) {
|
|
548
|
-
log(`[228] : ${err.toString()} ,${data.toString(
|
|
571
|
+
log(`[228] : ${err.toString()} ,${data.toString("hex")} `);
|
|
549
572
|
return false;
|
|
550
573
|
}
|
|
551
574
|
};
|
|
@@ -553,6 +576,42 @@ const checkNotEventUDP = (data) => {
|
|
|
553
576
|
const { commandId } = decodeUDPHeader(data.subarray(0, 8));
|
|
554
577
|
return commandId === COMMANDS.CMD_REG_EVENT;
|
|
555
578
|
};
|
|
579
|
+
const decodeRTEvent = (data) => {
|
|
580
|
+
const header = decodeTCPHeader(data);
|
|
581
|
+
console.log(header);
|
|
582
|
+
const event = header.sessionId;
|
|
583
|
+
const recvData = data.subarray(16);
|
|
584
|
+
const build = {
|
|
585
|
+
alarm4bytes: function (data) {
|
|
586
|
+
return {
|
|
587
|
+
alarm_type: data.readUintLE(0, 4),
|
|
588
|
+
alarm_cause: data.readUintLE(4, 2),
|
|
589
|
+
user_uid: data.readUintLE(6, 2),
|
|
590
|
+
match_type: data.readUintLE(8, 4),
|
|
591
|
+
};
|
|
592
|
+
},
|
|
593
|
+
enrolledFinger: function (data) {
|
|
594
|
+
return {
|
|
595
|
+
result: data.readUIntLE(0, 2),
|
|
596
|
+
size: data.readUintLE(2, 2),
|
|
597
|
+
pin: data.subarray(4, 4 + 9).toString("ascii"),
|
|
598
|
+
fid: data.readUIntLE(1, 13),
|
|
599
|
+
};
|
|
600
|
+
},
|
|
601
|
+
fingerScore: function (data) {
|
|
602
|
+
return { score: data.readUintLE(0, 1) };
|
|
603
|
+
},
|
|
604
|
+
};
|
|
605
|
+
switch (event) {
|
|
606
|
+
case RTEvent.EF_FINGER:
|
|
607
|
+
return { event };
|
|
608
|
+
case RTEvent.EF_FPFTR:
|
|
609
|
+
return { event, payload: build.fingerScore(recvData) };
|
|
610
|
+
default:
|
|
611
|
+
console.log("utils linea 284");
|
|
612
|
+
break;
|
|
613
|
+
}
|
|
614
|
+
};
|
|
556
615
|
const makeKey = (key, sessionId) => {
|
|
557
616
|
let k = 0;
|
|
558
617
|
for (let i = 0; i < 32; i++) {
|
|
@@ -565,30 +624,30 @@ const makeKey = (key, sessionId) => {
|
|
|
565
624
|
}
|
|
566
625
|
k += sessionId;
|
|
567
626
|
let hex = k.toString(16).padStart(8, "0");
|
|
568
|
-
|
|
627
|
+
const response = new Uint8Array(4);
|
|
569
628
|
let index = 3;
|
|
570
629
|
while (hex.length > 0) {
|
|
571
630
|
response[index] = parseInt(hex.substring(0, 2), 16);
|
|
572
631
|
index--;
|
|
573
632
|
hex = hex.substring(2);
|
|
574
633
|
}
|
|
575
|
-
response[0] ^=
|
|
576
|
-
response[1] ^=
|
|
577
|
-
response[2] ^=
|
|
578
|
-
response[3] ^=
|
|
634
|
+
response[0] ^= "Z".charCodeAt(0);
|
|
635
|
+
response[1] ^= "K".charCodeAt(0);
|
|
636
|
+
response[2] ^= "S".charCodeAt(0);
|
|
637
|
+
response[3] ^= "O".charCodeAt(0);
|
|
579
638
|
let finalKey = response[0] +
|
|
580
639
|
(response[1] << 8) +
|
|
581
640
|
(response[2] << 16) +
|
|
582
641
|
(response[3] << 24);
|
|
583
|
-
|
|
642
|
+
const swp = finalKey >>> 16;
|
|
584
643
|
finalKey = (finalKey << 16) | swp;
|
|
585
644
|
return finalKey >>> 0;
|
|
586
645
|
};
|
|
587
646
|
const authKey = (comKey, sessionId) => {
|
|
588
|
-
|
|
589
|
-
|
|
647
|
+
const k = makeKey(comKey, sessionId) >>> 0;
|
|
648
|
+
const rand = Math.floor(Math.random() * 256);
|
|
590
649
|
let hex = k.toString(16).padStart(8, "0");
|
|
591
|
-
|
|
650
|
+
const response = new Uint8Array(4);
|
|
592
651
|
let index = 3;
|
|
593
652
|
while (index >= 0) {
|
|
594
653
|
response[index] = parseInt(hex.substring(0, 2), 16);
|
|
@@ -601,59 +660,17 @@ const authKey = (comKey, sessionId) => {
|
|
|
601
660
|
response[3] ^= rand;
|
|
602
661
|
return Array.from(response);
|
|
603
662
|
};
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
err;
|
|
616
|
-
ip;
|
|
617
|
-
command;
|
|
618
|
-
/**
|
|
619
|
-
* Creates a new ZkError instance
|
|
620
|
-
* @param err The error object
|
|
621
|
-
* @param command The command that caused the error
|
|
622
|
-
* @param ip The IP address of the device
|
|
623
|
-
*/
|
|
624
|
-
constructor(err, command, ip) {
|
|
625
|
-
this.err = err;
|
|
626
|
-
this.ip = ip;
|
|
627
|
-
this.command = command;
|
|
628
|
-
}
|
|
629
|
-
/**
|
|
630
|
-
* Gets a user-friendly error message
|
|
631
|
-
* @returns A formatted error message
|
|
632
|
-
*/
|
|
633
|
-
toast() {
|
|
634
|
-
if (this.err.code === ERROR_TYPES.ECONNRESET) {
|
|
635
|
-
return 'Another device is connecting to the device so the connection is interrupted';
|
|
636
|
-
}
|
|
637
|
-
else if (this.err.code === ERROR_TYPES.ECONNREFUSED) {
|
|
638
|
-
return 'IP of the device is refused';
|
|
639
|
-
}
|
|
640
|
-
return this.err.message;
|
|
641
|
-
}
|
|
642
|
-
/**
|
|
643
|
-
* Gets detailed error information
|
|
644
|
-
* @returns An object containing error details
|
|
645
|
-
*/
|
|
646
|
-
getError() {
|
|
647
|
-
return {
|
|
648
|
-
err: {
|
|
649
|
-
message: this.err.message,
|
|
650
|
-
code: this.err.code
|
|
651
|
-
},
|
|
652
|
-
ip: this.ip,
|
|
653
|
-
command: this.command
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
}
|
|
663
|
+
/** Some Tcp packets receibed by the socket client can be merged in one single data event by the OS, and we need to split to handle correctly */
|
|
664
|
+
const splitTcpPackets = (data) => {
|
|
665
|
+
const packets = [];
|
|
666
|
+
let unProcessed = data;
|
|
667
|
+
while (unProcessed.length > 0) {
|
|
668
|
+
const headers = decodeTCPHeader(unProcessed);
|
|
669
|
+
packets.push(unProcessed.subarray(0, headers.payloadSize + 8));
|
|
670
|
+
unProcessed = unProcessed.subarray(headers.payloadSize + 8);
|
|
671
|
+
}
|
|
672
|
+
return packets;
|
|
673
|
+
};
|
|
657
674
|
|
|
658
675
|
/**
|
|
659
676
|
* Represents a fingerprint template with associated metadata
|
|
@@ -661,6 +678,7 @@ class ZkError {
|
|
|
661
678
|
class Finger {
|
|
662
679
|
uid;
|
|
663
680
|
fid;
|
|
681
|
+
/** Flag indicating 0 = invalid | 1 = valid | 3 = duress. if is not initilizaed, default is 1 = valid */
|
|
664
682
|
valid;
|
|
665
683
|
template;
|
|
666
684
|
size;
|
|
@@ -672,10 +690,10 @@ class Finger {
|
|
|
672
690
|
* @param valid Flag indicating 0 = invalid | 1 = valid | 3 = duress
|
|
673
691
|
* @param template Fingerprint template data buffer
|
|
674
692
|
*/
|
|
675
|
-
constructor(uid, fid,
|
|
693
|
+
constructor(uid, fid, template, valid) {
|
|
676
694
|
this.uid = Number(uid);
|
|
677
695
|
this.fid = Number(fid);
|
|
678
|
-
this.valid = Number(valid);
|
|
696
|
+
this.valid = valid ? Number(valid) : 1;
|
|
679
697
|
this.template = template;
|
|
680
698
|
this.size = template.length;
|
|
681
699
|
// Create mark showing first and last 8 bytes as hex
|
|
@@ -756,75 +774,75 @@ class UserService {
|
|
|
756
774
|
if (this._zkTcp.socket) {
|
|
757
775
|
await this._zkTcp.freeData();
|
|
758
776
|
}
|
|
759
|
-
|
|
760
|
-
const
|
|
777
|
+
await this._zkTcp.disableDevice();
|
|
778
|
+
const users = await new Promise((resolve, reject) => {
|
|
779
|
+
// Request user data
|
|
780
|
+
this._zkTcp
|
|
781
|
+
.readWithBuffer(REQUEST_DATA.GET_USERS)
|
|
782
|
+
.then(async (data) => {
|
|
783
|
+
// Ensure data.data is a valid buffer
|
|
784
|
+
if (!data.data || !(data.data instanceof Buffer)) {
|
|
785
|
+
reject(new Error("Invalid data received"));
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
let userData = data.data.subarray(4); // Skip the first 4 bytes (headers)
|
|
789
|
+
const users = [];
|
|
790
|
+
// Constants for user data processing
|
|
791
|
+
const USER_PACKET_SIZE = 72;
|
|
792
|
+
// Process each user packet
|
|
793
|
+
while (userData.length >= USER_PACKET_SIZE) {
|
|
794
|
+
// Decode user data and add to the users array
|
|
795
|
+
const user = decodeUserData72(userData.subarray(0, USER_PACKET_SIZE));
|
|
796
|
+
users.push(user);
|
|
797
|
+
this._users.set(user.user_id, user);
|
|
798
|
+
userData = userData.subarray(USER_PACKET_SIZE); // Move to the next packet
|
|
799
|
+
}
|
|
800
|
+
resolve(users);
|
|
801
|
+
})
|
|
802
|
+
.catch(reject);
|
|
803
|
+
});
|
|
761
804
|
// Free buffer data after receiving the data
|
|
762
|
-
if (this._zkTcp.socket) {
|
|
805
|
+
if (this._zkTcp.socket && users) {
|
|
806
|
+
await this._zkTcp.enableDevice();
|
|
763
807
|
await this._zkTcp.freeData();
|
|
764
808
|
}
|
|
765
|
-
// Constants for user data processing
|
|
766
|
-
const USER_PACKET_SIZE = 72;
|
|
767
|
-
// Ensure data.data is a valid buffer
|
|
768
|
-
if (!data.data || !(data.data instanceof Buffer)) {
|
|
769
|
-
throw new Error('Invalid data received');
|
|
770
|
-
}
|
|
771
|
-
let userData = data.data.subarray(4); // Skip the first 4 bytes (headers)
|
|
772
|
-
const users = [];
|
|
773
|
-
// Process each user packet
|
|
774
|
-
while (userData.length >= USER_PACKET_SIZE) {
|
|
775
|
-
// Decode user data and add to the users array
|
|
776
|
-
const user = decodeUserData72(userData.subarray(0, USER_PACKET_SIZE));
|
|
777
|
-
users.push(user);
|
|
778
|
-
this._users.set(user.user_id, user);
|
|
779
|
-
userData = userData.subarray(USER_PACKET_SIZE); // Move to the next packet
|
|
780
|
-
}
|
|
781
809
|
// Return the list of users
|
|
782
810
|
return { data: users };
|
|
783
811
|
}
|
|
784
812
|
catch (err) {
|
|
785
813
|
// Log the error for debugging
|
|
786
|
-
console.error(
|
|
814
|
+
console.error("Error getting users:", err);
|
|
787
815
|
// Re-throw the error to be handled by the caller
|
|
788
816
|
throw err;
|
|
789
817
|
}
|
|
790
818
|
}
|
|
791
819
|
async setUser(user_id, name, password, role = 0, cardno = 0) {
|
|
792
|
-
let user;
|
|
793
|
-
try {
|
|
794
|
-
user = await this.getUserByUserId(user_id);
|
|
795
|
-
}
|
|
796
|
-
catch (err) {
|
|
797
|
-
if (err.message.includes("user_id not exists")) {
|
|
798
|
-
user.uid = Math.max(...Array.from(this._users.values()).map(usr => usr.uid)) + 1;
|
|
799
|
-
this._users.set(user_id, user);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
820
|
try {
|
|
803
821
|
// Validate input parameters
|
|
804
822
|
if (user_id.length > 9 ||
|
|
805
823
|
name.length > 24 ||
|
|
806
824
|
password.length > 8 ||
|
|
807
|
-
typeof role !==
|
|
825
|
+
typeof role !== "number" ||
|
|
808
826
|
cardno.toString().length > 10) {
|
|
809
|
-
throw new Error(
|
|
827
|
+
throw new Error("Invalid input parameters");
|
|
810
828
|
}
|
|
811
829
|
// Allocate and initialize the buffer
|
|
812
830
|
const commandBuffer = Buffer.alloc(72);
|
|
813
831
|
// Fill the buffer with user data
|
|
814
|
-
commandBuffer.writeUInt16LE(
|
|
832
|
+
commandBuffer.writeUInt16LE(0, 0); // uid will be set in the device
|
|
815
833
|
commandBuffer.writeUInt16LE(role, 2);
|
|
816
|
-
commandBuffer.write(password.padEnd(8,
|
|
817
|
-
commandBuffer.write(name.padEnd(24,
|
|
834
|
+
commandBuffer.write(password.padEnd(8, "\0"), 3, 8); // Ensure password is 8 bytes
|
|
835
|
+
commandBuffer.write(name.padEnd(24, "\0"), 11, 24); // Ensure name is 24 bytes
|
|
818
836
|
commandBuffer.writeUInt16LE(cardno, 35);
|
|
819
837
|
commandBuffer.writeUInt32LE(0, 40); // Placeholder or reserved field
|
|
820
|
-
commandBuffer.write(user_id.padEnd(9,
|
|
838
|
+
commandBuffer.write(user_id.padEnd(9, "\0"), 48, 9); // Ensure userid is 9 bytes
|
|
821
839
|
// Send the command and return the result
|
|
822
840
|
const created = await this._zkTcp.executeCmd(COMMANDS.CMD_USER_WRQ, commandBuffer);
|
|
823
841
|
return !!created;
|
|
824
842
|
}
|
|
825
843
|
catch (err) {
|
|
826
844
|
// Log error details for debugging
|
|
827
|
-
console.error(
|
|
845
|
+
console.error("Error setting user:", err);
|
|
828
846
|
// Re-throw error for upstream handling
|
|
829
847
|
throw err;
|
|
830
848
|
}
|
|
@@ -842,22 +860,24 @@ class UserService {
|
|
|
842
860
|
}
|
|
843
861
|
catch (err) {
|
|
844
862
|
// Log error details for debugging
|
|
845
|
-
console.error(
|
|
863
|
+
console.error("Error deleting user:", err);
|
|
846
864
|
// Re-throw error for upstream handling
|
|
847
865
|
throw err;
|
|
848
866
|
}
|
|
849
867
|
}
|
|
850
|
-
async getTemplates(
|
|
851
|
-
|
|
868
|
+
async getTemplates(cb) {
|
|
869
|
+
const templates = [];
|
|
852
870
|
try {
|
|
871
|
+
await this._zkTcp.disableDevice();
|
|
853
872
|
if (this._zkTcp.socket) {
|
|
854
873
|
await this._zkTcp.freeData();
|
|
855
874
|
}
|
|
856
|
-
|
|
875
|
+
if (!this._zkTcp.fp_count) {
|
|
876
|
+
await this._zkTcp.getSizes();
|
|
877
|
+
}
|
|
857
878
|
if (this._zkTcp.fp_count == 0)
|
|
858
879
|
return { data: [] };
|
|
859
|
-
await this._zkTcp.
|
|
860
|
-
const resp = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_TEMPLATES);
|
|
880
|
+
const resp = (await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_TEMPLATES));
|
|
861
881
|
let templateData = resp.data.subarray(4);
|
|
862
882
|
let totalSize = resp.data.readUIntLE(0, 4);
|
|
863
883
|
while (totalSize) {
|
|
@@ -868,15 +888,17 @@ class UserService {
|
|
|
868
888
|
const valid = buf.readUIntLE(5, 1);
|
|
869
889
|
// Force-copy bytes so we don't retain the entire big backing buffer
|
|
870
890
|
const tplBytes = Buffer.from(templateData.subarray(6, size));
|
|
871
|
-
templates.push(new Finger(uid, fid,
|
|
891
|
+
templates.push(new Finger(uid, fid, tplBytes, valid));
|
|
872
892
|
templateData = templateData.subarray(size);
|
|
873
893
|
totalSize -= size;
|
|
874
894
|
}
|
|
895
|
+
if (cb)
|
|
896
|
+
cb(templates);
|
|
875
897
|
return { data: templates };
|
|
876
898
|
}
|
|
877
899
|
catch (err) {
|
|
878
900
|
this._zkTcp.verbose && console.log("Error getting templates", err);
|
|
879
|
-
|
|
901
|
+
throw err;
|
|
880
902
|
}
|
|
881
903
|
finally {
|
|
882
904
|
await this._zkTcp.freeData();
|
|
@@ -885,9 +907,9 @@ class UserService {
|
|
|
885
907
|
}
|
|
886
908
|
async DownloadFp(user_id, fid) {
|
|
887
909
|
try {
|
|
888
|
-
const user = await this.getUserByUserId(user_id);
|
|
910
|
+
const user = (await this.getUserByUserId(String(user_id)));
|
|
889
911
|
if (0 > fid || fid > 9)
|
|
890
|
-
throw new Error(
|
|
912
|
+
throw new Error("fid must be between 0 and 9");
|
|
891
913
|
// Allocate and initialize the buffer
|
|
892
914
|
const data = Buffer.alloc(3);
|
|
893
915
|
// Fill the buffer with user data
|
|
@@ -897,30 +919,30 @@ class UserService {
|
|
|
897
919
|
const packet = createTCPHeader(COMMANDS.CMD_USERTEMP_RRQ, this._zkTcp.sessionId, this._zkTcp.replyId, data);
|
|
898
920
|
let fingerSize = 0;
|
|
899
921
|
let fingerTemplate = Buffer.from([]);
|
|
900
|
-
|
|
922
|
+
const template = await new Promise((resolve, reject) => {
|
|
901
923
|
let timeout;
|
|
902
924
|
const cleanup = () => {
|
|
903
925
|
if (this._zkTcp.socket) {
|
|
904
|
-
this._zkTcp.socket.removeListener(
|
|
926
|
+
this._zkTcp.socket.removeListener("data", receiveData);
|
|
905
927
|
}
|
|
906
928
|
if (timeout)
|
|
907
929
|
clearTimeout(timeout);
|
|
908
930
|
};
|
|
909
931
|
let timer = () => setTimeout(() => {
|
|
910
932
|
cleanup();
|
|
911
|
-
reject(new Error(
|
|
933
|
+
reject(new Error("Time Out, Could not retrieve data"));
|
|
912
934
|
}, this._zkTcp.timeout);
|
|
913
935
|
const receiveData = (data) => {
|
|
914
936
|
timeout = timer();
|
|
915
937
|
if (data.length === 0)
|
|
916
938
|
return;
|
|
917
939
|
try {
|
|
918
|
-
if (data.length
|
|
940
|
+
if (data.length === 0)
|
|
919
941
|
return;
|
|
920
942
|
const headers = decodeTCPHeader(data);
|
|
921
943
|
switch (headers.commandId) {
|
|
922
944
|
case DISCOVERED_CMD.FID_NOT_FOUND:
|
|
923
|
-
throw new Error(
|
|
945
|
+
throw new Error("Could not retrieve data. maybe finger id not exists?");
|
|
924
946
|
case COMMANDS.CMD_PREPARE_DATA:
|
|
925
947
|
fingerSize = data.readUIntLE(16, 2);
|
|
926
948
|
break;
|
|
@@ -928,7 +950,10 @@ class UserService {
|
|
|
928
950
|
// A single 'data' event might contain multiple TCP packets combined by the OS
|
|
929
951
|
// in this method, is possible to get CMD_DATA and CMD_ACK_OK in the same event,
|
|
930
952
|
// so It's important to split data received for remove CMD_ACK_OK headers
|
|
931
|
-
fingerTemplate = Buffer.concat([
|
|
953
|
+
fingerTemplate = Buffer.concat([
|
|
954
|
+
fingerTemplate,
|
|
955
|
+
data.subarray(16, fingerSize + 10),
|
|
956
|
+
]);
|
|
932
957
|
// @ts-ignore
|
|
933
958
|
resolve(fingerTemplate);
|
|
934
959
|
break;
|
|
@@ -955,8 +980,8 @@ class UserService {
|
|
|
955
980
|
}
|
|
956
981
|
};
|
|
957
982
|
if (this._zkTcp.socket) {
|
|
958
|
-
this._zkTcp.socket.on(
|
|
959
|
-
this._zkTcp.socket.write(packet, (err) => {
|
|
983
|
+
this._zkTcp.socket.on("data", receiveData);
|
|
984
|
+
this._zkTcp.socket.write(packet, undefined, (err) => {
|
|
960
985
|
if (err) {
|
|
961
986
|
cleanup();
|
|
962
987
|
reject(err);
|
|
@@ -964,15 +989,16 @@ class UserService {
|
|
|
964
989
|
});
|
|
965
990
|
}
|
|
966
991
|
else {
|
|
967
|
-
reject(new Error(
|
|
992
|
+
reject(new Error("Socket not initialized"));
|
|
968
993
|
}
|
|
969
994
|
});
|
|
995
|
+
return new Finger(user.uid, fid, template);
|
|
970
996
|
}
|
|
971
997
|
catch (err) {
|
|
972
998
|
throw err;
|
|
973
999
|
}
|
|
974
1000
|
finally {
|
|
975
|
-
await this._zkTcp.
|
|
1001
|
+
await this._zkTcp.freeData();
|
|
976
1002
|
}
|
|
977
1003
|
}
|
|
978
1004
|
/**
|
|
@@ -1014,15 +1040,15 @@ class UserService {
|
|
|
1014
1040
|
head.writeUInt32LE(table.length, 4);
|
|
1015
1041
|
head.writeUInt32LE(fpack.length, 8);
|
|
1016
1042
|
const packet = Buffer.concat([head, upack, table, fpack]);
|
|
1017
|
-
|
|
1043
|
+
await this._zkTcp.sendWithBuffer(packet);
|
|
1018
1044
|
const command = 110;
|
|
1019
1045
|
const commandString = Buffer.alloc(8); // <IHH = I(4) + H(2) + H(2) = 8 bytes
|
|
1020
1046
|
commandString.writeUInt32LE(12, 0);
|
|
1021
1047
|
commandString.writeUInt16LE(0, 4);
|
|
1022
1048
|
commandString.writeUInt16LE(8, 6);
|
|
1023
|
-
|
|
1049
|
+
await this._zkTcp.executeCmd(command, commandString);
|
|
1024
1050
|
if (this._zkTcp.verbose)
|
|
1025
|
-
console.log("finally bulk save user templates: \n",
|
|
1051
|
+
console.log("finally bulk save user templates: \n", "templates saved successfully");
|
|
1026
1052
|
}
|
|
1027
1053
|
catch (error) {
|
|
1028
1054
|
throw error;
|
|
@@ -1034,9 +1060,7 @@ class UserService {
|
|
|
1034
1060
|
}
|
|
1035
1061
|
async deleteFinger(user_id, fid) {
|
|
1036
1062
|
try {
|
|
1037
|
-
|
|
1038
|
-
throw new Error("user_id not exists");
|
|
1039
|
-
const user = await this.getUserByUserId(user_id);
|
|
1063
|
+
const user = (await this.getUserByUserId(user_id));
|
|
1040
1064
|
const buf = Buffer.alloc(4);
|
|
1041
1065
|
buf.writeUInt16LE(user_id ? user.uid : 0, 0);
|
|
1042
1066
|
buf.writeUint16LE(fid ? fid : 0, 2);
|
|
@@ -1051,101 +1075,75 @@ class UserService {
|
|
|
1051
1075
|
}
|
|
1052
1076
|
}
|
|
1053
1077
|
async enrollInfo(user_id, tempId) {
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
const sendAckOk = async () => {
|
|
1063
|
-
try {
|
|
1064
|
-
const buf = createTCPHeader(COMMANDS.CMD_ACK_OK, this._zkTcp.sessionId, Constants.USHRT_MAX - 1, Buffer.from([]));
|
|
1065
|
-
this._zkTcp.socket.write(buf);
|
|
1066
|
-
}
|
|
1067
|
-
catch (e) {
|
|
1068
|
-
throw new ZkError(e, COMMANDS.CMD_ACK_OK, this._zkTcp.ip);
|
|
1069
|
-
}
|
|
1078
|
+
try {
|
|
1079
|
+
let timer;
|
|
1080
|
+
const setTimeoutTimer = (cb) => {
|
|
1081
|
+
if (timer)
|
|
1082
|
+
clearTimeout(timer);
|
|
1083
|
+
return setTimeout(() => {
|
|
1084
|
+
cb(new Error("[ENROLL_INFO] time out"));
|
|
1085
|
+
}, 1000 * 20);
|
|
1070
1086
|
};
|
|
1071
|
-
const
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1087
|
+
const cleanUp = () => {
|
|
1088
|
+
if (timer)
|
|
1089
|
+
clearTimeout(timer);
|
|
1090
|
+
};
|
|
1091
|
+
return await new Promise((resolve, reject) => {
|
|
1092
|
+
const handleRtEvent = (rtEvent) => {
|
|
1093
|
+
switch (rtEvent.event) {
|
|
1094
|
+
case RTEvent.EF_FPFTR:
|
|
1095
|
+
timer = setTimeoutTimer(reject);
|
|
1096
|
+
break;
|
|
1097
|
+
case RTEvent.EF_FINGER:
|
|
1098
|
+
console.log(rtEvent);
|
|
1099
|
+
break;
|
|
1100
|
+
case RTEvent.EF_ENROLLFINGER:
|
|
1101
|
+
cleanUp();
|
|
1102
|
+
resolve(rtEvent);
|
|
1103
|
+
break;
|
|
1104
|
+
default:
|
|
1105
|
+
console.log(rtEvent);
|
|
1106
|
+
break;
|
|
1089
1107
|
}
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
if (this._zkTcp.verbose)
|
|
1104
|
-
console.log("posible timeout o reg Fallido");
|
|
1105
|
-
break;
|
|
1108
|
+
};
|
|
1109
|
+
// Start enroll process
|
|
1110
|
+
this.getUserByUserId(user_id)
|
|
1111
|
+
.then(async (user) => {
|
|
1112
|
+
/** First check if Finger index already exists, and if so, it must be deleted */
|
|
1113
|
+
try {
|
|
1114
|
+
const exists = await this.DownloadFp(user_id, tempId);
|
|
1115
|
+
console.log("exists: ", exists);
|
|
1116
|
+
if (exists) {
|
|
1117
|
+
this._zkTcp.verbose &&
|
|
1118
|
+
console.debug("Deleting Finger index before start enroll");
|
|
1119
|
+
await this.deleteFinger(user_id, tempId);
|
|
1120
|
+
}
|
|
1106
1121
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
console.
|
|
1110
|
-
attempts--;
|
|
1122
|
+
catch (e) {
|
|
1123
|
+
this._zkTcp.verbose &&
|
|
1124
|
+
console.debug("Finger index is empty, skipping delete");
|
|
1111
1125
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
}
|
|
1127
|
-
if (res === 6 || res === 4) {
|
|
1128
|
-
if (this._zkTcp.verbose)
|
|
1129
|
-
console.log("posible timeout");
|
|
1130
|
-
}
|
|
1131
|
-
if (res === 0) {
|
|
1132
|
-
const size = padded.readUInt16LE(10);
|
|
1133
|
-
const pos = padded.readUInt16LE(12);
|
|
1134
|
-
if (this._zkTcp.verbose)
|
|
1135
|
-
console.log(`enroll ok ${size} ${pos}`);
|
|
1136
|
-
done = true;
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
//this.__sock.setTimeout(this.__timeout);
|
|
1140
|
-
await this._zkTcp.regEvent(0); // TODO: test
|
|
1141
|
-
return done;
|
|
1126
|
+
const userBuf = Buffer.alloc(24);
|
|
1127
|
+
userBuf.write(user_id, 0, 24, "ascii");
|
|
1128
|
+
const commandString = Buffer.concat([
|
|
1129
|
+
userBuf,
|
|
1130
|
+
Buffer.from([tempId, 1]),
|
|
1131
|
+
]);
|
|
1132
|
+
await this._zkTcp.executeCmd(COMMANDS.CMD_STARTENROLL, commandString); // #5
|
|
1133
|
+
this._zkTcp.timeout = 60000; // 60 seconds timeout
|
|
1134
|
+
await this._zkTcp.executeCmd(COMMANDS.CMD_STARTVERIFY, ""); // #17
|
|
1135
|
+
timer = setTimeoutTimer(reject);
|
|
1136
|
+
void (await this._zkTcp.getRealTimeLogs(handleRtEvent)); // #9
|
|
1137
|
+
})
|
|
1138
|
+
.catch(reject);
|
|
1139
|
+
});
|
|
1142
1140
|
}
|
|
1143
1141
|
catch (error) {
|
|
1144
1142
|
throw error;
|
|
1145
1143
|
}
|
|
1146
1144
|
finally {
|
|
1147
|
-
await this._zkTcp.cancelCapture();
|
|
1148
|
-
await this.verify(user_id);
|
|
1145
|
+
//await this._zkTcp.cancelCapture();
|
|
1146
|
+
//await this.verify(user_id);
|
|
1149
1147
|
}
|
|
1150
1148
|
}
|
|
1151
1149
|
async verify(user_id) {
|
|
@@ -1172,35 +1170,38 @@ class UserService {
|
|
|
1172
1170
|
*/
|
|
1173
1171
|
async uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid) {
|
|
1174
1172
|
try {
|
|
1175
|
-
const check_ACK_OK = (buf) => {
|
|
1176
|
-
let resp_cmd = initPacket.readUInt16LE(0);
|
|
1177
|
-
if (resp_cmd === COMMANDS.CMD_ACK_OK)
|
|
1178
|
-
return true;
|
|
1179
|
-
else
|
|
1180
|
-
throw new Error(`received unexpected command: ${resp_cmd}`);
|
|
1181
|
-
};
|
|
1182
1173
|
const user = this._users.get(user_id);
|
|
1183
1174
|
await this._zkTcp.disableDevice();
|
|
1184
1175
|
const prep_struct = Buffer.alloc(4);
|
|
1185
|
-
const fingerBuffer = Buffer.from(fingerTemplate,
|
|
1176
|
+
const fingerBuffer = Buffer.from(fingerTemplate, "base64");
|
|
1186
1177
|
const fp_size = fingerBuffer.length;
|
|
1187
1178
|
prep_struct.writeUInt16LE(fp_size, 0);
|
|
1188
1179
|
const initPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_PREPARE_DATA, prep_struct);
|
|
1189
|
-
|
|
1180
|
+
if (initPacket.readUInt16LE(0) !== COMMANDS.CMD_ACK_OK) {
|
|
1181
|
+
throw new Error(`received unexpected command: ${initPacket.readUInt16LE(0)}`);
|
|
1182
|
+
}
|
|
1190
1183
|
const fpPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_DATA, fingerBuffer);
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
const
|
|
1184
|
+
if (fpPacket.readUInt16LE(0) !== COMMANDS.CMD_ACK_OK) {
|
|
1185
|
+
throw new Error(`received unexpected command: ${fpPacket.readUInt16LE(0)}`);
|
|
1186
|
+
}
|
|
1187
|
+
const cheksumPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_CHECKSUM_BUFFER, "");
|
|
1188
|
+
if (cheksumPacket.readUInt16LE(0) !== COMMANDS.CMD_ACK_OK) {
|
|
1189
|
+
throw new Error(`received unexpected command: ${cheksumPacket.readUInt16LE(0)}`);
|
|
1190
|
+
}
|
|
1195
1191
|
const tmp_wreq = Buffer.alloc(6);
|
|
1196
1192
|
tmp_wreq.writeUInt16LE(user.uid, 0);
|
|
1197
1193
|
tmp_wreq.writeUIntLE(fid, 2, 1);
|
|
1198
1194
|
tmp_wreq.writeUIntLE(fp_valid, 3, 1);
|
|
1199
1195
|
tmp_wreq.writeUInt16LE(fp_size, 4);
|
|
1200
1196
|
const tmp_wreqPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_TMP_WRITE, tmp_wreq);
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1197
|
+
if (tmp_wreqPacket.readUInt16LE(0) !== COMMANDS.CMD_ACK_OK) {
|
|
1198
|
+
throw new Error(`received unexpected command: ${tmp_wreqPacket.readUInt16LE(0)}`);
|
|
1199
|
+
}
|
|
1200
|
+
const freeData = await this._zkTcp.executeCmd(COMMANDS.CMD_FREE_DATA, "");
|
|
1201
|
+
if (freeData.readUInt16LE(0) !== COMMANDS.CMD_ACK_OK) {
|
|
1202
|
+
throw new Error(`received unexpected command: ${freeData.readUInt16LE(0)}`);
|
|
1203
|
+
}
|
|
1204
|
+
return true;
|
|
1204
1205
|
}
|
|
1205
1206
|
catch (err) {
|
|
1206
1207
|
throw err;
|
|
@@ -1272,40 +1273,1016 @@ class TransactionService {
|
|
|
1272
1273
|
}
|
|
1273
1274
|
}
|
|
1274
1275
|
|
|
1275
|
-
|
|
1276
|
+
/**
|
|
1277
|
+
*
|
|
1278
|
+
* @param {number} time
|
|
1279
|
+
*/
|
|
1280
|
+
const decode = time => {
|
|
1281
|
+
const second = time % 60;
|
|
1282
|
+
time = (time - second) / 60;
|
|
1283
|
+
const minute = time % 60;
|
|
1284
|
+
time = (time - minute) / 60;
|
|
1285
|
+
const hour = time % 24;
|
|
1286
|
+
time = (time - hour) / 24;
|
|
1287
|
+
const day = time % 31 + 1;
|
|
1288
|
+
time = (time - (day - 1)) / 31;
|
|
1289
|
+
const month = time % 12;
|
|
1290
|
+
time = (time - month) / 12;
|
|
1291
|
+
const year = time + 2000;
|
|
1292
|
+
return new Date(year, month, day, hour, minute, second);
|
|
1293
|
+
};
|
|
1294
|
+
/**
|
|
1295
|
+
*
|
|
1296
|
+
* @param {Date} date
|
|
1297
|
+
*/
|
|
1298
|
+
const encode = date => {
|
|
1299
|
+
return (((date.getFullYear() % 100) * 12 * 31 + date.getMonth() * 31 + date.getDate() - 1) * (24 * 60 * 60) +
|
|
1300
|
+
(date.getHours() * 60 + date.getMinutes()) * 60 +
|
|
1301
|
+
date.getSeconds());
|
|
1302
|
+
};
|
|
1303
|
+
var timeParser = { encode, decode };
|
|
1304
|
+
|
|
1305
|
+
/**
|
|
1306
|
+
* SDK Parameters Enum
|
|
1307
|
+
*
|
|
1308
|
+
* Generated from SDK parameter table with the following structure:
|
|
1309
|
+
* - Keys: Parameter names in uppercase without ~ prefix
|
|
1310
|
+
* - Values: Original parameter names
|
|
1311
|
+
* - JSDoc: Includes description, permissions, and notes
|
|
1312
|
+
*/
|
|
1313
|
+
var SdkParameter;
|
|
1314
|
+
(function (SdkParameter) {
|
|
1276
1315
|
/**
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1316
|
+
* Device ID.
|
|
1317
|
+
* Permissions: RW
|
|
1318
|
+
* Notes: Value ranges from 1 to 254.
|
|
1319
|
+
*/
|
|
1320
|
+
SdkParameter["DEVICE_ID"] = "DeviceID";
|
|
1321
|
+
/**
|
|
1322
|
+
* Language.
|
|
1323
|
+
* Permissions: RW
|
|
1324
|
+
* Notes: For english it is 97.
|
|
1325
|
+
*/
|
|
1326
|
+
SdkParameter["NEW_LNG"] = "NewLng";
|
|
1327
|
+
/**
|
|
1328
|
+
* The machine will enter standby state or power off, after this time elapses.
|
|
1329
|
+
* Permissions: RW
|
|
1330
|
+
* Notes: Given in minutes.
|
|
1331
|
+
*/
|
|
1332
|
+
SdkParameter["IDLE_MINUTE"] = "IdleMinute";
|
|
1333
|
+
/**
|
|
1334
|
+
* Lock control time.
|
|
1335
|
+
* Permissions: RW
|
|
1336
|
+
* Notes: Given in seconds.
|
|
1337
|
+
*/
|
|
1338
|
+
SdkParameter["LOCK_ON"] = "LockOn";
|
|
1339
|
+
/**
|
|
1340
|
+
* Attendance record quantity alarm.
|
|
1341
|
+
* Permissions: RW
|
|
1342
|
+
* Notes:
|
|
1343
|
+
*/
|
|
1344
|
+
SdkParameter["ALARM_ATT_LOG"] = "AlarmAttLog";
|
|
1345
|
+
/**
|
|
1346
|
+
* Operation record quantity alarm.
|
|
1347
|
+
* Permissions: RW
|
|
1348
|
+
* Notes:
|
|
1349
|
+
*/
|
|
1350
|
+
SdkParameter["ALARM_OP_LOG"] = "AlarmOpLog";
|
|
1351
|
+
/**
|
|
1352
|
+
* Minimun time to record the same attendance state.
|
|
1353
|
+
* Permissions: RW
|
|
1354
|
+
* Notes: Units are unknown.
|
|
1355
|
+
*/
|
|
1356
|
+
SdkParameter["ALARM_RE_REC"] = "AlarmReRec";
|
|
1357
|
+
/**
|
|
1358
|
+
* Baud rate for RS232/485.
|
|
1359
|
+
* Permissions: RW
|
|
1360
|
+
* Notes: Valid values are 1200, 2400, 4800, 9600, 19200, 38400 57600, 115200.
|
|
1361
|
+
*/
|
|
1362
|
+
SdkParameter["RS232_BAUD_RATE"] = "RS232BaudRate";
|
|
1363
|
+
/**
|
|
1364
|
+
* Enable flag for network functions.
|
|
1365
|
+
* Permissions: RW
|
|
1366
|
+
* Notes:
|
|
1367
|
+
*/
|
|
1368
|
+
SdkParameter["NETWORK_ON"] = "NetworkOn";
|
|
1369
|
+
/**
|
|
1370
|
+
* Enable flag for RS232.
|
|
1371
|
+
* Permissions: RW
|
|
1372
|
+
* Notes:
|
|
1373
|
+
*/
|
|
1374
|
+
SdkParameter["RS232_ON"] = "RS232On";
|
|
1375
|
+
/**
|
|
1376
|
+
* Enable flag for RS485.
|
|
1377
|
+
* Permissions: RW
|
|
1378
|
+
* Notes:
|
|
1379
|
+
*/
|
|
1380
|
+
SdkParameter["RS485_ON"] = "RS485On";
|
|
1381
|
+
/**
|
|
1382
|
+
* Enable announcements(voice).
|
|
1383
|
+
* Permissions: RW
|
|
1384
|
+
* Notes:
|
|
1385
|
+
*/
|
|
1386
|
+
SdkParameter["VOICE_ON"] = "VoiceOn";
|
|
1387
|
+
/**
|
|
1388
|
+
* Perform high-speed comparison.
|
|
1389
|
+
* Permissions: RW
|
|
1390
|
+
* Notes: Value codification is unknown.
|
|
1391
|
+
*/
|
|
1392
|
+
SdkParameter["MSPEED"] = "MSpeed";
|
|
1393
|
+
/**
|
|
1394
|
+
* Idle mode.
|
|
1395
|
+
* Permissions: RW
|
|
1396
|
+
* Notes: 87 indicates shutdown and 88 indicates hibernation.
|
|
1397
|
+
*/
|
|
1398
|
+
SdkParameter["IDLE_POWER"] = "IdlePower";
|
|
1399
|
+
/**
|
|
1400
|
+
* Automatic shutdown time.
|
|
1401
|
+
* Permissions: RW
|
|
1402
|
+
* Notes: Value 255 indicates the machine to not shutdown automatically.
|
|
1403
|
+
*/
|
|
1404
|
+
SdkParameter["AUTO_POWER_OFF"] = "AutoPowerOff";
|
|
1405
|
+
/**
|
|
1406
|
+
* Automatic startup time.
|
|
1407
|
+
* Permissions: RW
|
|
1408
|
+
* Notes: Value 255 indicates the machine to not startup automatically.
|
|
1409
|
+
*/
|
|
1410
|
+
SdkParameter["AUTO_POWER_ON"] = "AutoPowerOn";
|
|
1411
|
+
/**
|
|
1412
|
+
* Automatic hibernation time.
|
|
1413
|
+
* Permissions: RW
|
|
1414
|
+
* Notes: Value 255 indicates the machine to not suspend automatically.
|
|
1415
|
+
*/
|
|
1416
|
+
SdkParameter["AUTO_POWER_SUSPEND"] = "AutoPowerSuspend";
|
|
1417
|
+
/**
|
|
1418
|
+
* Alarm 1 time.
|
|
1419
|
+
* Permissions: RW
|
|
1420
|
+
* Notes: Value 65535 disables the alarm(t).
|
|
1421
|
+
*/
|
|
1422
|
+
SdkParameter["AUTO_ALARM1"] = "AutoAlarm1";
|
|
1423
|
+
/**
|
|
1424
|
+
* 1:N comparison threshold.
|
|
1425
|
+
* Permissions: RW
|
|
1426
|
+
* Notes: Integer.
|
|
1427
|
+
*/
|
|
1428
|
+
SdkParameter["MTHRESHOLD"] = "MThreshold";
|
|
1429
|
+
/**
|
|
1430
|
+
* Registration threshold.
|
|
1431
|
+
* Permissions: RW
|
|
1432
|
+
* Notes: Integer.
|
|
1433
|
+
*/
|
|
1434
|
+
SdkParameter["ETHRESHOLD"] = "EThreshold";
|
|
1435
|
+
/**
|
|
1436
|
+
* 1:1 comparison threshold.
|
|
1437
|
+
* Permissions: RW
|
|
1438
|
+
* Notes: Integer.
|
|
1439
|
+
*/
|
|
1440
|
+
SdkParameter["VTHRESHOLD"] = "VThreshold";
|
|
1441
|
+
/**
|
|
1442
|
+
* Display matching score during verification.
|
|
1443
|
+
* Permissions: RW
|
|
1444
|
+
* Notes: Bool.
|
|
1445
|
+
*/
|
|
1446
|
+
SdkParameter["SHOW_SCORE"] = "ShowScore";
|
|
1447
|
+
/**
|
|
1448
|
+
* Number of people that may unlock the door at the same time.
|
|
1449
|
+
* Permissions: RW
|
|
1450
|
+
* Notes: Integer.
|
|
1451
|
+
*/
|
|
1452
|
+
SdkParameter["UNLOCK_PERSON"] = "UnlockPerson";
|
|
1453
|
+
/**
|
|
1454
|
+
* Verify only the card number.
|
|
1455
|
+
* Permissions: RW
|
|
1456
|
+
* Notes: Bool.
|
|
1457
|
+
*/
|
|
1458
|
+
SdkParameter["ONLY_PIN_CARD"] = "OnlyPINCard";
|
|
1459
|
+
/**
|
|
1460
|
+
* Network speed.
|
|
1461
|
+
* Permissions: RW
|
|
1462
|
+
* Notes: Value correspondence: 1=100M-H, 4=10M-F, 5=100M-F, 8=Auto, others=10M-H.
|
|
1463
|
+
*/
|
|
1464
|
+
SdkParameter["HI_SPEED_NET"] = "HiSpeedNet";
|
|
1465
|
+
/**
|
|
1466
|
+
* Accept only registered cards.
|
|
1467
|
+
* Permissions: RW
|
|
1468
|
+
* Notes: Bool.
|
|
1469
|
+
*/
|
|
1470
|
+
SdkParameter["MUST_ENROLL"] = "MustEnroll";
|
|
1471
|
+
/**
|
|
1472
|
+
* Timeout to return to the initial state.
|
|
1473
|
+
* Permissions: RW
|
|
1474
|
+
* Notes: Given in seconds.
|
|
1475
|
+
*/
|
|
1476
|
+
SdkParameter["TO_STATE"] = "TOState";
|
|
1477
|
+
/**
|
|
1478
|
+
* Timeout to return to the initial state if there are no inputs after entering PIN.
|
|
1479
|
+
* Permissions: RW
|
|
1480
|
+
* Notes: Given in seconds.
|
|
1481
|
+
*/
|
|
1482
|
+
SdkParameter["TO_STATE_PIN"] = "TOState";
|
|
1483
|
+
/**
|
|
1484
|
+
* Timeout to return to the initial state if there are no inputs after entering menu.
|
|
1485
|
+
* Permissions: RW
|
|
1486
|
+
* Notes: Given in seconds.
|
|
1487
|
+
*/
|
|
1488
|
+
SdkParameter["TO_MENU"] = "TOMenu";
|
|
1489
|
+
/**
|
|
1490
|
+
* Time format.
|
|
1491
|
+
* Permissions: NA
|
|
1492
|
+
* Notes: Value codification is unknown.
|
|
1493
|
+
*/
|
|
1494
|
+
SdkParameter["DT_FMT"] = "DtFmt";
|
|
1495
|
+
/**
|
|
1496
|
+
* Flag for mandatory 1:1 comparison.
|
|
1497
|
+
* Permissions: RW
|
|
1498
|
+
* Notes: Bool.
|
|
1499
|
+
*/
|
|
1500
|
+
SdkParameter["MUST_1TO1"] = "Must1To1";
|
|
1501
|
+
/**
|
|
1502
|
+
* Alarm 2 time.
|
|
1503
|
+
* Permissions: RW
|
|
1504
|
+
* Notes: Value 65535 disables the alarm(t).
|
|
1505
|
+
*/
|
|
1506
|
+
SdkParameter["AUTO_ALARM2"] = "AutoAlarm2";
|
|
1507
|
+
/**
|
|
1508
|
+
* Alarm 3 time.
|
|
1509
|
+
* Permissions: RW
|
|
1510
|
+
* Notes: Value 65535 disables the alarm(t).
|
|
1511
|
+
*/
|
|
1512
|
+
SdkParameter["AUTO_ALARM3"] = "AutoAlarm3";
|
|
1513
|
+
/**
|
|
1514
|
+
* Alarm 4 time.
|
|
1515
|
+
* Permissions: RW
|
|
1516
|
+
* Notes: Value 65535 disables the alarm(t).
|
|
1517
|
+
*/
|
|
1518
|
+
SdkParameter["AUTO_ALARM4"] = "AutoAlarm4";
|
|
1519
|
+
/**
|
|
1520
|
+
* Alarm 5 time.
|
|
1521
|
+
* Permissions: RW
|
|
1522
|
+
* Notes: Value 65535 disables the alarm(t).
|
|
1523
|
+
*/
|
|
1524
|
+
SdkParameter["AUTO_ALARM5"] = "AutoAlarm5";
|
|
1525
|
+
/**
|
|
1526
|
+
* Alarm 6 time.
|
|
1527
|
+
* Permissions: RW
|
|
1528
|
+
* Notes: Value 65535 disables the alarm(t).
|
|
1529
|
+
*/
|
|
1530
|
+
SdkParameter["AUTO_ALARM6"] = "AutoAlarm6";
|
|
1531
|
+
/**
|
|
1532
|
+
* Automatic status changing times.
|
|
1533
|
+
* Permissions: ?
|
|
1534
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1535
|
+
*/
|
|
1536
|
+
SdkParameter["AS1"] = "AS1";
|
|
1537
|
+
/**
|
|
1538
|
+
* Automatic status changing times.
|
|
1539
|
+
* Permissions: ?
|
|
1540
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1541
|
+
*/
|
|
1542
|
+
SdkParameter["AS2"] = "AS2";
|
|
1543
|
+
/**
|
|
1544
|
+
* Automatic status changing times.
|
|
1545
|
+
* Permissions: ?
|
|
1546
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1547
|
+
*/
|
|
1548
|
+
SdkParameter["AS3"] = "AS3";
|
|
1549
|
+
/**
|
|
1550
|
+
* Automatic status changing times.
|
|
1551
|
+
* Permissions: ?
|
|
1552
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1553
|
+
*/
|
|
1554
|
+
SdkParameter["AS4"] = "AS4";
|
|
1555
|
+
/**
|
|
1556
|
+
* Automatic status changing times.
|
|
1557
|
+
* Permissions: ?
|
|
1558
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1559
|
+
*/
|
|
1560
|
+
SdkParameter["AS5"] = "AS5";
|
|
1561
|
+
/**
|
|
1562
|
+
* Automatic status changing times.
|
|
1563
|
+
* Permissions: ?
|
|
1564
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1565
|
+
*/
|
|
1566
|
+
SdkParameter["AS6"] = "AS6";
|
|
1567
|
+
/**
|
|
1568
|
+
* Automatic status changing times.
|
|
1569
|
+
* Permissions: ?
|
|
1570
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1571
|
+
*/
|
|
1572
|
+
SdkParameter["AS7"] = "AS7";
|
|
1573
|
+
/**
|
|
1574
|
+
* Automatic status changing times.
|
|
1575
|
+
* Permissions: ?
|
|
1576
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1577
|
+
*/
|
|
1578
|
+
SdkParameter["AS8"] = "AS8";
|
|
1579
|
+
/**
|
|
1580
|
+
* Automatic status changing times.
|
|
1581
|
+
* Permissions: ?
|
|
1582
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1583
|
+
*/
|
|
1584
|
+
SdkParameter["AS9"] = "AS9";
|
|
1585
|
+
/**
|
|
1586
|
+
* Automatic status changing times.
|
|
1587
|
+
* Permissions: ?
|
|
1588
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1589
|
+
*/
|
|
1590
|
+
SdkParameter["AS10"] = "AS10";
|
|
1591
|
+
/**
|
|
1592
|
+
* Automatic status changing times.
|
|
1593
|
+
* Permissions: ?
|
|
1594
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1595
|
+
*/
|
|
1596
|
+
SdkParameter["AS11"] = "AS11";
|
|
1597
|
+
/**
|
|
1598
|
+
* Automatic status changing times.
|
|
1599
|
+
* Permissions: ?
|
|
1600
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1601
|
+
*/
|
|
1602
|
+
SdkParameter["AS12"] = "AS12";
|
|
1603
|
+
/**
|
|
1604
|
+
* Automatic status changing times.
|
|
1605
|
+
* Permissions: ?
|
|
1606
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1607
|
+
*/
|
|
1608
|
+
SdkParameter["AS13"] = "AS13";
|
|
1609
|
+
/**
|
|
1610
|
+
* Automatic status changing times.
|
|
1611
|
+
* Permissions: ?
|
|
1612
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1613
|
+
*/
|
|
1614
|
+
SdkParameter["AS14"] = "AS14";
|
|
1615
|
+
/**
|
|
1616
|
+
* Automatic status changing times.
|
|
1617
|
+
* Permissions: ?
|
|
1618
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1619
|
+
*/
|
|
1620
|
+
SdkParameter["AS15"] = "AS15";
|
|
1621
|
+
/**
|
|
1622
|
+
* Automatic status changing times.
|
|
1623
|
+
* Permissions: ?
|
|
1624
|
+
* Notes: -1 value indicates that the status will not change automatically.
|
|
1625
|
+
*/
|
|
1626
|
+
SdkParameter["AS16"] = "AS16";
|
|
1627
|
+
/**
|
|
1628
|
+
* Wiegand failure ID.
|
|
1629
|
+
* Permissions: ?
|
|
1630
|
+
* Notes:
|
|
1631
|
+
*/
|
|
1632
|
+
SdkParameter["WG_FAILED_ID"] = "WGFailedID";
|
|
1633
|
+
/**
|
|
1634
|
+
* Wiegand duress ID.
|
|
1635
|
+
* Permissions: ?
|
|
1636
|
+
* Notes:
|
|
1637
|
+
*/
|
|
1638
|
+
SdkParameter["WG_DURESS_ID"] = "WGDuressID";
|
|
1639
|
+
/**
|
|
1640
|
+
* Wiegand zone bit.
|
|
1641
|
+
* Permissions: ?
|
|
1642
|
+
* Notes:
|
|
1643
|
+
*/
|
|
1644
|
+
SdkParameter["WG_SITE_CODE"] = "WGSiteCode";
|
|
1645
|
+
/**
|
|
1646
|
+
* Pulse width of Wiegand outputs.
|
|
1647
|
+
* Permissions: ?
|
|
1648
|
+
* Notes:
|
|
1649
|
+
*/
|
|
1650
|
+
SdkParameter["WG_PULSE_WIDTH"] = "WGPulseWidth";
|
|
1651
|
+
/**
|
|
1652
|
+
* Pulse interval for Wiegand outputs.
|
|
1653
|
+
* Permissions: ?
|
|
1654
|
+
* Notes:
|
|
1655
|
+
*/
|
|
1656
|
+
SdkParameter["WG_PULSE_INTERVAL"] = "WGPulseInterval";
|
|
1657
|
+
/**
|
|
1658
|
+
* ID of the start sector on the Mifare card where fingerprints are stored.
|
|
1659
|
+
* Permissions: ?
|
|
1660
|
+
* Notes:
|
|
1661
|
+
*/
|
|
1662
|
+
SdkParameter["RF_START"] = "RFSStart";
|
|
1663
|
+
/**
|
|
1664
|
+
* Total number of sectors on the Mifare card where fingerprints are stored.
|
|
1665
|
+
* Permissions: ?
|
|
1666
|
+
* Notes:
|
|
1667
|
+
*/
|
|
1668
|
+
SdkParameter["RF_LEN"] = "RFSLen";
|
|
1669
|
+
/**
|
|
1670
|
+
* Number of fingerprints stored on the Mifare card.
|
|
1671
|
+
* Permissions: ?
|
|
1672
|
+
* Notes:
|
|
1673
|
+
*/
|
|
1674
|
+
SdkParameter["RF_FPC"] = "RFFPC";
|
|
1675
|
+
/**
|
|
1676
|
+
* Forbidden.
|
|
1677
|
+
* Permissions: NA
|
|
1678
|
+
* Notes:
|
|
1679
|
+
*/
|
|
1680
|
+
SdkParameter["FORBIDDEN"] = "Forbidden";
|
|
1681
|
+
/**
|
|
1682
|
+
* Wheter to display the attendance status.
|
|
1683
|
+
* Permissions: RW
|
|
1684
|
+
* Notes:
|
|
1685
|
+
*/
|
|
1686
|
+
SdkParameter["SHOW_STATE"] = "~ShowState";
|
|
1687
|
+
/**
|
|
1688
|
+
* TCP Port.
|
|
1689
|
+
* Permissions: ?
|
|
1690
|
+
* Notes:
|
|
1691
|
+
*/
|
|
1692
|
+
SdkParameter["TCP_PORT"] = "TCPPort";
|
|
1693
|
+
/**
|
|
1694
|
+
* UDP Port.
|
|
1695
|
+
* Permissions: ?
|
|
1696
|
+
* Notes:
|
|
1697
|
+
*/
|
|
1698
|
+
SdkParameter["UDP_PORT"] = "UDPPort";
|
|
1699
|
+
/**
|
|
1700
|
+
* Fingerprint algorithm version.
|
|
1701
|
+
* Permissions: R
|
|
1702
|
+
* Notes:
|
|
1703
|
+
*/
|
|
1704
|
+
SdkParameter["ZK_FP_VERSION"] = "~ZKFPVersion";
|
|
1705
|
+
/**
|
|
1706
|
+
* Face algorithm version.
|
|
1707
|
+
* Permissions: R
|
|
1708
|
+
* Notes:
|
|
1709
|
+
*/
|
|
1710
|
+
SdkParameter["ZK_FACE_VERSION"] = "~ZKFaceVersion";
|
|
1711
|
+
/**
|
|
1712
|
+
* Finger vein version.
|
|
1713
|
+
* Permissions: R
|
|
1714
|
+
* Notes:
|
|
1715
|
+
*/
|
|
1716
|
+
SdkParameter["ZK_FV_VERSION"] = "~ZKFVVersion";
|
|
1717
|
+
/**
|
|
1718
|
+
* Face function.
|
|
1719
|
+
* Permissions: R
|
|
1720
|
+
* Notes:
|
|
1721
|
+
*/
|
|
1722
|
+
SdkParameter["FACE_FUN_ON"] = "~FaceFunOn";
|
|
1723
|
+
/**
|
|
1724
|
+
* User id max length.
|
|
1725
|
+
* Permissions: R
|
|
1726
|
+
* Notes:
|
|
1727
|
+
*/
|
|
1728
|
+
SdkParameter["PIN2_WIDTH"] = "~PIN2Width";
|
|
1729
|
+
/**
|
|
1730
|
+
* Does the user id support chars.
|
|
1731
|
+
* Permissions: R
|
|
1732
|
+
* Notes:
|
|
1733
|
+
*/
|
|
1734
|
+
SdkParameter["IS_SUPPORT_ABC_PIN"] = "IsSupportABCPin";
|
|
1735
|
+
/**
|
|
1736
|
+
* ?
|
|
1737
|
+
* Permissions: ?
|
|
1738
|
+
* Notes:
|
|
1739
|
+
*/
|
|
1740
|
+
SdkParameter["IME_FUN_ON"] = "IMEFunOn";
|
|
1741
|
+
/**
|
|
1742
|
+
* ?
|
|
1743
|
+
* Permissions: ?
|
|
1744
|
+
* Notes:
|
|
1745
|
+
*/
|
|
1746
|
+
SdkParameter["IS_SUPPORT_ALARM_EXT"] = "IsSupportAlarmExt";
|
|
1747
|
+
/**
|
|
1748
|
+
* ?
|
|
1749
|
+
* Permissions: ?
|
|
1750
|
+
* Notes:
|
|
1751
|
+
*/
|
|
1752
|
+
SdkParameter["DCTZ"] = "~DCTZ";
|
|
1753
|
+
/**
|
|
1754
|
+
* ?
|
|
1755
|
+
* Permissions: ?
|
|
1756
|
+
* Notes:
|
|
1757
|
+
*/
|
|
1758
|
+
SdkParameter["DOTZ"] = "~DOTZ";
|
|
1759
|
+
/**
|
|
1760
|
+
* -
|
|
1761
|
+
* Permissions: ?
|
|
1762
|
+
* Notes:
|
|
1763
|
+
*/
|
|
1764
|
+
SdkParameter["EXTEND_OP_LOG"] = "ExtendOPLog";
|
|
1765
|
+
/**
|
|
1766
|
+
* Bool
|
|
1767
|
+
* Permissions: RW
|
|
1768
|
+
* Notes:
|
|
1769
|
+
*/
|
|
1770
|
+
SdkParameter["WORK_CODE"] = "WorkCode";
|
|
1771
|
+
/**
|
|
1772
|
+
* Integer
|
|
1773
|
+
* Permissions: RW
|
|
1774
|
+
* Notes:
|
|
1775
|
+
*/
|
|
1776
|
+
SdkParameter["LANGUAGE"] = "Language";
|
|
1777
|
+
/**
|
|
1778
|
+
* -
|
|
1779
|
+
* Permissions: ?
|
|
1780
|
+
* Notes:
|
|
1781
|
+
*/
|
|
1782
|
+
SdkParameter["BIOMETRIC_TYPE"] = "BiometricType";
|
|
1783
|
+
/**
|
|
1784
|
+
* Bool
|
|
1785
|
+
* Permissions: RW
|
|
1786
|
+
* Notes:
|
|
1787
|
+
*/
|
|
1788
|
+
SdkParameter["FINGER_FUN_ON"] = "FingerFunOn";
|
|
1789
|
+
/**
|
|
1790
|
+
* Bool
|
|
1791
|
+
* Permissions: ?
|
|
1792
|
+
* Notes:
|
|
1793
|
+
*/
|
|
1794
|
+
SdkParameter["IS_ONLY_RF_MACHINE"] = "~IsOnlyRFMachine";
|
|
1795
|
+
/**
|
|
1796
|
+
* Vendor name
|
|
1797
|
+
* Permissions: ?
|
|
1798
|
+
* Notes:
|
|
1799
|
+
*/
|
|
1800
|
+
SdkParameter["OEM_VENDOR"] = "~OEMVendor";
|
|
1801
|
+
/**
|
|
1802
|
+
* Device name
|
|
1803
|
+
* Permissions: ?
|
|
1804
|
+
* Notes:
|
|
1805
|
+
*/
|
|
1806
|
+
SdkParameter["DEVICE_NAME"] = "~DeviceName";
|
|
1807
|
+
/**
|
|
1808
|
+
* MAC address
|
|
1809
|
+
* Permissions: ?
|
|
1810
|
+
* Notes:
|
|
1811
|
+
*/
|
|
1812
|
+
SdkParameter["MAC"] = "MAC";
|
|
1813
|
+
/**
|
|
1814
|
+
* Serial number
|
|
1815
|
+
* Permissions: ?
|
|
1816
|
+
* Notes:
|
|
1817
|
+
*/
|
|
1818
|
+
SdkParameter["SERIAL_NUMBER"] = "~SerialNumber";
|
|
1819
|
+
/**
|
|
1820
|
+
* Date string
|
|
1821
|
+
* Permissions: ?
|
|
1822
|
+
* Notes:
|
|
1823
|
+
*/
|
|
1824
|
+
SdkParameter["PRODUCT_TIME"] = "~ProductTime";
|
|
1825
|
+
/**
|
|
1826
|
+
* Bool
|
|
1827
|
+
* Permissions: ?
|
|
1828
|
+
* Notes:
|
|
1829
|
+
*/
|
|
1830
|
+
SdkParameter["IS_ABC_PIN_ENABLE"] = "~IsABCPinEnable";
|
|
1831
|
+
/**
|
|
1832
|
+
* Bool
|
|
1833
|
+
* Permissions: ?
|
|
1834
|
+
* Notes:
|
|
1835
|
+
*/
|
|
1836
|
+
SdkParameter["T9_FUN_ON"] = "~T9FunOn";
|
|
1837
|
+
/**
|
|
1838
|
+
* Date Time
|
|
1839
|
+
* Permissions: RW
|
|
1840
|
+
*/
|
|
1841
|
+
SdkParameter["DATETIME"] = "DateTime";
|
|
1842
|
+
/**
|
|
1843
|
+
*
|
|
1844
|
+
*/
|
|
1845
|
+
SdkParameter["OS"] = "~OS";
|
|
1846
|
+
})(SdkParameter || (SdkParameter = {}));
|
|
1847
|
+
|
|
1848
|
+
class OptionsService {
|
|
1849
|
+
_zkTcp;
|
|
1850
|
+
constructor(zkTcp) {
|
|
1851
|
+
this._zkTcp = zkTcp;
|
|
1852
|
+
}
|
|
1853
|
+
/** Ask if the device doesn't support alphanumeric symbols for user id values. */
|
|
1854
|
+
async isAbcPinEnable() {
|
|
1855
|
+
const keyword = "~IsABCPinEnable";
|
|
1856
|
+
try {
|
|
1857
|
+
// Execute the command to get the PIN information
|
|
1858
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1859
|
+
// Extract and format the PIN information from the response data
|
|
1860
|
+
return data
|
|
1861
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
1862
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
1863
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
1864
|
+
.replace(/\u0000/g, ""); // Remove null characters 0x00
|
|
1865
|
+
}
|
|
1866
|
+
catch (err) {
|
|
1867
|
+
// Log the error for debugging
|
|
1868
|
+
console.error("Error getting PIN:", err);
|
|
1869
|
+
// Re-throw the error to be handled by the caller
|
|
1870
|
+
throw err;
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
/** Ask if the device doesn't support alphanumeric symbols for user id values. */
|
|
1874
|
+
async isT9FunOn() {
|
|
1875
|
+
const keyword = "~T9FunOn";
|
|
1876
|
+
try {
|
|
1877
|
+
// Execute the command to get the PIN information
|
|
1878
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1879
|
+
// Extract and format the PIN information from the response data
|
|
1880
|
+
return data
|
|
1881
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
1882
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
1883
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
1884
|
+
.replace(/\u0000/g, ""); // Remove null characters 0x00
|
|
1885
|
+
}
|
|
1886
|
+
catch (err) {
|
|
1887
|
+
// Log the error for debugging
|
|
1888
|
+
console.error("Error getting PIN:", err);
|
|
1889
|
+
// Re-throw the error to be handled by the caller
|
|
1890
|
+
throw err;
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
async getDeviceId() {
|
|
1894
|
+
const keyword = SdkParameter.DEVICE_ID;
|
|
1895
|
+
try {
|
|
1896
|
+
let result;
|
|
1897
|
+
let retry = true;
|
|
1898
|
+
while (retry) {
|
|
1899
|
+
// Execute the command to get the device name
|
|
1900
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1901
|
+
// Extract and format the device name from the response data
|
|
1902
|
+
result = data
|
|
1903
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
1904
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
1905
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
1906
|
+
.replace(/\u0000/g, ""); // Remove null characters
|
|
1907
|
+
retry = result.includes("=");
|
|
1908
|
+
}
|
|
1909
|
+
return result;
|
|
1910
|
+
}
|
|
1911
|
+
catch (err) {
|
|
1912
|
+
// Log the error for debugging
|
|
1913
|
+
console.error("Error getting vendor:", err);
|
|
1914
|
+
// Re-throw the error for higher-level handling
|
|
1915
|
+
throw err;
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
/**
|
|
1919
|
+
* Change Device ID
|
|
1920
|
+
* @param id a number between 1 and 254
|
|
1921
|
+
*/
|
|
1922
|
+
async setDeviceId(id) {
|
|
1923
|
+
if (id < 1 || id > 254)
|
|
1924
|
+
throw new Error("Device ID must be a number between 1 and 254");
|
|
1925
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_WRQ, `DeviceID=${id}\x00`);
|
|
1926
|
+
return data.readUInt16LE(0) === COMMANDS.CMD_ACK_OK;
|
|
1927
|
+
}
|
|
1928
|
+
async getVendor() {
|
|
1929
|
+
const keyword = "~OEMVendor";
|
|
1930
|
+
try {
|
|
1931
|
+
let result;
|
|
1932
|
+
let retry = true;
|
|
1933
|
+
while (retry) {
|
|
1934
|
+
// Execute the command to get the device name
|
|
1935
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1936
|
+
// Extract and format the device name from the response data
|
|
1937
|
+
result = data
|
|
1938
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
1939
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
1940
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
1941
|
+
.replace(/\u0000/g, ""); // Remove null characters
|
|
1942
|
+
retry = result.includes("=");
|
|
1943
|
+
}
|
|
1944
|
+
return result;
|
|
1945
|
+
}
|
|
1946
|
+
catch (err) {
|
|
1947
|
+
// Log the error for debugging
|
|
1948
|
+
console.error("Error getting vendor:", err);
|
|
1949
|
+
// Re-throw the error for higher-level handling
|
|
1950
|
+
throw err;
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
async getProductTime() {
|
|
1954
|
+
const keyword = "~ProductTime";
|
|
1955
|
+
try {
|
|
1956
|
+
// Execute the command to get serial number
|
|
1957
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1958
|
+
// Extract and format the serial number from the response data
|
|
1959
|
+
const ProductTime = data
|
|
1960
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
1961
|
+
.toString("ascii") // Convert buffer to string
|
|
1962
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
1963
|
+
.replace(/\u0000/g, ""); // Remove null characters
|
|
1964
|
+
return new Date(ProductTime);
|
|
1965
|
+
}
|
|
1966
|
+
catch (err) {
|
|
1967
|
+
// Log the error for debugging
|
|
1968
|
+
console.error("Error getting Product Time:", err);
|
|
1969
|
+
// Re-throw the error for higher-level handling
|
|
1970
|
+
throw err;
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
async getMacAddress() {
|
|
1974
|
+
const keyword = "MAC";
|
|
1975
|
+
try {
|
|
1976
|
+
// Execute the command to get serial number
|
|
1977
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1978
|
+
// Extract and format the serial number from the response data
|
|
1979
|
+
const macAddr = data
|
|
1980
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
1981
|
+
.toString("ascii") // Convert buffer to string
|
|
1982
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
1983
|
+
.replace(/\u0000/g, ""); // Remove null characters
|
|
1984
|
+
return macAddr;
|
|
1985
|
+
}
|
|
1986
|
+
catch (err) {
|
|
1987
|
+
// Log the error for debugging
|
|
1988
|
+
console.error("Error getting MAC address:", err);
|
|
1989
|
+
// Re-throw the error for higher-level handling
|
|
1990
|
+
throw err;
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
async getNetworkParams() {
|
|
1994
|
+
try {
|
|
1995
|
+
const params = {
|
|
1996
|
+
IPAddress: "",
|
|
1997
|
+
NetMask: "",
|
|
1998
|
+
GATEIPAddress: "",
|
|
1999
|
+
TCPPort: "",
|
|
2000
|
+
};
|
|
2001
|
+
const keywords = Object.keys(params);
|
|
2002
|
+
for await (const keyword of keywords) {
|
|
2003
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2004
|
+
params[keyword] = data
|
|
2005
|
+
.slice(8)
|
|
2006
|
+
.toString("utf-8")
|
|
2007
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
2008
|
+
.replace(/\u0000/g, "")
|
|
2009
|
+
.replace("=", "."); // Replace equal simbol to dot, due to sometimes there are parsing errors
|
|
2010
|
+
}
|
|
2011
|
+
return params;
|
|
2012
|
+
}
|
|
2013
|
+
catch (err) {
|
|
2014
|
+
console.error("Error getting Network Params: ", err);
|
|
2015
|
+
throw err;
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
async getSerialNumber() {
|
|
2019
|
+
const keyword = "~SerialNumber";
|
|
2020
|
+
let serialNumber = "";
|
|
2021
|
+
let count = 10;
|
|
2022
|
+
try {
|
|
2023
|
+
// Execute the command to get serial number
|
|
2024
|
+
/**
|
|
2025
|
+
* @dev implemented a counter and a while loop because sometimes serial number parses wrong for some reason
|
|
2026
|
+
* */
|
|
2027
|
+
while (serialNumber.length !== 13 && count > 0) {
|
|
2028
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2029
|
+
// Extract and format the serial number from the response data
|
|
2030
|
+
const SN = data
|
|
2031
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
2032
|
+
.toString("utf-8") // Convert buffer to string
|
|
2033
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
2034
|
+
.replace("=", "") // Remove sometines last number is a character equal to = or unknow character
|
|
2035
|
+
.replace(/\u0000/g, ""); // Remove null characters
|
|
2036
|
+
count--;
|
|
2037
|
+
serialNumber = SN;
|
|
2038
|
+
}
|
|
2039
|
+
return serialNumber;
|
|
2040
|
+
}
|
|
2041
|
+
catch (err) {
|
|
2042
|
+
// Log the error for debugging
|
|
2043
|
+
console.error("Error getting serial number:", err);
|
|
2044
|
+
// Re-throw the error for higher-level handling
|
|
2045
|
+
throw err;
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
/**
|
|
2049
|
+
* get Zkteko Template version
|
|
2050
|
+
* @returns number
|
|
2051
|
+
*/
|
|
2052
|
+
async getDeviceVersion() {
|
|
2053
|
+
const keyword = "~ZKFPVersion";
|
|
2054
|
+
try {
|
|
2055
|
+
// Execute the command to get device version
|
|
2056
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2057
|
+
// Extract and format the device version from the response data
|
|
2058
|
+
// Remove null characters
|
|
2059
|
+
return data
|
|
2060
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
2061
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
2062
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
2063
|
+
.replace(/\u0000/g, "");
|
|
2064
|
+
}
|
|
2065
|
+
catch (err) {
|
|
2066
|
+
// Log the error for debugging
|
|
2067
|
+
console.error("Error getting device version:", err);
|
|
2068
|
+
// Re-throw the error for higher-level handling
|
|
2069
|
+
throw err;
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
/**
|
|
2073
|
+
* get Device/Model Name
|
|
2074
|
+
* @returns
|
|
2075
|
+
*/
|
|
2076
|
+
async getDeviceName() {
|
|
2077
|
+
const keyword = "~DeviceName";
|
|
2078
|
+
try {
|
|
2079
|
+
let result;
|
|
2080
|
+
let retry = true;
|
|
2081
|
+
while (retry) {
|
|
2082
|
+
// Execute the command to get the device name
|
|
2083
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2084
|
+
// Extract and format the device name from the response data
|
|
2085
|
+
result = data
|
|
2086
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
2087
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
2088
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
2089
|
+
.replace(/\u0000/g, ""); // Remove null characters
|
|
2090
|
+
retry = result.includes("=");
|
|
2091
|
+
}
|
|
2092
|
+
return result;
|
|
2093
|
+
}
|
|
2094
|
+
catch (err) {
|
|
2095
|
+
// Log the error for debugging
|
|
2096
|
+
console.error("Error getting device name:", err);
|
|
2097
|
+
// Re-throw the error for higher-level handling
|
|
2098
|
+
throw err;
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
async getPlatform() {
|
|
2102
|
+
const keyword = "~Platform";
|
|
2103
|
+
try {
|
|
2104
|
+
let result;
|
|
2105
|
+
let retry = true;
|
|
2106
|
+
while (retry) {
|
|
2107
|
+
// Execute the command to get the device name
|
|
2108
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2109
|
+
// Extract and format the device name from the response data
|
|
2110
|
+
result = data
|
|
2111
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
2112
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
2113
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
2114
|
+
.replace(/\u0000/g, ""); // Remove null characters
|
|
2115
|
+
retry = result.includes("=");
|
|
2116
|
+
}
|
|
2117
|
+
return result;
|
|
2118
|
+
}
|
|
2119
|
+
catch (err) {
|
|
2120
|
+
// Log the error for debugging
|
|
2121
|
+
console.error("Error getting platform information:", err);
|
|
2122
|
+
// Re-throw the error for higher-level handling
|
|
2123
|
+
throw err;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
async getOS() {
|
|
2127
|
+
const keyword = "~OS";
|
|
2128
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2129
|
+
return data
|
|
2130
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
2131
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
2132
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
2133
|
+
.replace(/\u0000/g, "");
|
|
2134
|
+
}
|
|
2135
|
+
async getWorkCode() {
|
|
2136
|
+
const keyword = "WorkCode";
|
|
2137
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2138
|
+
// Extract and format the WorkCode information from the response data
|
|
2139
|
+
// Remove null characters
|
|
2140
|
+
return data
|
|
2141
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
2142
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
2143
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
2144
|
+
.replace(/\u0000/g, "");
|
|
2145
|
+
}
|
|
2146
|
+
/**
|
|
2147
|
+
* get User ID max length
|
|
2148
|
+
* @returns
|
|
2149
|
+
*/
|
|
2150
|
+
async getPIN() {
|
|
2151
|
+
const keyword = "~PIN2Width";
|
|
2152
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2153
|
+
return data
|
|
2154
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
2155
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
2156
|
+
.replace(`${keyword}=`, "") // Remove the keyword prefix
|
|
2157
|
+
.replace(/\u0000/g, "");
|
|
2158
|
+
}
|
|
2159
|
+
async getFaceOn() {
|
|
2160
|
+
const keyword = "FaceFunOn";
|
|
2161
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2162
|
+
const status = data
|
|
2163
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
2164
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
2165
|
+
.replace(`${keyword}=`, ""); // Remove the keyword prefix
|
|
2166
|
+
// Determine and return the face function status
|
|
2167
|
+
return status.includes("0") ? "No" : "Yes";
|
|
2168
|
+
}
|
|
2169
|
+
async getSSR() {
|
|
2170
|
+
const keyword = "~SSR";
|
|
2171
|
+
const data = await this._zkTcp.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2172
|
+
return data
|
|
2173
|
+
.slice(8) // Skip the first 8 bytes (header)
|
|
2174
|
+
.toString("ascii") // Convert buffer to ASCII string
|
|
2175
|
+
.replace(`${keyword}=`, "");
|
|
2176
|
+
}
|
|
2177
|
+
async getFirmware() {
|
|
2178
|
+
try {
|
|
2179
|
+
// Execute the command to get firmware information
|
|
2180
|
+
const data = await this._zkTcp.executeCmd(1100, "");
|
|
2181
|
+
// Extract and return the firmware version from the response data
|
|
2182
|
+
return data.slice(8).toString("ascii"); // Skip the first 8 bytes (header) and convert to ASCII string
|
|
2183
|
+
}
|
|
2184
|
+
catch (err) {
|
|
2185
|
+
// Log the error for debugging
|
|
2186
|
+
console.error("Error getting firmware version:", err);
|
|
2187
|
+
// Re-throw the error to be handled by the caller
|
|
2188
|
+
throw err;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
async getTime() {
|
|
2192
|
+
try {
|
|
2193
|
+
// Execute the command to get the current time
|
|
2194
|
+
const response = await this._zkTcp.executeCmd(COMMANDS.CMD_GET_TIME, "");
|
|
2195
|
+
// Check if the response is valid
|
|
2196
|
+
if (!response || response.length < 12) {
|
|
2197
|
+
throw new Error("Invalid response received for time command");
|
|
2198
|
+
}
|
|
2199
|
+
// Extract and decode the time value from the response
|
|
2200
|
+
const timeValue = response.readUInt32LE(8); // Read 4 bytes starting at offset 8
|
|
2201
|
+
const time = timeParser.decode(timeValue); // Parse and return the decoded time
|
|
2202
|
+
return time;
|
|
2203
|
+
}
|
|
2204
|
+
catch (err) {
|
|
2205
|
+
// Log the error for debugging
|
|
2206
|
+
console.error("Error getting time:", err);
|
|
2207
|
+
// Re-throw the error for the caller to handle
|
|
2208
|
+
throw err;
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
async setTime(tm) {
|
|
2212
|
+
try {
|
|
2213
|
+
// Validate the input time
|
|
2214
|
+
if (!(tm instanceof Date) && typeof tm !== "number") {
|
|
2215
|
+
throw new TypeError("Invalid time parameter. Must be a Date object or a timestamp.");
|
|
2216
|
+
}
|
|
2217
|
+
// Convert the input time to a Date object if it's not already
|
|
2218
|
+
const date = tm instanceof Date ? tm : new Date(tm);
|
|
2219
|
+
// Encode the time into the required format
|
|
2220
|
+
const encodedTime = timeParser.encode(date);
|
|
2221
|
+
// Create a buffer and write the encoded time
|
|
2222
|
+
const commandString = Buffer.alloc(32);
|
|
2223
|
+
commandString.writeUInt32LE(encodedTime, 0);
|
|
2224
|
+
// Send the command to set the time
|
|
2225
|
+
const time = await this._zkTcp.executeCmd(COMMANDS.CMD_SET_TIME, commandString);
|
|
2226
|
+
return !!time;
|
|
2227
|
+
}
|
|
2228
|
+
catch (err) {
|
|
2229
|
+
// Log the error for debugging
|
|
2230
|
+
console.error("Error setting time:", err);
|
|
2231
|
+
// Re-throw the error for the caller to handle
|
|
2232
|
+
throw err;
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
async voiceTest() {
|
|
2236
|
+
try {
|
|
2237
|
+
// Define the command data for the voice test
|
|
2238
|
+
const commandData = Buffer.from("\x00\x00", "binary");
|
|
2239
|
+
await this._zkTcp.executeCmd(COMMANDS.CMD_TESTVOICE, commandData);
|
|
2240
|
+
// Execute the command and return the result
|
|
2241
|
+
}
|
|
2242
|
+
catch (err) {
|
|
2243
|
+
// Log the error for debugging purposes
|
|
2244
|
+
console.error("Error executing voice test:", err);
|
|
2245
|
+
// Re-throw the error to be handled by the caller
|
|
2246
|
+
throw err;
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
class ZTCP {
|
|
2252
|
+
/**
|
|
2253
|
+
* @param_ip ip address of device
|
|
2254
|
+
* @param_port port number of device
|
|
2255
|
+
* @param_timeout connection timout
|
|
2256
|
+
* @param_comm_key communication key of device (if the case)
|
|
2257
|
+
* @return Zkteco TCP socket connection instance
|
|
2258
|
+
*/
|
|
2259
|
+
ip;
|
|
2260
|
+
port;
|
|
2261
|
+
timeout;
|
|
2262
|
+
sessionId = 0;
|
|
2263
|
+
replyId = 0;
|
|
2264
|
+
socket;
|
|
2265
|
+
comm_key;
|
|
2266
|
+
user_count = 0;
|
|
2267
|
+
fp_count = 0;
|
|
2268
|
+
pwd_count = 0;
|
|
2269
|
+
oplog_count = 0;
|
|
2270
|
+
attlog_count = 0;
|
|
2271
|
+
fp_cap = 0;
|
|
2272
|
+
user_cap = 0;
|
|
2273
|
+
attlog_cap = 0;
|
|
2274
|
+
fp_av = 0;
|
|
2275
|
+
user_av = 0;
|
|
2276
|
+
attlog_av = 0;
|
|
2277
|
+
face_count = 0;
|
|
2278
|
+
face_cap = 0;
|
|
2279
|
+
userPacketSize = 72;
|
|
2280
|
+
verbose = false;
|
|
2281
|
+
packetNumber = 0;
|
|
1306
2282
|
replyData = Buffer.from([]);
|
|
1307
|
-
|
|
2283
|
+
_optionsService;
|
|
1308
2284
|
_transactionService;
|
|
2285
|
+
_userService;
|
|
1309
2286
|
constructor(ip, port, timeout, comm_key, verbose) {
|
|
1310
2287
|
this.ip = ip;
|
|
1311
2288
|
this.port = port;
|
|
@@ -1313,6 +2290,7 @@ class ZTCP {
|
|
|
1313
2290
|
this.replyId = 0;
|
|
1314
2291
|
this.comm_key = comm_key;
|
|
1315
2292
|
this.verbose = verbose;
|
|
2293
|
+
this._optionsService = new OptionsService(this);
|
|
1316
2294
|
this._userService = new UserService(this);
|
|
1317
2295
|
this._transactionService = new TransactionService(this);
|
|
1318
2296
|
}
|
|
@@ -1320,21 +2298,21 @@ class ZTCP {
|
|
|
1320
2298
|
return new Promise((resolve, reject) => {
|
|
1321
2299
|
this.socket = new net.Socket();
|
|
1322
2300
|
// Handle socket error
|
|
1323
|
-
this.socket.once(
|
|
2301
|
+
this.socket.once("error", (err) => {
|
|
1324
2302
|
this.socket = undefined; // Ensure socket reference is cleared
|
|
1325
2303
|
reject(err);
|
|
1326
|
-
if (typeof cbError ===
|
|
2304
|
+
if (typeof cbError === "function")
|
|
1327
2305
|
cbError(err);
|
|
1328
2306
|
});
|
|
1329
2307
|
// Handle successful connection
|
|
1330
|
-
this.socket.once(
|
|
2308
|
+
this.socket.once("connect", () => {
|
|
1331
2309
|
resolve(this.socket);
|
|
1332
2310
|
});
|
|
1333
2311
|
// Handle socket closure
|
|
1334
|
-
this.socket.once(
|
|
2312
|
+
this.socket.once("close", () => {
|
|
1335
2313
|
this.socket = undefined; // Ensure socket reference is cleared
|
|
1336
|
-
if (typeof cbClose ===
|
|
1337
|
-
cbClose(
|
|
2314
|
+
if (typeof cbClose === "function")
|
|
2315
|
+
cbClose("tcp");
|
|
1338
2316
|
});
|
|
1339
2317
|
// Set socket timeout if provided
|
|
1340
2318
|
if (this.timeout) {
|
|
@@ -1346,7 +2324,7 @@ class ZTCP {
|
|
|
1346
2324
|
}
|
|
1347
2325
|
async connect() {
|
|
1348
2326
|
try {
|
|
1349
|
-
let reply = await this.executeCmd(COMMANDS.CMD_CONNECT,
|
|
2327
|
+
let reply = await this.executeCmd(COMMANDS.CMD_CONNECT, "");
|
|
1350
2328
|
if (reply.readUInt16LE(0) === COMMANDS.CMD_ACK_OK) {
|
|
1351
2329
|
return true;
|
|
1352
2330
|
}
|
|
@@ -1362,12 +2340,12 @@ class ZTCP {
|
|
|
1362
2340
|
}
|
|
1363
2341
|
else {
|
|
1364
2342
|
// No reply received; throw an error
|
|
1365
|
-
throw new Error(
|
|
2343
|
+
throw new Error("NO_REPLY_ON_CMD_CONNECT");
|
|
1366
2344
|
}
|
|
1367
2345
|
}
|
|
1368
2346
|
catch (err) {
|
|
1369
2347
|
// Log the error for debugging, if necessary
|
|
1370
|
-
console.error(
|
|
2348
|
+
console.error("Failed to connect:", err);
|
|
1371
2349
|
// Re-throw the error for handling by the caller
|
|
1372
2350
|
throw err;
|
|
1373
2351
|
}
|
|
@@ -1379,10 +2357,10 @@ class ZTCP {
|
|
|
1379
2357
|
return resolve(true);
|
|
1380
2358
|
}
|
|
1381
2359
|
// Clean up listeners to avoid potential memory leaks or duplicate handling
|
|
1382
|
-
this.socket.removeAllListeners(
|
|
2360
|
+
this.socket.removeAllListeners("data");
|
|
1383
2361
|
// Set a timeout to handle cases where socket.end might not resolve
|
|
1384
2362
|
const timer = setTimeout(() => {
|
|
1385
|
-
this.socket
|
|
2363
|
+
this.socket?.destroy(); // Forcibly close the socket if not closed properly
|
|
1386
2364
|
resolve(true); // Resolve even if the socket was not closed properly
|
|
1387
2365
|
}, 2000);
|
|
1388
2366
|
// Close the socket and clear the timeout upon successful completion
|
|
@@ -1391,49 +2369,44 @@ class ZTCP {
|
|
|
1391
2369
|
resolve(true); // Resolve once the socket has ended
|
|
1392
2370
|
});
|
|
1393
2371
|
// Handle socket errors during closing
|
|
1394
|
-
this.socket.once(
|
|
2372
|
+
this.socket.once("error", (err) => {
|
|
1395
2373
|
clearTimeout(timer);
|
|
1396
2374
|
reject(err); // Reject the promise with the error
|
|
1397
2375
|
});
|
|
1398
2376
|
});
|
|
1399
2377
|
}
|
|
1400
|
-
writeMessage(msg, connect) {
|
|
2378
|
+
writeMessage(msg, connect, cb) {
|
|
1401
2379
|
return new Promise((resolve, reject) => {
|
|
1402
2380
|
// Check if the socket is initialized
|
|
1403
2381
|
if (!this.socket) {
|
|
1404
|
-
return reject(new Error(
|
|
2382
|
+
return reject(new Error("Socket is not initialized"));
|
|
1405
2383
|
}
|
|
1406
2384
|
// Define a variable for the timeout reference
|
|
1407
|
-
|
|
2385
|
+
const timer = setTimeout(() => {
|
|
2386
|
+
// Check if the socket is still valid before trying to remove the listener
|
|
2387
|
+
cleanUp();
|
|
2388
|
+
reject(new Error("TIMEOUT_ON_WRITING_MESSAGE")); // Reject the promise on timeout
|
|
2389
|
+
}, connect ? 3000 : this.timeout);
|
|
1408
2390
|
// Handle incoming data
|
|
1409
2391
|
const onData = (data) => {
|
|
1410
2392
|
// Check if the socket is still valid before trying to remove the listener
|
|
2393
|
+
cleanUp(); // Clear the timeout once data is received
|
|
2394
|
+
resolve(cb(data)); // Resolve the promise with the received data
|
|
2395
|
+
};
|
|
2396
|
+
const cleanUp = () => {
|
|
2397
|
+
if (timer)
|
|
2398
|
+
clearTimeout(timer);
|
|
1411
2399
|
if (this.socket) {
|
|
1412
|
-
this.socket.removeListener(
|
|
2400
|
+
this.socket.removeListener("data", onData); // Remove the data event listener
|
|
1413
2401
|
}
|
|
1414
|
-
clearTimeout(timer); // Clear the timeout once data is received
|
|
1415
|
-
resolve(data); // Resolve the promise with the received data
|
|
1416
2402
|
};
|
|
1417
2403
|
// Attach the data event listener
|
|
1418
|
-
this.socket.
|
|
2404
|
+
this.socket.on("data", onData);
|
|
1419
2405
|
// Attempt to write the message to the socket
|
|
1420
|
-
this.socket.write(msg,
|
|
2406
|
+
this.socket.write(msg, undefined, (err) => {
|
|
1421
2407
|
if (err) {
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
this.socket.removeListener('data', onData); // Clean up listener on write error
|
|
1425
|
-
}
|
|
1426
|
-
return reject(err); // Reject the promise with the write error
|
|
1427
|
-
}
|
|
1428
|
-
// If a timeout is set, configure it
|
|
1429
|
-
if (this.timeout) {
|
|
1430
|
-
timer = setTimeout(() => {
|
|
1431
|
-
// Check if the socket is still valid before trying to remove the listener
|
|
1432
|
-
if (this.socket) {
|
|
1433
|
-
this.socket.removeListener('data', onData); // Remove listener on timeout
|
|
1434
|
-
}
|
|
1435
|
-
reject(new Error('TIMEOUT_ON_WRITING_MESSAGE')); // Reject the promise on timeout
|
|
1436
|
-
}, connect ? 2000 : this.timeout);
|
|
2408
|
+
cleanUp();
|
|
2409
|
+
reject(err); // Reject the promise with the write error
|
|
1437
2410
|
}
|
|
1438
2411
|
});
|
|
1439
2412
|
});
|
|
@@ -1446,12 +2419,18 @@ class ZTCP {
|
|
|
1446
2419
|
// Internal callback to handle data reception
|
|
1447
2420
|
const internalCallback = (data_1) => {
|
|
1448
2421
|
if (this.socket) {
|
|
1449
|
-
this.socket.removeListener(
|
|
2422
|
+
this.socket.removeListener("data", handleOnData); // Clean up listener
|
|
1450
2423
|
}
|
|
1451
2424
|
if (timer)
|
|
1452
2425
|
clearTimeout(timer); // Clear the timeout
|
|
1453
2426
|
resolve(data_1); // Resolve the promise with the data
|
|
1454
2427
|
};
|
|
2428
|
+
const onTimeOut = () => setTimeout(() => {
|
|
2429
|
+
if (this.socket) {
|
|
2430
|
+
this.socket.removeListener("data", handleOnData); // Clean up listener on timeout
|
|
2431
|
+
}
|
|
2432
|
+
reject(new Error("TIMEOUT_IN_RECEIVING_RESPONSE_AFTER_REQUESTING_DATA")); // Reject on timeout
|
|
2433
|
+
}, this.timeout);
|
|
1455
2434
|
// Handle incoming data
|
|
1456
2435
|
const handleOnData = (data_3) => {
|
|
1457
2436
|
replyBuffer = Buffer.concat([replyBuffer, data_3]); // Accumulate data
|
|
@@ -1461,7 +2440,7 @@ class ZTCP {
|
|
|
1461
2440
|
// Decode the TCP header
|
|
1462
2441
|
const header = decodeTCPHeader(replyBuffer.subarray(0, 16));
|
|
1463
2442
|
if (this.verbose) {
|
|
1464
|
-
console.log("
|
|
2443
|
+
console.log("response command: ", header.commandId, COMMANDS[header.commandId], "replyid: ", header.replyId);
|
|
1465
2444
|
}
|
|
1466
2445
|
// Handle based on command ID
|
|
1467
2446
|
if (header.commandId === COMMANDS.CMD_DATA) {
|
|
@@ -1472,12 +2451,7 @@ class ZTCP {
|
|
|
1472
2451
|
}
|
|
1473
2452
|
else {
|
|
1474
2453
|
// Set a timeout to handle errors
|
|
1475
|
-
timer =
|
|
1476
|
-
if (this.socket) {
|
|
1477
|
-
this.socket.removeListener('data', handleOnData); // Clean up listener on timeout
|
|
1478
|
-
}
|
|
1479
|
-
reject(new Error('TIMEOUT_ON_RECEIVING_REQUEST_DATA')); // Reject on timeout
|
|
1480
|
-
}, this.timeout);
|
|
2454
|
+
timer = onTimeOut();
|
|
1481
2455
|
// Extract packet length and handle accordingly
|
|
1482
2456
|
const packetLength = data_3.readUIntLE(4, 2);
|
|
1483
2457
|
if (packetLength > 8) {
|
|
@@ -1487,26 +2461,21 @@ class ZTCP {
|
|
|
1487
2461
|
};
|
|
1488
2462
|
// Ensure the socket is valid before attaching the listener
|
|
1489
2463
|
if (this.socket) {
|
|
1490
|
-
this.socket.on(
|
|
2464
|
+
this.socket.on("data", handleOnData);
|
|
1491
2465
|
// Write the message to the socket
|
|
1492
|
-
this.socket.write(msg,
|
|
2466
|
+
this.socket.write(msg, undefined, (err) => {
|
|
1493
2467
|
if (err) {
|
|
1494
2468
|
if (this.socket) {
|
|
1495
|
-
this.socket.removeListener(
|
|
2469
|
+
this.socket.removeListener("data", handleOnData); // Clean up listener on error
|
|
1496
2470
|
}
|
|
1497
2471
|
return reject(err); // Reject the promise with the error
|
|
1498
2472
|
}
|
|
1499
2473
|
// Set a timeout to handle cases where no response is received
|
|
1500
|
-
timer =
|
|
1501
|
-
if (this.socket) {
|
|
1502
|
-
this.socket.removeListener('data', handleOnData); // Clean up listener on timeout
|
|
1503
|
-
}
|
|
1504
|
-
reject(new Error('TIMEOUT_IN_RECEIVING_RESPONSE_AFTER_REQUESTING_DATA')); // Reject on timeout
|
|
1505
|
-
}, this.timeout);
|
|
2474
|
+
timer = onTimeOut();
|
|
1506
2475
|
});
|
|
1507
2476
|
}
|
|
1508
2477
|
else {
|
|
1509
|
-
reject(new Error(
|
|
2478
|
+
reject(new Error("SOCKET_NOT_INITIALIZED")); // Reject if socket is not initialized
|
|
1510
2479
|
}
|
|
1511
2480
|
});
|
|
1512
2481
|
}
|
|
@@ -1532,27 +2501,49 @@ class ZTCP {
|
|
|
1532
2501
|
else {
|
|
1533
2502
|
this.replyId++;
|
|
1534
2503
|
}
|
|
2504
|
+
const currentReply = this.replyId;
|
|
1535
2505
|
const buf = createTCPHeader(command, this.sessionId, this.replyId, data);
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
2506
|
+
const callback = (responseData) => {
|
|
2507
|
+
const packets = splitTcpPackets(responseData);
|
|
2508
|
+
for (const packet of packets) {
|
|
2509
|
+
const headers = decodeTCPHeader(packet);
|
|
2510
|
+
if (this.verbose) {
|
|
2511
|
+
const JOIN_CMD = { ...COMMANDS, ...DISCOVERED_CMD };
|
|
2512
|
+
console.debug("request command:", COMMANDS[command], "\nresponse command: ", JOIN_CMD[headers.commandId], "replyid: ", headers.replyId);
|
|
2513
|
+
}
|
|
2514
|
+
if (+headers.replyId === currentReply + 1) {
|
|
2515
|
+
return packet;
|
|
2516
|
+
}
|
|
2517
|
+
continue;
|
|
1548
2518
|
}
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
2519
|
+
};
|
|
2520
|
+
return new Promise((Resolve, Reject) => {
|
|
2521
|
+
// Write the message to the socket and wait for a response
|
|
2522
|
+
this.writeMessage(buf, command === COMMANDS.CMD_CONNECT || command === COMMANDS.CMD_EXIT, callback)
|
|
2523
|
+
.then((reply) => {
|
|
2524
|
+
// Remove TCP header from the response
|
|
2525
|
+
let rReply;
|
|
2526
|
+
try {
|
|
2527
|
+
rReply = removeTcpHeader(reply);
|
|
2528
|
+
}
|
|
2529
|
+
catch (e) {
|
|
2530
|
+
console.log("reply", reply);
|
|
2531
|
+
}
|
|
2532
|
+
// Update sessionId for connection command responses
|
|
2533
|
+
if (command === COMMANDS.CMD_CONNECT &&
|
|
2534
|
+
rReply &&
|
|
2535
|
+
rReply.length >= 6) {
|
|
2536
|
+
// Assuming sessionId is located at offset 4 and is 2 bytes long
|
|
2537
|
+
this.sessionId = rReply.readUInt16LE(4);
|
|
2538
|
+
}
|
|
2539
|
+
Resolve(rReply);
|
|
2540
|
+
})
|
|
2541
|
+
.catch((err) => {
|
|
2542
|
+
// Log or handle the error if necessary
|
|
2543
|
+
console.error("Error executing command:", err);
|
|
2544
|
+
Reject(err); // Re-throw the error for handling by the caller
|
|
2545
|
+
});
|
|
2546
|
+
});
|
|
1556
2547
|
}
|
|
1557
2548
|
async sendChunkRequest(start, size) {
|
|
1558
2549
|
this.replyId++;
|
|
@@ -1561,8 +2552,8 @@ class ZTCP {
|
|
|
1561
2552
|
reqData.writeUInt32LE(size, 4);
|
|
1562
2553
|
const buf = createTCPHeader(COMMANDS.CMD_DATA_RDY, this.sessionId, this.replyId, reqData);
|
|
1563
2554
|
try {
|
|
1564
|
-
|
|
1565
|
-
this.socket
|
|
2555
|
+
const promise = new Promise((resolve, reject) => {
|
|
2556
|
+
this.socket?.write(buf, undefined, (err) => {
|
|
1566
2557
|
if (err) {
|
|
1567
2558
|
console.error(`[TCP][SEND_CHUNK_REQUEST] Error sending chunk request: ${err.message}`);
|
|
1568
2559
|
reject(err); // Reject the promise if there is an error
|
|
@@ -1572,6 +2563,7 @@ class ZTCP {
|
|
|
1572
2563
|
}
|
|
1573
2564
|
});
|
|
1574
2565
|
});
|
|
2566
|
+
await promise;
|
|
1575
2567
|
}
|
|
1576
2568
|
catch (err) {
|
|
1577
2569
|
// Handle or log the error as needed
|
|
@@ -1587,18 +2579,18 @@ class ZTCP {
|
|
|
1587
2579
|
* readWithBuffer will reject error if it'wrong when starting request data
|
|
1588
2580
|
* readWithBuffer will return { data: replyData , err: Error } when receiving requested data
|
|
1589
2581
|
*/
|
|
1590
|
-
readWithBuffer(reqData, cb
|
|
2582
|
+
readWithBuffer(reqData, cb) {
|
|
1591
2583
|
return new Promise(async (resolve, reject) => {
|
|
1592
2584
|
this.replyId++;
|
|
1593
2585
|
const buf = createTCPHeader(COMMANDS.CMD_DATA_WRRQ, this.sessionId, this.replyId, reqData);
|
|
1594
|
-
let reply
|
|
2586
|
+
let reply;
|
|
1595
2587
|
try {
|
|
1596
2588
|
reply = await this.requestData(buf);
|
|
1597
2589
|
}
|
|
1598
2590
|
catch (err) {
|
|
1599
2591
|
reject(err);
|
|
1600
2592
|
}
|
|
1601
|
-
const header = decodeTCPHeader(reply
|
|
2593
|
+
const header = decodeTCPHeader(reply?.subarray(0, 16));
|
|
1602
2594
|
switch (header.commandId) {
|
|
1603
2595
|
case COMMANDS.CMD_DATA: {
|
|
1604
2596
|
resolve({ data: reply.subarray(16), mode: 8 });
|
|
@@ -1612,56 +2604,64 @@ class ZTCP {
|
|
|
1612
2604
|
const size = recvData.readUIntLE(1, 4);
|
|
1613
2605
|
// We need to split the data to many chunks to receive , because it's to large
|
|
1614
2606
|
// After receiving all chunk data , we concat it to TotalBuffer variable , that 's the data we want
|
|
1615
|
-
|
|
1616
|
-
|
|
2607
|
+
const remain = size % Constants.MAX_CHUNK;
|
|
2608
|
+
const numberChunks = Math.round(size - remain) / Constants.MAX_CHUNK;
|
|
1617
2609
|
this.packetNumber = numberChunks + (remain > 0 ? 1 : 0);
|
|
1618
2610
|
//let replyData = Buffer.from([])
|
|
1619
2611
|
let totalBuffer = Buffer.from([]);
|
|
1620
2612
|
let realTotalBuffer = Buffer.from([]);
|
|
1621
2613
|
let timer = setTimeout(() => {
|
|
1622
|
-
internalCallback(this.replyData, new Error(
|
|
2614
|
+
internalCallback(this.replyData, new Error("TIMEOUT WHEN RECEIVING PACKET"));
|
|
1623
2615
|
}, this.timeout);
|
|
1624
2616
|
const internalCallback = (replyData, err = null) => {
|
|
1625
|
-
this.socket && this.socket.removeAllListeners(
|
|
2617
|
+
this.socket && this.socket.removeAllListeners("data");
|
|
1626
2618
|
timer && clearTimeout(timer);
|
|
1627
2619
|
resolve({ data: replyData, err });
|
|
1628
2620
|
};
|
|
1629
|
-
this.socket
|
|
1630
|
-
internalCallback(this.replyData, new Error(
|
|
2621
|
+
this.socket?.once("close", () => {
|
|
2622
|
+
internalCallback(this.replyData, new Error("Socket is disconnected unexpectedly"));
|
|
1631
2623
|
});
|
|
1632
2624
|
for (let i = 0; i <= numberChunks; i++) {
|
|
1633
2625
|
const data = await new Promise((resolve2, reject2) => {
|
|
1634
2626
|
try {
|
|
1635
|
-
this.sendChunkRequest(i * Constants.MAX_CHUNK,
|
|
1636
|
-
|
|
1637
|
-
: Constants.MAX_CHUNK);
|
|
1638
|
-
this.socket.on('data', (reply) => {
|
|
2627
|
+
this.sendChunkRequest(i * Constants.MAX_CHUNK, i === numberChunks ? remain : Constants.MAX_CHUNK);
|
|
2628
|
+
this.socket?.on("data", (reply) => {
|
|
1639
2629
|
clearTimeout(timer);
|
|
1640
2630
|
timer = setTimeout(() => {
|
|
1641
2631
|
internalCallback(this.replyData, new Error(`TIME OUT !! ${this.packetNumber} PACKETS REMAIN !`));
|
|
1642
2632
|
}, this.timeout);
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
2633
|
+
if (this.verbose && reply.length >= 8) {
|
|
2634
|
+
const headers = decodeTCPHeader(reply);
|
|
2635
|
+
if (COMMANDS[headers.commandId]) {
|
|
2636
|
+
switch (headers.commandId) {
|
|
2637
|
+
case COMMANDS.CMD_ACK_OK:
|
|
2638
|
+
case COMMANDS.CMD_DATA:
|
|
2639
|
+
this.verbose &&
|
|
2640
|
+
console.log("CMD received: ", COMMANDS[headers.commandId]);
|
|
2641
|
+
break;
|
|
2642
|
+
case COMMANDS.CMD_PREPARE_DATA:
|
|
2643
|
+
this.verbose &&
|
|
2644
|
+
console.log("CMD received: ", COMMANDS[headers.commandId]);
|
|
2645
|
+
this.verbose &&
|
|
2646
|
+
console.log(`recieve chunk: prepare data size is ${headers.payloadSize}`);
|
|
2647
|
+
break;
|
|
2648
|
+
default:
|
|
2649
|
+
break;
|
|
2650
|
+
}
|
|
1656
2651
|
}
|
|
1657
2652
|
}
|
|
1658
2653
|
totalBuffer = Buffer.concat([totalBuffer, reply]);
|
|
1659
2654
|
const packetLength = totalBuffer.readUIntLE(4, 2);
|
|
1660
2655
|
if (totalBuffer.length >= 8 + packetLength) {
|
|
1661
|
-
realTotalBuffer = Buffer.concat([
|
|
2656
|
+
realTotalBuffer = Buffer.concat([
|
|
2657
|
+
realTotalBuffer,
|
|
2658
|
+
totalBuffer.subarray(16, 8 + packetLength),
|
|
2659
|
+
]);
|
|
1662
2660
|
totalBuffer = totalBuffer.subarray(8 + packetLength);
|
|
1663
|
-
if ((this.packetNumber > 1 &&
|
|
1664
|
-
|
|
2661
|
+
if ((this.packetNumber > 1 &&
|
|
2662
|
+
realTotalBuffer.length === Constants.MAX_CHUNK + 8) ||
|
|
2663
|
+
(this.packetNumber === 1 &&
|
|
2664
|
+
realTotalBuffer.length === remain + 8)) {
|
|
1665
2665
|
this.packetNumber--;
|
|
1666
2666
|
cb && cb(realTotalBuffer.length, size);
|
|
1667
2667
|
resolve2(realTotalBuffer.subarray(8));
|
|
@@ -1675,8 +2675,11 @@ class ZTCP {
|
|
|
1675
2675
|
reject2(e);
|
|
1676
2676
|
}
|
|
1677
2677
|
});
|
|
1678
|
-
this.replyData = Buffer.concat([
|
|
1679
|
-
|
|
2678
|
+
this.replyData = Buffer.concat([
|
|
2679
|
+
this.replyData,
|
|
2680
|
+
data,
|
|
2681
|
+
]);
|
|
2682
|
+
this.socket?.removeAllListeners("data");
|
|
1680
2683
|
if (this.packetNumber <= 0) {
|
|
1681
2684
|
resolve({ data: this.replyData });
|
|
1682
2685
|
}
|
|
@@ -1684,7 +2687,7 @@ class ZTCP {
|
|
|
1684
2687
|
break;
|
|
1685
2688
|
}
|
|
1686
2689
|
default: {
|
|
1687
|
-
reject(new Error(
|
|
2690
|
+
reject(new Error("ERROR_IN_UNHANDLE_CMD " + exportErrorMessage(header.commandId)));
|
|
1688
2691
|
}
|
|
1689
2692
|
}
|
|
1690
2693
|
});
|
|
@@ -1695,16 +2698,13 @@ class ZTCP {
|
|
|
1695
2698
|
* reject error when starting request data
|
|
1696
2699
|
* return { data: records, err: Error } when receiving requested data
|
|
1697
2700
|
*/
|
|
1698
|
-
async getAttendances(callbackInProcess = () => { }) {
|
|
1699
|
-
return await this._transactionService.getAttendances(callbackInProcess);
|
|
1700
|
-
}
|
|
1701
2701
|
async freeData() {
|
|
1702
2702
|
try {
|
|
1703
|
-
const resp = await this.executeCmd(COMMANDS.CMD_FREE_DATA,
|
|
2703
|
+
const resp = await this.executeCmd(COMMANDS.CMD_FREE_DATA, "");
|
|
1704
2704
|
return !!resp;
|
|
1705
2705
|
}
|
|
1706
2706
|
catch (err) {
|
|
1707
|
-
console.error(
|
|
2707
|
+
console.error("Error freeing data:", err);
|
|
1708
2708
|
throw err; // Optionally, re-throw the error if you need to handle it upstream
|
|
1709
2709
|
}
|
|
1710
2710
|
}
|
|
@@ -1714,28 +2714,28 @@ class ZTCP {
|
|
|
1714
2714
|
return !!resp;
|
|
1715
2715
|
}
|
|
1716
2716
|
catch (err) {
|
|
1717
|
-
console.error(
|
|
2717
|
+
console.error("Error disabling device:", err);
|
|
1718
2718
|
throw err; // Optionally, re-throw the error if you need to handle it upstream
|
|
1719
2719
|
}
|
|
1720
2720
|
}
|
|
1721
2721
|
async enableDevice() {
|
|
1722
2722
|
try {
|
|
1723
|
-
const resp = await this.executeCmd(COMMANDS.CMD_ENABLEDEVICE,
|
|
2723
|
+
const resp = await this.executeCmd(COMMANDS.CMD_ENABLEDEVICE, "");
|
|
1724
2724
|
return !!resp;
|
|
1725
2725
|
}
|
|
1726
2726
|
catch (err) {
|
|
1727
|
-
console.error(
|
|
2727
|
+
console.error("Error enabling device:", err);
|
|
1728
2728
|
throw err; // Optionally, re-throw the error if you need to handle it upstream
|
|
1729
2729
|
}
|
|
1730
2730
|
}
|
|
1731
2731
|
async disconnect() {
|
|
1732
2732
|
try {
|
|
1733
2733
|
// Attempt to execute the disconnect command
|
|
1734
|
-
await this.executeCmd(COMMANDS.CMD_EXIT,
|
|
2734
|
+
await this.executeCmd(COMMANDS.CMD_EXIT, "");
|
|
1735
2735
|
}
|
|
1736
2736
|
catch (err) {
|
|
1737
2737
|
// Log any errors encountered during command execution
|
|
1738
|
-
console.error(
|
|
2738
|
+
console.error("Error during disconnection:", err);
|
|
1739
2739
|
// Optionally, add more handling or recovery logic here
|
|
1740
2740
|
}
|
|
1741
2741
|
// Attempt to close the socket and return the result
|
|
@@ -1744,7 +2744,7 @@ class ZTCP {
|
|
|
1744
2744
|
}
|
|
1745
2745
|
catch (err) {
|
|
1746
2746
|
// Log any errors encountered while closing the socket
|
|
1747
|
-
console.error(
|
|
2747
|
+
console.error("Error during socket closure:", err);
|
|
1748
2748
|
// Optionally, rethrow or handle the error if necessary
|
|
1749
2749
|
throw err; // Re-throwing to propagate the error
|
|
1750
2750
|
}
|
|
@@ -1752,17 +2752,17 @@ class ZTCP {
|
|
|
1752
2752
|
async getInfo() {
|
|
1753
2753
|
try {
|
|
1754
2754
|
// Execute the command to retrieve free sizes from the device
|
|
1755
|
-
const data = await this.executeCmd(COMMANDS.CMD_GET_FREE_SIZES,
|
|
2755
|
+
const data = await this.executeCmd(COMMANDS.CMD_GET_FREE_SIZES, "");
|
|
1756
2756
|
// Parse the response data to extract and return relevant information
|
|
1757
2757
|
return {
|
|
1758
2758
|
userCounts: data.readUIntLE(24, 4), // Number of users
|
|
1759
2759
|
logCounts: data.readUIntLE(40, 4), // Number of logs
|
|
1760
|
-
logCapacity: data.readUIntLE(72, 4) // Capacity of logs in bytes
|
|
2760
|
+
logCapacity: data.readUIntLE(72, 4), // Capacity of logs in bytes
|
|
1761
2761
|
};
|
|
1762
2762
|
}
|
|
1763
2763
|
catch (err) {
|
|
1764
2764
|
// Log the error for debugging purposes
|
|
1765
|
-
console.error(
|
|
2765
|
+
console.error("Error getting device info:", err);
|
|
1766
2766
|
// Re-throw the error to allow upstream error handling
|
|
1767
2767
|
throw err;
|
|
1768
2768
|
}
|
|
@@ -1770,7 +2770,7 @@ class ZTCP {
|
|
|
1770
2770
|
async getSizes() {
|
|
1771
2771
|
try {
|
|
1772
2772
|
// Execute the command to retrieve free sizes from the device
|
|
1773
|
-
const data = await this.executeCmd(COMMANDS.CMD_GET_FREE_SIZES,
|
|
2773
|
+
const data = await this.executeCmd(COMMANDS.CMD_GET_FREE_SIZES, "");
|
|
1774
2774
|
// Parse the response data to extract and return relevant information
|
|
1775
2775
|
const buf = data.slice(8); // remove header
|
|
1776
2776
|
this.user_count = buf.readUIntLE(16, 4);
|
|
@@ -1800,362 +2800,27 @@ class ZTCP {
|
|
|
1800
2800
|
userAvailable: this.user_av,
|
|
1801
2801
|
attLogAvailable: this.attlog_av,
|
|
1802
2802
|
faceCount: this.face_count,
|
|
1803
|
-
faceCapacity: this.face_cap
|
|
2803
|
+
faceCapacity: this.face_cap,
|
|
1804
2804
|
};
|
|
1805
2805
|
}
|
|
1806
2806
|
catch (err) {
|
|
1807
2807
|
// Log the error for debugging purposes
|
|
1808
|
-
console.error(
|
|
2808
|
+
console.error("Error getting device info:", err);
|
|
1809
2809
|
// Re-throw the error to allow upstream error handling
|
|
1810
2810
|
throw err;
|
|
1811
2811
|
}
|
|
1812
2812
|
}
|
|
1813
|
-
|
|
1814
|
-
const keyword = '~OEMVendor';
|
|
1815
|
-
try {
|
|
1816
|
-
// Execute the command to get oem vendor
|
|
1817
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1818
|
-
// Extract and format the oem bendor from the response data
|
|
1819
|
-
const vendor = data.slice(8) // Skip the first 8 bytes (header)
|
|
1820
|
-
.toString('ascii') // Convert buffer to string
|
|
1821
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1822
|
-
.replace(/\u0000/g, ''); // Remove null characters
|
|
1823
|
-
return vendor;
|
|
1824
|
-
}
|
|
1825
|
-
catch (err) {
|
|
1826
|
-
// Log the error for debugging
|
|
1827
|
-
console.error('Error getting vendor:', err);
|
|
1828
|
-
// Re-throw the error for higher-level handling
|
|
1829
|
-
throw err;
|
|
1830
|
-
}
|
|
1831
|
-
}
|
|
1832
|
-
async getProductTime() {
|
|
1833
|
-
const keyword = '~ProductTime';
|
|
1834
|
-
try {
|
|
1835
|
-
// Execute the command to get serial number
|
|
1836
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1837
|
-
// Extract and format the serial number from the response data
|
|
1838
|
-
const ProductTime = data.slice(8) // Skip the first 8 bytes (header)
|
|
1839
|
-
.toString('ascii') // Convert buffer to string
|
|
1840
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1841
|
-
.replace(/\u0000/g, ''); // Remove null characters
|
|
1842
|
-
return new Date(ProductTime);
|
|
1843
|
-
}
|
|
1844
|
-
catch (err) {
|
|
1845
|
-
// Log the error for debugging
|
|
1846
|
-
console.error('Error getting Product Time:', err);
|
|
1847
|
-
// Re-throw the error for higher-level handling
|
|
1848
|
-
throw err;
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
|
-
async getMacAddress() {
|
|
1852
|
-
const keyword = 'MAC';
|
|
1853
|
-
try {
|
|
1854
|
-
// Execute the command to get serial number
|
|
1855
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1856
|
-
// Extract and format the serial number from the response data
|
|
1857
|
-
const macAddr = data.slice(8) // Skip the first 8 bytes (header)
|
|
1858
|
-
.toString('ascii') // Convert buffer to string
|
|
1859
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1860
|
-
.replace(/\u0000/g, ''); // Remove null characters
|
|
1861
|
-
return macAddr;
|
|
1862
|
-
}
|
|
1863
|
-
catch (err) {
|
|
1864
|
-
// Log the error for debugging
|
|
1865
|
-
console.error('Error getting MAC address:', err);
|
|
1866
|
-
// Re-throw the error for higher-level handling
|
|
1867
|
-
throw err;
|
|
1868
|
-
}
|
|
1869
|
-
}
|
|
1870
|
-
async getNetworkParams() {
|
|
1871
|
-
try {
|
|
1872
|
-
const params = {
|
|
1873
|
-
IPAddress: this.ip,
|
|
1874
|
-
NetMask: '',
|
|
1875
|
-
GATEIPAddress: ''
|
|
1876
|
-
};
|
|
1877
|
-
const keywords = Object.keys(params);
|
|
1878
|
-
for await (const keyword of keywords) {
|
|
1879
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1880
|
-
params[keyword] = data.slice(8)
|
|
1881
|
-
.toString('utf-8')
|
|
1882
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1883
|
-
.replace(/\u0000/g, '')
|
|
1884
|
-
.replace('=', '.'); // Replace equal simbol to dot, due to sometimes there are parsing errors
|
|
1885
|
-
}
|
|
1886
|
-
return params;
|
|
1887
|
-
}
|
|
1888
|
-
catch (err) {
|
|
1889
|
-
console.error("Error getting Network Params: ", err);
|
|
1890
|
-
throw err;
|
|
1891
|
-
}
|
|
1892
|
-
}
|
|
1893
|
-
async getSerialNumber() {
|
|
1894
|
-
const keyword = '~SerialNumber';
|
|
1895
|
-
let serialNumber = '';
|
|
1896
|
-
let count = 10;
|
|
1897
|
-
try {
|
|
1898
|
-
// Execute the command to get serial number
|
|
1899
|
-
/**
|
|
1900
|
-
* @dev implemented a counter and a while loop because sometimes serial number parses wrong for some reason
|
|
1901
|
-
* */
|
|
1902
|
-
while (serialNumber.length !== 13 && count > 0) {
|
|
1903
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1904
|
-
// Extract and format the serial number from the response data
|
|
1905
|
-
const SN = data.slice(8) // Skip the first 8 bytes (header)
|
|
1906
|
-
.toString('utf-8') // Convert buffer to string
|
|
1907
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1908
|
-
.replace('=', '') // Remove sometines last number is a character equal to = or unknow character
|
|
1909
|
-
.replace(/\u0000/g, ''); // Remove null characters
|
|
1910
|
-
if (serialNumber.length !== 13 && this.verbose) {
|
|
1911
|
-
console.warn('Serial number length not equal to 13, check');
|
|
1912
|
-
}
|
|
1913
|
-
count--;
|
|
1914
|
-
serialNumber = SN;
|
|
1915
|
-
}
|
|
1916
|
-
return serialNumber;
|
|
1917
|
-
}
|
|
1918
|
-
catch (err) {
|
|
1919
|
-
// Log the error for debugging
|
|
1920
|
-
console.error('Error getting serial number:', err);
|
|
1921
|
-
// Re-throw the error for higher-level handling
|
|
1922
|
-
throw err;
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
async getDeviceVersion() {
|
|
1926
|
-
const keyword = '~ZKFPVersion';
|
|
1927
|
-
try {
|
|
1928
|
-
// Execute the command to get device version
|
|
1929
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1930
|
-
// Extract and format the device version from the response data
|
|
1931
|
-
// Remove null characters
|
|
1932
|
-
return data.slice(8) // Skip the first 8 bytes (header)
|
|
1933
|
-
.toString('ascii') // Convert buffer to ASCII string
|
|
1934
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1935
|
-
.replace(/\u0000/g, '');
|
|
1936
|
-
}
|
|
1937
|
-
catch (err) {
|
|
1938
|
-
// Log the error for debugging
|
|
1939
|
-
console.error('Error getting device version:', err);
|
|
1940
|
-
// Re-throw the error for higher-level handling
|
|
1941
|
-
throw err;
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
async getDeviceName() {
|
|
1945
|
-
const keyword = '~DeviceName';
|
|
1946
|
-
try {
|
|
1947
|
-
// Execute the command to get the device name
|
|
1948
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1949
|
-
// Extract and format the device name from the response data
|
|
1950
|
-
// Remove null characters
|
|
1951
|
-
return data.slice(8) // Skip the first 8 bytes (header)
|
|
1952
|
-
.toString('ascii') // Convert buffer to ASCII string
|
|
1953
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1954
|
-
.replace(/\u0000/g, '');
|
|
1955
|
-
}
|
|
1956
|
-
catch (err) {
|
|
1957
|
-
// Log the error for debugging
|
|
1958
|
-
console.error('Error getting device name:', err);
|
|
1959
|
-
// Re-throw the error for higher-level handling
|
|
1960
|
-
throw err;
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
async getPlatform() {
|
|
1964
|
-
const keyword = '~Platform';
|
|
1965
|
-
try {
|
|
1966
|
-
// Execute the command to get the platform information
|
|
1967
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1968
|
-
// Extract and format the platform information from the response data
|
|
1969
|
-
// Remove null characters
|
|
1970
|
-
return data.slice(8) // Skip the first 8 bytes (header)
|
|
1971
|
-
.toString('ascii') // Convert buffer to ASCII string
|
|
1972
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1973
|
-
.replace(/\u0000/g, '');
|
|
1974
|
-
}
|
|
1975
|
-
catch (err) {
|
|
1976
|
-
// Log the error for debugging
|
|
1977
|
-
console.error('Error getting platform information:', err);
|
|
1978
|
-
// Re-throw the error for higher-level handling
|
|
1979
|
-
throw err;
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
async getOS() {
|
|
1983
|
-
const keyword = '~OS';
|
|
1984
|
-
try {
|
|
1985
|
-
// Execute the command to get the OS information
|
|
1986
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1987
|
-
// Extract and format the OS information from the response data
|
|
1988
|
-
// Remove null characters
|
|
1989
|
-
return data.slice(8) // Skip the first 8 bytes (header)
|
|
1990
|
-
.toString('ascii') // Convert buffer to ASCII string
|
|
1991
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1992
|
-
.replace(/\u0000/g, '');
|
|
1993
|
-
}
|
|
1994
|
-
catch (err) {
|
|
1995
|
-
// Log the error for debugging
|
|
1996
|
-
console.error('Error getting OS information:', err);
|
|
1997
|
-
// Re-throw the error for higher-level handling
|
|
1998
|
-
throw err;
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
async getWorkCode() {
|
|
2002
|
-
const keyword = 'WorkCode';
|
|
2003
|
-
try {
|
|
2004
|
-
// Execute the command to get the WorkCode information
|
|
2005
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2006
|
-
// Extract and format the WorkCode information from the response data
|
|
2007
|
-
// Remove null characters
|
|
2008
|
-
return data.slice(8) // Skip the first 8 bytes (header)
|
|
2009
|
-
.toString('ascii') // Convert buffer to ASCII string
|
|
2010
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
2011
|
-
.replace(/\u0000/g, '');
|
|
2012
|
-
}
|
|
2013
|
-
catch (err) {
|
|
2014
|
-
// Log the error for debugging
|
|
2015
|
-
console.error('Error getting WorkCode:', err);
|
|
2016
|
-
// Re-throw the error to be handled by the caller
|
|
2017
|
-
throw err;
|
|
2018
|
-
}
|
|
2019
|
-
}
|
|
2020
|
-
async getPIN() {
|
|
2021
|
-
const keyword = '~PIN2Width';
|
|
2022
|
-
try {
|
|
2023
|
-
// Execute the command to get the PIN information
|
|
2024
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2025
|
-
// Extract and format the PIN information from the response data
|
|
2026
|
-
return data.slice(8) // Skip the first 8 bytes (header)
|
|
2027
|
-
.toString('ascii') // Convert buffer to ASCII string
|
|
2028
|
-
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
2029
|
-
.replace(/\u0000/g, ''); // Remove null characters 0x00
|
|
2030
|
-
}
|
|
2031
|
-
catch (err) {
|
|
2032
|
-
// Log the error for debugging
|
|
2033
|
-
console.error('Error getting PIN:', err);
|
|
2034
|
-
// Re-throw the error to be handled by the caller
|
|
2035
|
-
throw err;
|
|
2036
|
-
}
|
|
2037
|
-
}
|
|
2038
|
-
async getFaceOn() {
|
|
2039
|
-
const keyword = 'FaceFunOn';
|
|
2040
|
-
try {
|
|
2041
|
-
// Execute the command to get the face function status
|
|
2042
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2043
|
-
// Extract and process the status from the response data
|
|
2044
|
-
const status = data.slice(8) // Skip the first 8 bytes (header)
|
|
2045
|
-
.toString('ascii') // Convert buffer to ASCII string
|
|
2046
|
-
.replace(`${keyword}=`, ''); // Remove the keyword prefix
|
|
2047
|
-
// Determine and return the face function status
|
|
2048
|
-
return status.includes('0') ? 'No' : 'Yes';
|
|
2049
|
-
}
|
|
2050
|
-
catch (err) {
|
|
2051
|
-
// Log the error for debugging
|
|
2052
|
-
console.error('Error getting face function status:', err);
|
|
2053
|
-
// Re-throw the error to be handled by the caller
|
|
2054
|
-
throw err;
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
async getSSR() {
|
|
2058
|
-
const keyword = '~SSR';
|
|
2059
|
-
try {
|
|
2060
|
-
// Execute the command to get the SSR value
|
|
2061
|
-
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
2062
|
-
// Extract and process the SSR value from the response data
|
|
2063
|
-
// Remove the keyword prefix
|
|
2064
|
-
// Return the SSR value
|
|
2065
|
-
return data.slice(8) // Skip the first 8 bytes (header)
|
|
2066
|
-
.toString('ascii') // Convert buffer to ASCII string
|
|
2067
|
-
.replace(`${keyword}=`, '');
|
|
2068
|
-
}
|
|
2069
|
-
catch (err) {
|
|
2070
|
-
// Log the error for debugging
|
|
2071
|
-
console.error('Error getting SSR value:', err);
|
|
2072
|
-
// Re-throw the error to be handled by the caller
|
|
2073
|
-
throw err;
|
|
2074
|
-
}
|
|
2075
|
-
}
|
|
2076
|
-
async getFirmware() {
|
|
2077
|
-
try {
|
|
2078
|
-
// Execute the command to get firmware information
|
|
2079
|
-
const data = await this.executeCmd(1100, '');
|
|
2080
|
-
// Extract and return the firmware version from the response data
|
|
2081
|
-
return data.slice(8) // Skip the first 8 bytes (header)
|
|
2082
|
-
.toString('ascii') // convert to ASCII string
|
|
2083
|
-
.replace(/\u0000/g, ''); // remove x00
|
|
2084
|
-
}
|
|
2085
|
-
catch (err) {
|
|
2086
|
-
// Log the error for debugging
|
|
2087
|
-
console.error('Error getting firmware version:', err);
|
|
2088
|
-
// Re-throw the error to be handled by the caller
|
|
2089
|
-
throw err;
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
async getTime() {
|
|
2093
|
-
try {
|
|
2094
|
-
// Execute the command to get the current time
|
|
2095
|
-
const response = await this.executeCmd(COMMANDS.CMD_GET_TIME, '');
|
|
2096
|
-
// Check if the response is valid
|
|
2097
|
-
if (!response || response.length < 12) {
|
|
2098
|
-
throw new Error('Invalid response received for time command');
|
|
2099
|
-
}
|
|
2100
|
-
// Extract and decode the time value from the response
|
|
2101
|
-
const timeValue = response.readUInt32LE(8); // Read 4 bytes starting at offset 8
|
|
2102
|
-
return timeParser.decode(timeValue); // Parse and return the decoded time
|
|
2103
|
-
}
|
|
2104
|
-
catch (err) {
|
|
2105
|
-
// Log the error for debugging
|
|
2106
|
-
console.error('Error getting time:', err);
|
|
2107
|
-
// Re-throw the error for the caller to handle
|
|
2108
|
-
throw err;
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2111
|
-
async setTime(tm) {
|
|
2112
|
-
try {
|
|
2113
|
-
// Validate the input time
|
|
2114
|
-
if (!(tm instanceof Date) && typeof tm !== 'number') {
|
|
2115
|
-
throw new TypeError('Invalid time parameter. Must be a Date object or a timestamp.');
|
|
2116
|
-
}
|
|
2117
|
-
// Convert the input time to a Date object if it's not already
|
|
2118
|
-
const date = (tm instanceof Date) ? tm : new Date(tm);
|
|
2119
|
-
// Encode the time into the required format
|
|
2120
|
-
const encodedTime = timeParser.encode(date);
|
|
2121
|
-
// Create a buffer and write the encoded time
|
|
2122
|
-
const commandString = Buffer.alloc(32);
|
|
2123
|
-
commandString.writeUInt32LE(encodedTime, 0);
|
|
2124
|
-
// Send the command to set the time
|
|
2125
|
-
const time = await this.executeCmd(COMMANDS.CMD_SET_TIME, commandString);
|
|
2126
|
-
return !!time;
|
|
2127
|
-
}
|
|
2128
|
-
catch (err) {
|
|
2129
|
-
// Log the error for debugging
|
|
2130
|
-
console.error('Error setting time:', err);
|
|
2131
|
-
// Re-throw the error for the caller to handle
|
|
2132
|
-
throw err;
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
|
-
async voiceTest() {
|
|
2136
|
-
try {
|
|
2137
|
-
// Define the command data for the voice test
|
|
2138
|
-
const commandData = Buffer.from('\x00\x00', 'binary');
|
|
2139
|
-
await this.executeCmd(COMMANDS.CMD_TESTVOICE, commandData);
|
|
2140
|
-
// Execute the command and return the result
|
|
2141
|
-
}
|
|
2142
|
-
catch (err) {
|
|
2143
|
-
// Log the error for debugging purposes
|
|
2144
|
-
console.error('Error executing voice test:', err);
|
|
2145
|
-
// Re-throw the error to be handled by the caller
|
|
2146
|
-
throw err;
|
|
2147
|
-
}
|
|
2148
|
-
}
|
|
2813
|
+
#listeners = new Map();
|
|
2149
2814
|
async getAttendanceSize() {
|
|
2150
2815
|
try {
|
|
2151
2816
|
// Execute command to get free sizes
|
|
2152
|
-
const data = await this.executeCmd(COMMANDS.CMD_GET_FREE_SIZES,
|
|
2817
|
+
const data = await this.executeCmd(COMMANDS.CMD_GET_FREE_SIZES, "");
|
|
2153
2818
|
// Parse and return the attendance size
|
|
2154
2819
|
return data.readUIntLE(40, 4); // Assuming data at offset 40 represents the attendance size
|
|
2155
2820
|
}
|
|
2156
2821
|
catch (err) {
|
|
2157
2822
|
// Log error details for debugging
|
|
2158
|
-
console.error(
|
|
2823
|
+
console.error("Error getting attendance size:", err);
|
|
2159
2824
|
// Re-throw the error to be handled by the caller
|
|
2160
2825
|
throw err;
|
|
2161
2826
|
}
|
|
@@ -2186,7 +2851,7 @@ class ZTCP {
|
|
|
2186
2851
|
}
|
|
2187
2852
|
catch (err) {
|
|
2188
2853
|
// Log the error for debugging purposes
|
|
2189
|
-
console.error(
|
|
2854
|
+
console.error("Error clearing data:", err);
|
|
2190
2855
|
// Re-throw the error to be handled by the caller
|
|
2191
2856
|
throw err;
|
|
2192
2857
|
}
|
|
@@ -2197,22 +2862,23 @@ class ZTCP {
|
|
|
2197
2862
|
// Create a buffer with the command header to request real-time logs
|
|
2198
2863
|
const buf = createTCPHeader(COMMANDS.CMD_REG_EVENT, this.sessionId, this.replyId, Buffer.from([0x01, 0x00, 0x00, 0x00]));
|
|
2199
2864
|
// Send the request to the device
|
|
2200
|
-
this.socket
|
|
2865
|
+
this.socket?.write(buf, undefined, (err) => {
|
|
2201
2866
|
if (err) {
|
|
2202
2867
|
// Log and reject the promise if there is an error writing to the socket
|
|
2203
|
-
console.error(
|
|
2868
|
+
console.error("Error sending real-time logs request:", err);
|
|
2204
2869
|
throw err;
|
|
2205
2870
|
}
|
|
2206
2871
|
});
|
|
2207
2872
|
// Ensure data listeners are added only once
|
|
2208
|
-
if (this.socket
|
|
2209
|
-
|
|
2873
|
+
if (this.socket?.listenerCount("data") === 0) {
|
|
2874
|
+
console.log("entraaa");
|
|
2875
|
+
this.socket.on("data", (data) => {
|
|
2210
2876
|
// Check if the data is an event and not just a regular response
|
|
2211
2877
|
if (checkNotEventTCP(data)) {
|
|
2212
2878
|
// Process the data if it is of the expected length
|
|
2213
2879
|
if (data.length > 16) {
|
|
2214
2880
|
// Decode and pass the log to the callback
|
|
2215
|
-
cb(
|
|
2881
|
+
cb(decodeRTEvent(data));
|
|
2216
2882
|
}
|
|
2217
2883
|
}
|
|
2218
2884
|
});
|
|
@@ -2220,7 +2886,7 @@ class ZTCP {
|
|
|
2220
2886
|
}
|
|
2221
2887
|
catch (err) {
|
|
2222
2888
|
// Handle errors and reject the promise
|
|
2223
|
-
console.error(
|
|
2889
|
+
console.error("Error getting real-time logs:", err);
|
|
2224
2890
|
throw err;
|
|
2225
2891
|
}
|
|
2226
2892
|
}
|
|
@@ -2252,11 +2918,11 @@ class ZTCP {
|
|
|
2252
2918
|
}
|
|
2253
2919
|
async refreshData() {
|
|
2254
2920
|
try {
|
|
2255
|
-
const reply = await this.executeCmd(COMMANDS.CMD_REFRESHDATA,
|
|
2921
|
+
const reply = await this.executeCmd(COMMANDS.CMD_REFRESHDATA, "");
|
|
2256
2922
|
return !!reply;
|
|
2257
2923
|
}
|
|
2258
2924
|
catch (err) {
|
|
2259
|
-
console.error(
|
|
2925
|
+
console.error("Error getting user templates: ", err);
|
|
2260
2926
|
throw err;
|
|
2261
2927
|
}
|
|
2262
2928
|
}
|
|
@@ -2307,13 +2973,13 @@ class ZTCP {
|
|
|
2307
2973
|
}
|
|
2308
2974
|
async readSocket(length, cb = null) {
|
|
2309
2975
|
let replyBufer = Buffer.from([]);
|
|
2310
|
-
|
|
2976
|
+
const totalPackets = 0;
|
|
2311
2977
|
return new Promise((resolve, reject) => {
|
|
2312
2978
|
let timer = setTimeout(() => {
|
|
2313
|
-
internalCallback(replyBufer, new Error(
|
|
2979
|
+
internalCallback(replyBufer, new Error("TIMEOUT WHEN RECEIVING PACKET"));
|
|
2314
2980
|
}, this.timeout);
|
|
2315
2981
|
const internalCallback = (replyData, err = null) => {
|
|
2316
|
-
this.socket && this.socket.removeListener(
|
|
2982
|
+
this.socket && this.socket.removeListener("data", onDataEnroll);
|
|
2317
2983
|
timer && clearTimeout(timer);
|
|
2318
2984
|
resolve({ data: replyData, err: err });
|
|
2319
2985
|
};
|
|
@@ -2327,10 +2993,10 @@ class ZTCP {
|
|
|
2327
2993
|
internalCallback(data);
|
|
2328
2994
|
}
|
|
2329
2995
|
}
|
|
2330
|
-
this.socket.once(
|
|
2331
|
-
internalCallback(replyBufer, new Error(
|
|
2996
|
+
this.socket.once("close", () => {
|
|
2997
|
+
internalCallback(replyBufer, new Error("Socket is disconnected unexpectedly"));
|
|
2332
2998
|
});
|
|
2333
|
-
this.socket.on(
|
|
2999
|
+
this.socket.on("data", onDataEnroll);
|
|
2334
3000
|
}).catch((err) => {
|
|
2335
3001
|
console.error("Promise Rejected:", err); // Log the rejection reason
|
|
2336
3002
|
throw err; // Re-throw the error to be handled by the caller
|
|
@@ -2356,7 +3022,7 @@ class ZTCP {
|
|
|
2356
3022
|
}
|
|
2357
3023
|
async cancelCapture() {
|
|
2358
3024
|
try {
|
|
2359
|
-
const reply = await this.executeCmd(COMMANDS.CMD_CANCELCAPTURE,
|
|
3025
|
+
const reply = await this.executeCmd(COMMANDS.CMD_CANCELCAPTURE, "");
|
|
2360
3026
|
return !!reply;
|
|
2361
3027
|
}
|
|
2362
3028
|
catch (e) {
|
|
@@ -2365,7 +3031,7 @@ class ZTCP {
|
|
|
2365
3031
|
}
|
|
2366
3032
|
async restartDevice() {
|
|
2367
3033
|
try {
|
|
2368
|
-
await this.executeCmd(COMMANDS.CMD_RESTART,
|
|
3034
|
+
await this.executeCmd(COMMANDS.CMD_RESTART, "");
|
|
2369
3035
|
}
|
|
2370
3036
|
catch (e) {
|
|
2371
3037
|
throw new ZkError(e, COMMANDS.CMD_RESTART, this.ip);
|
|
@@ -2434,7 +3100,7 @@ class ZUDP {
|
|
|
2434
3100
|
return true;
|
|
2435
3101
|
}
|
|
2436
3102
|
else {
|
|
2437
|
-
throw new Error(
|
|
3103
|
+
throw new Error('Authentication error');
|
|
2438
3104
|
}
|
|
2439
3105
|
}
|
|
2440
3106
|
else {
|
|
@@ -2862,22 +3528,22 @@ class Zklib {
|
|
|
2862
3528
|
async functionWrapper(tcpCallback, udpCallback, command) {
|
|
2863
3529
|
try {
|
|
2864
3530
|
switch (this._connectionType) {
|
|
2865
|
-
case
|
|
3531
|
+
case "tcp":
|
|
2866
3532
|
if (this.ztcp && this.ztcp.socket) {
|
|
2867
3533
|
return await tcpCallback();
|
|
2868
3534
|
}
|
|
2869
3535
|
else {
|
|
2870
|
-
throw new ZkError(new Error(
|
|
3536
|
+
throw new ZkError(new Error("TCP socket isn't connected!"), `[TCP] ${command}`, this.ip);
|
|
2871
3537
|
}
|
|
2872
|
-
case
|
|
3538
|
+
case "udp":
|
|
2873
3539
|
if (this.zudp && this.zudp.socket) {
|
|
2874
3540
|
return await udpCallback();
|
|
2875
3541
|
}
|
|
2876
3542
|
else {
|
|
2877
|
-
throw new ZkError(new Error(
|
|
3543
|
+
throw new ZkError(new Error("UDP socket isn't connected!"), `[UDP] ${command}`, this.ip);
|
|
2878
3544
|
}
|
|
2879
3545
|
default:
|
|
2880
|
-
throw new ZkError(new Error(
|
|
3546
|
+
throw new ZkError(new Error("Unsupported connection type or socket isn't connected!"), "", this.ip);
|
|
2881
3547
|
}
|
|
2882
3548
|
}
|
|
2883
3549
|
catch (err) {
|
|
@@ -2889,24 +3555,24 @@ class Zklib {
|
|
|
2889
3555
|
if (this.ztcp.socket) {
|
|
2890
3556
|
try {
|
|
2891
3557
|
await this.ztcp.connect();
|
|
2892
|
-
console.log(
|
|
2893
|
-
this._connectionType =
|
|
3558
|
+
console.log("TCP reconnection successful");
|
|
3559
|
+
this._connectionType = "tcp";
|
|
2894
3560
|
return true;
|
|
2895
3561
|
}
|
|
2896
3562
|
catch (err) {
|
|
2897
|
-
throw new ZkError(err,
|
|
3563
|
+
throw new ZkError(err, "TCP CONNECT", this.ip);
|
|
2898
3564
|
}
|
|
2899
3565
|
}
|
|
2900
3566
|
else {
|
|
2901
3567
|
try {
|
|
2902
3568
|
await this.ztcp.createSocket(cbErr, cbClose);
|
|
2903
3569
|
await this.ztcp.connect();
|
|
2904
|
-
console.log(
|
|
2905
|
-
this._connectionType =
|
|
3570
|
+
console.log("TCP connection successful");
|
|
3571
|
+
this._connectionType = "tcp";
|
|
2906
3572
|
return true;
|
|
2907
3573
|
}
|
|
2908
3574
|
catch (err) {
|
|
2909
|
-
throw new ZkError(err,
|
|
3575
|
+
throw new ZkError(err, "TCP CONNECT", this.ip);
|
|
2910
3576
|
}
|
|
2911
3577
|
}
|
|
2912
3578
|
}
|
|
@@ -2916,86 +3582,114 @@ class Zklib {
|
|
|
2916
3582
|
await this.ztcp.disconnect();
|
|
2917
3583
|
}
|
|
2918
3584
|
catch (disconnectErr) {
|
|
2919
|
-
console.error(
|
|
3585
|
+
console.error("Error disconnecting TCP:", disconnectErr);
|
|
2920
3586
|
}
|
|
2921
3587
|
if (err.code !== ERROR_TYPES.ECONNREFUSED) {
|
|
2922
|
-
throw new ZkError(err,
|
|
3588
|
+
throw new ZkError(err, "TCP CONNECT", this.ip);
|
|
2923
3589
|
}
|
|
2924
3590
|
try {
|
|
2925
3591
|
if (!this.zudp.socket) {
|
|
2926
3592
|
await this.zudp.createSocket(cbErr, cbClose);
|
|
2927
3593
|
}
|
|
2928
3594
|
await this.zudp.connect();
|
|
2929
|
-
console.log(
|
|
2930
|
-
this._connectionType =
|
|
3595
|
+
console.log("UDP connection successful");
|
|
3596
|
+
this._connectionType = "udp";
|
|
2931
3597
|
return true;
|
|
2932
3598
|
}
|
|
2933
3599
|
catch (err) {
|
|
2934
|
-
if (err.message !==
|
|
3600
|
+
if (err.message !== "EADDRINUSE") {
|
|
2935
3601
|
this._connectionType = null;
|
|
2936
3602
|
try {
|
|
2937
3603
|
await this.zudp.disconnect();
|
|
2938
3604
|
}
|
|
2939
3605
|
catch (disconnectErr) {
|
|
2940
|
-
console.error(
|
|
3606
|
+
console.error("Error disconnecting UDP:", disconnectErr);
|
|
2941
3607
|
}
|
|
2942
|
-
throw new ZkError(err,
|
|
3608
|
+
throw new ZkError(err, "UDP CONNECT", this.ip);
|
|
2943
3609
|
}
|
|
2944
|
-
this._connectionType =
|
|
3610
|
+
this._connectionType = "udp";
|
|
2945
3611
|
return true;
|
|
2946
3612
|
}
|
|
2947
3613
|
}
|
|
2948
3614
|
}
|
|
2949
3615
|
async getUsers() {
|
|
2950
|
-
return this.functionWrapper(() => this.ztcp._userService.getUsers(), () => this.zudp.getUsers(),
|
|
3616
|
+
return this.functionWrapper(() => this.ztcp._userService.getUsers(), () => this.zudp.getUsers(), "GET_USERS");
|
|
2951
3617
|
}
|
|
2952
3618
|
async getTime() {
|
|
2953
|
-
return this.functionWrapper(() => this.ztcp.getTime(), () => this.zudp.getTime(),
|
|
3619
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getTime(), () => this.zudp.getTime(), "GET_TIME");
|
|
2954
3620
|
}
|
|
2955
3621
|
async setTime(t) {
|
|
2956
|
-
return this.functionWrapper(() => this.ztcp.setTime(t), () => this.zudp.setTime(t),
|
|
3622
|
+
return this.functionWrapper(() => this.ztcp._optionsService.setTime(t), () => this.zudp.setTime(t), "SET_TIME");
|
|
2957
3623
|
}
|
|
2958
3624
|
async voiceTest() {
|
|
2959
|
-
return this.functionWrapper(() => this.ztcp.voiceTest(), async () => {
|
|
3625
|
+
return this.functionWrapper(() => this.ztcp._optionsService.voiceTest(), async () => {
|
|
3626
|
+
throw new Error("UDP voice test not supported");
|
|
3627
|
+
}, "VOICE_TEST");
|
|
2960
3628
|
}
|
|
2961
3629
|
async getProductTime() {
|
|
2962
|
-
return this.functionWrapper(() => this.ztcp.getProductTime(), async () => {
|
|
3630
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getProductTime(), async () => {
|
|
3631
|
+
throw new Error("UDP get product time not supported");
|
|
3632
|
+
}, "GET_PRODUCT_TIME");
|
|
2963
3633
|
}
|
|
2964
3634
|
async getVendor() {
|
|
2965
|
-
return this.functionWrapper(() => this.ztcp.getVendor(), async () => {
|
|
3635
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getVendor(), async () => {
|
|
3636
|
+
throw new Error("UDP get vendor not supported");
|
|
3637
|
+
}, "GET_VENDOR");
|
|
2966
3638
|
}
|
|
2967
3639
|
async getMacAddress() {
|
|
2968
|
-
return this.functionWrapper(() => this.ztcp.getMacAddress(), async () => {
|
|
3640
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getMacAddress(), async () => {
|
|
3641
|
+
throw new Error("UDP get MAC address not supported");
|
|
3642
|
+
}, "GET_MAC_ADDRESS");
|
|
2969
3643
|
}
|
|
2970
3644
|
async getSerialNumber() {
|
|
2971
|
-
return this.functionWrapper(() => this.ztcp.getSerialNumber(), async () => {
|
|
3645
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getSerialNumber(), async () => {
|
|
3646
|
+
throw new Error("UDP get serial number not supported");
|
|
3647
|
+
}, "GET_SERIAL_NUMBER");
|
|
2972
3648
|
}
|
|
2973
3649
|
async getDeviceVersion() {
|
|
2974
|
-
return this.functionWrapper(() => this.ztcp.getDeviceVersion(), async () => {
|
|
3650
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getDeviceVersion(), async () => {
|
|
3651
|
+
throw new Error("UDP get device version not supported");
|
|
3652
|
+
}, "GET_DEVICE_VERSION");
|
|
2975
3653
|
}
|
|
2976
3654
|
async getDeviceName() {
|
|
2977
|
-
return this.functionWrapper(() => this.ztcp.getDeviceName(), async () => {
|
|
3655
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getDeviceName(), async () => {
|
|
3656
|
+
throw new Error("UDP get device name not supported");
|
|
3657
|
+
}, "GET_DEVICE_NAME");
|
|
2978
3658
|
}
|
|
2979
3659
|
async getPlatform() {
|
|
2980
|
-
return this.functionWrapper(() => this.ztcp.getPlatform(), async () => {
|
|
3660
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getPlatform(), async () => {
|
|
3661
|
+
throw new Error("UDP get platform not supported");
|
|
3662
|
+
}, "GET_PLATFORM");
|
|
2981
3663
|
}
|
|
2982
3664
|
async getOS() {
|
|
2983
|
-
return this.functionWrapper(() => this.ztcp.getOS(), async () => {
|
|
3665
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getOS(), async () => {
|
|
3666
|
+
throw new Error("UDP get OS not supported");
|
|
3667
|
+
}, "GET_OS");
|
|
2984
3668
|
}
|
|
2985
3669
|
async getWorkCode() {
|
|
2986
|
-
return this.functionWrapper(() => this.ztcp.getWorkCode(), async () => {
|
|
3670
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getWorkCode(), async () => {
|
|
3671
|
+
throw new Error("UDP get work code not supported");
|
|
3672
|
+
}, "GET_WORK_CODE");
|
|
2987
3673
|
}
|
|
2988
3674
|
async getPIN() {
|
|
2989
|
-
return this.functionWrapper(() => this.ztcp.getPIN(), async () => {
|
|
3675
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getPIN(), async () => {
|
|
3676
|
+
throw new Error("UDP get PIN not supported");
|
|
3677
|
+
}, "GET_PIN");
|
|
2990
3678
|
}
|
|
2991
3679
|
async getFaceOn() {
|
|
2992
|
-
return this.functionWrapper(() => this.ztcp.getFaceOn(), async () => {
|
|
3680
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getFaceOn(), async () => {
|
|
3681
|
+
throw new Error("UDP get face on not supported");
|
|
3682
|
+
}, "GET_FACE_ON");
|
|
2993
3683
|
}
|
|
2994
3684
|
async getSSR() {
|
|
2995
|
-
return this.functionWrapper(() => this.ztcp.getSSR(), async () => {
|
|
3685
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getSSR(), async () => {
|
|
3686
|
+
throw new Error("UDP get SSR not supported");
|
|
3687
|
+
}, "GET_SSR");
|
|
2996
3688
|
}
|
|
2997
3689
|
async getFirmware() {
|
|
2998
|
-
return this.functionWrapper(() => this.ztcp.getFirmware(), async () => {
|
|
3690
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getFirmware(), async () => {
|
|
3691
|
+
throw new Error("UDP get firmware not supported");
|
|
3692
|
+
}, "GET_FIRMWARE");
|
|
2999
3693
|
}
|
|
3000
3694
|
/** Update or create a user if user id/pin not exists
|
|
3001
3695
|
* @param user_id {string} user id/pin for customer
|
|
@@ -3005,26 +3699,34 @@ class Zklib {
|
|
|
3005
3699
|
* @param cardno {number} card number/id
|
|
3006
3700
|
*/
|
|
3007
3701
|
async setUser(user_id, name, password, role = 0, cardno = 0) {
|
|
3008
|
-
return this.functionWrapper(() => this.ztcp._userService.setUser(user_id, name, password, role, cardno), async () => {
|
|
3702
|
+
return this.functionWrapper(() => this.ztcp._userService.setUser(user_id, name, password, role, cardno), async () => {
|
|
3703
|
+
throw new Error("UDP set user not supported");
|
|
3704
|
+
}, "SET_USER");
|
|
3009
3705
|
}
|
|
3010
3706
|
/**
|
|
3011
3707
|
* Delete user by a given user id/pin
|
|
3012
3708
|
* @param user_id {string}
|
|
3013
3709
|
*/
|
|
3014
3710
|
async deleteUser(user_id) {
|
|
3015
|
-
return this.functionWrapper(() => this.ztcp._userService.DeleteUser(user_id), async () => {
|
|
3711
|
+
return this.functionWrapper(() => this.ztcp._userService.DeleteUser(user_id), async () => {
|
|
3712
|
+
throw new Error("UDP delete user not supported");
|
|
3713
|
+
}, "DELETE_USER");
|
|
3016
3714
|
}
|
|
3017
3715
|
async getAttendanceSize() {
|
|
3018
|
-
return this.functionWrapper(() => this.ztcp.getAttendanceSize(), async () => {
|
|
3716
|
+
return this.functionWrapper(() => this.ztcp.getAttendanceSize(), async () => {
|
|
3717
|
+
throw new Error("UDP get attendance size not supported");
|
|
3718
|
+
}, "GET_ATTENDANCE_SIZE");
|
|
3019
3719
|
}
|
|
3020
3720
|
async getAttendances(cb) {
|
|
3021
|
-
return this.functionWrapper(() => this.ztcp.getAttendances(cb), () => this.zudp.getAttendances(cb),
|
|
3721
|
+
return this.functionWrapper(() => this.ztcp._transactionService.getAttendances(cb), () => this.zudp.getAttendances(cb), "GET_ATTENDANCES");
|
|
3022
3722
|
}
|
|
3023
3723
|
async getRealTimeLogs(cb) {
|
|
3024
|
-
return this.functionWrapper(() => this.ztcp.getRealTimeLogs(cb), () => this.zudp.getRealTimeLogs(cb),
|
|
3724
|
+
return this.functionWrapper(() => this.ztcp.getRealTimeLogs(cb), () => this.zudp.getRealTimeLogs(cb), "GET_REAL_TIME_LOGS");
|
|
3025
3725
|
}
|
|
3026
3726
|
async getTemplates() {
|
|
3027
|
-
return this.functionWrapper(() => this.ztcp.getTemplates(), async () => {
|
|
3727
|
+
return this.functionWrapper(() => this.ztcp.getTemplates(), async () => {
|
|
3728
|
+
throw new Error("UDP get templates not supported");
|
|
3729
|
+
}, "GET_TEMPLATES");
|
|
3028
3730
|
}
|
|
3029
3731
|
/**
|
|
3030
3732
|
* Get a user template for a given user id/pin and finger id
|
|
@@ -3032,7 +3734,9 @@ class Zklib {
|
|
|
3032
3734
|
* @param fid {number} finger index
|
|
3033
3735
|
*/
|
|
3034
3736
|
async getUserTemplate(user_id, fid) {
|
|
3035
|
-
return await this.functionWrapper(async () => await this.ztcp._userService.DownloadFp(user_id, fid), async () => {
|
|
3737
|
+
return await this.functionWrapper(async () => await this.ztcp._userService.DownloadFp(user_id, fid), async () => {
|
|
3738
|
+
throw new Error("UDP get user template not implemented");
|
|
3739
|
+
}, "GET_USER_TEMPLATE");
|
|
3036
3740
|
}
|
|
3037
3741
|
/**
|
|
3038
3742
|
* Upload a single fingerprint for a given user id
|
|
@@ -3042,7 +3746,9 @@ class Zklib {
|
|
|
3042
3746
|
* @param fp_valid {number} finger flag. e.g., valid=1, duress=3
|
|
3043
3747
|
*/
|
|
3044
3748
|
async uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid) {
|
|
3045
|
-
return await this.functionWrapper(async () => await this.ztcp._userService.uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid), async () => {
|
|
3749
|
+
return await this.functionWrapper(async () => await this.ztcp._userService.uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid), async () => {
|
|
3750
|
+
throw new Error("UDP get user template not implemented");
|
|
3751
|
+
}, "UPLOAD_USER_TEMPLATE");
|
|
3046
3752
|
}
|
|
3047
3753
|
/**
|
|
3048
3754
|
* save user and template
|
|
@@ -3051,7 +3757,9 @@ class Zklib {
|
|
|
3051
3757
|
* @param {Finger[]} fingers - Array of finger class
|
|
3052
3758
|
*/
|
|
3053
3759
|
async saveUserTemplate(user_id, fingers = []) {
|
|
3054
|
-
return await this.functionWrapper(async () => await this.ztcp._userService.saveTemplates(user_id, fingers), async () => {
|
|
3760
|
+
return await this.functionWrapper(async () => await this.ztcp._userService.saveTemplates(user_id, fingers), async () => {
|
|
3761
|
+
throw new Error("UDP save user template not supported");
|
|
3762
|
+
}, "SAVE_USER_TEMPLATE");
|
|
3055
3763
|
}
|
|
3056
3764
|
/**
|
|
3057
3765
|
* Delete a single finger template by user id and finger index
|
|
@@ -3061,7 +3769,9 @@ class Zklib {
|
|
|
3061
3769
|
async deleteFinger(user_id, fid) {
|
|
3062
3770
|
if (fid > 9 || 0 > fid)
|
|
3063
3771
|
throw new Error("fid params out of index");
|
|
3064
|
-
return this.functionWrapper(() => this.ztcp._userService.deleteFinger(user_id, fid), async () => {
|
|
3772
|
+
return this.functionWrapper(() => this.ztcp._userService.deleteFinger(user_id, fid), async () => {
|
|
3773
|
+
throw new Error("UDP delete finger not supported");
|
|
3774
|
+
}, "DELETE_FINGER");
|
|
3065
3775
|
}
|
|
3066
3776
|
/**
|
|
3067
3777
|
* Start to enroll a finger template
|
|
@@ -3071,43 +3781,53 @@ class Zklib {
|
|
|
3071
3781
|
async enrollUser(user_id, temp_id) {
|
|
3072
3782
|
if (temp_id < 0 || temp_id > 9)
|
|
3073
3783
|
throw new Error("temp_id out of range 0-9");
|
|
3074
|
-
return this.functionWrapper(() => this.ztcp._userService.enrollInfo(user_id, temp_id), async () => {
|
|
3784
|
+
return this.functionWrapper(() => this.ztcp._userService.enrollInfo(user_id, temp_id), async () => {
|
|
3785
|
+
throw new Error("UDP enroll user not supported");
|
|
3786
|
+
}, "ENROLL_USER");
|
|
3075
3787
|
}
|
|
3076
3788
|
async verifyUser(user_id) {
|
|
3077
|
-
return this.functionWrapper(() => this.ztcp._userService.verify(user_id), async () => {
|
|
3789
|
+
return this.functionWrapper(() => this.ztcp._userService.verify(user_id), async () => {
|
|
3790
|
+
throw new Error("UDP verify user not supported");
|
|
3791
|
+
}, "VERIFY_USER");
|
|
3078
3792
|
}
|
|
3079
3793
|
async restartDevice() {
|
|
3080
|
-
return this.functionWrapper(() => this.ztcp.restartDevice(), async () => {
|
|
3794
|
+
return this.functionWrapper(() => this.ztcp.restartDevice(), async () => {
|
|
3795
|
+
throw new Error("UDP restart device not supported");
|
|
3796
|
+
}, "RESTART_DEVICE");
|
|
3081
3797
|
}
|
|
3082
3798
|
async getSizes() {
|
|
3083
|
-
return this.functionWrapper(() => this.ztcp.getSizes(), () => {
|
|
3799
|
+
return this.functionWrapper(() => this.ztcp.getSizes(), () => {
|
|
3800
|
+
throw new Error("not implemented ofr UDP");
|
|
3801
|
+
}, "GET_SIZES");
|
|
3084
3802
|
}
|
|
3085
3803
|
async disconnect() {
|
|
3086
|
-
return this.functionWrapper(() => this.ztcp.disconnect(), () => this.zudp.disconnect(),
|
|
3804
|
+
return this.functionWrapper(() => this.ztcp.disconnect(), () => this.zudp.disconnect(), "DISCONNECT");
|
|
3087
3805
|
}
|
|
3088
3806
|
async freeData() {
|
|
3089
|
-
return this.functionWrapper(() => this.ztcp.freeData(), () => this.zudp.freeData(),
|
|
3807
|
+
return this.functionWrapper(() => this.ztcp.freeData(), () => this.zudp.freeData(), "FREE_DATA");
|
|
3090
3808
|
}
|
|
3091
3809
|
async disableDevice() {
|
|
3092
|
-
return this.functionWrapper(() => this.ztcp.disableDevice(), () => this.zudp.disableDevice(),
|
|
3810
|
+
return this.functionWrapper(() => this.ztcp.disableDevice(), () => this.zudp.disableDevice(), "DISABLE_DEVICE");
|
|
3093
3811
|
}
|
|
3094
3812
|
async enableDevice() {
|
|
3095
|
-
return this.functionWrapper(() => this.ztcp.enableDevice(), () => this.zudp.enableDevice(),
|
|
3813
|
+
return this.functionWrapper(() => this.ztcp.enableDevice(), () => this.zudp.enableDevice(), "ENABLE_DEVICE");
|
|
3096
3814
|
}
|
|
3097
3815
|
async getInfo() {
|
|
3098
|
-
return this.functionWrapper(() => this.ztcp.getInfo(), () => this.zudp.getInfo(),
|
|
3816
|
+
return this.functionWrapper(() => this.ztcp.getInfo(), () => this.zudp.getInfo(), "GET_INFO");
|
|
3099
3817
|
}
|
|
3100
3818
|
async clearAttendanceLog() {
|
|
3101
|
-
return this.functionWrapper(() => this.ztcp.clearAttendanceLog(), () => this.zudp.clearAttendanceLog(),
|
|
3819
|
+
return this.functionWrapper(() => this.ztcp.clearAttendanceLog(), () => this.zudp.clearAttendanceLog(), "CLEAR_ATTENDANCE_LOG");
|
|
3102
3820
|
}
|
|
3103
3821
|
async clearData() {
|
|
3104
|
-
return this.functionWrapper(() => this.ztcp.clearData(), () => this.zudp.clearData(),
|
|
3822
|
+
return this.functionWrapper(() => this.ztcp.clearData(), () => this.zudp.clearData(), "CLEAR_DATA");
|
|
3105
3823
|
}
|
|
3106
|
-
async executeCmd(command, data =
|
|
3107
|
-
return this.functionWrapper(() => this.ztcp.executeCmd(command, data), () => this.zudp.executeCmd(command, data),
|
|
3824
|
+
async executeCmd(command, data = "") {
|
|
3825
|
+
return this.functionWrapper(() => this.ztcp.executeCmd(command, data), () => this.zudp.executeCmd(command, data), "EXECUTE_CMD");
|
|
3108
3826
|
}
|
|
3109
3827
|
async getNetworkParams() {
|
|
3110
|
-
return this.functionWrapper(() => this.ztcp.getNetworkParams(), async () => {
|
|
3828
|
+
return this.functionWrapper(() => this.ztcp._optionsService.getNetworkParams(), async () => {
|
|
3829
|
+
throw new Error("UDP getNetworkParams not implemented");
|
|
3830
|
+
}, "NETWORK_PARAMS");
|
|
3111
3831
|
}
|
|
3112
3832
|
}
|
|
3113
3833
|
|