ewelink 2.1.1 → 2.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb352abf05d6bb6ef2f3b277c6f551d436bed969086478d3e121fd2e178fe4f9
4
- data.tar.gz: b74266f2cbc92457a3bb0dc087752299a5a9f8348d3928a79d8c3c0719653e6a
3
+ metadata.gz: 2392627c54c851fb5fd14194b484b56b1013b7a26e8d5bafe2a79e37dfa80464
4
+ data.tar.gz: 2a5362bafa04f9e3cf212a5899b4e6183514fdff68b3146a4fa245c52e8fcadd
5
5
  SHA512:
6
- metadata.gz: 2c5bb695c7d0094436454694008dd3c05c660fb1c7dfe2436ec1fa2fae3341559f901f3b9ae4ebfa99fcc276dcd4ceee02205ed1608d03e515b8da64b52f8a25
7
- data.tar.gz: 4713a948c736a40496b3b33fff3b83253a4559693d692cfaa7251a4fc2d3f0e67699834f6513226edcbfe6cf7759ab54b1cb6c5a24cbe1559f54a75d6cbda6fd
6
+ metadata.gz: b2d3ecbf884461e11a51cf7e4efe7438f1c066cc7c076629371c96b3255b50f2a3f4e0314f6a40f9b7247adef06d69eb0b1f66b31ebcabff1c46b7def21d8291
7
+ data.tar.gz: a2d064d2af9e800ef0165bf5d614e4857abb0503b1faad7e280f3f2df422f08c5c49e57e10b3202bfcac700dc667861690c0a29a44faaf13a5ae00307201fe87
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.1
1
+ 2.2.0
@@ -16,8 +16,8 @@ Gem::Specification.new do |s|
16
16
  s.required_ruby_version = '>= 2.0.0'
17
17
 
18
18
  s.add_dependency 'activesupport', '>= 6.0.0', '< 7.0.0'
19
+ s.add_dependency 'faye-websocket', '>= 0.11.0', '< 0.12.0'
19
20
  s.add_dependency 'httparty', '>= 0.18.0', '< 0.19.0'
20
- s.add_dependency 'websocket-client-simple', '>= 0.3.0', '< 0.4.0'
21
21
 
22
22
  s.add_development_dependency 'byebug', '>= 11.0.0', '< 12.0.0'
23
23
  s.add_development_dependency 'rake', '>= 12.0.0', '< 13.0.0'
@@ -1,6 +1,8 @@
1
1
  require 'active_support'
2
2
  require 'active_support/core_ext'
3
3
  require 'byebug' if ENV['DEBUGGER']
4
+ require 'eventmachine'
5
+ require 'faye/websocket'
4
6
  require 'httparty'
5
7
  require 'io/console'
6
8
  require 'json'
@@ -9,7 +11,6 @@ require 'openssl'
9
11
  require 'optparse'
10
12
  require 'set'
11
13
  require 'timeout'
12
- require 'websocket-client-simple'
13
14
 
14
15
  module Ewelink
15
16
 
@@ -50,7 +50,7 @@ module Ewelink
50
50
  end
51
51
 
52
52
  def reload
53
- Ewelink.logger.debug(self.class.name) { 'Reloading API (authentication token, devices, region, connections,...)' }
53
+ Ewelink.logger.debug(self.class.name) { 'Reloading API (authentication token, devices, region,...)' }
54
54
  dispose_web_socket
