rbzk 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/rbzk/zk.rb CHANGED
@@ -14,48 +14,45 @@ module RBZK
14
14
  end
15
15
 
16
16
  def test_ping
17
- begin
18
- Timeout.timeout(5) do
19
- s = TCPSocket.new(@ip, @port)
20
- s.close
21
- return true
22
- end
23
- rescue Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError => e
24
- return false
25
- rescue => e
26
- return false
17
+ Timeout.timeout(5) do
18
+ s = TCPSocket.new(@ip, @port)
19
+ s.close
20
+ return true
27
21
  end
22
+ rescue Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError
23
+ false
24
+ rescue StandardError
25
+ false
28
26
  end
29
27
 
30
28
  def test_tcp
31
- begin
32
- client = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
33
- client.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, [ 10, 0 ].pack('l_*'))
29
+ client = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
30
+ client.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, [ 10, 0 ].pack('l_*'))
34
31
 
35
- sockaddr = Socket.pack_sockaddr_in(@port, @ip)
36
- begin
37
- client.connect(sockaddr)
38
- result = 0 # Success code
39
- rescue Errno::EISCONN
40
- result = 0 # Already connected
41
- rescue => e
42
- # Some exceptions (e.g., Socket::ResolutionError) don't provide errno
43
- result = e.respond_to?(:errno) ? e.errno : 1 # Connection failed
44
- end
45
-
46
- client.close
47
- return result
48
- rescue => e
32
+ sockaddr = Socket.pack_sockaddr_in(@port, @ip)
33
+ begin
34
+ client.connect(sockaddr)
35
+ result = 0 # Success code
36
+ rescue Errno::EISCONN
37
+ result = 0 # Already connected
38
+ rescue StandardError => e
49
39
  # Some exceptions (e.g., Socket::ResolutionError) don't provide errno
50
- return e.respond_to?(:errno) ? e.errno : 1
40
+ result = e.respond_to?(:errno) ? e.errno : 1 # Connection failed
51
41
  end
42
+
43
+ client.close
44
+ result
45
+ rescue StandardError => e
46
+ # Some exceptions (e.g., Socket::ResolutionError) don't provide errno
47
+ e.respond_to?(:errno) ? e.errno : 1
52
48
  end
53
49
  end
54
50
 
55
51
  class ZK
56
52
  include RBZK::Constants
57
53
 
58
- def initialize(ip, port: 4370, timeout: 60, password: 0, force_udp: false, omit_ping: false, verbose: false, encoding: 'UTF-8')
54
+ def initialize(ip, port: 4370, timeout: 60, password: 0, force_udp: false, omit_ping: false, verbose: false,
55
+ encoding: 'UTF-8')
59
56
  # Initialize the ZK device connection
60
57
  RBZK::User.encoding = encoding
61
58
  @address = [ ip, port ]
@@ -79,6 +76,8 @@ module RBZK
79
76
  @data = nil
80
77
  @connected = false
81
78
  @next_uid = 1
79
+ @next_user_id = '1'
80
+ @user_packet_size = 28
82
81
 
83
82
  # Storage for user and attendance data
84
83
  @users = {}
@@ -104,22 +103,20 @@ module RBZK
104
103
  # Create helper for ping and TCP tests
105
104
  @helper = ZKHelper.new(ip, port)
106
105
 
107
- if @verbose
108
- puts "ZK instance created for device at #{@ip}:#{@port}"
109
- puts "Using #{@force_udp ? 'UDP' : 'TCP'} mode"
110
- end
106
+ return unless @verbose
107
+
108
+ puts "ZK instance created for device at #{@ip}:#{@port}"
109
+ puts "Using #{@force_udp ? 'UDP' : 'TCP'} mode"
111
110
  end
112
111
 
113
112
  def connect
114
113
  return self if @connected
115
114
 
116
115
  # Skip ping check if requested
117
- if !@omit_ping && !@helper.test_ping
118
- raise RBZK::ZKNetworkError, "Can't reach device (ping #{@ip})"
119
- end
116
+ raise RBZK::ZKNetworkError, "Can't reach device (ping #{@ip})" if !@omit_ping && !@helper.test_ping
120
117
 
121
118
  # Set user packet size if TCP connection is available
122
- if !@force_udp && @helper.test_tcp == 0
119
+ if !@force_udp && @helper.test_tcp.zero?
123
120
  @user_packet_size = 72 # Default for ZK8
124
121
  end
125
122
 
@@ -129,9 +126,7 @@ module RBZK
129
126
  @session_id = 0
130
127
  @reply_id = USHRT_MAX - 1
131
128
 
132
- if @verbose
133
- puts "Sending connect command to device"
134
- end
129
+ puts 'Sending connect command to device' if @verbose
135
130
 
136
131
  begin
137
132
  cmd_response = send_command(CMD_CONNECT)
@@ -139,9 +134,7 @@ module RBZK
139
134
 
140
135
  # Authenticate if needed
141
136
  if cmd_response[:code] == CMD_ACK_UNAUTH
142
- if @verbose
143
- puts "try auth"
144
- end
137
+ puts 'try auth' if @verbose
145
138
 
146
139
  command_string = make_commkey(@password, @session_id)
147
140
  cmd_response = send_command(CMD_AUTH, command_string)
@@ -150,23 +143,17 @@ module RBZK
150
143
  # Check response status
151
144
  if cmd_response[:status]
152
145
  @connected = true
153
- return self
146
+ self
154
147
  else
155
- if cmd_response[:code] == CMD_ACK_UNAUTH
156
- raise RBZK::ZKErrorResponse, "Unauthenticated"
157
- end
148
+ raise RBZK::ZKErrorResponse, 'Unauthenticated' if cmd_response[:code] == CMD_ACK_UNAUTH
158
149
 
159
- if @verbose
160
- puts "Connect error response: #{cmd_response[:code]}"
161
- end
150
+ puts "Connect error response: #{cmd_response[:code]}" if @verbose
162
151
 
163
152
  raise RBZK::ZKErrorResponse, "Invalid response: Can't connect"
164
153
  end
165
- rescue => e
154
+ rescue StandardError => e
166
155
  @connected = false
167
- if @verbose
168
- puts "Connection error: #{e.message}"
169
- end
156
+ puts "Connection error: #{e.message}" if @verbose
170
157
  raise e
171
158
  end
172
159
  end
@@ -178,11 +165,11 @@ module RBZK
178
165
  def disconnect
179
166
  return unless @connected
180
167
 
181
- self.send_command(CMD_EXIT)
182
- self.recv_reply
168
+ send_command(CMD_EXIT)
169
+ recv_reply
183
170
 
184
171
  @connected = false
185
- @socket.close if @socket
172
+ @socket&.close
186
173
 
187
174
  @socket = nil
188
175
  @tcp = nil
@@ -191,32 +178,28 @@ module RBZK
191
178
  end
192
179
 
193
180
  def enable_device
194
- self.send_command(CMD_ENABLEDEVICE)
195
- self.recv_reply
181
+ send_command(CMD_ENABLEDEVICE)
182
+ recv_reply
196
183
  true
197
184
  end
198
185
 
199
186
  def disable_device
200
- cmd_response = self.send_command(CMD_DISABLEDEVICE)
201
- if cmd_response[:status]
202
- @is_enabled = false
203
- true
204
- else
205
- raise RBZK::ZKErrorResponse, "Can't disable device"
206
- end
187
+ cmd_response = send_command(CMD_DISABLEDEVICE)
188
+ raise RBZK::ZKErrorResponse, "Can't disable device" unless cmd_response[:status]
189
+
190
+ @is_enabled = false
191
+ true
207
192
  end
208
193
 
209
194
  def get_firmware_version
210
195
  command = CMD_GET_VERSION
211
196
  response_size = 1024
212
- response = self.send_command(command, "", response_size)
197
+ response = send_command(command, '', response_size)
213
198
 
214
- if response && response[:status]
215
- firmware_version = @data.split("\x00")[0]
216
- firmware_version.to_s
217
- else
218
- raise RBZK::ZKErrorResponse, "Can't read firmware version"
219
- end
199
+ raise RBZK::ZKErrorResponse, "Can't read firmware version" unless response && response[:status]
200
+
201
+ firmware_version = @data.split("\x00")[0]
202
+ firmware_version.to_s
220
203
  end
221
204
 
222
205
  def get_serialnumber
@@ -224,15 +207,14 @@ module RBZK
224
207
  command_string = "~SerialNumber\x00".b
225
208
  response_size = 1024
226
209
 
227
- response = self.send_command(command, command_string, response_size)
210
+ response = send_command(command, command_string, response_size)
228
211
 
229
- if response && response[:status]
230
- serialnumber = @data.split("=", 2)[1]&.split("\x00")[0] || ""
231
- serialnumber = serialnumber.gsub("=", "")
232
- serialnumber.to_s
233
- else
234
- raise RBZK::ZKErrorResponse, "Can't read serial number"
235
- end
212
+ raise RBZK::ZKErrorResponse, "Can't read serial number" unless response && response[:status]
213
+
214
+ serialnumber_field = @data.split('=', 2)[1]
215
+ serialnumber = serialnumber_field ? serialnumber_field.split("\x00")[0] : ''
216
+ serialnumber = serialnumber.gsub('=', '')
217
+ serialnumber.to_s
236
218
  end
237
219
 
238
220
  def get_mac
@@ -240,14 +222,12 @@ module RBZK
240
222
  command_string = "MAC\x00".b
241
223
  response_size = 1024
242
224
 
243
- response = self.send_command(command, command_string, response_size)
225
+ response = send_command(command, command_string, response_size)
244
226
 
245
- if response && response[:status]
246
- mac = @data.split("=", 2)[1]&.split("\x00")[0] || ""
247
- mac.to_s
248
- else
249
- raise RBZK::ZKErrorResponse, "Can't read MAC address"
250
- end
227
+ raise RBZK::ZKErrorResponse, "Can't read MAC address" unless response && response[:status]
228
+
229
+ mac = @data.split('=', 2)[1]&.split("\x00")&.[](0) || ''
230
+ mac.to_s
251
231
  end
252
232
 
253
233
  def get_device_name
@@ -255,13 +235,14 @@ module RBZK
255
235
  command_string = "~DeviceName\x00".b
256
236
  response_size = 1024
257
237
 
258
- response = self.send_command(command, command_string, response_size)
238
+ response = send_command(command, command_string, response_size)
259
239
 
260
240
  if response && response[:status]
261
- device = @data.split("=", 2)[1]&.split("\x00")[0] || ""
241
+ device_field = @data.split('=', 2)[1]
242
+ device = device_field ? device_field.split("\x00")[0] : ''
262
243
  device.to_s
263
244
  else
264
- ""
245
+ ''
265
246
  end
266
247
  end
267
248
 
@@ -270,13 +251,16 @@ module RBZK
270
251
  command_string = "ZKFaceVersion\x00".b
271
252
  response_size = 1024
272
253
 
273
- response = self.send_command(command, command_string, response_size)
254
+ response = send_command(command, command_string, response_size)
274
255
 
