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/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
- COMMANDS[COMMANDS["EF_ALARM"] = 512] = "EF_ALARM";
193
+ RTEvent[RTEvent["EF_ALARM"] = 512] = "EF_ALARM";
191
194
  /** Attendance entry. */
192
- COMMANDS[COMMANDS["EF_ATTLOG"] = 1] = "EF_ATTLOG";
195
+ RTEvent[RTEvent["EF_ATTLOG"] = 1] = "EF_ATTLOG";
193
196
  /** Pressed keyboard key. */
194
- COMMANDS[COMMANDS["EF_BUTTON"] = 16] = "EF_BUTTON";
197
+ RTEvent[RTEvent["EF_BUTTON"] = 16] = "EF_BUTTON";
195
198
  /** Upload user data. */
196
- COMMANDS[COMMANDS["EF_ENROLLFINGER"] = 8] = "EF_ENROLLFINGER";
199
+ RTEvent[RTEvent["EF_ENROLLFINGER"] = 8] = "EF_ENROLLFINGER";
197
200
  /** Enrolled user. */
198
- COMMANDS[COMMANDS["EF_ENROLLUSER"] = 4] = "EF_ENROLLUSER";
201
+ RTEvent[RTEvent["EF_ENROLLUSER"] = 4] = "EF_ENROLLUSER";
199
202
  /** Pressed finger. */
200
- COMMANDS[COMMANDS["EF_FINGER"] = 2] = "EF_FINGER";
203
+ RTEvent[RTEvent["EF_FINGER"] = 2] = "EF_FINGER";
201
204
  /** Fingerprint score in enroll procedure. */
202
- COMMANDS[COMMANDS["EF_FPFTR"] = 256] = "EF_FPFTR";
205
+ RTEvent[RTEvent["EF_FPFTR"] = 256] = "EF_FPFTR";
203
206
  /** Restore access control to default. */
204
- COMMANDS[COMMANDS["EF_UNLOCK"] = 32] = "EF_UNLOCK";
207
+ RTEvent[RTEvent["EF_UNLOCK"] = 32] = "EF_UNLOCK";
205
208
  /** Registered user placed finger. */
206
- COMMANDS[COMMANDS["EF_VERIFY"] = 128] = "EF_VERIFY";
207
- })(COMMANDS || (COMMANDS = {}));
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 decode = time => {
234
- const second = time % 60;
235
- time = (time - second) / 60;
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
- const encode = date => {
252
- return (((date.getFullYear() % 100) * 12 * 31 + date.getMonth() * 31 + date.getDate() - 1) * (24 * 60 * 60) +
253
- (date.getHours() * 60 + date.getMinutes()) * 60 +
254
- date.getSeconds());
255
- };
256
- var timeParser = { encode, decode };
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 = "", group_id = "", user_id = "", card = 0) {
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([0x50, 0x50, 0x82, 0x7d, 0x13, 0x00, 0x00, 0x00]);
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('ascii')
464
- .split('\0')
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('ascii')
477
- .split('\0')
478
- .shift() || '', userData.readUIntLE(39, 1), userData
508
+ .toString("ascii")
509
+ .split("\0")
510
+ .shift() || "", userData.readUIntLE(39, 1), userData
479
511
  .slice(48, 48 + 9)
480
- .toString('ascii')
481
- .split('\0')
482
- .shift() || '', userData.readUIntLE(35, 4));
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('ascii')
488
- .split('\0')
489
- .shift() || '', recordData.readUIntLE(26, 1), parseTimeToDate(recordData.readUInt32LE(27)), recordData.readUIntLE(31, 1));
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 'AN UNKNOWN ERROR';
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 === COMMANDS.EF_ATTLOG && commandId === COMMANDS.CMD_REG_EVENT;
568
+ return isRTEvent(event) && commandId === COMMANDS.CMD_REG_EVENT;
546
569
  }
