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