275
- if response && response[:status]
276
- version = @data.split("=", 2)[1]&.split("\x00")[0] || ""
277
- version.to_i rescue 0
278
- else
279
- nil
256
+ return unless response && response[:status]
257
+
258
+ version_field = @data.split('=', 2)[1]
259
+ version = version_field ? version_field.split("\x00")[0] : ''
260
+ begin
261
+ version.to_i
262
+ rescue StandardError
263
+ 0
280
264
  end
281
265
  end
282
266
 
@@ -285,13 +269,16 @@ module RBZK
285
269
  command_string = "~ExtendFmt\x00".b
286
270
  response_size = 1024
287
271
 
288
- response = self.send_command(command, command_string, response_size)
272
+ response = send_command(command, command_string, response_size)
289
273
 
290
- if response && response[:status]
291
- fmt = @data.split("=", 2)[1]&.split("\x00")[0] || ""
292
- fmt.to_i rescue 0
293
- else
294
- nil
274
+ return unless response && response[:status]
275
+
276
+ fmt_field = @data.split('=', 2)[1]
277
+ fmt = fmt_field ? fmt_field.split("\x00")[0] : ''
278
+ begin
279
+ fmt.to_i
280
+ rescue StandardError
281
+ 0
295
282
  end
296
283
  end
297
284
 
@@ -300,15 +287,14 @@ module RBZK
300
287
  command_string = "~Platform\x00".b
301
288
  response_size = 1024
302
289
 
303
- response = self.send_command(command, command_string, response_size)
290
+ response = send_command(command, command_string, response_size)
304
291
 
305
- if response && response[:status]
306
- platform = @data.split("=", 2)[1]&.split("\x00")[0] || ""
307
- platform = platform.gsub("=", "")
308
- platform.to_s
309
- else
310
- raise RBZK::ZKErrorResponse, "Can't read platform name"
311
- end
292
+ raise RBZK::ZKErrorResponse, "Can't read platform name" unless response && response[:status]
293
+
294
+ platform_field = @data.split('=', 2)[1]
295
+ platform = platform_field ? platform_field.split("\x00")[0] : ''
296
+ platform = platform.gsub('=', '')
297
+ platform.to_s
312
298
  end
313
299
 
314
300
  def get_fp_version
@@ -316,32 +302,35 @@ module RBZK
316
302
  command_string = "~ZKFPVersion\x00".b
317
303
  response_size = 1024
318
304
 
319
- response = self.send_command(command, command_string, response_size)
305
+ response = send_command(command, command_string, response_size)
320
306
 
321
- if response && response[:status]
322
- version = @data.split("=", 2)[1]&.split("\x00")[0] || ""
323
- version = version.gsub("=", "")
324
- version.to_i rescue 0
325
- else
326
- raise RBZK::ZKErrorResponse, "Can't read fingerprint version"
307
+ raise RBZK::ZKErrorResponse, "Can't read fingerprint version" unless response && response[:status]
308
+
309
+ version_field = @data.split('=', 2)[1]
310
+ version = version_field ? version_field.split("\x00")[0] : ''
311
+ version = version.gsub('=', '')
312
+ begin
313
+ version.to_i
314
+ rescue StandardError
315
+ 0
327
316
  end
328
317
  end
329
318
 
330
319
  def restart
331
- self.send_command(CMD_RESTART)
332
- self.recv_reply
320
+ send_command(CMD_RESTART)
321
+ recv_reply
333
322
  true
334
323
  end
335
324
 
336
325
  def poweroff
337
- self.send_command(CMD_POWEROFF)
338
- self.recv_reply
326
+ send_command(CMD_POWEROFF)
327
+ recv_reply
339
328
  true
340
329
  end
341
330
 
342
331
  def test_voice(index = 0)
343
332
  command_string = [ index ].pack('L<')
344
- response = self.send_command(CMD_TESTVOICE, command_string)
333
+ response = send_command(CMD_TESTVOICE, command_string)
345
334
 
346
335
  if response && response[:status]
347
336
  true
@@ -354,20 +343,18 @@ module RBZK
354
343
  # @param time [Integer] define delay in seconds
355
344
  # @return [Boolean] true if successful, raises exception otherwise
356
345
  def unlock(time = 3)
357
- command_string = [time * 10].pack('L<')
358
- response = self.send_command(CMD_UNLOCK, command_string)
346
+ command_string = [ time * 10 ].pack('L<')
347
+ response = send_command(CMD_UNLOCK, command_string)
359
348
 
360
- if response && response[:status]
361
- true
362
- else
363
- raise RBZK::ZKErrorResponse, "Can't open door"
364
- end
349
+ raise RBZK::ZKErrorResponse, "Can't open door" unless response && response[:status]
350
+
351
+ true
365
352
  end
366
353
 
367
354
  # Get the lock state
368
355
  # @return [Boolean] true if door is open, false otherwise
369
356
  def get_lock_state
370
- response = self.send_command(CMD_DOORSTATE_RRQ)
357
+ response = send_command(CMD_DOORSTATE_RRQ)
371
358
 
372
359
  if response && response[:status]
373
360
  true
@@ -381,38 +368,32 @@ module RBZK
381
368
  # @param text [String] text to write
382
369
  # @return [Boolean] true if successful, raises exception otherwise
383
370
  def write_lcd(line_number, text)
384
- command_string = [line_number, 0].pack('s<c') + ' ' + text.encode(@encoding, invalid: :replace, undef: :replace)
385
- response = self.send_command(CMD_WRITE_LCD, command_string)
371
+ command_string = "#{[ line_number, 0 ].pack('s<c')} #{text.encode(@encoding, invalid: :replace, undef: :replace)}"
372
+ response = send_command(CMD_WRITE_LCD, command_string)
386
373
 
387
- if response && response[:status]
388
- true
389
- else
390
- raise RBZK::ZKErrorResponse, "Can't write lcd"
391
- end
374
+ raise RBZK::ZKErrorResponse, "Can't write lcd" unless response && response[:status]
375
+
376
+ true
392
377
  end
393
378
 
394
379
  # Clear LCD
395
380
  # @return [Boolean] true if successful, raises exception otherwise
396
381
  def clear_lcd
397
- response = self.send_command(CMD_CLEAR_LCD)
382
+ response = send_command(CMD_CLEAR_LCD)
398
383
 
399
- if response && response[:status]
400
- true
401
- else
402
- raise RBZK::ZKErrorResponse, "Can't clear lcd"
403
- end
384
+ raise RBZK::ZKErrorResponse, "Can't clear lcd" unless response && response[:status]
385
+
386
+ true
404
387
  end
405
388
 
406
389
  # Refresh the device data
407
390
  # @return [Boolean] true if successful, raises exception otherwise
408
391
  def refresh_data
409
- response = self.send_command(CMD_REFRESHDATA)
392
+ response = send_command(CMD_REFRESHDATA)
410
393
 
411
- if response && response[:status]
412
- true
413
- else
414
- raise RBZK::ZKErrorResponse, "Can't refresh data"
415
- end
394
+ raise RBZK::ZKErrorResponse, "Can't refresh data" unless response && response[:status]
395
+
396
+ true
416
397
  end
417
398
 
418
399
  # Create or update user by uid
@@ -425,23 +406,17 @@ module RBZK
425
406
  # @param card [Integer] card number
426
407
  # @return [Boolean] true if successful, raises exception otherwise
427
408
  def set_user(uid: nil, name: '', privilege: 0, password: '', group_id: '', user_id: '', card: 0)
428
- # If uid is not provided, use next_uid
429
409
  if uid.nil?
410
+ ensure_user_metadata!
430
411
  uid = @next_uid
431
- if user_id.empty?
432
- user_id = @next_user_id
433
- end
412
+ user_id = @next_user_id if user_id.empty? && @next_user_id
434
413
  end
435
414
 
436
- # If user_id is not provided, use uid as string
437
- if user_id.empty?
438
- user_id = uid.to_s # ZK6 needs uid2 == uid
439
- end
415
+ # If uid is not provided, use next_uid
416
+ user_id = uid.to_s if user_id.nil? || user_id.empty? # ZK6 needs uid2 == uid
440
417
 
441
418
  # Validate privilege
442
- if privilege != USER_DEFAULT && privilege != USER_ADMIN
443
- privilege = USER_DEFAULT
444
- end
419
+ privilege = USER_DEFAULT if privilege != USER_DEFAULT && privilege != USER_ADMIN
445
420
  privilege = privilege.to_i
446
421
 
447
422
  # Create command string based on user_packet_size
@@ -449,73 +424,79 @@ module RBZK
449
424
  group_id = 0 if group_id.empty?
450
425
 
451
426
  begin
452
- command_string = [uid, privilege].pack('S<C') +
453
- password.encode(@encoding, invalid: :replace, undef: :replace).ljust(5, "\x00")[0...5] +
454
- name.encode(@encoding, invalid: :replace, undef: :replace).ljust(8, "\x00")[0...8] +
455
- [card.to_i, 0, group_id.to_i, 0, user_id.to_i].pack('L<CS<S<L<')
456
- rescue => e
457
- if @verbose
458
- puts "Error packing user: #{e.message}"
459
- end
427
+ command_string = [ uid, privilege ].pack('S<C') +
428
+ password.encode(@encoding, invalid: :replace, undef: :replace).ljust(5, "\x00")[0...5] +
429
+ name.encode(@encoding, invalid: :replace, undef: :replace).ljust(8, "\x00")[0...8] +
430
+ [ card.to_i, 0, group_id.to_i, 0, user_id.to_i ].pack('L<CS<S<L<')
431
+ rescue StandardError => e
432
+ puts "Error packing user: #{e.message}" if @verbose
460
433
  raise RBZK::ZKErrorResponse, "Can't pack user"
461
434
  end
462
435
  else
463
436
  # For other firmware versions
464
437
  name_pad = name.encode(@encoding, invalid: :replace, undef: :replace).ljust(24, "\x00")[0...24]
465
- card_str = [card.to_i].pack('L<')[0...4]
466
- command_string = [uid, privilege].pack('S<C') +
467
- password.encode(@encoding, invalid: :replace, undef: :replace).ljust(8, "\x00")[0...8] +
468
- name_pad +
469
- card_str + "\x00" +
470
- group_id.encode(@encoding, invalid: :replace, undef: :replace).ljust(7, "\x00")[0...7] +
471
- "\x00" +
472
- user_id.encode(@encoding, invalid: :replace, undef: :replace).ljust(24, "\x00")[0...24]
438
+ card_str = [ card.to_i ].pack('L<')[0...4]
439
+ command_string = "#{[ uid,
440
+ privilege ].pack('S<C')}#{password.encode(@encoding, invalid: :replace, undef: :replace).ljust(8,
441
+ "\x00")[0...8]}#{name_pad}#{card_str}\u0000#{group_id.encode(@encoding, invalid: :replace, undef: :replace).ljust(7,
442
+ "\x00")[0...7]}\u0000#{user_id.encode(@encoding, invalid: :replace, undef: :replace).ljust(
443
+ 24, "\x00"
444
+ )[0...24]}"
473
445
  end
474
446
 
475
447
  # Send command
476
- response = self.send_command(CMD_USER_WRQ, command_string, 1024)
448
+ response = send_command(CMD_USER_WRQ, command_string, 1024)
477
449
 