55
55
  [
56
56
  :@api_keys,
@@ -102,21 +102,20 @@ module Ewelink
102
102
  def switch_on?(uuid)
103
103
  switch = find_switch!(uuid)
104
104
  if @web_socket_switches_statuses[switch[:uuid]].nil?
105
- params = {
106
- 'action' => 'query',
107
- 'apikey' => switch[:api_key],
108
- 'deviceid' => switch[:device_id],
109
- 'sequence' => web_socket_sequence,
110
- 'ts' => 0,
111
- 'userAgent' => 'app',
112
- }
113
105
  web_socket_wait_for(-> { web_socket_authenticated? }) do
114
106
  Ewelink.logger.debug(self.class.name) { "Checking switch #{switch[:uuid].inspect} status" }
107
+ params = {
108
+ 'action' => 'query',
109
+ 'apikey' => switch[:api_key],
110
+ 'deviceid' => switch[:device_id],
111
+ 'sequence' => web_socket_sequence,
112
+ 'ts' => 0,
113
+ 'userAgent' => 'app',
114
+ }
115
115
  send_to_web_socket(JSON.generate(params))
116
116
  end
117
117
  end
118
118
  web_socket_wait_for(-> { !@web_socket_switches_statuses[switch[:uuid]].nil? }) do
119
- Ewelink.logger.debug(self.class.name) { "Switch #{switch[:uuid].inspect} is #{@web_socket_switches_statuses[switch[:uuid]]}" }
120
119
  @web_socket_switches_statuses[switch[:uuid]] == 'on'
121
120
  end
122
121
  end
@@ -176,6 +175,24 @@ module Ewelink
176
175
  end
177
176
  end
178
177
 
178
+ def authenticate_web_socket_api_keys
179
+ api_keys.each do |api_key|
180
+ params = {
181
+ 'action' => 'userOnline',
182
+ 'apikey' => api_key,
183
+ 'appid' => APP_ID,
184
+ 'at' => authentication_token,
185
+ 'nonce' => nonce,
186
+ 'sequence' => web_socket_sequence,
187
+ 'ts' => Time.now.to_i,
188
+ 'userAgent' => 'app',
189
+ 'version' => VERSION,
190
+ }
191
+ Ewelink.logger.debug(self.class.name) { "Authenticating WebSocket API key: #{api_key.truncate(16).inspect}" }
192
+ send_to_web_socket(JSON.generate(params))
193
+ end
194
+ end
195
+
179
196
  def authentication_headers
180
197
  { 'Authorization' => "Bearer #{authentication_token}" }
181
198
  end
@@ -221,14 +238,16 @@ module Ewelink
221
238
  end
222
239
 
223
240
  def dispose_web_socket
241
+ Ewelink.logger.debug(self.class.name) { 'Dispose WebSocket' }
224
242
  @web_socket_authenticated_api_keys.clear
225
243
  @web_socket_switches_statuses.clear
226
244
 
227
- if @web_socket_ping_thread
228
- if Thread.current == @web_socket_ping_thread
229
- Thread.current[:stop] = true
245
+ [@web_socket_ping_thread, @web_socket_thread].each do |thread|
246
+ next unless thread
247
+ if Thread.current == thread
248
+ thread[:stop] = true
230
249
  else
231
- @web_socket_ping_thread.kill
250
+ thread.kill
232
251
  end
233
252
  end
234
253
 
@@ -244,6 +263,7 @@ module Ewelink
244
263
  :@last_web_socket_pong_at,
245
264
  :@web_socket_ping_interval,
246
265
  :@web_socket_ping_thread,
266
+ :@web_socket_thread,
247
267
  :@web_socket_url,
248
268
  :@web_socket,
249
269
  ].each do |variable|
@@ -286,15 +306,29 @@ module Ewelink
286
306
  raise Error.new(e)
287
307
  end
288
308
 
289
- def send_to_web_socket(data)
309
+ def send_to_web_socket(message)
290
310
  if web_socket_outdated_ping?
291
311
  Ewelink.logger.warn(self.class.name) { 'WebSocket ping is outdated' }
292
312
  dispose_web_socket
293
313
  end
294
- web_socket.send(data)
295
- rescue
314
+ web_socket.send(message)
315
+ rescue => e
296
316
  dispose_web_socket
297
- raise
317
+ raise Error.new(e)
318
+ end
319
+
320
+ def start_web_socket_ping_thread(interval)
321
+ @last_web_socket_pong_at = Time.now
322
+ @web_socket_ping_interval = interval
323
+ Ewelink.logger.debug(self.class.name) { "Creating thread for WebSocket ping every #{@web_socket_ping_interval} seconds" }
324
+ @web_socket_ping_thread = Thread.new do
325
+ loop do
326
+ break if Thread.current[:stop]
327
+ sleep(@web_socket_ping_interval)
328
+ Ewelink.logger.debug(self.class.name) { 'Sending WebSocket ping' }
329
+ send_to_web_socket('ping')
330
+ end
331
+ end
298
332
  end
299
333
 
300
334
  def synchronize(name, &block)