547
570
  catch (err) {
548
- log(`[228] : ${err.toString()} ,${data.toString('hex')} `);
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
- let response = new Uint8Array(4);
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] ^= 'Z'.charCodeAt(0);
576
- response[1] ^= 'K'.charCodeAt(0);
577
- response[2] ^= 'S'.charCodeAt(0);
578
- response[3] ^= 'O'.charCodeAt(0);
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
- let swp = finalKey >>> 16;
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
- let k = makeKey(comKey, sessionId) >>> 0;
589
- let rand = Math.floor(Math.random() * 256);
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
- let response = new Uint8Array(4);
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
- * Error types for device communication
607
- */
608
- const ERROR_TYPES = {
609
- ECONNRESET: 'ECONNRESET',
610
- ECONNREFUSED: 'ECONNREFUSED'};
611
- /**
612
- * Custom error class for device communication errors
613
- */
614
- class ZkError {
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, valid, template) {
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
- // Request user data
760
- const data = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_USERS);
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('Error getting users:', err);
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 !== 'number' ||
825
+ typeof role !== "number" ||
808
826
  cardno.toString().length > 10) {
809
- throw new Error('Invalid input parameters');
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(user.uid, 0);
832
+ commandBuffer.writeUInt16LE(0, 0); // uid will be set in the device
815
833
  commandBuffer.writeUInt16LE(role, 2);
816
- commandBuffer.write(password.padEnd(8, '\0'), 3, 8); // Ensure password is 8 bytes
817
- commandBuffer.write(name.padEnd(24, '\0'), 11, 24); // Ensure name is 24 bytes
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, '\0'), 48, 9); // Ensure userid is 9 bytes
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('Error setting user:', err);
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('Error deleting user:', err);
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(callbackInProcess = () => { }) {
851
- let templates = [];
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
- await this._zkTcp.getSizes();
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.disableDevice();
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, valid, tplBytes));
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
- return { data: templates };
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('fid must be between 0 and 9');
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
- return await new Promise((resolve, reject) => {
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('data', receiveData);
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('Time Out, Could not retrieve data'));
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 == 0)
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('Could not retrieve data. maybe finger id not exists?');
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([fingerTemplate, data.subarray(16, fingerSize + 10)]);
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('data', receiveData);
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('Socket not initialized'));
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.refreshData();
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
- const bufferResponse = await this._zkTcp.sendWithBuffer(packet);
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
- const cmdResponse = await this._zkTcp.executeCmd(command, commandString);
1049
+ await this._zkTcp.executeCmd(command, commandString);
1024
1050
  if (this._zkTcp.verbose)