478
450
  if response && response[:status]
479
451
  # Update next_uid and next_user_id if necessary
480
- self.refresh_data
481
- if @next_uid == uid
482
- @next_uid += 1
483
- end
484
- if @next_user_id == user_id
485
- @next_user_id = @next_uid.to_s
486
- end
452
+ refresh_data
453
+ @next_uid += 1 if @next_uid == uid
454
+ @next_user_id = @next_uid.to_s if @next_user_id == user_id
487
455
  true
488
456
  else
489
- raise RBZK::ZKErrorResponse, "Can't set user"
457
+ code = response[:code] if response
458
+ data_msg = @data && !@data.empty? ? " Data: #{format_as_python_bytes(@data)}" : ''
459
+ raise RBZK::ZKErrorResponse, "Can't set user (device response: #{code || 'NO_CODE'})#{data_msg}"
490
460
  end
491
461
  end
492
462
 
463
+ def ensure_user_metadata!
464
+ @next_uid ||= 1
465
+ @next_user_id ||= '1'
466
+ @user_packet_size ||= 28
467
+
468
+ return unless @next_uid <= 1 || @next_user_id.nil? || @user_packet_size.nil?
469
+
470
+ get_users
471
+ rescue StandardError => e
472
+ puts "Warning: unable to refresh user metadata before creating user: #{e.message}" if @verbose
473
+ @next_uid ||= 1
474
+ @next_user_id ||= '1'
475
+ @user_packet_size ||= 28
476
+ end
477
+ private :ensure_user_metadata!
478
+
493
479
  # Delete user by uid
494
480
  # @param uid [Integer] user ID that are generated from device
495
481
  # @return [Boolean] true if successful, raises exception otherwise
496
482
  def delete_user(uid: 0)
497
483
  # Send command
498
- command_string = [uid].pack('S<')
499
- response = self.send_command(CMD_DELETE_USER, command_string)
484
+ command_string = [ uid ].pack('S<')
485
+ response = send_command(CMD_DELETE_USER, command_string)
500
486
 
501
- if response && response[:status]
502
- self.refresh_data
503
- # Update next_uid if necessary
504
- if uid == (@next_uid - 1)
505
- @next_uid = uid
506
- end
507
- true
508
- else
509
- raise RBZK::ZKErrorResponse, "Can't delete user"
487
+ unless response && response[:status]
488
+ raise RBZK::ZKErrorResponse, "Can't delete user. User not found or other error."
510
489
  end
490
+
491
+ refresh_data
492
+ # Update next_uid if necessary
493
+ @next_uid = uid if uid == (@next_uid - 1)
494
+ true
511
495
  end
512
496
 
513
497
  # Helper method to read data with buffer (ZK6: 1503)
514
498
  def read_with_buffer(command, fct = 0, ext = 0)
515
-
516
- if @verbose
517
- puts "Reading data with buffer: command=#{command}, fct=#{fct}, ext=#{ext}"
518
- end
499
+ puts "Reading data with buffer: command=#{command}, fct=#{fct}, ext=#{ext}" if @verbose
519
500
 
520
501
  # Set max chunk size based on connection type
521
502
  max_chunk = @tcp ? 0xFFc0 : 16 * 1024
@@ -525,54 +506,39 @@ module RBZK
525
506
  # All in little-endian format
526
507
  command_string = [ 1, command, fct, ext ].pack('cs<l<l<')
527
508
 
528
- if @verbose
529
- puts "Command string: #{python_format(command_string)}"
530
- end
509
+ puts "Command string: #{python_format(command_string)}" if @verbose
531
510
 
532
511
  # Send the command to prepare the buffer
533
512
  response_size = 1024
534
- data = []
535
- start = 0
536
- response = self.send_command(CMD_PREPARE_BUFFER, command_string, response_size)
513
+ # local variables
514
+ response = send_command(CMD_PREPARE_BUFFER, command_string, response_size)
537
515
 
538
- if !response || !response[:status]
539
- raise RBZK::ZKErrorResponse, "Read with buffer not supported"
540
- end
516
+ raise RBZK::ZKErrorResponse, 'Read with buffer not supported' if !response || !response[:status]
541
517
 
542
518
  # Get data from the response
543
519
  data = @data
544
520
 
545
- if @verbose
546
- puts "Received #{data.size} bytes of data"
547
- end
521
+ puts "Received #{data.size} bytes of data" if @verbose
548
522
 
549
523
  # Check if we need more data
550
524
  if response[:code] == CMD_DATA
551
525
  if @tcp
552
- if @verbose
553
- puts "DATA! is #{data.size} bytes, tcp length is #{@tcp_length}"
554
- end
526
+ puts "DATA! is #{data.size} bytes, tcp length is #{@tcp_length}" if @verbose
555
527
 
556
528
  if data.size < (@tcp_length - 8)
557
529
  need = (@tcp_length - 8) - data.size
558
- if @verbose
559
- puts "need more data: #{need}"
560
- end
530
+ puts "need more data: #{need}" if @verbose
561
531
 
562
532
  # Receive more data to complete the buffer
563
533
  more_data = receive_raw_data(need)
564
534
 
565
- if @verbose
566
- puts "Read #{more_data.size} more bytes"
567
- end
535
+ puts "Read #{more_data.size} more bytes" if @verbose
568
536
 
569
537
  # Combine the data
570
538
  result = data + more_data
571
539
  return result, data.size + more_data.size
572
540
  else
573
- if @verbose
574
- puts "Enough data"
575
- end
541
+ puts 'Enough data' if @verbose
576
542
  size = data.size
577
543
  return data, size
578
544
  end
@@ -583,38 +549,30 @@ module RBZK
583
549
  end
584
550
 
585
551
  # Get the size from the first 4 bytes (unsigned long, little-endian)
586
- size = data[1..4].unpack('L<')[0]
552
+ size = data[1..4].unpack1('L<')
587
553
 
588
- if @verbose
589
- puts "size fill be #{size}"
590
- end
554
+ puts "size fill be #{size}" if @verbose
591
555
 
592
556
  # Calculate chunks
593
557
  remain = size % max_chunk
594
558
  # Calculate number of full-sized packets (integer division)
595
559
  packets = (size - remain).div(max_chunk)
596
560
 
597
- if @verbose
598
- puts "rwb: ##{packets} packets of max #{max_chunk} bytes, and extra #{remain} bytes remain"
599
- end
561
+ puts "rwb: ##{packets} packets of max #{max_chunk} bytes, and extra #{remain} bytes remain" if @verbose
600
562
 
601
563
  # Read chunks
602
564
  result_data = []
603
565
  start = 0
604
566
 
605
567
  packets.times do
606
- if @verbose
607
- puts "recieve chunk: prepare data size is #{max_chunk}"
608
- end
568
+ puts "recieve chunk: prepare data size is #{max_chunk}" if @verbose
609
569
  chunk = read_chunk(start, max_chunk)
610
570
  result_data << chunk
611
571
  start += max_chunk
612
572
  end
613
573
 
614
- if remain > 0
615
- if @verbose
616
- puts "recieve chunk: prepare data size is #{remain}"
617
- end
574
+ if remain.positive?
575
+ puts "recieve chunk: prepare data size is #{remain}" if @verbose
618
576
  chunk = read_chunk(start, remain)
619
577
  result_data << chunk
620
578
  start += remain
@@ -623,9 +581,7 @@ module RBZK
623
581
  # Free data (equivalent to Python's self.free_data())
624
582
  free_data
625
583
 
626
- if @verbose
627
- puts "_read w/chunk #{start} bytes"
628
- end
584
+ puts "_read w/chunk #{start} bytes" if @verbose
629
585
 
630
586
  # In Python: return b''.join(data), start
631
587
  result = result_data.join
@@ -635,8 +591,8 @@ module RBZK
635
591
  # Helper method to get data size from the current data
636
592
  def get_data_size
637
593
  if @data && @data.size >= 4
638
- size = @data[0...4].unpack('L<')[0]
639
- size
594
+ @data[0...4].unpack1('L<')
595
+
640
596
  else
641
597
  0
642
598
  end
@@ -650,12 +606,12 @@ module RBZK
650
606
  puts "tcp_length #{tcp_length}, size #{size}" if @verbose
651
607
 
652
608
  if tcp_length <= 0
653
- puts "Incorrect tcp packet" if @verbose
654
- return nil, "".b
609
+ puts 'Incorrect tcp packet' if @verbose
610
+ return nil, ''.b
655
611
  end
656
612
 
657
613
  if (tcp_length - 8) < size
658
- puts "tcp length too small... retrying" if @verbose
614
+ puts 'tcp length too small... retrying' if @verbose
659
615
 
660
616
  # Recursive call to handle smaller packet
661
617
  resp, bh = receive_tcp_data(data_recv, tcp_length - 8)
@@ -684,7 +640,7 @@ module RBZK
684
640
 
685
641
  # In Python: response = unpack('HHHH', data_recv[8:16])[0]
686
642
  # This unpacks 4 shorts (8 bytes) but only uses the first one
687
- response = data_recv[8...16].unpack('S<S<S<S<')[0]
643
+ response = data_recv[8...16].unpack1('S<S<S<S<')
688
644
 
689
645
  if received >= (size + 32)
690
646
  if response == CMD_DATA
@@ -692,28 +648,26 @@ module RBZK
692
648
 
693
649
  puts "resp complete len #{resp.size}" if @verbose
694
650
 
695
- return resp, data_recv[(size + 16)..]
651
+ [ resp, data_recv[(size + 16)..-1] ]
696
652
  else
697
653
  puts "incorrect response!!! #{response}" if @verbose
698
654
 
699
- return nil, "".b
655
+ [ nil, ''.b ]
700
656
  end
701
657
  else
702
658
  puts "try DATA incomplete (actual valid #{received - 16})" if @verbose
703
659
 
704
660
  data << data_recv[16...(size + 16)]
705
661
  size -= received - 16
706
- broken_header = "".b
662
+ broken_header = ''.b
707
663
 
708
- if size < 0
709
- broken_header = data_recv[size..]
664
+ if size.negative?
665
+ broken_header = data_recv[size..-1]
710
666
 
711
- if @verbose
712
- puts "broken: #{broken_header.bytes.map { |b| format('%02x', b) }.join}"
713
- end
667
+ puts "broken: #{broken_header.bytes.map { |b| format('%02x', b) }.join}" if @verbose
714
668
  end
715
669
 
716
- if size > 0
670
+ if size.positive?
717
671
  data_recv = receive_raw_data(size)
718
672
  data << data_recv
719
673
  end
@@ -732,14 +686,14 @@ module RBZK
732
686
  need = (@tcp_length - 8) - @data.size
733
687
  puts "need more data: #{need}" if @verbose
734
688
  more_data = receive_raw_data(need)
735
- return @data + more_data
689
+ @data + more_data
736
690
  else
737
- puts "Enough data" if @verbose
738
- return @data
691
+ puts 'Enough data' if @verbose
692
+ @data
739
693
  end
740
694
  else
741
695
  puts "_rc len is #{@data.size}" if @verbose
742
- return @data
696
+ @data
743
697
  end
744
698
  elsif @response == CMD_PREPARE_DATA