@@ -303,94 +337,73 @@ module Ewelink
303
337
 
304
338
  def web_socket
305
339
  synchronize(:web_socket) do
306
- @web_socket ||= begin
307
- api = self
340
+ next @web_socket if @web_socket
308
341
 
309
- WebSocket::Client::Simple.connect(web_socket_url) do |web_socket|
342
+ @web_socket_thread = Thread.new do
343
+ EventMachine.run do
310
344
  Ewelink.logger.debug(self.class.name) { "Opening WebSocket to #{web_socket_url.inspect}" }
311
345
 
312
- web_socket.on(:close) do
313
- api.instance_eval do
314
- Ewelink.logger.debug(self.class.name) { 'WebSocket closed' }
315
- dispose_web_socket
316
- end
346
+ @web_socket = Faye::WebSocket::Client.new('wss://as-pconnect3.coolkit.cc:8080/api/ws')
347
+
348
+ @web_socket.on(:close) do |event|
349
+ Ewelink.logger.debug(self.class.name) { 'WebSocket closed' }
350
+ dispose_web_socket
317
351
  end
318
352
 
319
- web_socket.on(:error) do |e|
320
- api.instance_eval do
321
- Ewelink.logger.warn(self.class.name) { "WebSocket error: #{e}" }
322
- dispose_web_socket
323
- end
353
+ @web_socket.on(:open) do |event|
354
+ Ewelink.logger.debug(self.class.name) { 'WebSocket opened' }
355
+ @last_web_socket_pong_at = Time.now
356
+ authenticate_web_socket_api_keys
324
357
  end
325
358
 
326
- web_socket.on(:message) do |message|
327
- api.instance_eval do
328
- if message.data == 'pong'
329
- Ewelink.logger.debug(self.class.name) { "Received WebSocket #{message.data.inspect} message" }
330
- @last_web_socket_pong_at = Time.now
331
- next
332
- end
359
+ @web_socket.on(:message) do |event|
360
+ message = event.data
333
361
 
334
- begin
335
- response = JSON.parse(message.data)
336
- rescue => e
337
- Ewelink.logger.error(self.class.name) { "WebSocket JSON parse error" }
338
- next
339
- end
362
+ if message == 'pong'
363
+ Ewelink.logger.debug(self.class.name) { "Received WebSocket #{message.inspect} message" }
364
+ @last_web_socket_pong_at = Time.now
365
+ next
366
+ end
340
367
 
341
- if response.key?('error') && response['error'] != 0
342
- Ewelink.logger.error(self.class.name) { "WebSocket message error: #{message.data}" }
343
- next
344
- end
368
+ begin
369
+ json = JSON.parse(message)
370
+ rescue => e
371
+ Ewelink.logger.error(self.class.name) { 'WebSocket JSON parse error' }
372
+ next
373
+ end
345
374
 
346
- if !@web_socket_ping_thread && response.key?('config') && response['config']['hb'] == 1 && response['config']['hbInterval'].present?
347
- @last_web_socket_pong_at = Time.now
348
- @web_socket_ping_interval = response['config']['hbInterval'] + 7
349
- Ewelink.logger.debug(self.class.name) { "Creating thread for WebSocket ping every #{@web_socket_ping_interval} seconds" }
350
- @web_socket_ping_thread = Thread.new do
351
- loop do
352
- break if Thread.current[:stop]
353
- sleep(@web_socket_ping_interval)
354
- Ewelink.logger.debug(self.class.name) { 'Sending WebSocket ping' }
355
- send_to_web_socket('ping')
356
- end
357
- end
358
- end
375
+ if json.key?('error') && json['error'] != 0
376
+ Ewelink.logger.error(self.class.name) { "WebSocket message error: #{message.inspect}" }
377
+ next
378
+ end
359
379
 
360
- if response['apikey'].present? && !@web_socket_authenticated_api_keys.include?(response['apikey'])
361
- @web_socket_authenticated_api_keys << response['apikey']
362
- Ewelink.logger.debug(self.class.name) { "WebSocket successfully authenticated API key: #{response['apikey'].truncate(16).inspect}" }
363
- end
380
+ if !@web_socket_ping_thread && json.key?('config') && json['config']['hb'] == 1 && json['config']['hbInterval'].present?
381
+ start_web_socket_ping_thread(json['config']['hbInterval'] + 7)
382
+ end
364
383
 
