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