745
699
  data = []
@@ -749,10 +703,10 @@ module RBZK
749
703
 
750
704
  if @tcp
751
705
  if @data.size >= (8 + size)
752
- data_recv = @data[8..]
706
+ data_recv = @data[8..-1]
753
707
  else
754
708
  # [80, 80, 130, 125, 92, 7, 0, 0, 221, 5, 142, 172, 0, 0, 4, 0, 80, 7, 0, 0, 1, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 65, 98, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 2, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 65, 110, 97, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 50, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 111, 110, 100, 111, 115, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 51, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 116, 97, 0, 111, 115, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 52, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 97, 121, 115, 0, 115, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 53, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 97, 119, 97, 110, 0, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 54, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 101, 110, 97, 110, 0, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 55, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 97, 114, 97, 104, 0, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 56, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 97, 98, 114, 101, 101, 110, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 57, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 97, 101, 101, 100, 0, 110, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 48, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 111, 102, 114, 97, 110, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 49, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 97, 110, 105, 97, 0, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 50, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 97, 109, 105, 97, 0, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 51, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 101, 101, 109, 0, 0, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 52, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 97, 108, 97, 97, 0, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 53, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 97, 110, 101, 101, 109, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 54, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 108, 97, 0, 101, 109, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 55, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 97, 114, 97, 104, 0, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 56, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 111, 110, 100, 111, 115, 72, 65, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 57, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 111, 0, 100, 111, 115, 72, 65, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 52, 53, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 119, 115, 0, 111, 115, 72, 65, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 52, 54, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 97, 109, 97, 114, 97, 0, 65, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 52, 53, 50, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 97, 115, 110, 101, 101, 109, 0, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 50, 48, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 115, 114, 97, 97, 0, 109, 0, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 50, 49, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 97, 114, 97, 106, 0, 109, 0, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 50, 49, 51, 53, 0, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 108, 97, 97, 110, 97, 115, 115, 101, 114, 0, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 50, 50, 0, 53, 0, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 80, 80, 130, 125, 8, 0, 0, 0, 208, 7, 73, 81, 226, 166, 4, 0]
755
- data_recv = @data[8..] + @socket.recv(size + 32)
709
+ data_recv = @data[8..-1] + @socket.recv(size + 32)
756
710
  end
757
711
 
758
712
  puts "data_recv: #{python_format(data_recv)}" if @verbose
@@ -762,36 +716,30 @@ module RBZK
762
716
  data << resp if resp
763
717
 
764
718
  # get CMD_ACK_OK
765
- if broken_header.size < 16
766
- data_recv = broken_header + @socket.recv(16)
767
- else
768
- data_recv = broken_header
769
- end
719
+ data_recv = if broken_header.size < 16
720
+ broken_header + @socket.recv(16)
721
+ else
722
+ broken_header
723
+ end
770
724
 
771
725
  if data_recv.size < 16
772
726
  puts "trying to complete broken ACK #{data_recv.size} /16"
773
- if @verbose
774
- puts "data_recv: #{data_recv.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
775
- end
727
+ puts "data_recv: #{data_recv.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}" if @verbose
776
728
  data_recv += @socket.recv(16 - data_recv.size) # TODO: CHECK HERE_!
777
729
  end
778
730
 
779
- if !test_tcp_top(data_recv)
780
- if @verbose
781
- puts "invalid chunk tcp ACK OK"
782
- end
731
+ unless test_tcp_top(data_recv)
732
+ puts 'invalid chunk tcp ACK OK' if @verbose
783
733
  return nil
784
734
  end
785
735
 
786
736
  # In Python: response = unpack('HHHH', data_recv[8:16])[0]
787
737
  # This unpacks 4 shorts (8 bytes) but only uses the first one
788
738
  # In Ruby, we need to use 'S<4' to unpack 4 shorts in little-endian format
789
- response = data_recv[8...16].unpack('S<4')[0]
739
+ response = data_recv[8...16].unpack1('S<4')
790
740
 
791
741
  if response == CMD_ACK_OK
792
- if @verbose
793
- puts "chunk tcp ACK OK!"
794
- end
742
+ puts 'chunk tcp ACK OK!' if @verbose
795
743
  return data.join
796
744
  end
797
745
 
@@ -800,40 +748,32 @@ module RBZK
800
748
  puts "data: #{data.map { |d| format_as_python_bytes(d) }.join(', ')}"
801
749
  end
802
750
 
803
- return nil
751
+ nil
804
752
  else
805
753
  # Non-TCP implementation
806
754
  loop do
807
755
  data_recv = @socket.recv(1024 + 8)
808
- response = data_recv[0...8].unpack('S<S<S<S<')[0]
756
+ response = data_recv[0...8].unpack1('S<S<S<S<')
809
757
 
810
- if @verbose
811
- puts "# packet response is: #{response}"
812
- end
758
+ puts "# packet response is: #{response}" if @verbose
813
759
 
814
760
  if response == CMD_DATA
815
- data << data_recv[8..]
761
+ data << data_recv[8..-1]
816
762
  size -= 1024
817
763
  elsif response == CMD_ACK_OK
818
764
  break
819
765
  else
820
- if @verbose
821
- puts "broken!"
822
- end
766
+ puts 'broken!' if @verbose
823
767
  break
824
768
  end
825
769
 
826
- if @verbose
827
- puts "still needs #{size}"
828
- end
770
+ puts "still needs #{size}" if @verbose
829
771
  end
830
772
 
831
- return data.join
773
+ data.join
832
774
  end
833
775
  else
834
- if @verbose
835
- puts "invalid response #{@response}"
836
- end
776
+ puts "invalid response #{@response}" if @verbose
837
777
  nil
838
778
  end
839
779
  end
@@ -841,27 +781,21 @@ module RBZK
841
781
  # Helper method to receive raw data (like Python's __recieve_raw_data)
842
782
  def receive_raw_data(size)
843
783
  data = []
844
- if @verbose
845
- puts "expecting #{size} bytes raw data"
846
- end
784
+ puts "expecting #{size} bytes raw data" if @verbose
847
785
 
848
- while size > 0
786
+ while size.positive?
849
787
  data_recv = @socket.recv(size)
850
788
  received = data_recv.size
851
789
 
852
790
  if @verbose
853
791
  puts "partial recv #{received}"
854
- if received < 100
855
- puts " recv #{data_recv.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
856
- end
792
+ puts " recv #{data_recv.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}" if received < 100
857
793
  end
858
794
 
859
795
  data << data_recv
860
796
  size -= received
861
797
 
862
- if @verbose
863
- puts "still need #{size}"
864
- end
798
+ puts "still need #{size}" if @verbose
865
799
  end
866
800
 
867
801
  data.join
@@ -870,13 +804,11 @@ module RBZK
870
804
  # Helper method to clear buffer (like Python's free_data)
871
805
  def free_data
872
806
  command = CMD_FREE_DATA
873
- response = self.send_command(command)
807
+ response = send_command(command)
874
808
 
875
- if response && response[:status]
876
- true
877
- else
878
- raise RBZK::ZKErrorResponse, "Can't free data"
879
- end
809
+ raise RBZK::ZKErrorResponse, "Can't free data" unless response && response[:status]
810
+
811
+ true
880
812
  end
881
813
 
882
814
  # Send data with buffer
@@ -885,15 +817,13 @@ module RBZK
885
817
  def send_with_buffer(buffer)
886
818
  max_chunk = 1024
887
819
  size = buffer.size
888
- self.free_data
820
+ free_data
889
821
 
890
822
  command = CMD_PREPARE_DATA
891
- command_string = [size].pack('L<')
892
- response = self.send_command(command, command_string)
823
+ command_string = [ size ].pack('L<')
824
+ response = send_command(command, command_string)
893
825
 
894
- if !response || !response[:status]
895
- raise RBZK::ZKErrorResponse, "Can't prepare data"
896
- end
826
+ raise RBZK::ZKErrorResponse, "Can't prepare data" if !response || !response[:status]
897
827
 
898
828
  remain = size % max_chunk
899
829
  packets = (size - remain) / max_chunk
@@ -904,7 +834,7 @@ module RBZK
904
834
  start += max_chunk
905
835
  end
906
836
 
907
- send_chunk(buffer[start, remain]) if remain > 0
837
+ send_chunk(buffer[start, remain]) if remain.positive?
908
838
 
909
839
  true
910
840
  end
@@ -914,22 +844,18 @@ module RBZK
914
844
  # @return [Boolean] true if successful, raises exception otherwise
915
845
  def send_chunk(command_string)
916
846
  command = CMD_DATA
917
- response = self.send_command(command, command_string)
847
+ response = send_command(command, command_string)
918
848
 
919
- if response && response[:status]
920
- true
921
- else
922
- raise RBZK::ZKErrorResponse, "Can't send chunk"
923
- end
849
+ raise RBZK::ZKErrorResponse, "Can't send chunk" unless response && response[:status]
850
+
851
+ true
924
852
  end
925
853
 
926
854
  # Helper method to read a chunk of data
927
855
  def read_chunk(start, size)
928
- if @verbose
929
- puts "Reading chunk: start=#{start}, size=#{size}"
930
- end
856
+ puts "Reading chunk: start=#{start}, size=#{size}" if @verbose
931
857
 
932
- 3.times do |_retries|
858
+ 3.times do |attempt|
933
859
  # In Python: command = const._CMD_READ_BUFFER (which is 1504)
934
860
  # In Ruby, we should use CMD_READ_BUFFER (1504) instead of CMD_READFILE_DATA (81)
935
861
  command = 1504 # CMD_READ_BUFFER
@@ -941,25 +867,21 @@ module RBZK
941
867
  response_size = @tcp ? size + 32 : 1024 + 8
942
868
 
943
869
  # In Python: cmd_response = self.__send_command(command, command_string, response_size)
944
- response = self.send_command(command, command_string, response_size)
870
+ response = send_command(command, command_string, response_size)
945
871
 
946
872
  if !response || !response[:status]
947
- if @verbose
948
- puts "Failed to read chunk on attempt #{_retries + 1}"
949
- end
873
+ puts "Failed to read chunk on attempt #{attempt + 1}" if @verbose
950
874
  next
951
875
  end
952
876
 
953
877
  # In Python: data = self.__recieve_chunk()
954
878
  data = receive_chunk
955
879
 
956
- if data
957
- if @verbose
958
- puts "Received chunk of #{data.size} bytes"
959
- end
880
+ next unless data
960
881
 
961
- return data
962
- end
882
+ puts "Received chunk of #{data.size} bytes" if @verbose
883
+
884
+ return data
963
885
  end
964
886
 
965
887
  # If we get here, all retries failed
@@ -968,12 +890,12 @@ module RBZK
968
890
 
969
891
  def get_users
970
892
  # Read sizes
971
- self.read_sizes
893
+ read_sizes
972
894
 
973
895
  puts "Device has #{@users} users" if @verbose
974
896
 
975
897
  # If no users, return empty array
976
- if @users == 0
898
+ if @users.zero?
977
899
  @next_uid = 1
978
900
  @next_user_id = '1'
979
901
  return []
@@ -981,46 +903,48 @@ module RBZK
981
903
 