365
- if response['deviceid'].present? && response['params'].is_a?(Hash) && response['params']['switch'].present?
366
- switch = switches.find { |switch| switch[:device_id] == response['deviceid'] }
367
- @web_socket_switches_statuses[switch[:uuid]] = response['params']['switch'] if switch.present?
368
- end
384
+ if json['apikey'].present? && !@web_socket_authenticated_api_keys.include?(json['apikey'])
385
+ @web_socket_authenticated_api_keys << json['apikey']
386
+ Ewelink.logger.debug(self.class.name) { "WebSocket successfully authenticated API key: #{json['apikey'].truncate(16).inspect}" }
369
387
  end
370
- end
371
388
 
372
- web_socket.on(:open) do
373
- api.instance_eval do
374
- Ewelink.logger.debug(self.class.name) { 'WebSocket opened' }
375
- api_keys.each do |api_key|
376
- params = {
377
- 'action' => 'userOnline',
378
- 'apikey' => api_key,
379
- 'appid' => APP_ID,
380
- 'at' => authentication_token,
381
- 'nonce' => nonce,
382
- 'sequence' => web_socket_sequence,
383
- 'ts' => Time.now.to_i,
384
- 'userAgent' => 'app',
385
- 'version' => VERSION,
386
- }
387
- Ewelink.logger.debug(self.class.name) { "Authenticating WebSocket API key: #{api_key.truncate(16).inspect}" }
388
- send_to_web_socket(JSON.generate(params))
389
+ if json['deviceid'].present? && json['params'].is_a?(Hash) && json['params']['switch'].present?
390
+ switch = switches.find { |switch| switch[:device_id] == json['deviceid'] }
391
+ if switch.present?
392
+ @web_socket_switches_statuses[switch[:uuid]] = json['params']['switch']
393
+ Ewelink.logger.debug(self.class.name) { "Switch #{switch[:uuid].inspect} is #{@web_socket_switches_statuses[switch[:uuid]]}" }
389
394
  end
390
395
  end
391
396
  end
392
397
  end
393
398
  end
399
+
400
+ Timeout.timeout(REQUEST_TIMEOUT) do
401
+ while @web_socket.blank?
402
+ sleep(WEB_SOCKET_WAIT_INTERVAL)
403
+ end
404
+ end
405
+
406
+ @web_socket
394
407
  end
395
408
  end
396
409
 
@@ -428,13 +441,10 @@ module Ewelink
428
441
  def web_socket_wait_for(condition, &block)
429
442
  web_socket # Initializes WebSocket
430
443
  Timeout.timeout(REQUEST_TIMEOUT) do
431
- loop do
432
- if condition.call
433
- return yield if block_given?
434
- return true
435
- end
444
+ while !condition.call
436
445
  sleep(WEB_SOCKET_WAIT_INTERVAL)
437
446
  end
447
+ block_given? ? yield : true
438
448
  end
439
449
  end
440
450
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ewelink
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexis Toulotte
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-02 00:00:00.000000000 Z
11
+ date: 2020-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -31,45 +31,45 @@ dependencies:
31
31
  - !ruby/object:Gem::Version
32
32
  version: 7.0.0
33
33
  - !ruby/object:Gem::Dependency
34
- name: httparty
34
+ name: faye-websocket
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: 0.18.0
39
+ version: 0.11.0
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: 0.19.0
42
+ version: 0.12.0
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: 0.18.0
49
+ version: 0.11.0
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: 0.19.0
52
+ version: 0.12.0
53
53
  - !ruby/object:Gem::Dependency
54
- name: websocket-client-simple
54
+ name: httparty
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: 0.3.0
59
+ version: 0.18.0
60
60
  - - "<"
61
61
  - !ruby/object:Gem::Version
62
- version: 0.4.0
62
+ version: 0.19.0
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 0.3.0
69
+ version: 0.18.0
70
70
  - - "<"
71
71
  - !ruby/object:Gem::Version
72
- version: 0.4.0
72
+ version: 0.19.0
73
73
  - !ruby/object:Gem::Dependency
74
74
  name: byebug
75
75
  requirement: !ruby/object:Gem::Requirement