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