982
904
  users = []
983
905
  max_uid = 0
984
- userdata, size = self.read_with_buffer(CMD_USERTEMP_RRQ, FCT_USER)
906
+ userdata, size = read_with_buffer(CMD_USERTEMP_RRQ, FCT_USER)
985
907
  puts "user size #{size} (= #{userdata.length})" if @verbose
986
908
 
987
909
  if size <= 4
988
- puts "WRN: missing user data"
910
+ puts 'WRN: missing user data'
989
911
  return []
990
912
  end
991
913
 
992
914
  total_size = userdata[0, 4].unpack1('L<')
993
915
  @user_packet_size = total_size / @users
994
916
 
995
- if ![ 28, 72 ].include?(@user_packet_size)
996
- puts "WRN packet size would be #{@user_packet_size}" if @verbose
997
- end
917
+ puts "WRN packet size would be #{@user_packet_size}" if ![ 28, 72 ].include?(@user_packet_size) && @verbose
998
918
 
999
919
  userdata = userdata[4..-1]
1000
920
 
1001
921
  if @user_packet_size == 28
1002
922
  while userdata.length >= 28
1003
- uid, privilege, password, name, card, group_id, timezone, user_id = userdata.ljust(28, "\x00")[0, 28].unpack('S<Ca5a8L<xCs<L<')
923
+ uid, privilege, password, name, card, group_id, timezone, user_id = userdata.ljust(28, "\x00")[0,
924
+ 28].unpack('S<Ca5a8L<xCs<L<')
1004
925
  max_uid = uid if uid > max_uid
1005
926
  password = password.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)
1006
927
  name = name.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)&.strip
1007
928
  group_id = group_id.to_s
1008
929
  user_id = user_id.to_s
1009
- name = "NN-#{user_id}" if !name
930
+ name ||= "NN-#{user_id}"
1010
931
  user = User.new(uid, name, privilege, password, group_id, user_id, card)
1011
932
  users << user
1012
- puts "[6]user: #{uid}, #{privilege}, #{password}, #{name}, #{card}, #{group_id}, #{timezone}, #{user_id}" if @verbose
933
+ if @verbose
934
+ puts "[6]user: #{uid}, #{privilege}, #{password}, #{name}, #{card}, #{group_id}, #{timezone}, #{user_id}"
935
+ end
1013
936
  userdata = userdata[28..-1]
1014
937
  end
1015
938
  else
1016
939
  while userdata.length >= 72
1017
- uid, privilege, password, name, card, group_id, user_id = userdata.ljust(72, "\x00")[0, 72].unpack('S<Ca8a24L<xa7xa24')
940
+ uid, privilege, password, name, card, group_id, user_id = userdata.ljust(72, "\x00")[0,
941
+ 72].unpack('S<Ca8a24L<xa7xa24')
1018
942
  max_uid = uid if uid > max_uid
1019
943
  password = password.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)
1020
944
  name = name.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)&.strip
1021
945
  group_id = group_id.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)&.strip
1022
946
  user_id = user_id.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)
1023
- name = "NN-#{user_id}" if !name
947
+ name ||= "NN-#{user_id}"
1024
948
  user = User.new(uid, name, privilege, password, group_id, user_id, card)
1025
949
  users << user
1026
950
  userdata = userdata[72..-1]
@@ -1032,12 +956,10 @@ module RBZK
1032
956
  @next_user_id = max_uid.to_s
1033
957
 
1034
958
  loop do
1035
- if users.any? { |u| u.user_id == @next_user_id }
1036
- max_uid += 1
1037
- @next_user_id = max_uid.to_s
1038
- else
1039
- break
1040
- end
959
+ break unless users.any? { |u| u.user_id == @next_user_id }
960
+
961
+ max_uid += 1
962
+ @next_user_id = max_uid.to_s
1041
963
  end
1042
964
 
1043
965
  users
@@ -1045,41 +967,33 @@ module RBZK
1045
967
 
1046
968
  def get_attendance_logs
1047
969
  # First, read device sizes to get record count
1048
- self.read_sizes
970
+ read_sizes
1049
971
 
1050
972
  # If no records, return empty array
1051
- if @records == 0
1052
- return []
1053
- end
973
+ return [] if @records.zero?
1054
974
 
1055
975
  # Get users for lookup
1056
- users = self.get_users
976
+ users = get_users
1057
977
 
1058
- if @verbose
1059
- puts "Found #{users.size} users"
1060
- end
978
+ puts "Found #{users.size} users" if @verbose
1061
979
 
1062
980
  logs = []
1063
981
 
1064
982
  # Read attendance data with buffer
1065
- attendance_data, size = self.read_with_buffer(CMD_ATTLOG_RRQ)
983
+ attendance_data, size = read_with_buffer(CMD_ATTLOG_RRQ)
1066
984
 
1067
985
  if size < 4
1068
- if @verbose
1069
- puts "WRN: no attendance data"
1070
- end
986
+ puts 'WRN: no attendance data' if @verbose
1071
987
  return []
1072
988
  end
1073
989
 
1074
990
  # Get total size from first 4 bytes
1075
- total_size = attendance_data[0...4].unpack('I')[0]
991
+ total_size = attendance_data[0...4].unpack1('I')
1076
992
 
1077
993
  # Calculate record size
1078
- record_size = @records > 0 ? total_size / @records : 0
994
+ record_size = @records.positive? ? total_size / @records : 0
1079
995
 
1080
- if @verbose
1081
- puts "record_size is #{record_size}"
1082
- end
996
+ puts "record_size is #{record_size}" if @verbose
1083
997
 
1084
998
  # Remove the first 4 bytes (total size)
1085
999
  attendance_data = attendance_data[4..-1]
@@ -1091,18 +1005,20 @@ module RBZK
1091
1005
  uid, status, timestamp_raw, punch = attendance_data[0...8].ljust(8, "\x00".b).unpack('S<C4sC')
1092
1006
 
1093
1007
  if @verbose
1094
- puts "Attendance data (hex): #{attendance_data[0...8].bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1008
+ puts "Attendance data (hex): #{attendance_data[0...8].bytes.map do |b|
1009
+ "0x#{b.to_s(16).rjust(2, '0')}"
1010
+ end.join(' ')}"
1095
1011
  end
1096
1012
 
1097
1013
  attendance_data = attendance_data[8..-1]
1098
1014
 
1099
1015
  # Look up user by uid
1100
1016
  tuser = users.find { |u| u.uid == uid }
1101
- if !tuser
1102
- user_id = uid.to_s
1103
- else
1104
- user_id = tuser.user_id
1105
- end
1017
+ user_id = if !tuser
1018
+ uid.to_s
1019
+ else
1020
+ tuser.user_id
1021
+ end
1106
1022
 
1107
1023
  # Decode timestamp
1108
1024
  timestamp = decode_time(timestamp_raw)
@@ -1115,10 +1031,13 @@ module RBZK
1115
1031
  # Handle 16-byte records
1116
1032
  while attendance_data && attendance_data.size >= 16
1117
1033
  # In Python: user_id, timestamp, status, punch, reserved, workcode = unpack('<I4sBB2sI', attendance_data.ljust(16, b'\x00')[:16])
1118
- user_id_raw, timestamp_raw, status, punch, reserved, workcode = attendance_data[0...16].ljust(16, "\x00".b).unpack('L<4sCCa2L<')
1034
+ user_id_raw, timestamp_raw, status, punch, _reserved, _workcode = attendance_data[0...16].ljust(16,
1035
+ "\x00".b).unpack('L<4sCCa2L<')
1119
1036
 
1120
1037
  if @verbose
1121
- puts "Attendance data (hex): #{attendance_data[0...16].bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1038
+ puts "Attendance data (hex): #{attendance_data[0...16].bytes.map do |b|
1039
+ "0x#{b.to_s(16).rjust(2, '0')}"
1040
+ end.join(' ')}"
1122
1041
  end
1123
1042
 
1124
1043
  attendance_data = attendance_data[16..-1]
@@ -1129,9 +1048,7 @@ module RBZK
1129
1048
  # Look up user by user_id and uid
1130
1049
  tuser = users.find { |u| u.user_id == user_id }
1131
1050
  if !tuser
1132
- if @verbose
1133
- puts "no uid #{user_id}"
1134
- end
1051
+ puts "no uid #{user_id}" if @verbose
1135
1052
  uid = user_id
1136
1053
  tuser = users.find { |u| u.uid.to_s == user_id }
1137
1054
  if !tuser
@@ -1155,10 +1072,13 @@ module RBZK
1155
1072
  # Handle 40-byte records (default)
1156
1073
  while attendance_data && attendance_data.size >= 40
1157
1074
  # In Python: uid, user_id, status, timestamp, punch, space = unpack('<H24sB4sB8s', attendance_data.ljust(40, b'\x00')[:40])
1158
- uid, user_id_raw, status, timestamp_raw, punch, space = attendance_data[0...40].ljust(40, "\x00".b).unpack('S<a24Ca4Ca8')
1075
+ uid, user_id_raw, status, timestamp_raw, punch, _space = attendance_data[0...40].ljust(40,
1076
+ "\x00".b).unpack('S<a24Ca4Ca8')
1159
1077
 
1160
1078
  if @verbose
1161
- puts "Attendance data (hex): #{attendance_data[0...40].bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1079
+ puts "Attendance data (hex): #{attendance_data[0...40].bytes.map do |b|
1080
+ "0x#{b.to_s(16).rjust(2, '0')}"
1081
+ end.join(' ')}"
1162
1082
  end
1163
1083
 
1164
1084
  # Extract user_id from null-terminated string
@@ -1180,23 +1100,23 @@ module RBZK
1180
1100
 
1181
1101
  def decode_time(t)
1182
1102
  # Convert binary timestamp to integer
1183
- t = t.unpack("L<")[0]
1103
+ t = t.unpack1('L<')
1184
1104
 
1185
1105
  # Extract time components
1186
1106
  second = t % 60
1187
- t = t / 60
1107
+ t /= 60
1188
1108
 
1189
1109
  minute = t % 60
1190
- t = t / 60
1110
+ t /= 60
1191
1111
 
1192
1112
  hour = t % 24
1193
- t = t / 24
1113
+ t /= 24
1194
1114
 
1195
1115
  day = t % 31 + 1
1196
- t = t / 31
1116
+ t /= 31
1197
1117
 
1198
1118
  month = t % 12 + 1
1199
- t = t / 12
1119
+ t /= 12
1200
1120
 
1201
1121
  year = t + 2000
1202
1122
 
@@ -1208,7 +1128,7 @@ module RBZK
1208
1128
  # Match Python's __decode_timehex method
1209
1129
  def decode_timehex(timehex)
1210
1130
  # Extract time components
1211
- year, month, day, hour, minute, second = timehex.unpack("C6")
1131
+ year, month, day, hour, minute, second = timehex.unpack('C6')
1212
1132
  year += 2000
1213
1133
 
1214
1134
  # Create Time object
@@ -1217,23 +1137,20 @@ module RBZK
1217
1137
 
1218
1138
  def encode_time(t)
1219
1139
  # Calculate encoded timestamp