1025
- console.log("finally bulk save user templates: \n", cmdResponse.readUInt16LE(0));
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
- if (!this._users.has(user_id))
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
- let done = false;
1055
- try {
1056
- const userBuf = Buffer.alloc(24);
1057
- userBuf.write(user_id, 0, 24, 'ascii');
1058
- let commandString = Buffer.concat([
1059
- userBuf,
1060
- Buffer.from([tempId, 1])
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 cancel = await this._zkTcp.cancelCapture();
1072
- const cmdResponse = await this._zkTcp.executeCmd(COMMANDS.CMD_STARTENROLL, commandString);
1073
- this._zkTcp.timeout = 60000; // 60 seconds timeout
1074
- let attempts = 3;
1075
- while (attempts > 0) {
1076
- if (this._zkTcp.verbose)
1077
- console.log(`A:${attempts} esperando primer regevent`);
1078
- let dataRecv = await this._zkTcp.readSocket(17);
1079
- await sendAckOk();
1080
- if (dataRecv.length > 16) {
1081
- const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
1082
- const res = padded.readUInt16LE(16);
1083
- if (this._zkTcp.verbose)
1084
- console.log(`res ${res}`);
1085
- if (res === 0 || res === 6 || res === 4) {
1086
- if (this._zkTcp.verbose)
1087
- console.log("posible timeout o reg Fallido");
1088
- break;
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
- if (this._zkTcp.verbose)
1092
- console.log(`A:${attempts} esperando 2do regevent`);
1093
- dataRecv = await this._zkTcp.readSocket(17);
1094
- await sendAckOk();
1095
- if (this._zkTcp.verbose)
1096
- console.log(dataRecv);
1097
- if (dataRecv.length > 8) {
1098
- const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
1099
- const res = padded.readUInt16LE(16);
1100
- if (this._zkTcp.verbose)
1101
- console.log(`res ${res}`);
1102
- if (res === 6 || res === 4) {
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
- else if (res === 0x64) {
1108
- if (this._zkTcp.verbose)
1109
- console.log("ok, continue?");
1110
- attempts--;
1122
+ catch (e) {
1123
+ this._zkTcp.verbose &&
1124
+ console.debug("Finger index is empty, skipping delete");
1111
1125
  }
1112
- }
1113
- }
1114
- if (attempts === 0) {
1115
- const dataRecv = await this._zkTcp.readSocket(17);
1116
- await sendAckOk();
1117
- if (this._zkTcp.verbose)
1118
- console.log(dataRecv.toString('hex'));
1119
- const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
1120
- let res = padded.readUInt16LE(16);
1121
- if (this._zkTcp.verbose)
1122
- console.log(`res ${res}`);
1123
- if (res === 5) {
1124
- if (this._zkTcp.verbose)
1125
- console.log("finger duplicate");
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, 'base64');
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
- check_ACK_OK(initPacket);
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
- check_ACK_OK(fpPacket);
1192
- const cheksumPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_CHECKSUM_BUFFER, '');
1193
- check_ACK_OK(cheksumPacket);
1194
- const checksum = cheksumPacket.readUInt32LE(8);
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
- check_ACK_OK(tmp_wreqPacket);
1202
- const freeData = await this._zkTcp.executeCmd(COMMANDS.CMD_FREE_DATA, '');
1203
- return check_ACK_OK(freeData);
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
- class ZTCP {
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
- * @param_ip ip address of device
1278
- * @param_port port number of device
1279
- * @param_timeout connection timout
1280
- * @param_comm_key communication key of device (if the case)
1281
- * @return Zkteco TCP socket connection instance
1282
- */
1283
- ip;
1284
- port;
1285
- timeout;
1286
- sessionId = 0;
1287
- replyId = 0;
1288
- socket;
1289
- comm_key;
1290
- user_count = 0;
1291
- fp_count = 0;
1292
- pwd_count = 0;
1293
- oplog_count = 0;
1294
- attlog_count = 0;
1295
- fp_cap = 0;
1296
- user_cap = 0;
1297
- attlog_cap = 0;
1298
- fp_av = 0;
1299
- user_av = 0;
1300
- attlog_av = 0;
1301
- face_count = 0;
1302
- face_cap = 0;
1303
- userPacketSize = 72;
1304
- verbose = false;
1305
- packetNumber = 0;
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
- _userService;
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('error', (err) => {
2301
+ this.socket.once("error", (err) => {
1324
2302
  this.socket = undefined; // Ensure socket reference is cleared
1325
2303
  reject(err);
1326
- if (typeof cbError === 'function')
2304
+ if (typeof cbError === "function")
1327
2305
  cbError(err);
1328
2306
  });
1329
2307
  // Handle successful connection
1330
- this.socket.once('connect', () => {
2308
+ this.socket.once("connect", () => {
1331
2309
  resolve(this.socket);
1332
2310
  });
1333
2311
  // Handle socket closure
1334
- this.socket.once('close', () => {
2312
+ this.socket.once("close", () => {
1335
2313
  this.socket = undefined; // Ensure socket reference is cleared
1336
- if (typeof cbClose === 'function')
1337
- cbClose('tcp');
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('NO_REPLY_ON_CMD_CONNECT');
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('Failed to connect:', err);
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('data');
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.destroy(); // Forcibly close the socket if not closed properly
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('error', (err) => {
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('Socket is not initialized'));
2382
+ return reject(new Error("Socket is not initialized"));
1405
2383
  }
1406
2384
  // Define a variable for the timeout reference
1407
- let timer = null;
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('data', onData); // Remove the data event listener
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.once('data', onData);
2404
+ this.socket.on("data", onData);
1419
2405
  // Attempt to write the message to the socket
1420
- this.socket.write(msg, null, (err) => {
2406
+ this.socket.write(msg, undefined, (err) => {
1421
2407
  if (err) {
1422
- // Check if the socket is still valid before trying to remove the listener
1423
- if (this.socket) {
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('data', handleOnData); // Clean up listener
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("linea 232: replyId: ", header.replyId, " command: ", header.commandId, Object.keys(COMMANDS).find(c => COMMANDS[c] == header.commandId));
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 = setTimeout(() => {
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('data', handleOnData);
2464
+ this.socket.on("data", handleOnData);
1491
2465
  // Write the message to the socket
1492
- this.socket.write(msg, null, (err) => {
2466
+ this.socket.write(msg, undefined, (err) => {
1493
2467
  if (err) {
1494
2468
  if (this.socket) {
1495
- this.socket.removeListener('data', handleOnData); // Clean up listener on error
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 = setTimeout(() => {
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('SOCKET_NOT_INITIALIZED')); // Reject if socket is not initialized
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
- try {
1537
- // Write the message to the socket and wait for a response
1538
- const reply = await this.writeMessage(buf, command === COMMANDS.CMD_CONNECT || command === COMMANDS.CMD_EXIT);
1539
- if (this.verbose) {
1540
- let headers = decodeTCPHeader(reply);
1541
- console.log('command: ', COMMANDS[headers.commandId], 'replyid: ', headers.replyId);
1542
- }
1543
- // Remove TCP header from the response
1544
- const rReply = removeTcpHeader(reply);
1545
- // Update sessionId for connection command responses
1546
- if (command === COMMANDS.CMD_CONNECT && rReply && rReply.length >= 6) { // Assuming sessionId is located at offset 4 and is 2 bytes long
1547
- this.sessionId = rReply.readUInt16LE(4);
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
- return rReply;
1550
- }
1551
- catch (err) {
1552
- // Log or handle the error if necessary
1553
- console.error('Error executing command:', err);
1554
- throw err; // Re-throw the error for handling by the caller
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
- await new Promise((resolve, reject) => {
1565
- this.socket.write(buf, null, (err) => {
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 = null) {
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 = null;
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.subarray(0, 16));
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
- let remain = size % Constants.MAX_CHUNK;
1616
- let numberChunks = Math.round(size - remain) / Constants.MAX_CHUNK;
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('TIMEOUT WHEN RECEIVING PACKET'));
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('data');
2617
+ this.socket && this.socket.removeAllListeners("data");
1626
2618
  timer && clearTimeout(timer);
1627
2619
  resolve({ data: replyData, err });
1628
2620
  };
1629
- this.socket.once('close', () => {
1630
- internalCallback(this.replyData, new Error('Socket is disconnected unexpectedly'));
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, (i === numberChunks)
1636
- ? remain
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
- const headers = decodeTCPHeader(reply);
1644
- if (COMMANDS[headers.commandId]) {
1645
- switch (headers.commandId) {
1646
- case COMMANDS.CMD_ACK_OK:
1647
- case COMMANDS.CMD_DATA:
1648
- this.verbose && console.log("CMD received: ", COMMANDS[headers.commandId]);
1649
- break;
1650
- case COMMANDS.CMD_PREPARE_DATA:
1651
- this.verbose && console.log("CMD received: ", COMMANDS[headers.commandId]);
1652
- this.verbose && console.log(`recieve chunk: prepare data size is ${headers.payloadSize}`);
1653
- break;
1654
- default:
1655
- break;
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([realTotalBuffer, totalBuffer.subarray(16, 8 + packetLength)]);
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 && realTotalBuffer.length === (Constants.MAX_CHUNK + 8))
1664
- || (this.packetNumber === 1 && realTotalBuffer.length === remain + 8)) {
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([this.replyData, data]);
1679
- this.socket.removeAllListeners('data');
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('ERROR_IN_UNHANDLE_CMD ' + exportErrorMessage(header.commandId)));
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('Error freeing data:', err);
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('Error disabling device:', err);
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('Error enabling device:', err);
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('Error during disconnection:', err);
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('Error during socket closure:', err);
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('Error getting device info:', err);
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('Error getting device info:', err);
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
- async getVendor() {
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('Error getting attendance size:', err);
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('Error clearing data:', err);
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.write(buf, null, (err) => {
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('Error sending real-time logs request:', err);
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.listenerCount('data') === 0) {
2209
- this.socket.on('data', (data) => {
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(decodeRecordRealTimeLog52(data));
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('Error getting real-time logs:', err);
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('Error getting user templates: ', err);
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
- let totalPackets = 0;
2976
+ const totalPackets = 0;
2311
2977
  return new Promise((resolve, reject) => {
2312
2978
  let timer = setTimeout(() => {
2313
- internalCallback(replyBufer, new Error('TIMEOUT WHEN RECEIVING PACKET'));
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('data', onDataEnroll);
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('close', () => {
2331
- internalCallback(replyBufer, new Error('Socket is disconnected unexpectedly'));
2996
+ this.socket.once("close", () => {
2997
+ internalCallback(replyBufer, new Error("Socket is disconnected unexpectedly"));
2332
2998
  });
2333
- this.socket.on('data', onDataEnroll);
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("Authentication 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 'tcp':
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(`TCP socket isn't connected!`), `[TCP] ${command}`, this.ip);
3536
+ throw new ZkError(new Error("TCP socket isn't connected!"), `[TCP] ${command}`, this.ip);
2871
3537
  }
2872
- case 'udp':
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(`UDP socket isn't connected!`), `[UDP] ${command}`, this.ip);
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(`Unsupported connection type or socket isn't connected!`), '', this.ip);
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('TCP reconnection successful');
2893
- this._connectionType = 'tcp';
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, 'TCP CONNECT', this.ip);
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('TCP connection successful');
2905
- this._connectionType = 'tcp';
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, 'TCP CONNECT', this.ip);
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('Error disconnecting TCP:', disconnectErr);
3585
+ console.error("Error disconnecting TCP:", disconnectErr);
2920
3586
  }
2921
3587
  if (err.code !== ERROR_TYPES.ECONNREFUSED) {
2922
- throw new ZkError(err, 'TCP CONNECT', this.ip);
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('UDP connection successful');
2930
- this._connectionType = 'udp';
3595
+ console.log("UDP connection successful");
3596
+ this._connectionType = "udp";
2931
3597
  return true;
2932
3598
  }
2933
3599
  catch (err) {
2934
- if (err.message !== 'EADDRINUSE') {
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('Error disconnecting UDP:', disconnectErr);
3606
+ console.error("Error disconnecting UDP:", disconnectErr);
2941
3607
  }
2942
- throw new ZkError(err, 'UDP CONNECT', this.ip);
3608
+ throw new ZkError(err, "UDP CONNECT", this.ip);
2943
3609
  }
2944
- this._connectionType = 'udp';
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(), 'GET_USERS');
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(), 'GET_TIME');
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), 'SET_TIME');
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 () => { throw new Error('UDP voice test not supported'); }, 'VOICE_TEST');
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 () => { throw new Error('UDP get product time not supported'); }, 'GET_PRODUCT_TIME');
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 () => { throw new Error('UDP get vendor not supported'); }, 'GET_VENDOR');
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 () => { throw new Error('UDP get MAC address not supported'); }, 'GET_MAC_ADDRESS');
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 () => { throw new Error('UDP get serial number not supported'); }, 'GET_SERIAL_NUMBER');
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 () => { throw new Error('UDP get device version not supported'); }, 'GET_DEVICE_VERSION');
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 () => { throw new Error('UDP get device name not supported'); }, 'GET_DEVICE_NAME');
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 () => { throw new Error('UDP get platform not supported'); }, 'GET_PLATFORM');
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 () => { throw new Error('UDP get OS not supported'); }, 'GET_OS');
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 () => { throw new Error('UDP get work code not supported'); }, 'GET_WORK_CODE');
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 () => { throw new Error('UDP get PIN not supported'); }, 'GET_PIN');
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 () => { throw new Error('UDP get face on not supported'); }, 'GET_FACE_ON');
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 () => { throw new Error('UDP get SSR not supported'); }, 'GET_SSR');
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 () => { throw new Error('UDP get firmware not supported'); }, 'GET_FIRMWARE');
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 () => { throw new Error('UDP set user not supported'); }, 'SET_USER');
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 () => { throw new Error('UDP delete user not supported'); }, 'DELETE_USER');
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 () => { throw new Error('UDP get attendance size not supported'); }, 'GET_ATTENDANCE_SIZE');
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), 'GET_ATTENDANCES');
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), 'GET_REAL_TIME_LOGS');
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 () => { throw new Error('UDP get templates not supported'); }, 'GET_TEMPLATES');
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 () => { throw new Error('UDP get user template not implemented'); }, 'GET_USER_TEMPLATE');
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 () => { throw new Error('UDP get user template not implemented'); }, 'UPLOAD_USER_TEMPLATE');
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 () => { throw new Error('UDP save user template not supported'); }, 'SAVE_USER_TEMPLATE');
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 () => { throw new Error('UDP delete finger not supported'); }, 'DELETE_FINGER');
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 () => { throw new Error('UDP enroll user not supported'); }, 'ENROLL_USER');
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 () => { throw new Error('UDP verify user not supported'); }, 'VERIFY_USER');
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 () => { throw new Error('UDP restart device not supported'); }, 'RESTART_DEVICE');
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(), () => { throw new Error('not implemented ofr UDP'); }, 'GET_SIZES');
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(), '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(), 'FREE_DATA');
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(), 'DISABLE_DEVICE');
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(), 'ENABLE_DEVICE');
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(), 'GET_INFO');
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(), 'CLEAR_ATTENDANCE_LOG');
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(), 'CLEAR_DATA');
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), 'EXECUTE_CMD');
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 () => { throw new Error('UDP getNetworkParams not implemented'); }, 'NETWORK_PARAMS');
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