zklib-ts 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -1,2834 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var net = require('net');
4
- var fs = require('fs');
5
- var dgram = require('node:dgram');
6
-
7
- function _interopNamespaceDefault(e) {
8
- var n = Object.create(null);
9
- if (e) {
10
- Object.keys(e).forEach(function (k) {
11
- if (k !== 'default') {
12
- var d = Object.getOwnPropertyDescriptor(e, k);
13
- Object.defineProperty(n, k, d.get ? d : {
14
- enumerable: true,
15
- get: function () { return e[k]; }
16
- });
17
- }
18
- });
19
- }
20
- n.default = e;
21
- return Object.freeze(n);
22
- }
23
-
24
- var dgram__namespace = /*#__PURE__*/_interopNamespaceDefault(dgram);
25
-
26
- var COMMANDS;
27
- (function (COMMANDS) {
28
- COMMANDS[COMMANDS["CMD_ACK_DATA"] = 2002] = "CMD_ACK_DATA";
29
- /** There was an error when processing the request.*/
30
- COMMANDS[COMMANDS["CMD_ACK_ERROR"] = 2001] = "CMD_ACK_ERROR";
31
- COMMANDS[COMMANDS["CMD_ACK_ERROR_CMD"] = 65533] = "CMD_ACK_ERROR_CMD";
32
- COMMANDS[COMMANDS["CMD_ACK_ERROR_DATA"] = 65531] = "CMD_ACK_ERROR_DATA";
33
- COMMANDS[COMMANDS["CMD_ACK_ERROR_INIT"] = 65532] = "CMD_ACK_ERROR_INIT";
34
- /** [0xD0, 0x07] The request was processed sucessfully. */
35
- COMMANDS[COMMANDS["CMD_ACK_OK"] = 2000] = "CMD_ACK_OK";
36
- COMMANDS[COMMANDS["CMD_ACK_REPEAT"] = 2004] = "CMD_ACK_REPEAT";
37
- COMMANDS[COMMANDS["CMD_ACK_RETRY"] = 2003] = "CMD_ACK_RETRY";
38
- /** [0xD5, 0x07] Connection not authorized. */
39
- COMMANDS[COMMANDS["CMD_ACK_UNAUTH"] = 2005] = "CMD_ACK_UNAUTH";
40
- /** Received unknown command. */
41
- COMMANDS[COMMANDS["CMD_ACK_UNKNOWN"] = 65535] = "CMD_ACK_UNKNOWN";
42
- /** Request attendance log. */
43
- COMMANDS[COMMANDS["CMD_ATTLOG_RRQ"] = 13] = "CMD_ATTLOG_RRQ";
44
- /** [0x4E, 0x04] Request to begin session using commkey. */
45
- COMMANDS[COMMANDS["CMD_AUTH"] = 1102] = "CMD_AUTH";
46
- /** Disable normal authentication of users. */
47
- COMMANDS[COMMANDS["CMD_CANCELCAPTURE"] = 62] = "CMD_CANCELCAPTURE";
48
- /** Capture fingerprint picture. */
49
- COMMANDS[COMMANDS["CMD_CAPTUREFINGER"] = 1009] = "CMD_CAPTUREFINGER";
50
- /** Capture the entire image. */
51
- COMMANDS[COMMANDS["CMD_CAPTUREIMAGE"] = 1012] = "CMD_CAPTUREIMAGE";
52
- /** Change transmission speed. */
53
- COMMANDS[COMMANDS["CMD_CHANGE_SPEED"] = 1101] = "CMD_CHANGE_SPEED";
54
- /** [0x77, 0x00] Get checksum of machine's buffer. */
55
- COMMANDS[COMMANDS["CMD_CHECKSUM_BUFFER"] = 119] = "CMD_CHECKSUM_BUFFER";
56
- /** Restore access control to default. */
57
- COMMANDS[COMMANDS["CMD_CLEAR_ACC"] = 32] = "CMD_CLEAR_ACC";
58
- /** Clears admins privileges. */
59
- COMMANDS[COMMANDS["CMD_CLEAR_ADMIN"] = 20] = "CMD_CLEAR_ADMIN";
60
- /** Delete attendance record. */
61
- COMMANDS[COMMANDS["CMD_CLEAR_ATTLOG"] = 15] = "CMD_CLEAR_ATTLOG";
62
- /** Delete data. */
63
- COMMANDS[COMMANDS["CMD_CLEAR_DATA"] = 14] = "CMD_CLEAR_DATA";
64
- /** Clear screen captions. */
65
- COMMANDS[COMMANDS["CMD_CLEAR_LCD"] = 67] = "CMD_CLEAR_LCD";
66
- /** Delete operations log. */
67
- COMMANDS[COMMANDS["CMD_CLEAR_OPLOG"] = 33] = "CMD_CLEAR_OPLOG";
68
- /** [0xE8, 0x03] Begin connection. */
69
- COMMANDS[COMMANDS["CMD_CONNECT"] = 1000] = "CMD_CONNECT";
70
- /** [0xDD, 0x05] Data packet. */
71
- COMMANDS[COMMANDS["CMD_DATA"] = 1501] = "CMD_DATA";
72
- /** Indicates that it is ready to receive data. */
73
- COMMANDS[COMMANDS["CMD_DATA_RDY"] = 1504] = "CMD_DATA_RDY";
74
- /** Read/Write a large data set. */
75
- COMMANDS[COMMANDS["CMD_DATA_WRRQ"] = 1503] = "CMD_DATA_WRRQ";
76
- /** Read saved data. */
77
- COMMANDS[COMMANDS["CMD_DB_RRQ"] = 7] = "CMD_DB_RRQ";
78
- /** Deletes fingerprint template. */
79
- COMMANDS[COMMANDS["CMD_DEL_FPTMP"] = 134] = "CMD_DEL_FPTMP";
80
- /** Delete short message. */
81
- COMMANDS[COMMANDS["CMD_DELETE_SMS"] = 72] = "CMD_DELETE_SMS";
82
- /** Delete user short message. */
83
- COMMANDS[COMMANDS["CMD_DELETE_UDATA"] = 74] = "CMD_DELETE_UDATA";
84
- /** Delete user. */
85
- COMMANDS[COMMANDS["CMD_DELETE_USER"] = 18] = "CMD_DELETE_USER";
86
- /** Delete user fingerprint template. */
87
- COMMANDS[COMMANDS["CMD_DELETE_USERTEMP"] = 19] = "CMD_DELETE_USERTEMP";
88
- /** Disables fingerprint, rfid reader and keyboard. */
89
- COMMANDS[COMMANDS["CMD_DISABLEDEVICE"] = 1003] = "CMD_DISABLEDEVICE";
90
- /** Get door state. */
91
- COMMANDS[COMMANDS["CMD_DOORSTATE_RRQ"] = 75] = "CMD_DOORSTATE_RRQ";
92
- /** Clear Mifare card. */
93
- COMMANDS[COMMANDS["CMD_EMPTY_MIFARE"] = 78] = "CMD_EMPTY_MIFARE";
94
- /** Enables the ":" in screen clock. */
95
- COMMANDS[COMMANDS["CMD_ENABLE_CLOCK"] = 57] = "CMD_ENABLE_CLOCK";
96
- /** Change machine state to "normal work". */
97
- COMMANDS[COMMANDS["CMD_ENABLEDEVICE"] = 1002] = "CMD_ENABLEDEVICE";
98
- /** [0xE9, 0x03] Disconnect. */
99
- COMMANDS[COMMANDS["CMD_EXIT"] = 1001] = "CMD_EXIT";
100
- /** [0xDE, 0x05] Release buffer used for data transmission. */
101
- COMMANDS[COMMANDS["CMD_FREE_DATA"] = 1502] = "CMD_FREE_DATA";
102
- /** Request machine status (remaining space). */
103
- COMMANDS[COMMANDS["CMD_GET_FREE_SIZES"] = 50] = "CMD_GET_FREE_SIZES";
104
- /** Request max size for users id. */
105
- COMMANDS[COMMANDS["CMD_GET_PINWIDTH"] = 69] = "CMD_GET_PINWIDTH";
106
- /** Request machine time. */
107
- COMMANDS[COMMANDS["CMD_GET_TIME"] = 201] = "CMD_GET_TIME";
108
- COMMANDS[COMMANDS["CMD_GET_USERTEMP"] = 88] = "CMD_GET_USERTEMP";
109
- /** Request the firmware edition. */
110
- COMMANDS[COMMANDS["CMD_GET_VERSION"] = 1100] = "CMD_GET_VERSION";
111
- /** Get group timezone. */
112
- COMMANDS[COMMANDS["CMD_GRPTZ_RRQ"] = 25] = "CMD_GRPTZ_RRQ";
113
- /** Set group timezone. */
114
- COMMANDS[COMMANDS["CMD_GRPTZ_WRQ"] = 26] = "CMD_GRPTZ_WRQ";
115
- /** Read operations log. */
116
- COMMANDS[COMMANDS["CMD_OPLOG_RRQ"] = 34] = "CMD_OPLOG_RRQ";
117
- /** Read configuration value of the machine. */
118
- COMMANDS[COMMANDS["CMD_OPTIONS_RRQ"] = 11] = "CMD_OPTIONS_RRQ";
119
- /** Change configuration value of the machine. */
120
- COMMANDS[COMMANDS["CMD_OPTIONS_WRQ"] = 12] = "CMD_OPTIONS_WRQ";
121
- /** Shut-down machine. */
122
- COMMANDS[COMMANDS["CMD_POWEROFF"] = 1005] = "CMD_POWEROFF";
123
- /** [0xDC, 0x05] Prepare for data transmission. */
124
- COMMANDS[COMMANDS["CMD_PREPARE_DATA"] = 1500] = "CMD_PREPARE_DATA";
125
- /** [0xF5, 0x03] Refresh the machine stored data. */
126
- COMMANDS[COMMANDS["CMD_REFRESHDATA"] = 1013] = "CMD_REFRESHDATA";
127
- /** Refresh the configuration parameters. */
128
- COMMANDS[COMMANDS["CMD_REFRESHOPTION"] = 1014] = "CMD_REFRESHOPTION";
129
- /** Realtime events. */
130
- COMMANDS[COMMANDS["CMD_REG_EVENT"] = 500] = "CMD_REG_EVENT";
131
- /** Restart machine. */
132
- COMMANDS[COMMANDS["CMD_RESTART"] = 1004] = "CMD_RESTART";
133
- /** Change machine state to "awaken". */
134
- COMMANDS[COMMANDS["CMD_RESUME"] = 1007] = "CMD_RESUME";
135
- /** Set machine time. */
136
- COMMANDS[COMMANDS["CMD_SET_TIME"] = 202] = "CMD_SET_TIME";
137
- /** Change machine state to "idle". */
138
- COMMANDS[COMMANDS["CMD_SLEEP"] = 1006] = "CMD_SLEEP";
139
- /** Download short message. */
140
- COMMANDS[COMMANDS["CMD_SMS_RRQ"] = 71] = "CMD_SMS_RRQ";
141
- /** Upload short message. */
142
- COMMANDS[COMMANDS["CMD_SMS_WRQ"] = 70] = "CMD_SMS_WRQ";
143
- /** Start enroll procedure. */
144
- COMMANDS[COMMANDS["CMD_STARTENROLL"] = 61] = "CMD_STARTENROLL";
145
- /** Set the machine to authentication state. */
146
- COMMANDS[COMMANDS["CMD_STARTVERIFY"] = 60] = "CMD_STARTVERIFY";
147
- /** Query state. */
148
- COMMANDS[COMMANDS["CMD_STATE_RRQ"] = 64] = "CMD_STATE_RRQ";
149
- /** Test if fingerprint exists. */
150
- COMMANDS[COMMANDS["CMD_TEST_TEMP"] = 1011] = "CMD_TEST_TEMP";
151
- /** Test voice. */
152
- COMMANDS[COMMANDS["CMD_TESTVOICE"] = 1017] = "CMD_TESTVOICE";
153
- /** [0x77, 0x00] Transfer fp template from buffer. */
154
- COMMANDS[COMMANDS["CMD_TMP_WRITE"] = 87] = "CMD_TMP_WRITE";
155
- /** Get device timezones. */
156
- COMMANDS[COMMANDS["CMD_TZ_RRQ"] = 27] = "CMD_TZ_RRQ";
157
- /** Set device timezones. */
158
- COMMANDS[COMMANDS["CMD_TZ_WRQ"] = 28] = "CMD_TZ_WRQ";
159
- /** Set user short message. */
160
- COMMANDS[COMMANDS["CMD_UDATA_WRQ"] = 73] = "CMD_UDATA_WRQ";
161
- /** Get group combination to unlock. */
162
- COMMANDS[COMMANDS["CMD_ULG_RRQ"] = 29] = "CMD_ULG_RRQ";
163
- /** Set group combination to unlock. */
164
- COMMANDS[COMMANDS["CMD_ULG_WRQ"] = 30] = "CMD_ULG_WRQ";
165
- /** Unlock door for a specified amount of time. */
166
- COMMANDS[COMMANDS["CMD_UNLOCK"] = 31] = "CMD_UNLOCK";
167
- /** Upload user data. */
168
- COMMANDS[COMMANDS["CMD_USER_WRQ"] = 8] = "CMD_USER_WRQ";
169
- /** Read user group. */
170
- COMMANDS[COMMANDS["CMD_USERGRP_RRQ"] = 21] = "CMD_USERGRP_RRQ";
171
- /** Set user group. */
172
- COMMANDS[COMMANDS["CMD_USERGRP_WRQ"] = 22] = "CMD_USERGRP_WRQ";
173
- /** [0x09, 0x00] Read user fingerprint template. */
174
- COMMANDS[COMMANDS["CMD_USERTEMP_RRQ"] = 9] = "CMD_USERTEMP_RRQ";
175
- /** Upload user fingerprint template. */
176
- COMMANDS[COMMANDS["CMD_USERTEMP_WRQ"] = 10] = "CMD_USERTEMP_WRQ";
177
- /** Get user timezones. */
178
- COMMANDS[COMMANDS["CMD_USERTZ_RRQ"] = 23] = "CMD_USERTZ_RRQ";
179
- /** Set the user timezones. */
180
- COMMANDS[COMMANDS["CMD_USERTZ_WRQ"] = 24] = "CMD_USERTZ_WRQ";
181
- /** Read verification style of a given user. */
182
- COMMANDS[COMMANDS["CMD_VERIFY_RRQ"] = 80] = "CMD_VERIFY_RRQ";
183
- /** Change verification style of a given user. */
184
- COMMANDS[COMMANDS["CMD_VERIFY_WRQ"] = 79] = "CMD_VERIFY_WRQ";
185
- /** Prints chars to the device screen. */
186
- COMMANDS[COMMANDS["CMD_WRITE_LCD"] = 66] = "CMD_WRITE_LCD";
187
- /** Write data to Mifare card. */
188
- COMMANDS[COMMANDS["CMD_WRITE_MIFARE"] = 76] = "CMD_WRITE_MIFARE";
189
- /** Triggered alarm. */
190
- COMMANDS[COMMANDS["EF_ALARM"] = 512] = "EF_ALARM";
191
- /** Attendance entry. */
192
- COMMANDS[COMMANDS["EF_ATTLOG"] = 1] = "EF_ATTLOG";
193
- /** Pressed keyboard key. */
194
- COMMANDS[COMMANDS["EF_BUTTON"] = 16] = "EF_BUTTON";
195
- /** Upload user data. */
196
- COMMANDS[COMMANDS["EF_ENROLLFINGER"] = 8] = "EF_ENROLLFINGER";
197
- /** Enrolled user. */
198
- COMMANDS[COMMANDS["EF_ENROLLUSER"] = 4] = "EF_ENROLLUSER";
199
- /** Pressed finger. */
200
- COMMANDS[COMMANDS["EF_FINGER"] = 2] = "EF_FINGER";
201
- /** Fingerprint score in enroll procedure. */
202
- COMMANDS[COMMANDS["EF_FPFTR"] = 256] = "EF_FPFTR";
203
- /** Restore access control to default. */
204
- COMMANDS[COMMANDS["EF_UNLOCK"] = 32] = "EF_UNLOCK";
205
- /** Registered user placed finger. */
206
- COMMANDS[COMMANDS["EF_VERIFY"] = 128] = "EF_VERIFY";
207
- })(COMMANDS || (COMMANDS = {}));
208
- var DISCOVERED_CMD;
209
- (function (DISCOVERED_CMD) {
210
- /** Returned when the Finger id not exists in the user uid, when attempting to download single finger template */
211
- DISCOVERED_CMD[DISCOVERED_CMD["FID_NOT_FOUND"] = 4993] = "FID_NOT_FOUND";
212
- })(DISCOVERED_CMD || (DISCOVERED_CMD = {}));
213
- var Constants;
214
- (function (Constants) {
215
- Constants[Constants["USHRT_MAX"] = 65535] = "USHRT_MAX";
216
- Constants[Constants["MAX_CHUNK"] = 65472] = "MAX_CHUNK";
217
- Constants[Constants["MACHINE_PREPARE_DATA_1"] = 20560] = "MACHINE_PREPARE_DATA_1";
218
- Constants[Constants["MACHINE_PREPARE_DATA_2"] = 32130] = "MACHINE_PREPARE_DATA_2";
219
- })(Constants || (Constants = {}));
220
- const REQUEST_DATA = {
221
- START_TAG: Buffer.from([0x50, 0x50, 0x82, 0x7d]),
222
- DISABLE_DEVICE: Buffer.from([0, 0, 0, 0]),
223
- GET_REAL_TIME_EVENT: Buffer.from([0x01, 0x00, 0x00, 0x00]),
224
- GET_ATTENDANCE_LOGS: Buffer.from([0x01, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
225
- GET_USERS: Buffer.from([0x01, 0x09, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
226
- GET_TEMPLATES: Buffer.from([0x01, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
227
- };
228
-
229
- /**
230
- *
231
- * @param {number} time
232
- */
233
- const decode = time => {
234
- const second = time % 60;
235
- time = (time - second) / 60;
236
- const minute = time % 60;
237
- time = (time - minute) / 60;
238
- const hour = time % 24;
239
- time = (time - hour) / 24;
240
- const day = time % 31 + 1;
241
- time = (time - (day - 1)) / 31;
242
- const month = time % 12;
243
- time = (time - month) / 12;
244
- const year = time + 2000;
245
- return new Date(year, month, day, hour, minute, second);
246
- };
247
- /**
248
- *
249
- * @param {Date} date
250
- */
251
- const encode = date => {
252
- return (((date.getFullYear() % 100) * 12 * 31 + date.getMonth() * 31 + date.getDate() - 1) * (24 * 60 * 60) +
253
- (date.getHours() * 60 + date.getMinutes()) * 60 +
254
- date.getSeconds());
255
- };
256
- var timeParser = { encode, decode };
257
-
258
- const parseCurrentTime = () => {
259
- const currentTime = new Date();
260
- return {
261
- year: currentTime.getFullYear(),
262
- month: currentTime.getMonth() + 1,
263
- day: currentTime.getDate(),
264
- hour: currentTime.getHours(),
265
- second: currentTime.getSeconds()
266
- };
267
- };
268
- const log = (text) => {
269
- const currentTime = parseCurrentTime();
270
- const fileName = `${currentTime.day}`.padStart(2, '0') +
271
- `${currentTime.month}`.padStart(2, '0') +
272
- `${currentTime.year}.err.log`;
273
- const logMessage = `\n [${currentTime.hour}:${currentTime.second}] ${text}`;
274
- fs.appendFile(fileName, logMessage, () => { });
275
- };
276
-
277
- /**
278
- * Represents a User as is from ZkDevice and contain methods
279
- * */
280
- class User {
281
- uid;
282
- name;
283
- privilege;
284
- password;
285
- group_id;
286
- user_id;
287
- card;
288
- /**
289
- * Creates a new User instance
290
- * @param uid User ID
291
- * @param name User name
292
- * @param privilege Privilege level
293
- * @param password User password (default: "")
294
- * @param group_id Group ID (default: "")
295
- * @param user_id Alternate user ID (default: "")
296
- * @param card Card number (default: 0)
297
- */
298
- constructor(uid, name, privilege, password = "", group_id = "", user_id = "", card = 0) {
299
- this.uid = uid;
300
- this.name = name;
301
- this.privilege = privilege;
302
- this.password = password;
303
- this.group_id = group_id;
304
- this.user_id = user_id;
305
- this.card = card;
306
- }
307
- ensureEncoding(string) {
308
- try {
309
- return decodeURIComponent(string);
310
- }
311
- catch (e) {
312
- return unescape(string);
313
- }
314
- }
315
- repack29() {
316
- // Pack format: <BHB5s8sIxBhI (total 29 bytes)
317
- const buf = Buffer.alloc(29);
318
- let offset = 0;
319
- buf.writeUInt8(2, offset);
320
- offset += 1;
321
- buf.writeUInt16LE(this.uid, offset);
322
- offset += 2;
323
- buf.writeUInt8(this.privilege, offset);
324
- offset += 1;
325
- const passwordBuf = Buffer.from(this.ensureEncoding(this.password));
326
- passwordBuf.copy(buf, offset, 0, 5);
327
- offset += 5;
328
- const nameBuf = Buffer.from(this.ensureEncoding(this.name));
329
- nameBuf.copy(buf, offset, 0, 8);
330
- offset += 8;
331
- buf.writeUInt32LE(this.card, offset);
332
- offset += 4;
333
- offset += 1; // padding byte
334
- buf.writeUInt8(0, offset);
335
- offset += 1;
336
- buf.writeUInt32LE(parseInt(this.user_id) || 0, offset);
337
- return buf;
338
- }
339
- repack73() {
340
- // Pack format: <BHB8s24sIB7sx24s (total 73 bytes)
341
- const buf = Buffer.alloc(73);
342
- let offset = 0;
343
- buf.writeUInt8(2, offset);
344
- offset += 1;
345
- buf.writeUInt16LE(this.uid, offset);
346
- offset += 2;
347
- buf.writeUInt8(this.privilege, offset);
348
- offset += 1;
349
- const passwordBuf = Buffer.from(this.ensureEncoding(this.password));
350
- passwordBuf.copy(buf, offset, 0, 8);
351
- offset += 8;
352
- const nameBuf = Buffer.from(this.ensureEncoding(this.name));
353
- nameBuf.copy(buf, offset, 0, 24);
354
- offset += 24;
355
- buf.writeUInt32LE(this.card, offset);
356
- offset += 4;
357
- buf.writeUInt8(1, offset);
358
- offset += 1;
359
- const groupBuf = Buffer.from(this.ensureEncoding(String(this.group_id)));
360
- groupBuf.copy(buf, offset, 0, 7);
361
- offset += 8;
362
- const userIdBuf = Buffer.from(this.ensureEncoding(String(this.user_id)));
363
- userIdBuf.copy(buf, offset, 0, 24);
364
- return buf;
365
- }
366
- }
367
-
368
- class Attendance {
369
- /** Internal serial number for the user */
370
- sn;
371
- /** User ID/Pin stored as a string */
372
- user_id;
373
- /** Verification type */
374
- type;
375
- /** Time of the attendance event */
376
- record_time;
377
- /** Verify state */
378
- state;
379
- ip;
380
- constructor(sn, user_id, type, record_time, state) {
381
- this.sn = sn;
382
- this.user_id = user_id;
383
- this.type = type || undefined;
384
- this.record_time = record_time;
385
- this.state = state || undefined;
386
- }
387
- }
388
-
389
- const parseHexToTime = (hex) => {
390
- const time = {
391
- year: hex.readUIntLE(0, 1),
392
- month: hex.readUIntLE(1, 1),
393
- date: hex.readUIntLE(2, 1),
394
- hour: hex.readUIntLE(3, 1),
395
- minute: hex.readUIntLE(4, 1),
396
- second: hex.readUIntLE(5, 1)
397
- };
398
- return new Date(2000 + time.year, time.month - 1, time.date, time.hour, time.minute, time.second);
399
- };
400
- const createChkSum = (buf) => {
401
- let chksum = 0;
402
- for (let i = 0; i < buf.length; i += 2) {
403
- if (i === buf.length - 1) {
404
- chksum += buf[i];
405
- }
406
- else {
407
- chksum += buf.readUInt16LE(i);
408
- }
409
- chksum %= Constants.USHRT_MAX;
410
- }
411
- chksum = Constants.USHRT_MAX - chksum - 1;
412
- return chksum;
413
- };
414
- const createUDPHeader = (command, sessionId, replyId, data) => {
415
- const dataBuffer = Buffer.from(data);
416
- const buf = Buffer.alloc(8 + dataBuffer.length);
417
- buf.writeUInt16LE(command, 0);
418
- buf.writeUInt16LE(0, 2);
419
- buf.writeUInt16LE(sessionId, 4);
420
- buf.writeUInt16LE(replyId, 6);
421
- dataBuffer.copy(buf, 8);
422
- const chksum2 = createChkSum(buf);
423
- buf.writeUInt16LE(chksum2, 2);
424
- replyId = (replyId + 1) % Constants.USHRT_MAX;
425
- buf.writeUInt16LE(replyId, 6);
426
- return buf;
427
- };
428
- const createTCPHeader = (command, sessionId, replyId, data) => {
429
- const buf = createUDPHeader(command, sessionId, replyId, data);
430
- const prefixBuf = Buffer.from([0x50, 0x50, 0x82, 0x7d, 0x13, 0x00, 0x00, 0x00]);
431
- prefixBuf.writeUInt16LE(buf.length, 4);
432
- return Buffer.concat([prefixBuf, buf]);
433
- };
434
- const removeTcpHeader = (buf) => {
435
- if (buf.length < 8) {
436
- return buf;
437
- }
438
- if (buf.compare(Buffer.from([0x50, 0x50, 0x82, 0x7d]), 0, 4, 0, 4) !== 0) {
439
- return buf;
440
- }
441
- return buf.slice(8);
442
- };
443
- const parseTimeToDate = (time) => {
444
- const second = time % 60;
445
- time = (time - second) / 60;
446
- const minute = time % 60;
447
- time = (time - minute) / 60;
448
- const hour = time % 24;
449
- time = (time - hour) / 24;
450
- const day = time % 31 + 1;
451
- time = (time - (day - 1)) / 31;
452
- const month = time % 12;
453
- time = (time - month) / 12;
454
- const year = time + 2000;
455
- return new Date(Date.UTC(year, month, day, hour, minute, second));
456
- };
457
- const decodeUserData28 = (userData) => {
458
- return {
459
- uid: userData.readUIntLE(0, 2),
460
- privilege: userData.readUIntLE(2, 1),
461
- name: userData
462
- .slice(8, 8 + 8)
463
- .toString('ascii')
464
- .split('\0')
465
- .shift() || '',
466
- user_id: userData.readUIntLE(24, 4).toString(),
467
- };
468
- };
469
- const decodeUserData72 = (userData) => {
470
- return new User(userData.readUIntLE(0, 2), userData
471
- .slice(11)
472
- .toString('ascii')
473
- .split('\0')
474
- .shift() || '', userData.readUIntLE(2, 1), userData
475
- .subarray(3, 3 + 8)
476
- .toString('ascii')
477
- .split('\0')
478
- .shift() || '', userData.readUIntLE(39, 1), userData
479
- .slice(48, 48 + 9)
480
- .toString('ascii')
481
- .split('\0')
482
- .shift() || '', userData.readUIntLE(35, 4));
483
- };
484
- const decodeRecordData40 = (recordData) => {
485
- return new Attendance(recordData.readUIntLE(0, 2), recordData
486
- .slice(2, 2 + 9)
487
- .toString('ascii')
488
- .split('\0')
489
- .shift() || '', recordData.readUIntLE(26, 1), parseTimeToDate(recordData.readUInt32LE(27)), recordData.readUIntLE(31, 1));
490
- };
491
- const decodeRecordData16 = (recordData) => {
492
- return {
493
- user_id: recordData.readUIntLE(0, 2).toString(),
494
- record_time: parseTimeToDate(recordData.readUInt32LE(4))
495
- };
496
- };
497
- const decodeRecordRealTimeLog18 = (recordData) => {
498
- const user_id = recordData.readUIntLE(8, 1).toString();
499
- const record_time = parseHexToTime(recordData.subarray(12, 18));
500
- return { user_id, record_time };
501
- };
502
- const decodeRecordRealTimeLog52 = (recordData) => {
503
- const payload = removeTcpHeader(recordData);
504
- const recvData = payload.subarray(8);
505
- const user_id = recvData.slice(0, 9)
506
- .toString('ascii')
507
- .split('\0')
508
- .shift() || '';
509
- const record_time = parseHexToTime(recvData.subarray(26, 26 + 6));
510
- return { user_id, record_time };
511
- };
512
- const decodeUDPHeader = (header) => {
513
- return {
514
- commandId: header.readUIntLE(0, 2),
515
- checkSum: header.readUIntLE(2, 2),
516
- sessionId: header.readUIntLE(4, 2),
517
- replyId: header.readUIntLE(6, 2)
518
- };
519
- };
520
- const decodeTCPHeader = (header) => {
521
- const recvData = header.subarray(8);
522
- const payloadSize = header.readUIntLE(4, 2);
523
- return {
524
- commandId: recvData.readUIntLE(0, 2),
525
- checkSum: recvData.readUIntLE(2, 2),
526
- sessionId: recvData.readUIntLE(4, 2),
527
- replyId: recvData.readUIntLE(6, 2),
528
- payloadSize
529
- };
530
- };
531
- const exportErrorMessage = (commandValue) => {
532
- const keys = Object.keys(COMMANDS);
533
- for (const key of keys) {
534
- if (COMMANDS[key] === commandValue) {
535
- return key.toString();
536
- }
537
- }
538
- return 'AN UNKNOWN ERROR';
539
- };
540
- const checkNotEventTCP = (data) => {
541
- try {
542
- const cleanedData = removeTcpHeader(data);
543
- const commandId = cleanedData.readUIntLE(0, 2);
544
- const event = cleanedData.readUIntLE(4, 2);
545
- return event === COMMANDS.EF_ATTLOG && commandId === COMMANDS.CMD_REG_EVENT;
546
- }
547
- catch (err) {
548
- log(`[228] : ${err.toString()} ,${data.toString('hex')} `);
549
- return false;
550
- }
551
- };
552
- const checkNotEventUDP = (data) => {
553
- const { commandId } = decodeUDPHeader(data.subarray(0, 8));
554
- return commandId === COMMANDS.CMD_REG_EVENT;
555
- };
556
- const makeKey = (key, sessionId) => {
557
- let k = 0;
558
- for (let i = 0; i < 32; i++) {
559
- if ((key & (1 << i)) !== 0) {
560
- k = (k << 1) | 1;
561
- }
562
- else {
563
- k = k << 1;
564
- }
565
- }
566
- k += sessionId;
567
- let hex = k.toString(16).padStart(8, "0");
568
- let response = new Uint8Array(4);
569
- let index = 3;
570
- while (hex.length > 0) {
571
- response[index] = parseInt(hex.substring(0, 2), 16);
572
- index--;
573
- hex = hex.substring(2);
574
- }
575
- response[0] ^= 'Z'.charCodeAt(0);
576
- response[1] ^= 'K'.charCodeAt(0);
577
- response[2] ^= 'S'.charCodeAt(0);
578
- response[3] ^= 'O'.charCodeAt(0);
579
- let finalKey = response[0] +
580
- (response[1] << 8) +
581
- (response[2] << 16) +
582
- (response[3] << 24);
583
- let swp = finalKey >>> 16;
584
- finalKey = (finalKey << 16) | swp;
585
- return finalKey >>> 0;
586
- };
587
- const authKey = (comKey, sessionId) => {
588
- let k = makeKey(comKey, sessionId) >>> 0;
589
- let rand = Math.floor(Math.random() * 256);
590
- let hex = k.toString(16).padStart(8, "0");
591
- let response = new Uint8Array(4);
592
- let index = 3;
593
- while (index >= 0) {
594
- response[index] = parseInt(hex.substring(0, 2), 16);
595
- index--;
596
- hex = hex.substring(2);
597
- }
598
- response[0] ^= rand;
599
- response[1] ^= rand;
600
- response[2] = rand;
601
- response[3] ^= rand;
602
- return Array.from(response);
603
- };
604
-
605
- /**
606
- * Error types for device communication
607
- */
608
- const ERROR_TYPES = {
609
- ECONNRESET: 'ECONNRESET',
610
- ECONNREFUSED: 'ECONNREFUSED'};
611
- /**
612
- * Custom error class for device communication errors
613
- */
614
- class ZkError {
615
- err;
616
- ip;
617
- command;
618
- /**
619
- * Creates a new ZkError instance
620
- * @param err The error object
621
- * @param command The command that caused the error
622
- * @param ip The IP address of the device
623
- */
624
- constructor(err, command, ip) {
625
- this.err = err;
626
- this.ip = ip;
627
- this.command = command;
628
- }
629
- /**
630
- * Gets a user-friendly error message
631
- * @returns A formatted error message
632
- */
633
- toast() {
634
- if (this.err.code === ERROR_TYPES.ECONNRESET) {
635
- return 'Another device is connecting to the device so the connection is interrupted';
636
- }
637
- else if (this.err.code === ERROR_TYPES.ECONNREFUSED) {
638
- return 'IP of the device is refused';
639
- }
640
- return this.err.message;
641
- }
642
- /**
643
- * Gets detailed error information
644
- * @returns An object containing error details
645
- */
646
- getError() {
647
- return {
648
- err: {
649
- message: this.err.message,
650
- code: this.err.code
651
- },
652
- ip: this.ip,
653
- command: this.command
654
- };
655
- }
656
- }
657
-
658
- /**
659
- * Represents a fingerprint template with associated metadata
660
- */
661
- class Finger {
662
- uid;
663
- fid;
664
- valid;
665
- template;
666
- size;
667
- mark;
668
- /**
669
- * Creates a new Finger instance
670
- * @param uid User internal reference
671
- * @param fid Finger ID (value >= 0 && value <= 9)
672
- * @param valid Flag indicating 0 = invalid | 1 = valid | 3 = duress
673
- * @param template Fingerprint template data buffer
674
- */
675
- constructor(uid, fid, valid, template) {
676
- this.uid = Number(uid);
677
- this.fid = Number(fid);
678
- this.valid = Number(valid);
679
- this.template = template;
680
- this.size = template.length;
681
- // Create mark showing first and last 8 bytes as hex
682
- const start = Uint8Array.prototype.slice.call(template, 0, 8).toString('hex');
683
- const end = Uint8Array.prototype.slice.call(template, -8).toString('hex');
684
- this.mark = `${start}...${end}`;
685
- }
686
- /**
687
- * Packs the fingerprint data with metadata into a Buffer
688
- * @returns Buffer containing packed fingerprint data
689
- */
690
- repack() {
691
- // pack("HHbb%is" % (self.size), self.size+6, self.uid, self.fid, self.valid, self.template)
692
- const buf = Buffer.alloc(6 + this.size); // HHbb = 6 bytes + template size
693
- let offset = 0;
694
- buf.writeUInt16LE(this.size + 6, offset);
695
- offset += 2;
696
- buf.writeUInt16LE(this.uid, offset);
697
- offset += 2;
698
- buf.writeUInt8(this.fid, offset);
699
- offset += 1;
700
- buf.writeUInt8(this.valid, offset);
701
- offset += 1;
702
- this.template.copy(buf, offset);
703
- return buf;
704
- }
705
- /**
706
- * Packs only the fingerprint template data into a Buffer
707
- * @returns Buffer containing just the template data
708
- */
709
- repackOnly() {
710
- // pack("H%is" % (self.size), self.size, self.template)
711
- const buf = Buffer.alloc(2 + this.size); // H = 2 bytes + template size
712
- buf.writeUInt16LE(this.size, 0);
713
- this.template.copy(buf, 2);
714
- return buf;
715
- }
716
- /**
717
- * Compares this fingerprint with another for equality
718
- * @param other Another Finger instance to compare with
719
- * @returns true if all properties and template data match
720
- */
721
- equals(other) {
722
- if (!(other instanceof Finger))
723
- return false;
724
- return this.uid === other.uid &&
725
- this.fid === other.fid &&
726
- this.valid === other.valid &&
727
- this.template.equals(other.template);
728
- }
729
- }
730
-
731
- class UserService {
732
- _zkTcp;
733
- _users;
734
- constructor(zkTcp) {
735
- this._zkTcp = zkTcp;
736
- }
737
- async getUserByUserId(user_id) {
738
- if (!this._users) {
739
- await this.getUsers();
740
- }
741
- if (this._users.has(String(user_id))) {
742
- return this._users.get(String(user_id));
743
- }
744
- else
745
- throw new Error("user_id not exists");
746
- }
747
- async getUsers() {
748
- try {
749
- // Free any existing buffer data to prepare for a new request
750
- if (this._users) {
751
- return { data: Array.from(this._users.values()) };
752
- }
753
- else {
754
- this._users = new Map([]);
755
- }
756
- if (this._zkTcp.socket) {
757
- await this._zkTcp.freeData();
758
- }
759
- // Request user data
760
- const data = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_USERS);
761
- // Free buffer data after receiving the data
762
- if (this._zkTcp.socket) {
763
- await this._zkTcp.freeData();
764
- }
765
- // Constants for user data processing
766
- const USER_PACKET_SIZE = 72;
767
- // Ensure data.data is a valid buffer
768
- if (!data.data || !(data.data instanceof Buffer)) {
769
- throw new Error('Invalid data received');
770
- }
771
- let userData = data.data.subarray(4); // Skip the first 4 bytes (headers)
772
- const users = [];
773
- // Process each user packet
774
- while (userData.length >= USER_PACKET_SIZE) {
775
- // Decode user data and add to the users array
776
- const user = decodeUserData72(userData.subarray(0, USER_PACKET_SIZE));
777
- users.push(user);
778
- this._users.set(user.user_id, user);
779
- userData = userData.subarray(USER_PACKET_SIZE); // Move to the next packet
780
- }
781
- // Return the list of users
782
- return { data: users };
783
- }
784
- catch (err) {
785
- // Log the error for debugging
786
- console.error('Error getting users:', err);
787
- // Re-throw the error to be handled by the caller
788
- throw err;
789
- }
790
- }
791
- async setUser(user_id, name, password, role = 0, cardno = 0) {
792
- let user;
793
- try {
794
- user = await this.getUserByUserId(user_id);
795
- }
796
- catch (err) {
797
- if (err.message.includes("user_id not exists")) {
798
- user.uid = Math.max(...Array.from(this._users.values()).map(usr => usr.uid)) + 1;
799
- this._users.set(user_id, user);
800
- }
801
- }
802
- try {
803
- // Validate input parameters
804
- if (user_id.length > 9 ||
805
- name.length > 24 ||
806
- password.length > 8 ||
807
- typeof role !== 'number' ||
808
- cardno.toString().length > 10) {
809
- throw new Error('Invalid input parameters');
810
- }
811
- // Allocate and initialize the buffer
812
- const commandBuffer = Buffer.alloc(72);
813
- // Fill the buffer with user data
814
- commandBuffer.writeUInt16LE(user.uid, 0);
815
- commandBuffer.writeUInt16LE(role, 2);
816
- commandBuffer.write(password.padEnd(8, '\0'), 3, 8); // Ensure password is 8 bytes
817
- commandBuffer.write(name.padEnd(24, '\0'), 11, 24); // Ensure name is 24 bytes
818
- commandBuffer.writeUInt16LE(cardno, 35);
819
- commandBuffer.writeUInt32LE(0, 40); // Placeholder or reserved field
820
- commandBuffer.write(user_id.padEnd(9, '\0'), 48, 9); // Ensure userid is 9 bytes
821
- // Send the command and return the result
822
- const created = await this._zkTcp.executeCmd(COMMANDS.CMD_USER_WRQ, commandBuffer);
823
- return !!created;
824
- }
825
- catch (err) {
826
- // Log error details for debugging
827
- console.error('Error setting user:', err);
828
- // Re-throw error for upstream handling
829
- throw err;
830
- }
831
- }
832
- async DeleteUser(user_id) {
833
- try {
834
- const user = await this.getUserByUserId(user_id);
835
- // Allocate and initialize the buffer
836
- const commandBuffer = Buffer.alloc(72);
837
- // Write UID to the buffer
838
- commandBuffer.writeUInt16LE(user.uid, 0);
839
- // Send the delete command and return the result
840
- const deleted = await this._zkTcp.executeCmd(COMMANDS.CMD_DELETE_USER, commandBuffer);
841
- return !!deleted;
842
- }
843
- catch (err) {
844
- // Log error details for debugging
845
- console.error('Error deleting user:', err);
846
- // Re-throw error for upstream handling
847
- throw err;
848
- }
849
- }
850
- async getTemplates(callbackInProcess = () => { }) {
851
- let templates = [];
852
- try {
853
- if (this._zkTcp.socket) {
854
- await this._zkTcp.freeData();
855
- }
856
- await this._zkTcp.getSizes();
857
- if (this._zkTcp.fp_count == 0)
858
- return { data: [] };
859
- await this._zkTcp.disableDevice();
860
- const resp = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_TEMPLATES);
861
- let templateData = resp.data.subarray(4);
862
- let totalSize = resp.data.readUIntLE(0, 4);
863
- while (totalSize) {
864
- const buf = templateData.subarray(0, 6);
865
- const size = buf.readUIntLE(0, 2);
866
- const uid = buf.readUIntLE(2, 2);
867
- const fid = buf.readUIntLE(4, 1);
868
- const valid = buf.readUIntLE(5, 1);
869
- // Force-copy bytes so we don't retain the entire big backing buffer
870
- const tplBytes = Buffer.from(templateData.subarray(6, size));
871
- templates.push(new Finger(uid, fid, valid, tplBytes));
872
- templateData = templateData.subarray(size);
873
- totalSize -= size;
874
- }
875
- return { data: templates };
876
- }
877
- catch (err) {
878
- this._zkTcp.verbose && console.log("Error getting templates", err);
879
- return { data: templates };
880
- }
881
- finally {
882
- await this._zkTcp.freeData();
883
- await this._zkTcp.enableDevice();
884
- }
885
- }
886
- async DownloadFp(user_id, fid) {
887
- try {
888
- const user = await this.getUserByUserId(user_id);
889
- if (0 > fid || fid > 9)
890
- throw new Error('fid must be between 0 and 9');
891
- // Allocate and initialize the buffer
892
- const data = Buffer.alloc(3);
893
- // Fill the buffer with user data
894
- data.writeUInt16LE(user.uid, 0);
895
- data.writeUIntLE(fid, 2, 1);
896
- this._zkTcp.replyId++;
897
- const packet = createTCPHeader(COMMANDS.CMD_USERTEMP_RRQ, this._zkTcp.sessionId, this._zkTcp.replyId, data);
898
- let fingerSize = 0;
899
- let fingerTemplate = Buffer.from([]);
900
- return await new Promise((resolve, reject) => {
901
- let timeout;
902
- const cleanup = () => {
903
- if (this._zkTcp.socket) {
904
- this._zkTcp.socket.removeListener('data', receiveData);
905
- }
906
- if (timeout)
907
- clearTimeout(timeout);
908
- };
909
- let timer = () => setTimeout(() => {
910
- cleanup();
911
- reject(new Error('Time Out, Could not retrieve data'));
912
- }, this._zkTcp.timeout);
913
- const receiveData = (data) => {
914
- timeout = timer();
915
- if (data.length === 0)
916
- return;
917
- try {
918
- if (data.length == 0)
919
- return;
920
- const headers = decodeTCPHeader(data);
921
- switch (headers.commandId) {
922
- case DISCOVERED_CMD.FID_NOT_FOUND:
923
- throw new Error('Could not retrieve data. maybe finger id not exists?');
924
- case COMMANDS.CMD_PREPARE_DATA:
925
- fingerSize = data.readUIntLE(16, 2);
926
- break;
927
- case COMMANDS.CMD_DATA:
928
- // A single 'data' event might contain multiple TCP packets combined by the OS
929
- // in this method, is possible to get CMD_DATA and CMD_ACK_OK in the same event,
930
- // so It's important to split data received for remove CMD_ACK_OK headers
931
- fingerTemplate = Buffer.concat([fingerTemplate, data.subarray(16, fingerSize + 10)]);
932
- // @ts-ignore
933
- resolve(fingerTemplate);
934
- break;
935
- case COMMANDS.CMD_ACK_OK:
936
- cleanup();
937
- // @ts-ignore
938
- resolve(fingerTemplate);
939
- return;
940
- default:
941
- // If it's not a recognized command but has data, it might be raw template data
942
- if (headers.commandId > 2000 && headers.commandId < 3000) {
943
- // Likely another ACK or system msg
944
- }
945
- else {
946
- fingerTemplate = Buffer.concat([fingerTemplate, data]);
947
- }
948
- break;
949
- }
950
- clearTimeout(timeout);
951
- }
952
- catch (e) {
953
- cleanup();
954
- reject(e);
955
- }
956
- };
957
- if (this._zkTcp.socket) {
958
- this._zkTcp.socket.on('data', receiveData);
959
- this._zkTcp.socket.write(packet, (err) => {
960
- if (err) {
961
- cleanup();
962
- reject(err);
963
- }
964
- });
965
- }
966
- else {
967
- reject(new Error('Socket not initialized'));
968
- }
969
- });
970
- }
971
- catch (err) {
972
- throw err;
973
- }
974
- finally {
975
- await this._zkTcp.refreshData();
976
- }
977
- }
978
- /**
979
- *
980
- * @param user_id {string} user
981
- * @param fingers {Finger[]} array of finger templates instances
982
- * */
983
- async saveTemplates(user_id, fingers = []) {
984
- if (fingers.length > 9 || fingers.length == 0)
985
- throw new Error("maximum finger length is 10 and can't be empty");
986
- try {
987
- await this._zkTcp.disableDevice();
988
- // check users exists
989
- const user = await this.getUserByUserId(user_id);
990
- let fpack = Buffer.alloc(0);
991
- let table = Buffer.alloc(0);
992
- const fnum = 0x10;
993
- let tstart = 0;
994
- for (const finger of fingers) {
995
- const tfp = finger.repackOnly();
996
- const tableEntry = Buffer.alloc(11); // b=1, H=2, b=1, I=4 => 1+2+1+4=8? Wait, bHbI is 1+2+1+4=8 bytes
997
- tableEntry.writeInt8(2, 0);
998
- tableEntry.writeUInt16LE(user.uid, 1);
999
- tableEntry.writeInt8(fnum + finger.fid, 3);
1000
- tableEntry.writeUInt32LE(tstart, 4);
1001
- table = Buffer.concat([table, tableEntry]);
1002
- tstart += tfp.length;
1003
- fpack = Buffer.concat([fpack, tfp]);
1004
- }
1005
- let upack;
1006
- if (this._zkTcp.userPacketSize === 28) {
1007
- upack = user.repack29();
1008
- }
1009
- else {
1010
- upack = user.repack73();
1011
- }
1012
- const head = Buffer.alloc(12); // III = 3*4 bytes
1013
- head.writeUInt32LE(upack.length, 0);
1014
- head.writeUInt32LE(table.length, 4);
1015
- head.writeUInt32LE(fpack.length, 8);
1016
- const packet = Buffer.concat([head, upack, table, fpack]);
1017
- const bufferResponse = await this._zkTcp.sendWithBuffer(packet);
1018
- const command = 110;
1019
- const commandString = Buffer.alloc(8); // <IHH = I(4) + H(2) + H(2) = 8 bytes
1020
- commandString.writeUInt32LE(12, 0);
1021
- commandString.writeUInt16LE(0, 4);
1022
- commandString.writeUInt16LE(8, 6);
1023
- const cmdResponse = await this._zkTcp.executeCmd(command, commandString);
1024
- if (this._zkTcp.verbose)
1025
- console.log("finally bulk save user templates: \n", cmdResponse.readUInt16LE(0));
1026
- }
1027
- catch (error) {
1028
- throw error;
1029
- }
1030
- finally {
1031
- await this._zkTcp.refreshData();
1032
- await this._zkTcp.enableDevice();
1033
- }
1034
- }
1035
- async deleteFinger(user_id, fid) {
1036
- try {
1037
- if (!this._users.has(user_id))
1038
- throw new Error("user_id not exists");
1039
- const user = await this.getUserByUserId(user_id);
1040
- const buf = Buffer.alloc(4);
1041
- buf.writeUInt16LE(user_id ? user.uid : 0, 0);
1042
- buf.writeUint16LE(fid ? fid : 0, 2);
1043
- const reply = await this._zkTcp.executeCmd(COMMANDS.CMD_DELETE_USERTEMP, buf);
1044
- return !!reply;
1045
- }
1046
- catch (error) {
1047
- throw new Error("Can't save utemp");
1048
- }
1049
- finally {
1050
- await this._zkTcp.refreshData();
1051
- }
1052
- }
1053
- async enrollInfo(user_id, tempId) {
1054
- let done = false;
1055
- try {
1056
- const userBuf = Buffer.alloc(24);
1057
- userBuf.write(user_id, 0, 24, 'ascii');
1058
- let commandString = Buffer.concat([
1059
- userBuf,
1060
- Buffer.from([tempId, 1])
1061
- ]);
1062
- const sendAckOk = async () => {
1063
- try {
1064
- const buf = createTCPHeader(COMMANDS.CMD_ACK_OK, this._zkTcp.sessionId, Constants.USHRT_MAX - 1, Buffer.from([]));
1065
- this._zkTcp.socket.write(buf);
1066
- }
1067
- catch (e) {
1068
- throw new ZkError(e, COMMANDS.CMD_ACK_OK, this._zkTcp.ip);
1069
- }
1070
- };
1071
- const cancel = await this._zkTcp.cancelCapture();
1072
- const cmdResponse = await this._zkTcp.executeCmd(COMMANDS.CMD_STARTENROLL, commandString);
1073
- this._zkTcp.timeout = 60000; // 60 seconds timeout
1074
- let attempts = 3;
1075
- while (attempts > 0) {
1076
- if (this._zkTcp.verbose)
1077
- console.log(`A:${attempts} esperando primer regevent`);
1078
- let dataRecv = await this._zkTcp.readSocket(17);
1079
- await sendAckOk();
1080
- if (dataRecv.length > 16) {
1081
- const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
1082
- const res = padded.readUInt16LE(16);
1083
- if (this._zkTcp.verbose)
1084
- console.log(`res ${res}`);
1085
- if (res === 0 || res === 6 || res === 4) {
1086
- if (this._zkTcp.verbose)
1087
- console.log("posible timeout o reg Fallido");
1088
- break;
1089
- }
1090
- }
1091
- if (this._zkTcp.verbose)
1092
- console.log(`A:${attempts} esperando 2do regevent`);
1093
- dataRecv = await this._zkTcp.readSocket(17);
1094
- await sendAckOk();
1095
- if (this._zkTcp.verbose)
1096
- console.log(dataRecv);
1097
- if (dataRecv.length > 8) {
1098
- const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
1099
- const res = padded.readUInt16LE(16);
1100
- if (this._zkTcp.verbose)
1101
- console.log(`res ${res}`);
1102
- if (res === 6 || res === 4) {
1103
- if (this._zkTcp.verbose)
1104
- console.log("posible timeout o reg Fallido");
1105
- break;
1106
- }
1107
- else if (res === 0x64) {
1108
- if (this._zkTcp.verbose)
1109
- console.log("ok, continue?");
1110
- attempts--;
1111
- }
1112
- }
1113
- }
1114
- if (attempts === 0) {
1115
- const dataRecv = await this._zkTcp.readSocket(17);
1116
- await sendAckOk();
1117
- if (this._zkTcp.verbose)
1118
- console.log(dataRecv.toString('hex'));
1119
- const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
1120
- let res = padded.readUInt16LE(16);
1121
- if (this._zkTcp.verbose)
1122
- console.log(`res ${res}`);
1123
- if (res === 5) {
1124
- if (this._zkTcp.verbose)
1125
- console.log("finger duplicate");
1126
- }
1127
- if (res === 6 || res === 4) {
1128
- if (this._zkTcp.verbose)
1129
- console.log("posible timeout");
1130
- }
1131
- if (res === 0) {
1132
- const size = padded.readUInt16LE(10);
1133
- const pos = padded.readUInt16LE(12);
1134
- if (this._zkTcp.verbose)
1135
- console.log(`enroll ok ${size} ${pos}`);
1136
- done = true;
1137
- }
1138
- }
1139
- //this.__sock.setTimeout(this.__timeout);
1140
- await this._zkTcp.regEvent(0); // TODO: test
1141
- return done;
1142
- }
1143
- catch (error) {
1144
- throw error;
1145
- }
1146
- finally {
1147
- await this._zkTcp.cancelCapture();
1148
- await this.verify(user_id);
1149
- }
1150
- }
1151
- async verify(user_id) {
1152
- try {
1153
- const user = await this.getUserByUserId(user_id);
1154
- const command_string = Buffer.alloc(4);
1155
- command_string.writeUInt32LE(user.uid, 0);
1156
- const reply = await this._zkTcp.executeCmd(COMMANDS.CMD_STARTVERIFY, command_string);
1157
- if (this._zkTcp.verbose)
1158
- console.log(reply.readUInt16LE(0));
1159
- return !!reply;
1160
- }
1161
- catch (error) {
1162
- console.error(error);
1163
- throw error;
1164
- }
1165
- }
1166
- /**
1167
- * Upload a single fingerprint for a given user id
1168
- * @param user_id {string} user id for customer
1169
- * @param fingerTemplate {string} finger template in base64 string
1170
- * @param fid {number} finger id is a number between 0 and 9
1171
- * @param fp_valid {number} finger flag. e.g., valid=1, duress=3
1172
- */
1173
- async uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid) {
1174
- try {
1175
- const check_ACK_OK = (buf) => {
1176
- let resp_cmd = initPacket.readUInt16LE(0);
1177
- if (resp_cmd === COMMANDS.CMD_ACK_OK)
1178
- return true;
1179
- else
1180
- throw new Error(`received unexpected command: ${resp_cmd}`);
1181
- };
1182
- const user = this._users.get(user_id);
1183
- await this._zkTcp.disableDevice();
1184
- const prep_struct = Buffer.alloc(4);
1185
- const fingerBuffer = Buffer.from(fingerTemplate, 'base64');
1186
- const fp_size = fingerBuffer.length;
1187
- prep_struct.writeUInt16LE(fp_size, 0);
1188
- const initPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_PREPARE_DATA, prep_struct);
1189
- check_ACK_OK(initPacket);
1190
- const fpPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_DATA, fingerBuffer);
1191
- check_ACK_OK(fpPacket);
1192
- const cheksumPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_CHECKSUM_BUFFER, '');
1193
- check_ACK_OK(cheksumPacket);
1194
- const checksum = cheksumPacket.readUInt32LE(8);
1195
- const tmp_wreq = Buffer.alloc(6);
1196
- tmp_wreq.writeUInt16LE(user.uid, 0);
1197
- tmp_wreq.writeUIntLE(fid, 2, 1);
1198
- tmp_wreq.writeUIntLE(fp_valid, 3, 1);
1199
- tmp_wreq.writeUInt16LE(fp_size, 4);
1200
- const tmp_wreqPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_TMP_WRITE, tmp_wreq);
1201
- check_ACK_OK(tmp_wreqPacket);
1202
- const freeData = await this._zkTcp.executeCmd(COMMANDS.CMD_FREE_DATA, '');
1203
- return check_ACK_OK(freeData);
1204
- }
1205
- catch (err) {
1206
- throw err;
1207
- }
1208
- finally {
1209
- await this._zkTcp.refreshData();
1210
- await this._zkTcp.enableDevice();
1211
- }
1212
- }
1213
- }
1214
-
1215
- class TransactionService {
1216
- _zkTcp;
1217
- constructor(zkTcp) {
1218
- this._zkTcp = zkTcp;
1219
- }
1220
- async getAttendances(callbackInProcess = () => { }) {
1221
- try {
1222
- // Free any existing buffer data to prepare for a new request
1223
- if (this._zkTcp.socket) {
1224
- await this._zkTcp.freeData();
1225
- }
1226
- // Request attendance logs and handle chunked data
1227
- const data = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_ATTENDANCE_LOGS, callbackInProcess);
1228
- // Free buffer data after receiving the attendance logs
1229
- if (this._zkTcp.socket) {
1230
- await this._zkTcp.freeData();
1231
- }
1232
- // Constants for record processing
1233
- const RECORD_PACKET_SIZE = 40;
1234
- // Ensure data.data is a valid buffer
1235
- if (!data.data || !(data.data instanceof Buffer)) {
1236
- throw new Error('Invalid data received');
1237
- }
1238
- // Process the record data
1239
- let recordData = data.data.subarray(4); // Skip header
1240
- const records = [];
1241
- // Process each attendance record
1242
- while (recordData.length >= RECORD_PACKET_SIZE) {
1243
- const record = decodeRecordData40(recordData.subarray(0, RECORD_PACKET_SIZE));
1244
- records.push({ ...record, ip: this._zkTcp.ip }); // Add IP address to each record
1245
- recordData = recordData.subarray(RECORD_PACKET_SIZE); // Move to the next packet
1246
- }
1247
- // Return the list of attendance records
1248
- return { data: records };
1249
- }
1250
- catch (err) {
1251
- // Log and re-throw the error
1252
- console.error('Error getting attendance records:', err);
1253
- throw err; // Re-throw the error for handling by the caller
1254
- }
1255
- }
1256
- // Clears the attendance logs on the device
1257
- async clearAttendanceLog() {
1258
- try {
1259
- // Execute the command to clear attendance logs
1260
- await this._zkTcp.disableDevice();
1261
- const buf = await this._zkTcp.executeCmd(COMMANDS.CMD_CLEAR_ATTLOG, '');
1262
- await this._zkTcp.refreshData();
1263
- await this._zkTcp.enableDevice();
1264
- return !!buf;
1265
- }
1266
- catch (err) {
1267
- // Log the error for debugging purposes
1268
- console.error('Error clearing attendance log:', err);
1269
- // Re-throw the error to be handled by the caller
1270
- throw err;
1271
- }
1272
- }
1273
- }
1274
-
1275
- class ZTCP {
1276
- /**
1277
- * @param_ip ip address of device
1278
- * @param_port port number of device
1279
- * @param_timeout connection timout
1280
- * @param_comm_key communication key of device (if the case)
1281
- * @return Zkteco TCP socket connection instance
1282
- */
1283
- ip;
1284
- port;
1285
- timeout;
1286
- sessionId = 0;
1287
- replyId = 0;
1288
- socket;
1289
- comm_key;
1290
- user_count = 0;
1291
- fp_count = 0;
1292
- pwd_count = 0;
1293
- oplog_count = 0;
1294
- attlog_count = 0;
1295
- fp_cap = 0;
1296
- user_cap = 0;
1297
- attlog_cap = 0;
1298
- fp_av = 0;
1299
- user_av = 0;
1300
- attlog_av = 0;
1301
- face_count = 0;
1302
- face_cap = 0;
1303
- userPacketSize = 72;
1304
- verbose = false;
1305
- packetNumber = 0;
1306
- replyData = Buffer.from([]);
1307
- _userService;
1308
- _transactionService;
1309
- constructor(ip, port, timeout, comm_key, verbose) {
1310
- this.ip = ip;
1311
- this.port = port;
1312
- this.timeout = timeout ? timeout : 10000;
1313
- this.replyId = 0;
1314
- this.comm_key = comm_key;
1315
- this.verbose = verbose;
1316
- this._userService = new UserService(this);
1317
- this._transactionService = new TransactionService(this);
1318
- }
1319
- createSocket(cbError, cbClose) {
1320
- return new Promise((resolve, reject) => {
1321
- this.socket = new net.Socket();
1322
- // Handle socket error
1323
- this.socket.once('error', (err) => {
1324
- this.socket = undefined; // Ensure socket reference is cleared
1325
- reject(err);
1326
- if (typeof cbError === 'function')
1327
- cbError(err);
1328
- });
1329
- // Handle successful connection
1330
- this.socket.once('connect', () => {
1331
- resolve(this.socket);
1332
- });
1333
- // Handle socket closure
1334
- this.socket.once('close', () => {
1335
- this.socket = undefined; // Ensure socket reference is cleared
1336
- if (typeof cbClose === 'function')
1337
- cbClose('tcp');
1338
- });
1339
- // Set socket timeout if provided
1340
- if (this.timeout) {
1341
- this.socket.setTimeout(this.timeout);
1342
- }
1343
- // Initiate connection
1344
- this.socket.connect(this.port, this.ip);
1345
- });
1346
- }
1347
- async connect() {
1348
- try {
1349
- let reply = await this.executeCmd(COMMANDS.CMD_CONNECT, '');
1350
- if (reply.readUInt16LE(0) === COMMANDS.CMD_ACK_OK) {
1351
- return true;
1352
- }
1353
- if (reply.readUInt16LE(0) === COMMANDS.CMD_ACK_UNAUTH) {
1354
- const hashedCommkey = authKey(this.comm_key, this.sessionId);
1355
- reply = await this.executeCmd(COMMANDS.CMD_AUTH, hashedCommkey);
1356
- if (reply.readUInt16LE(0) === COMMANDS.CMD_ACK_OK) {
1357
- return true;
1358
- }
1359
- else {
1360
- throw new Error("error de authenticacion");
1361
- }
1362
- }
1363
- else {
1364
- // No reply received; throw an error
1365
- throw new Error('NO_REPLY_ON_CMD_CONNECT');
1366
- }
1367
- }
1368
- catch (err) {
1369
- // Log the error for debugging, if necessary
1370
- console.error('Failed to connect:', err);
1371
- // Re-throw the error for handling by the caller
1372
- throw err;
1373
- }
1374
- }
1375
- async closeSocket() {
1376
- return new Promise((resolve, reject) => {
1377
- // If no socket is present, resolve immediately
1378
- if (!this.socket) {
1379
- return resolve(true);
1380
- }
1381
- // Clean up listeners to avoid potential memory leaks or duplicate handling
1382
- this.socket.removeAllListeners('data');
1383
- // Set a timeout to handle cases where socket.end might not resolve
1384
- const timer = setTimeout(() => {
1385
- this.socket.destroy(); // Forcibly close the socket if not closed properly
1386
- resolve(true); // Resolve even if the socket was not closed properly
1387
- }, 2000);
1388
- // Close the socket and clear the timeout upon successful completion
1389
- this.socket.end(() => {
1390
- clearTimeout(timer);
1391
- resolve(true); // Resolve once the socket has ended
1392
- });
1393
- // Handle socket errors during closing
1394
- this.socket.once('error', (err) => {
1395
- clearTimeout(timer);
1396
- reject(err); // Reject the promise with the error
1397
- });
1398
- });
1399
- }
1400
- writeMessage(msg, connect) {
1401
- return new Promise((resolve, reject) => {
1402
- // Check if the socket is initialized
1403
- if (!this.socket) {
1404
- return reject(new Error('Socket is not initialized'));
1405
- }
1406
- // Define a variable for the timeout reference
1407
- let timer = null;
1408
- // Handle incoming data
1409
- const onData = (data) => {
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 the data event listener
1413
- }
1414
- clearTimeout(timer); // Clear the timeout once data is received
1415
- resolve(data); // Resolve the promise with the received data
1416
- };
1417
- // Attach the data event listener
1418
- this.socket.once('data', onData);
1419
- // Attempt to write the message to the socket
1420
- this.socket.write(msg, null, (err) => {
1421
- if (err) {
1422
- // Check if the socket is still valid before trying to remove the listener
1423
- if (this.socket) {
1424
- this.socket.removeListener('data', onData); // Clean up listener on write error
1425
- }
1426
- return reject(err); // Reject the promise with the write error
1427
- }
1428
- // If a timeout is set, configure it
1429
- if (this.timeout) {
1430
- timer = setTimeout(() => {
1431
- // Check if the socket is still valid before trying to remove the listener
1432
- if (this.socket) {
1433
- this.socket.removeListener('data', onData); // Remove listener on timeout
1434
- }
1435
- reject(new Error('TIMEOUT_ON_WRITING_MESSAGE')); // Reject the promise on timeout
1436
- }, connect ? 2000 : this.timeout);
1437
- }
1438
- });
1439
- });
1440
- }
1441
- async requestData(msg) {
1442
- try {
1443
- return await new Promise((resolve, reject) => {
1444
- let timer = null;
1445
- let replyBuffer = Buffer.from([]);
1446
- // Internal callback to handle data reception
1447
- const internalCallback = (data_1) => {
1448
- if (this.socket) {
1449
- this.socket.removeListener('data', handleOnData); // Clean up listener
1450
- }
1451
- if (timer)
1452
- clearTimeout(timer); // Clear the timeout
1453
- resolve(data_1); // Resolve the promise with the data
1454
- };
1455
- // Handle incoming data
1456
- const handleOnData = (data_3) => {
1457
- replyBuffer = Buffer.concat([replyBuffer, data_3]); // Accumulate data
1458
- // Check if the data is a valid TCP event
1459
- if (checkNotEventTCP(data_3))
1460
- return;
1461
- // Decode the TCP header
1462
- const header = decodeTCPHeader(replyBuffer.subarray(0, 16));
1463
- if (this.verbose) {
1464
- console.log("linea 232: replyId: ", header.replyId, " command: ", header.commandId, Object.keys(COMMANDS).find(c => COMMANDS[c] == header.commandId));
1465
- }
1466
- // Handle based on command ID
1467
- if (header.commandId === COMMANDS.CMD_DATA) {
1468
- // Set a timeout to handle delayed responses
1469
- timer = setTimeout(() => {
1470
- internalCallback(replyBuffer); // Resolve with accumulated buffer
1471
- }, 1000);
1472
- }
1473
- else {
1474
- // Set a timeout to handle errors
1475
- timer = setTimeout(() => {
1476
- if (this.socket) {
1477
- this.socket.removeListener('data', handleOnData); // Clean up listener on timeout
1478
- }
1479
- reject(new Error('TIMEOUT_ON_RECEIVING_REQUEST_DATA')); // Reject on timeout
1480
- }, this.timeout);
1481
- // Extract packet length and handle accordingly
1482
- const packetLength = data_3.readUIntLE(4, 2);
1483
- if (packetLength > 8) {
1484
- internalCallback(data_3); // Resolve immediately if sufficient data
1485
- }
1486
- }
1487
- };
1488
- // Ensure the socket is valid before attaching the listener
1489
- if (this.socket) {
1490
- this.socket.on('data', handleOnData);
1491
- // Write the message to the socket
1492
- this.socket.write(msg, null, (err) => {
1493
- if (err) {
1494
- if (this.socket) {
1495
- this.socket.removeListener('data', handleOnData); // Clean up listener on error
1496
- }
1497
- return reject(err); // Reject the promise with the error
1498
- }
1499
- // Set a timeout to handle cases where no response is received
1500
- timer = setTimeout(() => {
1501
- if (this.socket) {
1502
- this.socket.removeListener('data', handleOnData); // Clean up listener on timeout
1503
- }
1504
- reject(new Error('TIMEOUT_IN_RECEIVING_RESPONSE_AFTER_REQUESTING_DATA')); // Reject on timeout
1505
- }, this.timeout);
1506
- });
1507
- }
1508
- else {
1509
- reject(new Error('SOCKET_NOT_INITIALIZED')); // Reject if socket is not initialized
1510
- }
1511
- });
1512
- }
1513
- catch (err_1) {
1514
- console.error("Promise Rejected:", err_1); // Log the rejection reason
1515
- throw err_1; // Re-throw the error to be handled by the caller
1516
- }
1517
- }
1518
- /**
1519
- *
1520
- * @param {*} command
1521
- * @param {*} data
1522
- *
1523
- *
1524
- * reject error when command fail and resolve data when success
1525
- */
1526
- async executeCmd(command, data) {
1527
- // Reset sessionId and replyId for connection commands
1528
- if (command === COMMANDS.CMD_CONNECT) {
1529
- this.sessionId = 0;
1530
- this.replyId = 0;
1531
- }
1532
- else {
1533
- this.replyId++;
1534
- }
1535
- const buf = createTCPHeader(command, this.sessionId, this.replyId, data);
1536
- try {
1537
- // Write the message to the socket and wait for a response
1538
- const reply = await this.writeMessage(buf, command === COMMANDS.CMD_CONNECT || command === COMMANDS.CMD_EXIT);
1539
- if (this.verbose) {
1540
- let headers = decodeTCPHeader(reply);
1541
- console.log('command: ', COMMANDS[headers.commandId], 'replyid: ', headers.replyId);
1542
- }
1543
- // Remove TCP header from the response
1544
- const rReply = removeTcpHeader(reply);
1545
- // Update sessionId for connection command responses
1546
- if (command === COMMANDS.CMD_CONNECT && rReply && rReply.length >= 6) { // Assuming sessionId is located at offset 4 and is 2 bytes long
1547
- this.sessionId = rReply.readUInt16LE(4);
1548
- }
1549
- return rReply;
1550
- }
1551
- catch (err) {
1552
- // Log or handle the error if necessary
1553
- console.error('Error executing command:', err);
1554
- throw err; // Re-throw the error for handling by the caller
1555
- }
1556
- }
1557
- async sendChunkRequest(start, size) {
1558
- this.replyId++;
1559
- const reqData = Buffer.alloc(8);
1560
- reqData.writeUInt32LE(start, 0);
1561
- reqData.writeUInt32LE(size, 4);
1562
- const buf = createTCPHeader(COMMANDS.CMD_DATA_RDY, this.sessionId, this.replyId, reqData);
1563
- try {
1564
- await new Promise((resolve, reject) => {
1565
- this.socket.write(buf, null, (err) => {
1566
- if (err) {
1567
- console.error(`[TCP][SEND_CHUNK_REQUEST] Error sending chunk request: ${err.message}`);
1568
- reject(err); // Reject the promise if there is an error
1569
- }
1570
- else {
1571
- resolve(true); // Resolve the promise if the write operation succeeds
1572
- }
1573
- });
1574
- });
1575
- }
1576
- catch (err) {
1577
- // Handle or log the error as needed
1578
- console.error(`[TCP][SEND_CHUNK_REQUEST] Exception: ${err.message}`);
1579
- throw err; // Re-throw the error for handling by the caller
1580
- }
1581
- }
1582
- /**
1583
- *
1584
- * @param {Buffer} reqData - indicate the type of data that need to receive ( user or attLog)
1585
- * @param {Function} cb - callback is triggered when receiving packets
1586
- *
1587
- * readWithBuffer will reject error if it'wrong when starting request data
1588
- * readWithBuffer will return { data: replyData , err: Error } when receiving requested data
1589
- */
1590
- readWithBuffer(reqData, cb = null) {
1591
- return new Promise(async (resolve, reject) => {
1592
- this.replyId++;
1593
- const buf = createTCPHeader(COMMANDS.CMD_DATA_WRRQ, this.sessionId, this.replyId, reqData);
1594
- let reply = null;
1595
- try {
1596
- reply = await this.requestData(buf);
1597
- }
1598
- catch (err) {
1599
- reject(err);
1600
- }
1601
- const header = decodeTCPHeader(reply.subarray(0, 16));
1602
- switch (header.commandId) {
1603
- case COMMANDS.CMD_DATA: {
1604
- resolve({ data: reply.subarray(16), mode: 8 });
1605
- break;
1606
- }
1607
- case COMMANDS.CMD_ACK_OK:
1608
- case COMMANDS.CMD_PREPARE_DATA: {
1609
- // this case show that data is prepared => send command to get these data
1610
- // reply variable includes information about the size of following data
1611
- const recvData = reply.subarray(16);
1612
- const size = recvData.readUIntLE(1, 4);
1613
- // We need to split the data to many chunks to receive , because it's to large
1614
- // After receiving all chunk data , we concat it to TotalBuffer variable , that 's the data we want
1615
- let remain = size % Constants.MAX_CHUNK;
1616
- let numberChunks = Math.round(size - remain) / Constants.MAX_CHUNK;
1617
- this.packetNumber = numberChunks + (remain > 0 ? 1 : 0);
1618
- //let replyData = Buffer.from([])
1619
- let totalBuffer = Buffer.from([]);
1620
- let realTotalBuffer = Buffer.from([]);
1621
- let timer = setTimeout(() => {
1622
- internalCallback(this.replyData, new Error('TIMEOUT WHEN RECEIVING PACKET'));
1623
- }, this.timeout);
1624
- const internalCallback = (replyData, err = null) => {
1625
- this.socket && this.socket.removeAllListeners('data');
1626
- timer && clearTimeout(timer);
1627
- resolve({ data: replyData, err });
1628
- };
1629
- this.socket.once('close', () => {
1630
- internalCallback(this.replyData, new Error('Socket is disconnected unexpectedly'));
1631
- });
1632
- for (let i = 0; i <= numberChunks; i++) {
1633
- const data = await new Promise((resolve2, reject2) => {
1634
- try {
1635
- this.sendChunkRequest(i * Constants.MAX_CHUNK, (i === numberChunks)
1636
- ? remain
1637
- : Constants.MAX_CHUNK);
1638
- this.socket.on('data', (reply) => {
1639
- clearTimeout(timer);
1640
- timer = setTimeout(() => {
1641
- internalCallback(this.replyData, new Error(`TIME OUT !! ${this.packetNumber} PACKETS REMAIN !`));
1642
- }, this.timeout);
1643
- const headers = decodeTCPHeader(reply);
1644
- if (COMMANDS[headers.commandId]) {
1645
- switch (headers.commandId) {
1646
- case COMMANDS.CMD_ACK_OK:
1647
- case COMMANDS.CMD_DATA:
1648
- this.verbose && console.log("CMD received: ", COMMANDS[headers.commandId]);
1649
- break;
1650
- case COMMANDS.CMD_PREPARE_DATA:
1651
- this.verbose && console.log("CMD received: ", COMMANDS[headers.commandId]);
1652
- this.verbose && console.log(`recieve chunk: prepare data size is ${headers.payloadSize}`);
1653
- break;
1654
- default:
1655
- break;
1656
- }
1657
- }
1658
- totalBuffer = Buffer.concat([totalBuffer, reply]);
1659
- const packetLength = totalBuffer.readUIntLE(4, 2);
1660
- if (totalBuffer.length >= 8 + packetLength) {
1661
- realTotalBuffer = Buffer.concat([realTotalBuffer, totalBuffer.subarray(16, 8 + packetLength)]);
1662
- totalBuffer = totalBuffer.subarray(8 + packetLength);
1663
- if ((this.packetNumber > 1 && realTotalBuffer.length === (Constants.MAX_CHUNK + 8))
1664
- || (this.packetNumber === 1 && realTotalBuffer.length === remain + 8)) {
1665
- this.packetNumber--;
1666
- cb && cb(realTotalBuffer.length, size);
1667
- resolve2(realTotalBuffer.subarray(8));
1668
- totalBuffer = Buffer.from([]);
1669
- realTotalBuffer = Buffer.from([]);
1670
- }
1671
- }
1672
- });
1673
- }
1674
- catch (e) {
1675
- reject2(e);
1676
- }
1677
- });
1678
- this.replyData = Buffer.concat([this.replyData, data]);
1679
- this.socket.removeAllListeners('data');
1680
- if (this.packetNumber <= 0) {
1681
- resolve({ data: this.replyData });
1682
- }
1683
- }
1684
- break;
1685
- }
1686
- default: {
1687
- reject(new Error('ERROR_IN_UNHANDLE_CMD ' + exportErrorMessage(header.commandId)));
1688
- }
1689
- }
1690
- });
1691
- }
1692
- /**
1693
- *
1694
- * @param {*} callbackInProcess
1695
- * reject error when starting request data
1696
- * return { data: records, err: Error } when receiving requested data
1697
- */
1698
- async getAttendances(callbackInProcess = () => { }) {
1699
- return await this._transactionService.getAttendances(callbackInProcess);
1700
- }
1701
- async freeData() {
1702
- try {
1703
- const resp = await this.executeCmd(COMMANDS.CMD_FREE_DATA, '');
1704
- return !!resp;
1705
- }
1706
- catch (err) {
1707
- console.error('Error freeing data:', err);
1708
- throw err; // Optionally, re-throw the error if you need to handle it upstream
1709
- }
1710
- }
1711
- async disableDevice() {
1712
- try {
1713
- const resp = await this.executeCmd(COMMANDS.CMD_DISABLEDEVICE, REQUEST_DATA.DISABLE_DEVICE);
1714
- return !!resp;
1715
- }
1716
- catch (err) {
1717
- console.error('Error disabling device:', err);
1718
- throw err; // Optionally, re-throw the error if you need to handle it upstream
1719
- }
1720
- }
1721
- async enableDevice() {
1722
- try {
1723
- const resp = await this.executeCmd(COMMANDS.CMD_ENABLEDEVICE, '');
1724
- return !!resp;
1725
- }
1726
- catch (err) {
1727
- console.error('Error enabling device:', err);
1728
- throw err; // Optionally, re-throw the error if you need to handle it upstream
1729
- }
1730
- }
1731
- async disconnect() {
1732
- try {
1733
- // Attempt to execute the disconnect command
1734
- await this.executeCmd(COMMANDS.CMD_EXIT, '');
1735
- }
1736
- catch (err) {
1737
- // Log any errors encountered during command execution
1738
- console.error('Error during disconnection:', err);
1739
- // Optionally, add more handling or recovery logic here
1740
- }
1741
- // Attempt to close the socket and return the result
1742
- try {
1743
- await this.closeSocket();
1744
- }
1745
- catch (err) {
1746
- // Log any errors encountered while closing the socket
1747
- console.error('Error during socket closure:', err);
1748
- // Optionally, rethrow or handle the error if necessary
1749
- throw err; // Re-throwing to propagate the error
1750
- }
1751
- }
1752
- async getInfo() {
1753
- try {
1754
- // Execute the command to retrieve free sizes from the device
1755
- const data = await this.executeCmd(COMMANDS.CMD_GET_FREE_SIZES, '');
1756
- // Parse the response data to extract and return relevant information
1757
- return {
1758
- userCounts: data.readUIntLE(24, 4), // Number of users
1759
- logCounts: data.readUIntLE(40, 4), // Number of logs
1760
- logCapacity: data.readUIntLE(72, 4) // Capacity of logs in bytes
1761
- };
1762
- }
1763
- catch (err) {
1764
- // Log the error for debugging purposes
1765
- console.error('Error getting device info:', err);
1766
- // Re-throw the error to allow upstream error handling
1767
- throw err;
1768
- }
1769
- }
1770
- async getSizes() {
1771
- try {
1772
- // Execute the command to retrieve free sizes from the device
1773
- const data = await this.executeCmd(COMMANDS.CMD_GET_FREE_SIZES, '');
1774
- // Parse the response data to extract and return relevant information
1775
- const buf = data.slice(8); // remove header
1776
- this.user_count = buf.readUIntLE(16, 4);
1777
- this.fp_count = buf.readUIntLE(24, 4);
1778
- this.pwd_count = buf.readUIntLE(52, 4);
1779
- this.oplog_count = buf.readUIntLE(40, 4);
1780
- this.attlog_count = buf.readUIntLE(32, 4);
1781
- this.fp_cap = buf.readUIntLE(56, 4);
1782
- this.user_cap = buf.readUIntLE(60, 4);
1783
- this.attlog_cap = buf.readUIntLE(64, 4);
1784
- this.fp_av = buf.readUIntLE(68, 4);
1785
- this.user_av = buf.readUIntLE(72, 4);
1786
- this.attlog_av = buf.readUIntLE(76, 4);
1787
- this.face_count = buf.readUIntLE(80, 4);
1788
- this.face_cap = buf.readUIntLE(88, 4);
1789
- return {
1790
- userCounts: this.user_count, // Number of users
1791
- logCounts: this.attlog_count, // Number of logs
1792
- fingerCount: this.fp_count,
1793
- adminCount: this.pwd_count,
1794
- opLogCount: this.oplog_count,
1795
- logCapacity: this.attlog_cap, // Capacity of logs in bytes
1796
- fingerCapacity: this.fp_cap,
1797
- userCapacity: this.user_cap,
1798
- attLogCapacity: this.attlog_cap,
1799
- fingerAvailable: this.fp_av,
1800
- userAvailable: this.user_av,
1801
- attLogAvailable: this.attlog_av,
1802
- faceCount: this.face_count,
1803
- faceCapacity: this.face_cap
1804
- };
1805
- }
1806
- catch (err) {
1807
- // Log the error for debugging purposes
1808
- console.error('Error getting device info:', err);
1809
- // Re-throw the error to allow upstream error handling
1810
- throw err;
1811
- }
1812
- }
1813
- async getVendor() {
1814
- const keyword = '~OEMVendor';
1815
- try {
1816
- // Execute the command to get oem vendor
1817
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
1818
- // Extract and format the oem bendor from the response data
1819
- const vendor = data.slice(8) // Skip the first 8 bytes (header)
1820
- .toString('ascii') // Convert buffer to string
1821
- .replace(`${keyword}=`, '') // Remove the keyword prefix
1822
- .replace(/\u0000/g, ''); // Remove null characters
1823
- return vendor;
1824
- }
1825
- catch (err) {
1826
- // Log the error for debugging
1827
- console.error('Error getting vendor:', err);
1828
- // Re-throw the error for higher-level handling
1829
- throw err;
1830
- }
1831
- }
1832
- async getProductTime() {
1833
- const keyword = '~ProductTime';
1834
- try {
1835
- // Execute the command to get serial number
1836
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
1837
- // Extract and format the serial number from the response data
1838
- const ProductTime = data.slice(8) // Skip the first 8 bytes (header)
1839
- .toString('ascii') // Convert buffer to string
1840
- .replace(`${keyword}=`, '') // Remove the keyword prefix
1841
- .replace(/\u0000/g, ''); // Remove null characters
1842
- return new Date(ProductTime);
1843
- }
1844
- catch (err) {
1845
- // Log the error for debugging
1846
- console.error('Error getting Product Time:', err);
1847
- // Re-throw the error for higher-level handling
1848
- throw err;
1849
- }
1850
- }
1851
- async getMacAddress() {
1852
- const keyword = 'MAC';
1853
- try {
1854
- // Execute the command to get serial number
1855
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
1856
- // Extract and format the serial number from the response data
1857
- const macAddr = data.slice(8) // Skip the first 8 bytes (header)
1858
- .toString('ascii') // Convert buffer to string
1859
- .replace(`${keyword}=`, '') // Remove the keyword prefix
1860
- .replace(/\u0000/g, ''); // Remove null characters
1861
- return macAddr;
1862
- }
1863
- catch (err) {
1864
- // Log the error for debugging
1865
- console.error('Error getting MAC address:', err);
1866
- // Re-throw the error for higher-level handling
1867
- throw err;
1868
- }
1869
- }
1870
- async getNetworkParams() {
1871
- try {
1872
- const params = {
1873
- IPAddress: this.ip,
1874
- NetMask: '',
1875
- GATEIPAddress: ''
1876
- };
1877
- const keywords = Object.keys(params);
1878
- for await (const keyword of keywords) {
1879
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
1880
- params[keyword] = data.slice(8)
1881
- .toString('utf-8')
1882
- .replace(`${keyword}=`, '') // Remove the keyword prefix
1883
- .replace(/\u0000/g, '')
1884
- .replace('=', '.'); // Replace equal simbol to dot, due to sometimes there are parsing errors
1885
- }
1886
- return params;
1887
- }
1888
- catch (err) {
1889
- console.error("Error getting Network Params: ", err);
1890
- throw err;
1891
- }
1892
- }
1893
- async getSerialNumber() {
1894
- const keyword = '~SerialNumber';
1895
- let serialNumber = '';
1896
- let count = 10;
1897
- try {
1898
- // Execute the command to get serial number
1899
- /**
1900
- * @dev implemented a counter and a while loop because sometimes serial number parses wrong for some reason
1901
- * */
1902
- while (serialNumber.length !== 13 && count > 0) {
1903
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
1904
- // Extract and format the serial number from the response data
1905
- const SN = data.slice(8) // Skip the first 8 bytes (header)
1906
- .toString('utf-8') // Convert buffer to string
1907
- .replace(`${keyword}=`, '') // Remove the keyword prefix
1908
- .replace('=', '') // Remove sometines last number is a character equal to = or unknow character
1909
- .replace(/\u0000/g, ''); // Remove null characters
1910
- if (serialNumber.length !== 13 && this.verbose) {
1911
- console.warn('Serial number length not equal to 13, check');
1912
- }
1913
- count--;
1914
- serialNumber = SN;
1915
- }
1916
- return serialNumber;
1917
- }
1918
- catch (err) {
1919
- // Log the error for debugging
1920
- console.error('Error getting serial number:', err);
1921
- // Re-throw the error for higher-level handling
1922
- throw err;
1923
- }
1924
- }
1925
- async getDeviceVersion() {
1926
- const keyword = '~ZKFPVersion';
1927
- try {
1928
- // Execute the command to get device version
1929
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
1930
- // Extract and format the device version from the response data
1931
- // Remove null characters
1932
- return data.slice(8) // Skip the first 8 bytes (header)
1933
- .toString('ascii') // Convert buffer to ASCII string
1934
- .replace(`${keyword}=`, '') // Remove the keyword prefix
1935
- .replace(/\u0000/g, '');
1936
- }
1937
- catch (err) {
1938
- // Log the error for debugging
1939
- console.error('Error getting device version:', err);
1940
- // Re-throw the error for higher-level handling
1941
- throw err;
1942
- }
1943
- }
1944
- async getDeviceName() {
1945
- const keyword = '~DeviceName';
1946
- try {
1947
- // Execute the command to get the device name
1948
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
1949
- // Extract and format the device name from the response data
1950
- // Remove null characters
1951
- return data.slice(8) // Skip the first 8 bytes (header)
1952
- .toString('ascii') // Convert buffer to ASCII string
1953
- .replace(`${keyword}=`, '') // Remove the keyword prefix
1954
- .replace(/\u0000/g, '');
1955
- }
1956
- catch (err) {
1957
- // Log the error for debugging
1958
- console.error('Error getting device name:', err);
1959
- // Re-throw the error for higher-level handling
1960
- throw err;
1961
- }
1962
- }
1963
- async getPlatform() {
1964
- const keyword = '~Platform';
1965
- try {
1966
- // Execute the command to get the platform information
1967
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
1968
- // Extract and format the platform information from the response data
1969
- // Remove null characters
1970
- return data.slice(8) // Skip the first 8 bytes (header)
1971
- .toString('ascii') // Convert buffer to ASCII string
1972
- .replace(`${keyword}=`, '') // Remove the keyword prefix
1973
- .replace(/\u0000/g, '');
1974
- }
1975
- catch (err) {
1976
- // Log the error for debugging
1977
- console.error('Error getting platform information:', err);
1978
- // Re-throw the error for higher-level handling
1979
- throw err;
1980
- }
1981
- }
1982
- async getOS() {
1983
- const keyword = '~OS';
1984
- try {
1985
- // Execute the command to get the OS information
1986
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
1987
- // Extract and format the OS information from the response data
1988
- // Remove null characters
1989
- return data.slice(8) // Skip the first 8 bytes (header)
1990
- .toString('ascii') // Convert buffer to ASCII string
1991
- .replace(`${keyword}=`, '') // Remove the keyword prefix
1992
- .replace(/\u0000/g, '');
1993
- }
1994
- catch (err) {
1995
- // Log the error for debugging
1996
- console.error('Error getting OS information:', err);
1997
- // Re-throw the error for higher-level handling
1998
- throw err;
1999
- }
2000
- }
2001
- async getWorkCode() {
2002
- const keyword = 'WorkCode';
2003
- try {
2004
- // Execute the command to get the WorkCode information
2005
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
2006
- // Extract and format the WorkCode information from the response data
2007
- // Remove null characters
2008
- return data.slice(8) // Skip the first 8 bytes (header)
2009
- .toString('ascii') // Convert buffer to ASCII string
2010
- .replace(`${keyword}=`, '') // Remove the keyword prefix
2011
- .replace(/\u0000/g, '');
2012
- }
2013
- catch (err) {
2014
- // Log the error for debugging
2015
- console.error('Error getting WorkCode:', err);
2016
- // Re-throw the error to be handled by the caller
2017
- throw err;
2018
- }
2019
- }
2020
- async getPIN() {
2021
- const keyword = '~PIN2Width';
2022
- try {
2023
- // Execute the command to get the PIN information
2024
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
2025
- // Extract and format the PIN information from the response data
2026
- return data.slice(8) // Skip the first 8 bytes (header)
2027
- .toString('ascii') // Convert buffer to ASCII string
2028
- .replace(`${keyword}=`, '') // Remove the keyword prefix
2029
- .replace(/\u0000/g, ''); // Remove null characters 0x00
2030
- }
2031
- catch (err) {
2032
- // Log the error for debugging
2033
- console.error('Error getting PIN:', err);
2034
- // Re-throw the error to be handled by the caller
2035
- throw err;
2036
- }
2037
- }
2038
- async getFaceOn() {
2039
- const keyword = 'FaceFunOn';
2040
- try {
2041
- // Execute the command to get the face function status
2042
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
2043
- // Extract and process the status from the response data
2044
- const status = data.slice(8) // Skip the first 8 bytes (header)
2045
- .toString('ascii') // Convert buffer to ASCII string
2046
- .replace(`${keyword}=`, ''); // Remove the keyword prefix
2047
- // Determine and return the face function status
2048
- return status.includes('0') ? 'No' : 'Yes';
2049
- }
2050
- catch (err) {
2051
- // Log the error for debugging
2052
- console.error('Error getting face function status:', err);
2053
- // Re-throw the error to be handled by the caller
2054
- throw err;
2055
- }
2056
- }
2057
- async getSSR() {
2058
- const keyword = '~SSR';
2059
- try {
2060
- // Execute the command to get the SSR value
2061
- const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
2062
- // Extract and process the SSR value from the response data
2063
- // Remove the keyword prefix
2064
- // Return the SSR value
2065
- return data.slice(8) // Skip the first 8 bytes (header)
2066
- .toString('ascii') // Convert buffer to ASCII string
2067
- .replace(`${keyword}=`, '');
2068
- }
2069
- catch (err) {
2070
- // Log the error for debugging
2071
- console.error('Error getting SSR value:', err);
2072
- // Re-throw the error to be handled by the caller
2073
- throw err;
2074
- }
2075
- }
2076
- async getFirmware() {
2077
- try {
2078
- // Execute the command to get firmware information
2079
- const data = await this.executeCmd(1100, '');
2080
- // Extract and return the firmware version from the response data
2081
- return data.slice(8) // Skip the first 8 bytes (header)
2082
- .toString('ascii') // convert to ASCII string
2083
- .replace(/\u0000/g, ''); // remove x00
2084
- }
2085
- catch (err) {
2086
- // Log the error for debugging
2087
- console.error('Error getting firmware version:', err);
2088
- // Re-throw the error to be handled by the caller
2089
- throw err;
2090
- }
2091
- }
2092
- async getTime() {
2093
- try {
2094
- // Execute the command to get the current time
2095
- const response = await this.executeCmd(COMMANDS.CMD_GET_TIME, '');
2096
- // Check if the response is valid
2097
- if (!response || response.length < 12) {
2098
- throw new Error('Invalid response received for time command');
2099
- }
2100
- // Extract and decode the time value from the response
2101
- const timeValue = response.readUInt32LE(8); // Read 4 bytes starting at offset 8
2102
- return timeParser.decode(timeValue); // Parse and return the decoded time
2103
- }
2104
- catch (err) {
2105
- // Log the error for debugging
2106
- console.error('Error getting time:', err);
2107
- // Re-throw the error for the caller to handle
2108
- throw err;
2109
- }
2110
- }
2111
- async setTime(tm) {
2112
- try {
2113
- // Validate the input time
2114
- if (!(tm instanceof Date) && typeof tm !== 'number') {
2115
- throw new TypeError('Invalid time parameter. Must be a Date object or a timestamp.');
2116
- }
2117
- // Convert the input time to a Date object if it's not already
2118
- const date = (tm instanceof Date) ? tm : new Date(tm);
2119
- // Encode the time into the required format
2120
- const encodedTime = timeParser.encode(date);
2121
- // Create a buffer and write the encoded time
2122
- const commandString = Buffer.alloc(32);
2123
- commandString.writeUInt32LE(encodedTime, 0);
2124
- // Send the command to set the time
2125
- const time = await this.executeCmd(COMMANDS.CMD_SET_TIME, commandString);
2126
- return !!time;
2127
- }
2128
- catch (err) {
2129
- // Log the error for debugging
2130
- console.error('Error setting time:', err);
2131
- // Re-throw the error for the caller to handle
2132
- throw err;
2133
- }
2134
- }
2135
- async voiceTest() {
2136
- try {
2137
- // Define the command data for the voice test
2138
- const commandData = Buffer.from('\x00\x00', 'binary');
2139
- await this.executeCmd(COMMANDS.CMD_TESTVOICE, commandData);
2140
- // Execute the command and return the result
2141
- }
2142
- catch (err) {
2143
- // Log the error for debugging purposes
2144
- console.error('Error executing voice test:', err);
2145
- // Re-throw the error to be handled by the caller
2146
- throw err;
2147
- }
2148
- }
2149
- async getAttendanceSize() {
2150
- try {
2151
- // Execute command to get free sizes
2152
- const data = await this.executeCmd(COMMANDS.CMD_GET_FREE_SIZES, '');
2153
- // Parse and return the attendance size
2154
- return data.readUIntLE(40, 4); // Assuming data at offset 40 represents the attendance size
2155
- }
2156
- catch (err) {
2157
- // Log error details for debugging
2158
- console.error('Error getting attendance size:', err);
2159
- // Re-throw the error to be handled by the caller
2160
- throw err;
2161
- }
2162
- }
2163
- // Clears the attendance logs on the device
2164
- async clearAttendanceLog() {
2165
- return await this._transactionService.clearAttendanceLog();
2166
- }
2167
- /**
2168
- * Clears all data on the device
2169
- * @value 1 Attendance records
2170
- * @value 2 Fingerprint templates
2171
- * @value 3 None
2172
- * @value 4 Operation records
2173
- * @value 5 User information
2174
- * @default 0 Delete all
2175
- */
2176
- async clearData(value) {
2177
- try {
2178
- // Execute the command to clear all data
2179
- await this.disableDevice();
2180
- if (!value)
2181
- value = 3;
2182
- const buf = await this.executeCmd(COMMANDS.CMD_CLEAR_DATA, value.toString());
2183
- await this.refreshData();
2184
- await this.enableDevice();
2185
- return !!buf;
2186
- }
2187
- catch (err) {
2188
- // Log the error for debugging purposes
2189
- console.error('Error clearing data:', err);
2190
- // Re-throw the error to be handled by the caller
2191
- throw err;
2192
- }
2193
- }
2194
- async getRealTimeLogs(cb = (realTimeLog) => { }) {
2195
- this.replyId++; // Increment the reply ID for this request
2196
- try {
2197
- // Create a buffer with the command header to request real-time logs
2198
- const buf = createTCPHeader(COMMANDS.CMD_REG_EVENT, this.sessionId, this.replyId, Buffer.from([0x01, 0x00, 0x00, 0x00]));
2199
- // Send the request to the device
2200
- this.socket.write(buf, null, (err) => {
2201
- if (err) {
2202
- // Log and reject the promise if there is an error writing to the socket
2203
- console.error('Error sending real-time logs request:', err);
2204
- throw err;
2205
- }
2206
- });
2207
- // Ensure data listeners are added only once
2208
- if (this.socket.listenerCount('data') === 0) {
2209
- this.socket.on('data', (data) => {
2210
- // Check if the data is an event and not just a regular response
2211
- if (checkNotEventTCP(data)) {
2212
- // Process the data if it is of the expected length
2213
- if (data.length > 16) {
2214
- // Decode and pass the log to the callback
2215
- cb(decodeRecordRealTimeLog52(data));
2216
- }
2217
- }
2218
- });
2219
- }
2220
- }
2221
- catch (err) {
2222
- // Handle errors and reject the promise
2223
- console.error('Error getting real-time logs:', err);
2224
- throw err;
2225
- }
2226
- }
2227
- /**
2228
- * Get all Finger objects
2229
- * @returns {Record<string, Finger[]>}
2230
- */
2231
- async getTemplates(callbackInProcess = () => { }) {
2232
- return await this._userService.getTemplates(callbackInProcess);
2233
- }
2234
- /**
2235
- * Return size
2236
- * @param packet
2237
- */
2238
- testTcpTop(packet) {
2239
- // Check if packet is too small
2240
- if (packet.length <= 8)
2241
- return 0;
2242
- // Extract header values using little-endian format
2243
- const headerValue1 = packet.readUInt16LE(0);
2244
- const headerValue2 = packet.readUInt16LE(2);
2245
- const size = packet.readUInt32LE(4);
2246
- // Check if magic numbers match
2247
- if (headerValue1 === Constants.MACHINE_PREPARE_DATA_1 &&
2248
- headerValue2 === Constants.MACHINE_PREPARE_DATA_2) {
2249
- return size;
2250
- }
2251
- return 0;
2252
- }
2253
- async refreshData() {
2254
- try {
2255
- const reply = await this.executeCmd(COMMANDS.CMD_REFRESHDATA, '');
2256
- return !!reply;
2257
- }
2258
- catch (err) {
2259
- console.error('Error getting user templates: ', err);
2260
- throw err;
2261
- }
2262
- }
2263
- async sendWithBuffer(buffer) {
2264
- const MAX_CHUNK = 1024;
2265
- const size = buffer.length;
2266
- await this.freeData();
2267
- const commandString = Buffer.alloc(4); // 'I' is 4 bytes
2268
- commandString.writeUInt32LE(size, 0);
2269
- try {
2270
- const cmdResponse = await this.executeCmd(COMMANDS.CMD_PREPARE_DATA, commandString);
2271
- // responds with 2000 = CMD_ACK_OK
2272
- if (!cmdResponse) {
2273
- throw new Error("Can't prepare data");
2274
- }
2275
- }
2276
- catch (e) {
2277
- console.error(e);
2278
- }
2279
- const remain = size % MAX_CHUNK;
2280
- const packets = Math.floor((size - remain) / MAX_CHUNK);
2281
- let start = 0;
2282
- try {
2283
- for (let i = 0; i < packets; i++) {
2284
- const resp = await this.sendChunk(buffer.slice(start, start + MAX_CHUNK));
2285
- if (resp) {
2286
- start += MAX_CHUNK;
2287
- if (i == packets - 1 && remain) {
2288
- const lastPacket = await this.sendChunk(buffer.slice(start, start + remain));
2289
- return lastPacket;
2290
- }
2291
- }
2292
- }
2293
- }
2294
- catch (e) {
2295
- console.error(e);
2296
- }
2297
- }
2298
- async sendChunk(commandString) {
2299
- try {
2300
- return await new Promise((resolve, reject) => {
2301
- resolve(this.executeCmd(COMMANDS.CMD_DATA, commandString));
2302
- });
2303
- }
2304
- catch (e) {
2305
- throw new ZkError(e, COMMANDS.CMD_DATA, this.ip);
2306
- }
2307
- }
2308
- async readSocket(length, cb = null) {
2309
- let replyBufer = Buffer.from([]);
2310
- let totalPackets = 0;
2311
- return new Promise((resolve, reject) => {
2312
- let timer = setTimeout(() => {
2313
- internalCallback(replyBufer, new Error('TIMEOUT WHEN RECEIVING PACKET'));
2314
- }, this.timeout);
2315
- const internalCallback = (replyData, err = null) => {
2316
- this.socket && this.socket.removeListener('data', onDataEnroll);
2317
- timer && clearTimeout(timer);
2318
- resolve({ data: replyData, err: err });
2319
- };
2320
- function onDataEnroll(data) {
2321
- clearTimeout(timer);
2322
- timer = setTimeout(() => {
2323
- internalCallback(replyBufer, new Error(`TIME OUT !! ${totalPackets} PACKETS REMAIN !`));
2324
- }, this.timeout);
2325
- replyBufer = Buffer.concat([replyBufer, data], replyBufer.length + data.length);
2326
- if (data.length == length) {
2327
- internalCallback(data);
2328
- }
2329
- }
2330
- this.socket.once('close', () => {
2331
- internalCallback(replyBufer, new Error('Socket is disconnected unexpectedly'));
2332
- });
2333
- this.socket.on('data', onDataEnroll);
2334
- }).catch((err) => {
2335
- console.error("Promise Rejected:", err); // Log the rejection reason
2336
- throw err; // Re-throw the error to be handled by the caller
2337
- });
2338
- }
2339
- /**
2340
- * Register events
2341
- * @param {number} flags - Event flags
2342
- * @returns {Promise<void>}
2343
- * @throws {ZKErrorResponse} If registration fails
2344
- */
2345
- async regEvent(flags) {
2346
- try {
2347
- const commandString = Buffer.alloc(4); // 'I' format is 4 bytes
2348
- commandString.writeUInt32LE(flags, 0); // Little-endian unsigned int
2349
- const cmdResponse = await this.executeCmd(COMMANDS.CMD_REG_EVENT, commandString);
2350
- if (this.verbose)
2351
- console.log("regEvent: ", cmdResponse.readUInt16LE(0));
2352
- }
2353
- catch (e) {
2354
- throw new ZkError(e, COMMANDS.CMD_REG_EVENT, this.ip);
2355
- }
2356
- }
2357
- async cancelCapture() {
2358
- try {
2359
- const reply = await this.executeCmd(COMMANDS.CMD_CANCELCAPTURE, '');
2360
- return !!reply;
2361
- }
2362
- catch (e) {
2363
- throw new ZkError(e, COMMANDS.CMD_CANCELCAPTURE, this.ip);
2364
- }
2365
- }
2366
- async restartDevice() {
2367
- try {
2368
- await this.executeCmd(COMMANDS.CMD_RESTART, '');
2369
- }
2370
- catch (e) {
2371
- throw new ZkError(e, COMMANDS.CMD_RESTART, this.ip);
2372
- }
2373
- }
2374
- }
2375
-
2376
- class ZUDP {
2377
- ip;
2378
- port;
2379
- timeout;
2380
- socket;
2381
- sessionId;
2382
- replyId;
2383
- inport;
2384
- comm_key;
2385
- constructor(ip, port, timeout, inport, comm_key = 0) {
2386
- this.ip = ip;
2387
- this.port = port;
2388
- this.timeout = timeout;
2389
- this.socket = null;
2390
- this.sessionId = null;
2391
- this.replyId = 0;
2392
- this.inport = inport;
2393
- this.comm_key = comm_key;
2394
- }
2395
- createSocket(cbError, cbClose) {
2396
- return new Promise((resolve, reject) => {
2397
- this.socket = dgram__namespace.createSocket('udp4');
2398
- this.socket.setMaxListeners(Infinity);
2399
- this.socket.once('error', (err) => {
2400
- this.socket = null;
2401
- reject(err);
2402
- if (cbError)
2403
- cbError(err);
2404
- });
2405
- this.socket.once('close', () => {
2406
- this.socket = null;
2407
- if (cbClose)
2408
- cbClose('udp');
2409
- });
2410
- this.socket.once('listening', () => {
2411
- resolve(this.socket);
2412
- });
2413
- try {
2414
- this.socket.bind(this.inport);
2415
- }
2416
- catch (err) {
2417
- this.socket = null;
2418
- reject(err);
2419
- if (cbError)
2420
- cbError(err);
2421
- }
2422
- });
2423
- }
2424
- async connect() {
2425
- try {
2426
- let reply = await this.executeCmd(COMMANDS.CMD_CONNECT, '');
2427
- if (reply.readUInt16LE(0) === COMMANDS.CMD_ACK_OK) {
2428
- return true;
2429
- }
2430
- if (reply.readUInt16LE(0) === COMMANDS.CMD_ACK_UNAUTH) {
2431
- const hashedCommkey = authKey(this.comm_key, this.sessionId);
2432
- reply = await this.executeCmd(COMMANDS.CMD_AUTH, hashedCommkey);
2433
- if (reply.readUInt16LE(0) === COMMANDS.CMD_ACK_OK) {
2434
- return true;
2435
- }
2436
- else {
2437
- throw new Error("Authentication error");
2438
- }
2439
- }
2440
- else {
2441
- throw new Error('NO_REPLY_ON_CMD_CONNECT');
2442
- }
2443
- }
2444
- catch (err) {
2445
- console.error('Error in connect method:', err);
2446
- throw err;
2447
- }
2448
- }
2449
- async closeSocket() {
2450
- return new Promise((resolve, reject) => {
2451
- if (!this.socket) {
2452
- resolve(true);
2453
- return;
2454
- }
2455
- const timeout = 2000;
2456
- const timer = setTimeout(() => {
2457
- console.warn('Socket close timeout');
2458
- resolve(true);
2459
- }, timeout);
2460
- this.socket.removeAllListeners('message');
2461
- // @ts-ignore
2462
- this.socket.close((err) => {
2463
- clearTimeout(timer);
2464
- if (err) {
2465
- console.error('Error closing socket:', err);
2466
- reject(err);
2467
- }
2468
- else {
2469
- resolve(true);
2470
- }
2471
- this.socket = null;
2472
- });
2473
- });
2474
- }
2475
- writeMessage(msg, connect) {
2476
- return new Promise((resolve, reject) => {
2477
- if (!this.socket) {
2478
- reject(new Error('Socket not initialized'));
2479
- return;
2480
- }
2481
- let sendTimeoutId;
2482
- const onMessage = (data) => {
2483
- clearTimeout(sendTimeoutId);
2484
- this.socket.removeListener('message', onMessage);
2485
- resolve(data);
2486
- };
2487
- this.socket.once('message', onMessage);
2488
- this.socket.send(msg, 0, msg.length, this.port, this.ip, (err) => {
2489
- if (err) {
2490
- this.socket.removeListener('message', onMessage);
2491
- reject(err);
2492
- return;
2493
- }
2494
- if (this.timeout) {
2495
- sendTimeoutId = setTimeout(() => {
2496
- this.socket.removeListener('message', onMessage);
2497
- reject(new Error('TIMEOUT_ON_WRITING_MESSAGE'));
2498
- }, connect ? 2000 : this.timeout);
2499
- }
2500
- });
2501
- });
2502
- }
2503
- requestData(msg) {
2504
- return new Promise((resolve, reject) => {
2505
- if (!this.socket) {
2506
- reject(new Error('Socket not initialized'));
2507
- return;
2508
- }
2509
- let sendTimeoutId;
2510
- let responseTimeoutId;
2511
- const handleOnData = (data) => {
2512
- if (checkNotEventUDP(data))
2513
- return;
2514
- clearTimeout(sendTimeoutId);
2515
- clearTimeout(responseTimeoutId);
2516
- this.socket.removeListener('message', handleOnData);
2517
- resolve(data);
2518
- };
2519
- const onReceiveTimeout = () => {
2520
- this.socket.removeListener('message', handleOnData);
2521
- reject(new Error('TIMEOUT_ON_RECEIVING_REQUEST_DATA'));
2522
- };
2523
- this.socket.on('message', handleOnData);
2524
- this.socket.send(msg, 0, msg.length, this.port, this.ip, (err) => {
2525
- if (err) {
2526
- this.socket.removeListener('message', handleOnData);
2527
- reject(err);
2528
- return;
2529
- }
2530
- responseTimeoutId = setTimeout(onReceiveTimeout, this.timeout);
2531
- });
2532
- sendTimeoutId = setTimeout(() => {
2533
- this.socket.removeListener('message', handleOnData);
2534
- reject(new Error('TIMEOUT_IN_RECEIVING_RESPONSE_AFTER_REQUESTING_DATA'));
2535
- }, this.timeout);
2536
- });
2537
- }
2538
- async executeCmd(command, data) {
2539
- try {
2540
- if (command === COMMANDS.CMD_CONNECT) {
2541
- this.sessionId = 0;
2542
- this.replyId = 0;
2543
- }
2544
- else {
2545
- this.replyId++;
2546
- }
2547
- const buf = createUDPHeader(command, this.sessionId, this.replyId, data);
2548
- const reply = await this.writeMessage(buf, command === COMMANDS.CMD_CONNECT || command === COMMANDS.CMD_EXIT);
2549
- if (reply && reply.length > 0) {
2550
- if (command === COMMANDS.CMD_CONNECT) {
2551
- this.sessionId = reply.readUInt16LE(4);
2552
- }
2553
- }
2554
- return reply;
2555
- }
2556
- catch (err) {
2557
- console.error(`Error executing command ${command}:`, err);
2558
- throw err;
2559
- }
2560
- }
2561
- async sendChunkRequest(start, size) {
2562
- this.replyId++;
2563
- const reqData = Buffer.alloc(8);
2564
- reqData.writeUInt32LE(start, 0);
2565
- reqData.writeUInt32LE(size, 4);
2566
- const buf = createUDPHeader(COMMANDS.CMD_DATA_RDY, this.sessionId, this.replyId, reqData);
2567
- try {
2568
- await new Promise((resolve, reject) => {
2569
- this.socket.send(buf, 0, buf.length, this.port, this.ip, (err) => {
2570
- if (err) {
2571
- log(`[UDP][SEND_CHUNK_REQUEST] Error sending chunk request: ${err.message}`);
2572
- reject(err);
2573
- }
2574
- else {
2575
- resolve();
2576
- }
2577
- });
2578
- });
2579
- }
2580
- catch (error) {
2581
- log(`[UDP][SEND_CHUNK_REQUEST] Exception: ${error.message}`);
2582
- throw error;
2583
- }
2584
- }
2585
- async readWithBuffer(reqData, cb = null) {
2586
- this.replyId++;
2587
- const buf = createUDPHeader(COMMANDS.CMD_DATA_WRRQ, this.sessionId, this.replyId, reqData);
2588
- try {
2589
- const reply = await this.requestData(buf);
2590
- const header = decodeUDPHeader(reply.subarray(0, 8));
2591
- switch (header.commandId) {
2592
- case COMMANDS.CMD_DATA:
2593
- return { data: reply.subarray(8), err: null };
2594
- case COMMANDS.CMD_ACK_OK:
2595
- case COMMANDS.CMD_PREPARE_DATA:
2596
- return await this.handleChunkedData(reply, header.commandId, cb);
2597
- default:
2598
- throw new Error('ERROR_IN_UNHANDLE_CMD ' + exportErrorMessage(header.commandId));
2599
- }
2600
- }
2601
- catch (err) {
2602
- return { data: null, err: err };
2603
- }
2604
- }
2605
- async handleChunkedData(reply, commandId, cb) {
2606
- return new Promise((resolve) => {
2607
- const recvData = reply.subarray(8);
2608
- const size = recvData.readUIntLE(1, 4);
2609
- let totalBuffer = Buffer.from([]);
2610
- const timeout = 3000;
2611
- let timer = setTimeout(() => {
2612
- this.socket.removeListener('message', handleOnData);
2613
- resolve({ data: null, err: new Error('TIMEOUT WHEN RECEIVING PACKET') });
2614
- }, timeout);
2615
- const internalCallback = (replyData, err = null) => {
2616
- this.socket.removeListener('message', handleOnData);
2617
- clearTimeout(timer);
2618
- resolve({ data: err ? null : replyData, err });
2619
- };
2620
- const handleOnData = (reply) => {
2621
- if (checkNotEventUDP(reply))
2622
- return;
2623
- clearTimeout(timer);
2624
- timer = setTimeout(() => {
2625
- internalCallback(totalBuffer, new Error(`TIMEOUT !! ${(size - totalBuffer.length) / size} % REMAIN !`));
2626
- }, timeout);
2627
- const header = decodeUDPHeader(reply);
2628
- switch (header.commandId) {
2629
- case COMMANDS.CMD_PREPARE_DATA:
2630
- break;
2631
- case COMMANDS.CMD_DATA:
2632
- totalBuffer = Buffer.concat([totalBuffer, reply.subarray(8)]);
2633
- cb && cb(totalBuffer.length, size);
2634
- break;
2635
- case COMMANDS.CMD_ACK_OK:
2636
- if (totalBuffer.length === size) {
2637
- internalCallback(totalBuffer);
2638
- }
2639
- break;
2640
- default:
2641
- internalCallback(Buffer.from([]), new Error('ERROR_IN_UNHANDLE_CMD ' + exportErrorMessage(header.commandId)));
2642
- }
2643
- };
2644
- this.socket.on('message', handleOnData);
2645
- const chunkCount = Math.ceil(size / Constants.MAX_CHUNK);
2646
- for (let i = 0; i < chunkCount; i++) {
2647
- const start = i * Constants.MAX_CHUNK;
2648
- const chunkSize = (i === chunkCount - 1) ? size % Constants.MAX_CHUNK : Constants.MAX_CHUNK;
2649
- this.sendChunkRequest(start, chunkSize).catch(err => {
2650
- internalCallback(Buffer.from([]), err);
2651
- });
2652
- }
2653
- });
2654
- }
2655
- async getUsers() {
2656
- try {
2657
- if (this.socket) {
2658
- await this.freeData();
2659
- }
2660
- const data = await this.readWithBuffer(REQUEST_DATA.GET_USERS);
2661
- if (this.socket) {
2662
- await this.freeData();
2663
- }
2664
- const USER_PACKET_SIZE = 28;
2665
- let userData = data.data?.subarray(4) || Buffer.from([]);
2666
- const users = [];
2667
- while (userData.length >= USER_PACKET_SIZE) {
2668
- const user = decodeUserData28(userData.subarray(0, USER_PACKET_SIZE));
2669
- users.push(user);
2670
- userData = userData.subarray(USER_PACKET_SIZE);
2671
- }
2672
- return { data: users };
2673
- }
2674
- catch (err) {
2675
- throw new Error(err.message);
2676
- }
2677
- }
2678
- async getAttendances(callbackInProcess) {
2679
- try {
2680
- if (this.socket) {
2681
- await this.freeData();
2682
- }
2683
- const data = await this.readWithBuffer(REQUEST_DATA.GET_ATTENDANCE_LOGS);
2684
- if (this.socket) {
2685
- await this.freeData();
2686
- }
2687
- const RECORD_PACKET_SIZE = 16;
2688
- let recordData = data.data?.subarray(4) || Buffer.from([]);
2689
- const records = [];
2690
- while (recordData.length >= RECORD_PACKET_SIZE) {
2691
- const record = decodeRecordData16(recordData.subarray(0, RECORD_PACKET_SIZE));
2692
- records.push({ ...record, ip: this.ip });
2693
- recordData = recordData.subarray(RECORD_PACKET_SIZE);
2694
- }
2695
- return { data: records, err: data.err };
2696
- }
2697
- catch (err) {
2698
- return { data: [], err: err };
2699
- }
2700
- }
2701
- async freeData() {
2702
- try {
2703
- const resp = await this.executeCmd(COMMANDS.CMD_FREE_DATA, Buffer.alloc(0));
2704
- return !!resp;
2705
- }
2706
- catch (err) {
2707
- console.error('Error freeing data:', err);
2708
- throw err;
2709
- }
2710
- }
2711
- async getInfo() {
2712
- try {
2713
- const data = await this.executeCmd(COMMANDS.CMD_GET_FREE_SIZES, Buffer.alloc(0));
2714
- return {
2715
- userCounts: data.readUIntLE(24, 4),
2716
- logCounts: data.readUIntLE(40, 4),
2717
- logCapacity: data.readUIntLE(72, 4)
2718
- };
2719
- }
2720
- catch (err) {
2721
- console.error('Error retrieving info:', err);
2722
- throw err;
2723
- }
2724
- }
2725
- async getTime() {
2726
- try {
2727
- const response = await this.executeCmd(COMMANDS.CMD_GET_TIME, Buffer.alloc(0));
2728
- const timeValue = response.readUInt32LE(8);
2729
- return timeParser.decode(timeValue);
2730
- }
2731
- catch (err) {
2732
- console.error('Error retrieving time:', err);
2733
- throw err;
2734
- }
2735
- }
2736
- async setTime(tm) {
2737
- try {
2738
- const commandBuffer = Buffer.alloc(32);
2739
- commandBuffer.writeUInt32LE(timeParser.encode(new Date(tm)), 0);
2740
- await this.executeCmd(COMMANDS.CMD_SET_TIME, commandBuffer);
2741
- return true;
2742
- }
2743
- catch (err) {
2744
- console.error('Error setting time:', err);
2745
- throw err;
2746
- }
2747
- }
2748
- async clearAttendanceLog() {
2749
- try {
2750
- return !!await this.executeCmd(COMMANDS.CMD_CLEAR_ATTLOG, Buffer.alloc(0));
2751
- }
2752
- catch (err) {
2753
- console.error('Error clearing attendance log:', err);
2754
- throw err;
2755
- }
2756
- }
2757
- async clearData() {
2758
- try {
2759
- return !!await this.executeCmd(COMMANDS.CMD_CLEAR_DATA, Buffer.alloc(0));
2760
- }
2761
- catch (err) {
2762
- console.error('Error clearing data:', err);
2763
- throw err;
2764
- }
2765
- }
2766
- async disableDevice() {
2767
- try {
2768
- const resp = await this.executeCmd(COMMANDS.CMD_DISABLEDEVICE, REQUEST_DATA.DISABLE_DEVICE);
2769
- return !!resp;
2770
- }
2771
- catch (err) {
2772
- console.error('Error disabling device:', err);
2773
- throw err;
2774
- }
2775
- }
2776
- async enableDevice() {
2777
- try {
2778
- const resp = await this.executeCmd(COMMANDS.CMD_ENABLEDEVICE, Buffer.alloc(0));
2779
- return !!resp;
2780
- }
2781
- catch (err) {
2782
- console.error('Error enabling device:', err);
2783
- throw err;
2784
- }
2785
- }
2786
- async disconnect() {
2787
- try {
2788
- await this.executeCmd(COMMANDS.CMD_EXIT, Buffer.alloc(0));
2789
- }
2790
- catch (err) {
2791
- console.error('Error executing disconnect command:', err);
2792
- }
2793
- try {
2794
- await this.closeSocket();
2795
- }
2796
- catch (err) {
2797
- console.error('Error closing the socket:', err);
2798
- }
2799
- }
2800
- async getRealTimeLogs(cb = () => { }) {
2801
- this.replyId++;
2802
- const buf = createUDPHeader(COMMANDS.CMD_REG_EVENT, this.sessionId, this.replyId, REQUEST_DATA.GET_REAL_TIME_EVENT);
2803
- try {
2804
- this.socket.send(buf, 0, buf.length, this.port, this.ip, (err) => {
2805
- if (err) {
2806
- console.error('Error sending UDP message:', err);
2807
- return;
2808
- }
2809
- console.log('UDP message sent successfully');
2810
- });
2811
- }
2812
- catch (err) {
2813
- console.error('Error during send operation:', err);
2814
- return;
2815
- }
2816
- const handleMessage = (data) => {
2817
- if (!checkNotEventUDP(data))
2818
- return;
2819
- if (data.length === 18) {
2820
- cb(decodeRecordRealTimeLog18(data));
2821
- }
2822
- };
2823
- if (this.socket.listenerCount('message') === 0) {
2824
- this.socket.on('message', handleMessage);
2825
- }
2826
- else {
2827
- console.warn('Multiple message listeners detected. Ensure only one listener is attached.');
2828
- }
2829
- }
2830
- }
2831
-
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const ztcp_1 = require("./ztcp");
5
+ const zudp_1 = require("./zudp");
6
+ const handler_1 = require("./exceptions/handler");
2832
7
  class Zklib {
2833
8
  set connectionType(value) {
2834
9
  this._connectionType = value;
@@ -2856,32 +31,32 @@ class Zklib {
2856
31
  constructor(ip, port = 4370, timeout = 5000, inport = 10000, comm_key = 0, verbose = false) {
2857
32
  this.ip = ip;
2858
33
  this.comm_key = comm_key;
2859
- this.ztcp = new ZTCP(ip, port, timeout, comm_key, verbose);
2860
- this.zudp = new ZUDP(ip, port, timeout, inport);
34
+ this.ztcp = new ztcp_1.ZTCP(ip, port, timeout, comm_key, verbose);
35
+ this.zudp = new zudp_1.ZUDP(ip, port, timeout, inport);
2861
36
  }
2862
37
  async functionWrapper(tcpCallback, udpCallback, command) {
2863
38
  try {
2864
39
  switch (this._connectionType) {
2865
- case 'tcp':
40
+ case "tcp":
2866
41
  if (this.ztcp && this.ztcp.socket) {
2867
42
  return await tcpCallback();
2868
43
  }
2869
44
  else {
2870
- throw new ZkError(new Error(`TCP socket isn't connected!`), `[TCP] ${command}`, this.ip);
45
+ throw new handler_1.ZkError(new Error("TCP socket isn't connected!"), `[TCP] ${command}`, this.ip);
2871
46
  }
2872
- case 'udp':
47
+ case "udp":
2873
48
  if (this.zudp && this.zudp.socket) {
2874
49
  return await udpCallback();
2875
50
  }
2876
51
  else {
2877
- throw new ZkError(new Error(`UDP socket isn't connected!`), `[UDP] ${command}`, this.ip);
52
+ throw new handler_1.ZkError(new Error("UDP socket isn't connected!"), `[UDP] ${command}`, this.ip);
2878
53
  }
2879
54
  default:
2880
- throw new ZkError(new Error(`Unsupported connection type or socket isn't connected!`), '', this.ip);
55
+ throw new handler_1.ZkError(new Error("Unsupported connection type or socket isn't connected!"), "", this.ip);
2881
56
  }
2882
57
  }
2883
58
  catch (err) {
2884
- throw new ZkError(err, `[${this._connectionType?.toUpperCase()}] ${command}`, this.ip);
59
+ throw new handler_1.ZkError(err, `[${this._connectionType?.toUpperCase()}] ${command}`, this.ip);
2885
60
  }
2886
61
  }
2887
62
  async createSocket(cbErr, cbClose) {
@@ -2889,24 +64,24 @@ class Zklib {
2889
64
  if (this.ztcp.socket) {
2890
65
  try {
2891
66
  await this.ztcp.connect();
2892
- console.log('TCP reconnection successful');
2893
- this._connectionType = 'tcp';
67
+ console.log("TCP reconnection successful");
68
+ this._connectionType = "tcp";
2894
69
  return true;
2895
70
  }
2896
71
  catch (err) {
2897
- throw new ZkError(err, 'TCP CONNECT', this.ip);
72
+ throw new handler_1.ZkError(err, "TCP CONNECT", this.ip);
2898
73
  }
2899
74
  }
2900
75
  else {
2901
76
  try {
2902
77
  await this.ztcp.createSocket(cbErr, cbClose);
2903
78
  await this.ztcp.connect();
2904
- console.log('TCP connection successful');
2905
- this._connectionType = 'tcp';
79
+ console.log("TCP connection successful");
80
+ this._connectionType = "tcp";
2906
81
  return true;
2907
82
  }
2908
83
  catch (err) {
2909
- throw new ZkError(err, 'TCP CONNECT', this.ip);
84
+ throw new handler_1.ZkError(err, "TCP CONNECT", this.ip);
2910
85
  }
2911
86
  }
2912
87
  }
@@ -2916,86 +91,114 @@ class Zklib {
2916
91
  await this.ztcp.disconnect();
2917
92
  }
2918
93
  catch (disconnectErr) {
2919
- console.error('Error disconnecting TCP:', disconnectErr);
94
+ console.error("Error disconnecting TCP:", disconnectErr);
2920
95
  }
2921
- if (err.code !== ERROR_TYPES.ECONNREFUSED) {
2922
- throw new ZkError(err, 'TCP CONNECT', this.ip);
96
+ if (err.code !== handler_1.ERROR_TYPES.ECONNREFUSED) {
97
+ throw new handler_1.ZkError(err, "TCP CONNECT", this.ip);
2923
98
  }
2924
99
  try {
2925
100
  if (!this.zudp.socket) {
2926
101
  await this.zudp.createSocket(cbErr, cbClose);
2927
102
  }
2928
103
  await this.zudp.connect();
2929
- console.log('UDP connection successful');
2930
- this._connectionType = 'udp';
104
+ console.log("UDP connection successful");
105
+ this._connectionType = "udp";
2931
106
  return true;
2932
107
  }
2933
108
  catch (err) {
2934
- if (err.message !== 'EADDRINUSE') {
109
+ if (err.message !== "EADDRINUSE") {
2935
110
  this._connectionType = null;
2936
111
  try {
2937
112
  await this.zudp.disconnect();
2938
113
  }
2939
114
  catch (disconnectErr) {
2940
- console.error('Error disconnecting UDP:', disconnectErr);
115
+ console.error("Error disconnecting UDP:", disconnectErr);
2941
116
  }
2942
- throw new ZkError(err, 'UDP CONNECT', this.ip);
117
+ throw new handler_1.ZkError(err, "UDP CONNECT", this.ip);
2943
118
  }
2944
- this._connectionType = 'udp';
119
+ this._connectionType = "udp";
2945
120
  return true;
2946
121
  }
2947
122
  }
2948
123
  }
2949
124
  async getUsers() {
2950
- return this.functionWrapper(() => this.ztcp._userService.getUsers(), () => this.zudp.getUsers(), 'GET_USERS');
125
+ return this.functionWrapper(() => this.ztcp._userService.getUsers(), () => this.zudp.getUsers(), "GET_USERS");
2951
126
  }
2952
127
  async getTime() {
2953
- return this.functionWrapper(() => this.ztcp.getTime(), () => this.zudp.getTime(), 'GET_TIME');
128
+ return this.functionWrapper(() => this.ztcp._optionsService.getTime(), () => this.zudp.getTime(), "GET_TIME");
2954
129
  }
2955
130
  async setTime(t) {
2956
- return this.functionWrapper(() => this.ztcp.setTime(t), () => this.zudp.setTime(t), 'SET_TIME');
131
+ return this.functionWrapper(() => this.ztcp._optionsService.setTime(t), () => this.zudp.setTime(t), "SET_TIME");
2957
132
  }
2958
133
  async voiceTest() {
2959
- return this.functionWrapper(() => this.ztcp.voiceTest(), async () => { throw new Error('UDP voice test not supported'); }, 'VOICE_TEST');
134
+ return this.functionWrapper(() => this.ztcp._optionsService.voiceTest(), async () => {
135
+ throw new Error("UDP voice test not supported");
136
+ }, "VOICE_TEST");
2960
137
  }
2961
138
  async getProductTime() {
2962
- return this.functionWrapper(() => this.ztcp.getProductTime(), async () => { throw new Error('UDP get product time not supported'); }, 'GET_PRODUCT_TIME');
139
+ return this.functionWrapper(() => this.ztcp._optionsService.getProductTime(), async () => {
140
+ throw new Error("UDP get product time not supported");
141
+ }, "GET_PRODUCT_TIME");
2963
142
  }
2964
143
  async getVendor() {
2965
- return this.functionWrapper(() => this.ztcp.getVendor(), async () => { throw new Error('UDP get vendor not supported'); }, 'GET_VENDOR');
144
+ return this.functionWrapper(() => this.ztcp._optionsService.getVendor(), async () => {
145
+ throw new Error("UDP get vendor not supported");
146
+ }, "GET_VENDOR");
2966
147
  }
2967
148
  async getMacAddress() {
2968
- return this.functionWrapper(() => this.ztcp.getMacAddress(), async () => { throw new Error('UDP get MAC address not supported'); }, 'GET_MAC_ADDRESS');
149
+ return this.functionWrapper(() => this.ztcp._optionsService.getMacAddress(), async () => {
150
+ throw new Error("UDP get MAC address not supported");
151
+ }, "GET_MAC_ADDRESS");
2969
152
  }
2970
153
  async getSerialNumber() {
2971
- return this.functionWrapper(() => this.ztcp.getSerialNumber(), async () => { throw new Error('UDP get serial number not supported'); }, 'GET_SERIAL_NUMBER');
154
+ return this.functionWrapper(() => this.ztcp._optionsService.getSerialNumber(), async () => {
155
+ throw new Error("UDP get serial number not supported");
156
+ }, "GET_SERIAL_NUMBER");
2972
157
  }
2973
158
  async getDeviceVersion() {
2974
- return this.functionWrapper(() => this.ztcp.getDeviceVersion(), async () => { throw new Error('UDP get device version not supported'); }, 'GET_DEVICE_VERSION');
159
+ return this.functionWrapper(() => this.ztcp._optionsService.getDeviceVersion(), async () => {
160
+ throw new Error("UDP get device version not supported");
161
+ }, "GET_DEVICE_VERSION");
2975
162
  }
2976
163
  async getDeviceName() {
2977
- return this.functionWrapper(() => this.ztcp.getDeviceName(), async () => { throw new Error('UDP get device name not supported'); }, 'GET_DEVICE_NAME');
164
+ return this.functionWrapper(() => this.ztcp._optionsService.getDeviceName(), async () => {
165
+ throw new Error("UDP get device name not supported");
166
+ }, "GET_DEVICE_NAME");
2978
167
  }
2979
168
  async getPlatform() {
2980
- return this.functionWrapper(() => this.ztcp.getPlatform(), async () => { throw new Error('UDP get platform not supported'); }, 'GET_PLATFORM');
169
+ return this.functionWrapper(() => this.ztcp._optionsService.getPlatform(), async () => {
170
+ throw new Error("UDP get platform not supported");
171
+ }, "GET_PLATFORM");
2981
172
  }
2982
173
  async getOS() {
2983
- return this.functionWrapper(() => this.ztcp.getOS(), async () => { throw new Error('UDP get OS not supported'); }, 'GET_OS');
174
+ return this.functionWrapper(() => this.ztcp._optionsService.getOS(), async () => {
175
+ throw new Error("UDP get OS not supported");
176
+ }, "GET_OS");
2984
177
  }
2985
178
  async getWorkCode() {
2986
- return this.functionWrapper(() => this.ztcp.getWorkCode(), async () => { throw new Error('UDP get work code not supported'); }, 'GET_WORK_CODE');
179
+ return this.functionWrapper(() => this.ztcp._optionsService.getWorkCode(), async () => {
180
+ throw new Error("UDP get work code not supported");
181
+ }, "GET_WORK_CODE");
2987
182
  }
2988
183
  async getPIN() {
2989
- return this.functionWrapper(() => this.ztcp.getPIN(), async () => { throw new Error('UDP get PIN not supported'); }, 'GET_PIN');
184
+ return this.functionWrapper(() => this.ztcp._optionsService.getPIN(), async () => {
185
+ throw new Error("UDP get PIN not supported");
186
+ }, "GET_PIN");
2990
187
  }
2991
188
  async getFaceOn() {
2992
- return this.functionWrapper(() => this.ztcp.getFaceOn(), async () => { throw new Error('UDP get face on not supported'); }, 'GET_FACE_ON');
189
+ return this.functionWrapper(() => this.ztcp._optionsService.getFaceOn(), async () => {
190
+ throw new Error("UDP get face on not supported");
191
+ }, "GET_FACE_ON");
2993
192
  }
2994
193
  async getSSR() {
2995
- return this.functionWrapper(() => this.ztcp.getSSR(), async () => { throw new Error('UDP get SSR not supported'); }, 'GET_SSR');
194
+ return this.functionWrapper(() => this.ztcp._optionsService.getSSR(), async () => {
195
+ throw new Error("UDP get SSR not supported");
196
+ }, "GET_SSR");
2996
197
  }
2997
198
  async getFirmware() {
2998
- return this.functionWrapper(() => this.ztcp.getFirmware(), async () => { throw new Error('UDP get firmware not supported'); }, 'GET_FIRMWARE');
199
+ return this.functionWrapper(() => this.ztcp._optionsService.getFirmware(), async () => {
200
+ throw new Error("UDP get firmware not supported");
201
+ }, "GET_FIRMWARE");
2999
202
  }
3000
203
  /** Update or create a user if user id/pin not exists
3001
204
  * @param user_id {string} user id/pin for customer
@@ -3005,26 +208,34 @@ class Zklib {
3005
208
  * @param cardno {number} card number/id
3006
209
  */
3007
210
  async setUser(user_id, name, password, role = 0, cardno = 0) {
3008
- return this.functionWrapper(() => this.ztcp._userService.setUser(user_id, name, password, role, cardno), async () => { throw new Error('UDP set user not supported'); }, 'SET_USER');
211
+ return this.functionWrapper(() => this.ztcp._userService.setUser(user_id, name, password, role, cardno), async () => {
212
+ throw new Error("UDP set user not supported");
213
+ }, "SET_USER");
3009
214
  }
3010
215
  /**
3011
216
  * Delete user by a given user id/pin
3012
217
  * @param user_id {string}
3013
218
  */
3014
219
  async deleteUser(user_id) {
3015
- return this.functionWrapper(() => this.ztcp._userService.DeleteUser(user_id), async () => { throw new Error('UDP delete user not supported'); }, 'DELETE_USER');
220
+ return this.functionWrapper(() => this.ztcp._userService.DeleteUser(user_id), async () => {
221
+ throw new Error("UDP delete user not supported");
222
+ }, "DELETE_USER");
3016
223
  }
3017
224
  async getAttendanceSize() {
3018
- return this.functionWrapper(() => this.ztcp.getAttendanceSize(), async () => { throw new Error('UDP get attendance size not supported'); }, 'GET_ATTENDANCE_SIZE');
225
+ return this.functionWrapper(() => this.ztcp.getAttendanceSize(), async () => {
226
+ throw new Error("UDP get attendance size not supported");
227
+ }, "GET_ATTENDANCE_SIZE");
3019
228
  }
3020
229
  async getAttendances(cb) {
3021
- return this.functionWrapper(() => this.ztcp.getAttendances(cb), () => this.zudp.getAttendances(cb), 'GET_ATTENDANCES');
230
+ return this.functionWrapper(() => this.ztcp._transactionService.getAttendances(cb), () => this.zudp.getAttendances(cb), "GET_ATTENDANCES");
3022
231
  }
3023
232
  async getRealTimeLogs(cb) {
3024
- return this.functionWrapper(() => this.ztcp.getRealTimeLogs(cb), () => this.zudp.getRealTimeLogs(cb), 'GET_REAL_TIME_LOGS');
233
+ return this.functionWrapper(() => this.ztcp.getRealTimeLogs(cb), () => this.zudp.getRealTimeLogs(cb), "GET_REAL_TIME_LOGS");
3025
234
  }
3026
235
  async getTemplates() {
3027
- return this.functionWrapper(() => this.ztcp.getTemplates(), async () => { throw new Error('UDP get templates not supported'); }, 'GET_TEMPLATES');
236
+ return this.functionWrapper(() => this.ztcp.getTemplates(), async () => {
237
+ throw new Error("UDP get templates not supported");
238
+ }, "GET_TEMPLATES");
3028
239
  }
3029
240
  /**
3030
241
  * Get a user template for a given user id/pin and finger id
@@ -3032,7 +243,9 @@ class Zklib {
3032
243
  * @param fid {number} finger index
3033
244
  */
3034
245
  async getUserTemplate(user_id, fid) {
3035
- return await this.functionWrapper(async () => await this.ztcp._userService.DownloadFp(user_id, fid), async () => { throw new Error('UDP get user template not implemented'); }, 'GET_USER_TEMPLATE');
246
+ return await this.functionWrapper(async () => await this.ztcp._userService.DownloadFp(user_id, fid), async () => {
247
+ throw new Error("UDP get user template not implemented");
248
+ }, "GET_USER_TEMPLATE");
3036
249
  }
3037
250
  /**
3038
251
  * Upload a single fingerprint for a given user id
@@ -3042,7 +255,9 @@ class Zklib {
3042
255
  * @param fp_valid {number} finger flag. e.g., valid=1, duress=3
3043
256
  */
3044
257
  async uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid) {
3045
- return await this.functionWrapper(async () => await this.ztcp._userService.uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid), async () => { throw new Error('UDP get user template not implemented'); }, 'UPLOAD_USER_TEMPLATE');
258
+ return await this.functionWrapper(async () => await this.ztcp._userService.uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid), async () => {
259
+ throw new Error("UDP get user template not implemented");
260
+ }, "UPLOAD_USER_TEMPLATE");
3046
261
  }
3047
262
  /**
3048
263
  * save user and template
@@ -3051,7 +266,9 @@ class Zklib {
3051
266
  * @param {Finger[]} fingers - Array of finger class
3052
267
  */
3053
268
  async saveUserTemplate(user_id, fingers = []) {
3054
- return await this.functionWrapper(async () => await this.ztcp._userService.saveTemplates(user_id, fingers), async () => { throw new Error('UDP save user template not supported'); }, 'SAVE_USER_TEMPLATE');
269
+ return await this.functionWrapper(async () => await this.ztcp._userService.saveTemplates(user_id, fingers), async () => {
270
+ throw new Error("UDP save user template not supported");
271
+ }, "SAVE_USER_TEMPLATE");
3055
272
  }
3056
273
  /**
3057
274
  * Delete a single finger template by user id and finger index
@@ -3061,7 +278,9 @@ class Zklib {
3061
278
  async deleteFinger(user_id, fid) {
3062
279
  if (fid > 9 || 0 > fid)
3063
280
  throw new Error("fid params out of index");
3064
- return this.functionWrapper(() => this.ztcp._userService.deleteFinger(user_id, fid), async () => { throw new Error('UDP delete finger not supported'); }, 'DELETE_FINGER');
281
+ return this.functionWrapper(() => this.ztcp._userService.deleteFinger(user_id, fid), async () => {
282
+ throw new Error("UDP delete finger not supported");
283
+ }, "DELETE_FINGER");
3065
284
  }
3066
285
  /**
3067
286
  * Start to enroll a finger template
@@ -3071,44 +290,53 @@ class Zklib {
3071
290
  async enrollUser(user_id, temp_id) {
3072
291
  if (temp_id < 0 || temp_id > 9)
3073
292
  throw new Error("temp_id out of range 0-9");
3074
- return this.functionWrapper(() => this.ztcp._userService.enrollInfo(user_id, temp_id), async () => { throw new Error('UDP enroll user not supported'); }, 'ENROLL_USER');
293
+ return this.functionWrapper(() => this.ztcp._userService.enrollInfo(user_id, temp_id), async () => {
294
+ throw new Error("UDP enroll user not supported");
295
+ }, "ENROLL_USER");
3075
296
  }
3076
297
  async verifyUser(user_id) {
3077
- return this.functionWrapper(() => this.ztcp._userService.verify(user_id), async () => { throw new Error('UDP verify user not supported'); }, 'VERIFY_USER');
298
+ return this.functionWrapper(() => this.ztcp._userService.verify(user_id), async () => {
299
+ throw new Error("UDP verify user not supported");
300
+ }, "VERIFY_USER");
3078
301
  }
3079
302
  async restartDevice() {
3080
- return this.functionWrapper(() => this.ztcp.restartDevice(), async () => { throw new Error('UDP restart device not supported'); }, 'RESTART_DEVICE');
303
+ return this.functionWrapper(() => this.ztcp.restartDevice(), async () => {
304
+ throw new Error("UDP restart device not supported");
305
+ }, "RESTART_DEVICE");
3081
306
  }
3082
307
  async getSizes() {
3083
- return this.functionWrapper(() => this.ztcp.getSizes(), () => { throw new Error('not implemented ofr UDP'); }, 'GET_SIZES');
308
+ return this.functionWrapper(() => this.ztcp.getSizes(), () => {
309
+ throw new Error("not implemented ofr UDP");
310
+ }, "GET_SIZES");
3084
311
  }
3085
312
  async disconnect() {
3086
- return this.functionWrapper(() => this.ztcp.disconnect(), () => this.zudp.disconnect(), 'DISCONNECT');
313
+ return this.functionWrapper(() => this.ztcp.disconnect(), () => this.zudp.disconnect(), "DISCONNECT");
3087
314
  }
3088
315
  async freeData() {
3089
- return this.functionWrapper(() => this.ztcp.freeData(), () => this.zudp.freeData(), 'FREE_DATA');
316
+ return this.functionWrapper(() => this.ztcp.freeData(), () => this.zudp.freeData(), "FREE_DATA");
3090
317
  }
3091
318
  async disableDevice() {
3092
- return this.functionWrapper(() => this.ztcp.disableDevice(), () => this.zudp.disableDevice(), 'DISABLE_DEVICE');
319
+ return this.functionWrapper(() => this.ztcp.disableDevice(), () => this.zudp.disableDevice(), "DISABLE_DEVICE");
3093
320
  }
3094
321
  async enableDevice() {
3095
- return this.functionWrapper(() => this.ztcp.enableDevice(), () => this.zudp.enableDevice(), 'ENABLE_DEVICE');
322
+ return this.functionWrapper(() => this.ztcp.enableDevice(), () => this.zudp.enableDevice(), "ENABLE_DEVICE");
3096
323
  }
3097
324
  async getInfo() {
3098
- return this.functionWrapper(() => this.ztcp.getInfo(), () => this.zudp.getInfo(), 'GET_INFO');
325
+ return this.functionWrapper(() => this.ztcp.getInfo(), () => this.zudp.getInfo(), "GET_INFO");
3099
326
  }
3100
327
  async clearAttendanceLog() {
3101
- return this.functionWrapper(() => this.ztcp.clearAttendanceLog(), () => this.zudp.clearAttendanceLog(), 'CLEAR_ATTENDANCE_LOG');
328
+ return this.functionWrapper(() => this.ztcp.clearAttendanceLog(), () => this.zudp.clearAttendanceLog(), "CLEAR_ATTENDANCE_LOG");
3102
329
  }
3103
330
  async clearData() {
3104
- return this.functionWrapper(() => this.ztcp.clearData(), () => this.zudp.clearData(), 'CLEAR_DATA');
331
+ return this.functionWrapper(() => this.ztcp.clearData(), () => this.zudp.clearData(), "CLEAR_DATA");
3105
332
  }
3106
- async executeCmd(command, data = '') {
3107
- return this.functionWrapper(() => this.ztcp.executeCmd(command, data), () => this.zudp.executeCmd(command, data), 'EXECUTE_CMD');
333
+ async executeCmd(command, data = "") {
334
+ return this.functionWrapper(() => this.ztcp.executeCmd(command, data), () => this.zudp.executeCmd(command, data), "EXECUTE_CMD");
3108
335
  }
3109
336
  async getNetworkParams() {
3110
- return this.functionWrapper(() => this.ztcp.getNetworkParams(), async () => { throw new Error('UDP getNetworkParams not implemented'); }, 'NETWORK_PARAMS');
337
+ return this.functionWrapper(() => this.ztcp._optionsService.getNetworkParams(), async () => {
338
+ throw new Error("UDP getNetworkParams not implemented");
339
+ }, "NETWORK_PARAMS");
3111
340
  }
3112
341
  }
3113
-
3114
- module.exports = Zklib;
342
+ exports.default = Zklib;