1220
- d = (
1140
+ (
1221
1141
  ((t.year % 100) * 12 * 31 + ((t.month - 1) * 31) + t.day - 1) *
1222
1142
  (24 * 60 * 60) + (t.hour * 60 + t.minute) * 60 + t.second
1223
1143
  )
1224
- d
1225
1144
  end
1226
1145
 
1227
1146
  def get_time
1228
1147
  command = CMD_GET_TIME
1229
1148
  response_size = 1032
1230
- response = self.send_command(command, "", response_size)
1149
+ response = send_command(command, '', response_size)
1231
1150
 
1232
- if response && response[:status]
1233
- decode_time(@data[0...4])
1234
- else
1235
- raise RBZK::ZKErrorResponse, "Can't get time"
1236
- end
1151
+ raise RBZK::ZKErrorResponse, "Can't get time" unless response && response[:status]
1152
+
1153
+ decode_time(@data[0...4])
1237
1154
  end
1238
1155
 
1239
1156
  def set_time(timestamp = nil)
@@ -1242,24 +1159,22 @@ module RBZK
1242
1159
 
1243
1160
  command = CMD_SET_TIME
1244
1161
  command_string = [ encode_time(timestamp) ].pack('L<')
1245
- response = self.send_command(command, command_string)
1162
+ response = send_command(command, command_string)
1246
1163
 
1247
- if response && response[:status]
1248
- true
1249
- else
1250
- raise RBZK::ZKErrorResponse, "Can't set time"
1251
- end
1164
+ raise RBZK::ZKErrorResponse, "Can't set time" unless response && response[:status]
1165
+
1166
+ true
1252
1167
  end
1253
1168
 
1254
1169
  def clear_attendance_logs
1255
- self.send_command(CMD_CLEAR_ATTLOG)
1256
- self.recv_reply
1170
+ send_command(CMD_CLEAR_ATTLOG)
1171
+ recv_reply
1257
1172
  true
1258
1173
  end
1259
1174
 
1260
1175
  def clear_data
1261
- self.send_command(CMD_CLEAR_DATA)
1262
- self.recv_reply
1176
+ send_command(CMD_CLEAR_DATA)
1177
+ recv_reply
1263
1178
  true
1264
1179
  end
1265
1180
 
@@ -1269,33 +1184,33 @@ module RBZK
1269
1184
 
1270
1185
  result = "b'"
1271
1186
  binary_string.each_byte do |byte|
1272
- case byte
1273
- when 0x0d # Carriage return - Python shows as \r
1274
- result += "\\r"
1275
- when 0x0a # Line feed - Python shows as \n
1276
- result += "\\n"
1277
- when 0x09 # Tab - Python shows as \t
1278
- result += "\\t"
1279
- when 0x07 # Bell - Python can show as \a or \x07
1280
- result += "\\x07"
1281
- when 0x08 # Backspace - Python shows as \b
1282
- result += "\\b"
1283
- when 0x0c # Form feed - Python shows as \f
1284
- result += "\\f"
1285
- when 0x0b # Vertical tab - Python shows as \v
1286
- result += "\\v"
1287
- when 0x5c # Backslash - Python shows as \\
1288
- result += "\\\\"
1289
- when 0x27 # Single quote - Python shows as \'
1290
- result += "\\'"
1291
- when 0x22 # Double quote - Python shows as \"
1292
- result += "\\\""
1293
- when 32..126 # Printable ASCII
1294
- result += byte.chr
1295
- else
1296
- # All other bytes - Python shows as \xHH
1297
- result += "\\x#{byte.to_s(16).rjust(2, '0')}"
1298
- end
1187
+ result += case byte
1188
+ when 0x0d # Carriage return - Python shows as \r
1189
+ '\\r'
1190
+ when 0x0a # Line feed - Python shows as \n
1191
+ '\\n'
1192
+ when 0x09 # Tab - Python shows as \t
1193
+ '\\t'
1194
+ when 0x07 # Bell - Python can show as \a or \x07
1195
+ '\\x07'
1196
+ when 0x08 # Backspace - Python shows as \b
1197
+ '\\b'
1198
+ when 0x0c # Form feed - Python shows as \f
1199
+ '\\f'
1200
+ when 0x0b # Vertical tab - Python shows as \v
1201
+ '\\v'
1202
+ when 0x5c # Backslash - Python shows as \\
1203
+ '\\\\'
1204
+ when 0x27 # Single quote - Python shows as \'
1205
+ "\\'"
1206
+ when 0x22 # Double quote - Python shows as \"
1207
+ '\"'
1208
+ when 32..126 # Printable ASCII
1209
+ byte.chr
1210
+ else
1211
+ # All other bytes - Python shows as \xHH
1212
+ "\\x#{byte.to_s(16).rjust(2, '0')}"
1213
+ end
1299
1214
  end
1300
1215
  result += "'"
1301
1216
  result
@@ -1310,7 +1225,7 @@ module RBZK
1310
1225
  puts "Python expected: #{python_expected}"
1311
1226
 
1312
1227
  if ruby_formatted != python_expected
1313
- puts "DIFFERENCE DETECTED!"
1228
+ puts 'DIFFERENCE DETECTED!'
1314
1229
  # Show byte-by-byte comparison
1315
1230
  ruby_bytes = binary_string.bytes
1316
1231
  # Parse Python bytes string (format: b'\x01\x02')
@@ -1346,16 +1261,27 @@ module RBZK
1346
1261
  end
1347
1262
 
1348
1263
  # Show differences
1349
- puts "Byte-by-byte comparison:"
1264
+ puts 'Byte-by-byte comparison:'
1350
1265
  max_len = [ ruby_bytes.length, python_bytes.length ].max
1351
1266
  (0...max_len).each do |j|
1352
1267
  ruby_byte = j < ruby_bytes.length ? ruby_bytes[j] : nil
1353
1268
  python_byte = j < python_bytes.length ? python_bytes[j] : nil
1354
- match = ruby_byte == python_byte ? "" : ""
1355
- puts " Byte #{j}: Ruby=#{ruby_byte.nil? ? 'nil' : "0x#{ruby_byte.to_s(16).rjust(2, '0')}"}, Python=#{python_byte.nil? ? 'nil' : "0x#{python_byte.to_s(16).rjust(2, '0')}"} #{match}"
1269
+ match = ruby_byte == python_byte ? '' : ''
1270
+ puts " Byte #{j}: Ruby=#{if ruby_byte.nil?
1271
+ 'nil'
1272
+ else
1273
+ "0x#{ruby_byte.to_s(16).rjust(2,
1274
+ '0')}"
1275
+ end}, Python=#{if python_byte.nil?
1276
+ 'nil'
1277
+ else
1278
+ "0x#{python_byte.to_s(16).rjust(
1279
+ 2, '0'
1280
+ )}"
1281
+ end} #{match}"
1356
1282
  end
1357
1283
  else
1358
- puts "Binary data matches exactly!"
1284
+ puts 'Binary data matches exactly!'
1359
1285
  end
1360
1286
  end
1361
1287
 
@@ -1373,70 +1299,62 @@ module RBZK
1373
1299
  def read_sizes
1374
1300
  command = CMD_GET_FREE_SIZES
1375
1301
  response_size = 1024
1376
- cmd_response = self.send_command(command, "", response_size)
1302
+ cmd_response = send_command(command, '', response_size)
1377
1303
 
1378
- if cmd_response && cmd_response[:status]
1379
- if @verbose
1380
- puts "Data hex: #{@data.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1381
- puts "Data Python format: #{python_format(@data)}"
1304
+ raise RBZK::ZKErrorResponse, "Can't read sizes" unless cmd_response && cmd_response[:status]
1305
+
1306
+ if @verbose
1307
+ puts "Data hex: #{@data.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1308
+ puts "Data Python format: #{python_format(@data)}"
1309
+ end
1310
+
1311
+ size = @data.size
1312
+ puts "Data size: #{size} bytes" if @verbose
1313
+
1314
+ if @data.size >= 80
1315
+ # In Python: fields = unpack('20i', self.__data[:80])
1316
+ # In Ruby, 'l<' is a signed 32-bit integer (4 bytes) in little-endian format, which matches Python's 'i'
1317
+ fields = @data[0...80].unpack('l<20')
1318
+
1319
+ puts "Unpacked fields: #{fields.inspect}" if @verbose
1320
+
1321
+ @users = fields[4]
1322
+ @fingers = fields[6]
1323
+ @records = fields[8]
1324
+ @dummy = fields[10] # ???
1325
+ @cards = fields[12]
1326
+ @fingers_cap = fields[14]
1327
+ @users_cap = fields[15]
1328
+ @rec_cap = fields[16]
1329
+ @fingers_av = fields[17]
1330
+ @users_av = fields[18]
1331
+ @rec_av = fields[19]
1332
+ @data = @data[80..-1]
1333
+
1334
+ # Check for face information (added to match Python implementation)
1335
+ if @data.size >= 12 # face info
1336
+ # In Python: fields = unpack('3i', self.__data[:12]) #dirty hack! we need more information
1337
+ face_fields = @data[0...12].unpack('l<3')
1338
+ @faces = face_fields[0]
1339
+ @faces_cap = face_fields[2]
1340
+
1341
+ puts "Face info: faces=#{@faces}, capacity=#{@faces_cap}" if @verbose
1382
1342
  end
1383
1343
 
1384
- size = @data.size
1385
1344
  if @verbose
1386
- puts "Data size: #{size} bytes"
1345
+ puts "Device info: users=#{@users}, fingers=#{@fingers}, records=#{@records}"
1346
+ puts "Capacity: users=#{@users_cap}, fingers=#{@fingers_cap}, records=#{@rec_cap}"
1387
1347
  end
1388
1348
 
1389
- if @data.size >= 80
1390
- # In Python: fields = unpack('20i', self.__data[:80])
1391
- # In Ruby, 'l<' is a signed 32-bit integer (4 bytes) in little-endian format, which matches Python's 'i'
1392
- fields = @data[0...80].unpack('l<20')
1393
-
1394
- if @verbose
1395
- puts "Unpacked fields: #{fields.inspect}"
1396
- end
1397
-
1398
- @users = fields[4]
1399
- @fingers = fields[6]
1400
- @records = fields[8]
1401
- @dummy = fields[10] # ???
1402
- @cards = fields[12]
1403
- @fingers_cap = fields[14]
1404
- @users_cap = fields[15]
1405
- @rec_cap = fields[16]
1406
- @fingers_av = fields[17]
1407
- @users_av = fields[18]
1408
- @rec_av = fields[19]
1409
- @data = @data[80..-1]
1410
-
1411
- # Check for face information (added to match Python implementation)
1412
- if @data.size >= 12 # face info
1413
- # In Python: fields = unpack('3i', self.__data[:12]) #dirty hack! we need more information
1414
- face_fields = @data[0...12].unpack('l<3')
1415
- @faces = face_fields[0]
1416
- @faces_cap = face_fields[2]
1417
-
1418
- if @verbose
1419
- puts "Face info: faces=#{@faces}, capacity=#{@faces_cap}"
1420
- end
1421
- end
1422
-
1423
- if @verbose
1424
- puts "Device info: users=#{@users}, fingers=#{@fingers}, records=#{@records}"
1425
- puts "Capacity: users=#{@users_cap}, fingers=#{@fingers_cap}, records=#{@rec_cap}"
1426
- end
1427
-
1428
- return true
1429
- end
1430
- else
1431
- raise RBZK::ZKErrorResponse, "Can't read sizes"
1349
+ return true
1432
1350
  end
