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/README.md +18 -0
- package/dist/asd.csv +1142 -0
- package/dist/helper/command.d.ts +183 -85
- package/dist/helper/terminal.d.ts +541 -0
- package/dist/helper/utils.d.ts +42 -5
- package/dist/index.cjs.js +173 -2629
- package/dist/index.d.ts +52 -10
- package/dist/index.es.js +173 -2610
- package/dist/models/Attendance.d.ts +10 -2
- package/dist/models/Finger.d.ts +2 -1
- package/dist/services/options.service.d.ts +49 -0
- package/dist/services/transaction.service.d.ts +9 -0
- package/dist/services/user.service.d.ts +33 -0
- package/dist/ztcp.d.ts +37 -67
- package/dist/zudp.d.ts +3 -3
- package/package.json +70 -69
package/dist/index.cjs.js
CHANGED
|
@@ -1,2559 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
|
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(
|
|
45
|
+
throw new handler_1.ZkError(new Error("TCP socket isn't connected!"), `[TCP] ${command}`, this.ip);
|
|
2596
46
|
}
|
|
2597
|
-
case
|
|
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(
|
|
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(
|
|
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(
|
|
2618
|
-
this._connectionType =
|
|
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,
|
|
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(
|
|
2630
|
-
this._connectionType =
|
|
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,
|
|
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(
|
|
94
|
+
console.error("Error disconnecting TCP:", disconnectErr);
|
|
2645
95
|
}
|
|
2646
|
-
if (err.code !== ERROR_TYPES.ECONNREFUSED) {
|
|
2647
|
-
throw new ZkError(err,
|
|
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(
|
|
2655
|
-
this._connectionType =
|
|
104
|
+
console.log("UDP connection successful");
|
|
105
|
+
this._connectionType = "udp";
|
|
2656
106
|
return true;
|
|
2657
107
|
}
|
|
2658
108
|
catch (err) {
|
|
2659
|
-
if (err.message !==
|
|
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(
|
|
115
|
+
console.error("Error disconnecting UDP:", disconnectErr);
|
|
2666
116
|
}
|
|
2667
|
-
throw new ZkError(err,
|
|
117
|
+
throw new handler_1.ZkError(err, "UDP CONNECT", this.ip);
|
|
2668
118
|
}
|
|
2669
|
-
this._connectionType =
|
|
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(),
|
|
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(),
|
|
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),
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
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 () => {
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
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
|
-
|
|
2729
|
-
|
|
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 () => {
|
|
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),
|
|
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),
|
|
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 () => {
|
|
236
|
+
return this.functionWrapper(() => this.ztcp.getTemplates(), async () => {
|
|
237
|
+
throw new Error("UDP get templates not supported");
|
|
238
|
+
}, "GET_TEMPLATES");
|
|
2742
239
|
}
|
|
2743
|
-
|
|
2744
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2750
|
-
throw new Error("
|
|
2751
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2757
|
-
throw new Error("
|
|
2758
|
-
|
|
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(
|
|
2761
|
-
return this.functionWrapper(() => this.ztcp.
|
|
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 () => {
|
|
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(), () => {
|
|
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(),
|
|
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(),
|
|
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(),
|
|
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(),
|
|
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(),
|
|
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(),
|
|
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(),
|
|
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),
|
|
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 () => {
|
|
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;
|