1433
1351
 
1434
1352
  false
1435
1353
  end
1436
1354
 
1437
1355
  def get_free_sizes
1438
- self.send_command(CMD_GET_FREE_SIZES)
1439
- reply = self.recv_reply
1356
+ send_command(CMD_GET_FREE_SIZES)
1357
+ reply = recv_reply
1440
1358
 
1441
1359
  if reply && reply.size >= 8
1442
1360
  sizes_data = reply[8..-1].unpack('S<*')
@@ -1456,11 +1374,11 @@ module RBZK
1456
1374
  def get_templates
1457
1375
  fingers = []
1458
1376
 
1459
- self.send_command(CMD_PREPARE_DATA, [ FCT_FINGERTMP ].pack('C'))
1460
- self.recv_reply
1377
+ send_command(CMD_PREPARE_DATA, [ FCT_FINGERTMP ].pack('C'))
1378
+ recv_reply
1461
1379
 
1462
- data_size = self.recv_long
1463
- templates_data = self.recv_chunk(data_size)
1380
+ data_size = recv_long
1381
+ templates_data = recv_chunk(data_size)
1464
1382
 
1465
1383
  if templates_data && !templates_data.empty?
1466
1384
  offset = 0
@@ -1480,8 +1398,8 @@ module RBZK
1480
1398
  end
1481
1399
 
1482
1400
  def get_user_template(uid, finger_id)
1483
- self.send_command(CMD_GET_USERTEMP, [ uid, finger_id ].pack('S<S<'))
1484
- reply = self.recv_reply
1401
+ send_command(CMD_GET_USERTEMP, [ uid, finger_id ].pack('S<S<'))
1402
+ reply = recv_reply
1485
1403
 
1486
1404
  if reply && reply.size >= 8
1487
1405
  template_data = reply[8..-1]
@@ -1512,9 +1430,7 @@ module RBZK
1512
1430
  # Use connect_ex like Python (returns error code instead of raising exception)
1513
1431
  sockaddr = Socket.pack_sockaddr_in(@port, @ip)
1514
1432
  @socket.connect_nonblock(sockaddr)
1515
- if @verbose
1516
- puts "TCP socket connected successfully"
1517
- end
1433
+ puts 'TCP socket connected successfully' if @verbose
1518
1434
  rescue IO::WaitWritable
1519
1435
  # Socket is in progress of connecting
1520
1436
  ready = IO.select(nil, [ @socket ], nil, @timeout)
@@ -1523,42 +1439,30 @@ module RBZK
1523
1439
  @socket.connect_nonblock(sockaddr)
1524
1440
  rescue Errno::EISCONN
1525
1441
  # Already connected, which is fine
1526
- if @verbose
1527
- puts "TCP socket connected successfully"
1528
- end
1529
- rescue => e
1442
+ puts 'TCP socket connected successfully' if @verbose
1443
+ rescue StandardError => e
1530
1444
  # Connection failed
1531
- if @verbose
1532
- puts "TCP socket connection failed: #{e.message}"
1533
- end
1445
+ puts "TCP socket connection failed: #{e.message}" if @verbose
1534
1446
  raise e
1535
1447
  end
1536
1448
  else
1537
1449
  # Connection timed out
1538
- if @verbose
1539
- puts "TCP socket connection timed out"
1540
- end
1450
+ puts 'TCP socket connection timed out' if @verbose
1541
1451
  raise Errno::ETIMEDOUT
1542
1452
  end
1543
1453
  rescue Errno::EISCONN
1544
1454
  # Already connected, which is fine
1545
- if @verbose
1546
- puts "TCP socket already connected"
1547
- end
1455
+ puts 'TCP socket already connected' if @verbose
1548
1456
  end
1549
1457
  else
1550
1458
  # Create UDP socket (like Python's socket(AF_INET, SOCK_DGRAM))
1551
1459
  @socket = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM)
1552
1460
  @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, [ @timeout, 0 ].pack('l_*'))
1553
1461
 
1554
- if @verbose
1555
- puts "UDP socket created successfully"
1556
- end
1557
- end
1558
- rescue => e
1559
- if @verbose
1560
- puts "Socket creation failed: #{e.message}"
1462
+ puts 'UDP socket created successfully' if @verbose
1561
1463
  end
1464
+ rescue StandardError => e
1465
+ puts "Socket creation failed: #{e.message}" if @verbose
1562
1466
  raise RBZK::ZKNetworkError, "Failed to create socket: #{e.message}"
1563
1467
  end
1564
1468
 
@@ -1584,24 +1488,18 @@ module RBZK
1584
1488
  end
1585
1489
 
1586
1490
  def ping
1587
- if @verbose
1588
- puts "Pinging device at #{@ip}:#{@port}..."
1589
- end
1491
+ puts "Pinging device at #{@ip}:#{@port}..." if @verbose
1590
1492
 
1591
1493
  # Try TCP ping first
1592
1494
  begin
1593
1495
  Timeout.timeout(5) do
1594
1496
  s = TCPSocket.new(@ip, @port)
1595
1497
  s.close
1596
- if @verbose
1597
- puts "TCP ping successful"
1598
- end
1498
+ puts 'TCP ping successful' if @verbose
1599
1499
  return true
1600
1500
  end
1601
1501
  rescue Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTUNREACH => e
1602
- if @verbose
1603
- puts "TCP ping failed: #{e.message}"
1604
- end
1502
+ puts "TCP ping failed: #{e.message}" if @verbose
1605
1503
  end
1606
1504
 
1607
1505
  # If TCP ping fails, try UDP ping
@@ -1612,23 +1510,17 @@ module RBZK
1612
1510
  ready = IO.select([ udp_socket ], nil, nil, 5)
1613
1511
 
1614
1512
  if ready
1615
- if @verbose
1616
- puts "UDP ping successful"
1617
- end
1513
+ puts 'UDP ping successful' if @verbose
1618
1514
  udp_socket.close
1619
- return true
1515
+ true
1620
1516
  else
1621
- if @verbose
1622
- puts "UDP ping timed out"
1623
- end
1517
+ puts 'UDP ping timed out' if @verbose
1624
1518
  udp_socket.close
1625
- return false
1626
- end
1627
- rescue => e
1628
- if @verbose
1629
- puts "UDP ping failed: #{e.message}"
1519
+ false
1630
1520
  end
1631
- return false
1521
+ rescue StandardError => e
1522
+ puts "UDP ping failed: #{e.message}" if @verbose
1523
+ false
1632
1524
  end
1633
1525
  end
1634
1526
 
@@ -1647,24 +1539,18 @@ module RBZK
1647
1539
 
1648
1540
  # In Python: if checksum > const.USHRT_MAX: checksum -= const.USHRT_MAX
1649
1541
  # Handle overflow immediately after each addition
1650
- if checksum > USHRT_MAX
1651
- checksum -= USHRT_MAX
1652
- end
1542
+ checksum -= USHRT_MAX if checksum > USHRT_MAX
1653
1543
 
1654
1544
  l -= 2
1655
1545
  end
1656
1546
 
1657
1547
  # Handle odd byte if present
1658
1548
  # In Python: if l: checksum = checksum + p[-1]
1659
- if l > 0
1660
- checksum += buf[i]
1661
- end
1549
+ checksum += buf[i] if l.positive?
1662
1550
 
1663
1551
  # Handle overflow
1664
1552
  # In Python: while checksum > const.USHRT_MAX: checksum -= const.USHRT_MAX
1665
- while checksum > USHRT_MAX
1666
- checksum -= USHRT_MAX
1667
- end
1553
+ checksum -= USHRT_MAX while checksum > USHRT_MAX
1668
1554
 
1669
1555
  # Bitwise complement
1670
1556
  # In Python: checksum = ~checksum
@@ -1672,9 +1558,7 @@ module RBZK
1672
1558
 
1673
1559
  # Handle negative values
1674
1560
  # In Python: while checksum < 0: checksum += const.USHRT_MAX
1675
- while checksum < 0
1676
- checksum += USHRT_MAX
1677
- end
1561
+ checksum += USHRT_MAX while checksum.negative?
1678
1562
 
1679
1563
  # Return the checksum
1680
1564
  checksum
@@ -1683,6 +1567,7 @@ module RBZK
1683
1567
  # Helper method to debug binary data in both Python and Ruby formats
1684
1568
  def debug_binary(name, data)
1685
1569
  return unless @verbose
1570
+
1686
1571
  puts "#{name} (hex): #{data.bytes.map { |b| "\\x#{b.to_s(16).rjust(2, '0')}" }.join('')}"
1687
1572
  puts "#{name} (Ruby): #{data.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1688
1573
  puts "#{name} (Python): #{format_as_python_bytes(data)}"
@@ -1694,18 +1579,18 @@ module RBZK
1694
1579
  top = [ MACHINE_PREPARE_DATA_1, MACHINE_PREPARE_DATA_2, length ].pack('S<S<I<')
1695
1580
 
1696
1581
  if @verbose
1697
- puts "TCP header components:"
1582
+ puts 'TCP header components:'
1698
1583
  puts " MACHINE_PREPARE_DATA_1: 0x#{MACHINE_PREPARE_DATA_1.to_s(16)}"
1699
1584
  puts " MACHINE_PREPARE_DATA_2: 0x#{MACHINE_PREPARE_DATA_2.to_s(16)}"
1700
1585
  puts " packet length: #{length}"
1701
- debug_binary("TCP header", top)
1702
- debug_binary("Full TCP packet", top + packet)
1586
+ debug_binary('TCP header', top)
1587
+ debug_binary('Full TCP packet', top + packet)
1703
1588
  end
1704
1589
 
1705
1590
  top + packet
1706
1591
  end
1707
1592
 
1708
- def create_header(command, command_string = "".b, session_id = 0, reply_id = 0)
1593
+ def create_header(command, command_string = ''.b, session_id = 0, reply_id = 0)
1709
1594
  # Ensure command_string is a binary string
1710
1595
  command_string = command_string.to_s.b
1711
1596
 
@@ -1720,35 +1605,33 @@ module RBZK
1720
1605
 
1721
1606
  # Update reply_id
1722
1607
  reply_id += 1
1723
- if reply_id >= USHRT_MAX
1724
- reply_id -= USHRT_MAX
1725
- end
1608
+ reply_id -= USHRT_MAX if reply_id >= USHRT_MAX
1726
1609
 
1727
1610
  # Create final header with updated values
1728
1611
  buf = [ command, checksum, session_id, reply_id ].pack('v4')
1729
1612
 
1730
1613
  if @verbose
1731
- puts "Header components:"
1614
+ puts 'Header components:'
1732
1615
  puts " Command: #{command}"
1733
1616
  puts " Checksum: #{checksum}"
1734
1617
  puts " Session ID: #{session_id}"
1735
1618
  puts " Reply ID: #{reply_id}"
1736
1619
 
1737
1620
  if !command_string.empty?
1738
- debug_binary("Command string", command_string)
1621
+ debug_binary('Command string', command_string)
1739
1622
  else
1740
- puts "Command string: (empty)"
1623
+ puts 'Command string: (empty)'
1741
1624
  end
1742
- debug_binary("Final header", buf)
1625
+ debug_binary('Final header', buf)
1743
1626
  end
1744
1627
 
1745
1628
  buf + command_string
1746
1629
  end
1747
1630
 
1748
- def send_command(command, command_string = "".b, response_size = 8)
1631
+ def send_command(command, command_string = ''.b, response_size = 8)
1749
1632
  # Check connection status (except for connect and auth commands)
1750
1633
  if command != CMD_CONNECT && command != CMD_AUTH && !@connected
1751
- raise RBZK::ZKErrorConnection, "Instance are not connected."
1634
+ raise RBZK::ZKErrorConnection, 'Instance are not connected.'
1752
1635
  end
1753
1636
 
1754
1637
  # In Python, command_string is a bytes object (b'')
@@ -1782,9 +1665,9 @@ module RBZK
1782
1665
  if @verbose
1783
1666
  puts "\nSending TCP packet:"
1784
1667
  puts "Note: In send_command, 'top' variable contains the full packet (header + command packet)"
1785
- puts "This is because create_tcp_top returns the full packet, not just the header"
1786
- debug_binary("Command packet (buf)", buf)
1787
- debug_binary("Full TCP packet (top)", top) # 'top' contains the full packet here
1668
+ puts 'This is because create_tcp_top returns the full packet, not just the header'
1669
+ debug_binary('Command packet (buf)', buf)
1670
+ debug_binary('Full TCP packet (top)', top) # 'top' contains the full packet here
1788
1671
  end
1789
1672
 
1790
1673
  @socket.send(top, 0)
@@ -1793,12 +1676,10 @@ module RBZK
1793
1676
 
1794
1677
  if @verbose
1795
1678
  puts "\nReceived TCP response:"
1796
- debug_binary("TCP response", @tcp_data_recv)
1679
+ debug_binary('TCP response', @tcp_data_recv)
1797
1680
  end
1798
1681
 
1799
- if @tcp_length == 0
1800
- raise RBZK::ZKNetworkError, "TCP packet invalid"
1801
- end
1682
+ raise RBZK::ZKNetworkError, 'TCP packet invalid' if @tcp_length.zero?
1802
1683
 
1803
1684
  @header = @tcp_data_recv[8..15].unpack('v4')
1804
1685
  @data_recv = @tcp_data_recv[8..-1]
@@ -1808,10 +1689,8 @@ module RBZK
1808
1689
  @data_recv = @socket.recv(response_size)
1809
1690
  @header = @data_recv[0..7].unpack('S<4')
1810
1691
  end
1811
- rescue => e
1812
- if @verbose
1813
- puts "Connection error during send: #{e.message}"
1814
- end
1692
+ rescue StandardError => e
1693
+ puts "Connection error during send: #{e.message}" if @verbose
1815
1694
  raise RBZK::ZKNetworkError, e.message
1816
1695
  end
1817
1696
 
@@ -1836,9 +1715,7 @@ module RBZK
1836
1715
 
1837
1716
  def recv_reply
1838
1717
  begin
1839
- if @verbose
1840
- puts "Waiting for TCP reply"
1841
- end
1718
+ puts 'Waiting for TCP reply' if @verbose
1842
1719
 
1843
1720
  # Set a timeout for the read operation
1844
1721
  Timeout.timeout(5) do
@@ -1849,15 +1726,11 @@ module RBZK
1849
1726
  # Parse TCP header
1850
1727
  tcp_format1, tcp_format2, tcp_length = tcp_header.unpack('S<S<I<')
1851
1728
 
1852
- if @verbose
1853
- puts "TCP header: format1=#{tcp_format1}, format2=#{tcp_format2}, length=#{tcp_length}"
1854
- end
1729
+ puts "TCP header: format1=#{tcp_format1}, format2=#{tcp_format2}, length=#{tcp_length}" if @verbose
1855
1730
 
1856
1731
  # Verify TCP header format
1857
1732
  if tcp_format1 != MACHINE_PREPARE_DATA_1 || tcp_format2 != MACHINE_PREPARE_DATA_2
1858
- if @verbose
1859
- puts "Invalid TCP header format: #{tcp_format1}, #{tcp_format2}"
1860
- end
1733
+ puts "Invalid TCP header format: #{tcp_format1}, #{tcp_format2}" if @verbose
1861
1734
  return nil
1862
1735
  end
1863
1736
 
@@ -1876,30 +1749,24 @@ module RBZK
1876
1749
  data_size = tcp_length - 8
1877
1750
 
1878
1751
  # Read data if available
1879
- data = ""
1880
- if data_size > 0
1881
- if @verbose
1882
- puts "Reading #{data_size} bytes of data"
1883
- end
1752
+ data = ''
1753
+ if data_size.positive?
1754
+ puts "Reading #{data_size} bytes of data" if @verbose
1884
1755
 
1885
1756
  # Read data in chunks to handle large responses (like Python implementation)
1886
1757
  remaining = data_size
1887
- while remaining > 0
1758
+ while remaining.positive?
1888
1759
  chunk_size = [ remaining, 4096 ].min
1889
1760
  chunk = @socket.read(chunk_size)
1890
1761
  if chunk.nil? || chunk.empty?
1891
- if @verbose
1892
- puts "Failed to read data chunk, got #{chunk.inspect}"
1893
- end
1762
+ puts "Failed to read data chunk, got #{chunk.inspect}" if @verbose
1894
1763
  break
1895
1764
  end
1896
1765
 
1897
1766
  data += chunk
1898
1767
  remaining -= chunk.size
1899
1768
 
1900
- if @verbose && remaining > 0
1901
- puts "Read #{chunk.size} bytes, #{remaining} remaining"
1902
- end
1769
+ puts "Read #{chunk.size} bytes, #{remaining} remaining" if @verbose && remaining.positive?
1903
1770
  end
1904
1771
  end
1905
1772
 
@@ -1910,47 +1777,33 @@ module RBZK
1910
1777
  @session_id = session_id
1911
1778
 
1912
1779
  # Check command type and handle accordingly (like Python implementation)
1913
- if command == CMD_ACK_OK
1914
- if @verbose
1915
- puts "Received ACK_OK"
1916
- end
1780
+ case command
1781
+ when CMD_ACK_OK
1782
+ puts 'Received ACK_OK' if @verbose
1917
1783
  return cmd_header + data
1918
- elsif command == CMD_ACK_ERROR
1919
- if @verbose
1920
- puts "Received ACK_ERROR"
1921
- end
1784
+ when CMD_ACK_ERROR
1785
+ puts 'Received ACK_ERROR' if @verbose
1922
1786
  return nil
1923
- elsif command == CMD_ACK_DATA
1924
- if @verbose
1925
- puts "Received ACK_DATA"
1926
- end
1927
- if data_size > 0
1928
- return cmd_header + data
1929
- else
1930
- return nil
1931
- end
1787
+ when CMD_ACK_DATA
1788
+ puts 'Received ACK_DATA' if @verbose
1789
+ return cmd_header + data if data_size.positive?
1790
+
1791
+ return nil
1792
+
1932
1793
  else
1933
- if @verbose
1934
- puts "Received unknown command: #{command}"
1935
- end
1794
+ puts "Received unknown command: #{command}" if @verbose
1936
1795
  return cmd_header + data
1937
1796
  end
1938
1797
  end
1939
1798
  rescue Timeout::Error => e
1940
- if @verbose
1941
- puts "Timeout waiting for response: #{e.message}"
1942
- end
1943
- raise RBZK::ZKErrorResponse, "Timeout waiting for response"
1799
+ puts "Timeout waiting for response: #{e.message}" if @verbose
1800
+ raise RBZK::ZKErrorResponse, 'Timeout waiting for response'
1944
1801
  rescue Errno::ECONNRESET, Errno::EPIPE => e
1945
- if @verbose
1946
- puts "Connection error during receive: #{e.message}"
1947
- end
1802
+ puts "Connection error during receive: #{e.message}" if @verbose
1948
1803
  raise RBZK::ZKNetworkError, "Connection error: #{e.message}"
1949
1804
  rescue Errno::EAGAIN, Errno::EWOULDBLOCK => e
1950
- if @verbose
1951
- puts "Timeout waiting for response: #{e.message}"
1952
- end
1953
- raise RBZK::ZKErrorResponse, "Timeout waiting for response"
1805
+ puts "Timeout waiting for response: #{e.message}" if @verbose
1806
+ raise RBZK::ZKErrorResponse, 'Timeout waiting for response'
1954
1807
  end
1955
1808
 
1956
1809
  nil
@@ -1960,31 +1813,25 @@ module RBZK
1960
1813
  if @data_recv && @data_recv.size >= 4
1961
1814
  data = @data_recv[0..3]
1962
1815
  @data_recv = @data_recv[4..-1]
1963
- return data.unpack('L<')[0]
1816
+ return data.unpack1('L<')
1964
1817
  end
1965
1818
 
1966
1819
  0
1967
1820
  end
1968
1821
 
1969
1822
  def recv_chunk(size)
1970
- if @verbose
1971
- puts "Receiving chunk of #{size} bytes"
1972
- end
1823
+ puts "Receiving chunk of #{size} bytes" if @verbose
1973
1824
 
1974
1825
  if @data_recv && @data_recv.size >= size
1975
1826
  data = @data_recv[0...size]
1976
1827
  @data_recv = @data_recv[size..-1]
1977
1828
 
1978
- if @verbose
1979
- puts "Received #{data.size} bytes from buffer"
1980
- end
1829
+ puts "Received #{data.size} bytes from buffer" if @verbose
1981
1830
 
1982
1831
  return data
1983
1832
  end
1984
1833
 
1985
- if @verbose
1986
- puts "Warning: No data available in buffer"
1987
- end
1834
+ puts 'Warning: No data available in buffer' if @verbose
1988
1835
 
1989
1836
  # Return empty string if no data is available
1990
1837
  ''
@@ -2001,11 +1848,11 @@ module RBZK
2001
1848
  k = 0
2002
1849
 
2003
1850
  32.times do |i|
2004
- if (key & (1 << i)) != 0
2005
- k = (k << 1 | 1)
2006
- else
2007
- k = k << 1
2008
- end
1851
+ k = if (key & (1 << i)) != 0
1852
+ (k << 1 | 1)
1853
+ else
1854
+ k << 1
1855
+ end
2009
1856
  end
2010
1857
 
2011
1858
  k += session_id
@@ -2038,9 +1885,7 @@ module RBZK
2038
1885
  # Note: The third byte is just B, not k[2] ^ B
2039
1886
  result = [ k_bytes[0] ^ b, k_bytes[1] ^ b, b, k_bytes[3] ^ b ].pack('C4')
2040
1887
 
2041
- if @verbose
2042
- puts "Final commkey bytes: #{result.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
2043
- end
1888
+ puts "Final commkey bytes: #{result.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}" if @verbose
2044
1889
 
2045
1890
  result
2046
1891
  end