lifx 0.4.7 → 0.4.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +5 -0
- data/bin/lifx-snoop +2 -2
- data/lib/lifx.rb +2 -0
- data/lib/lifx/color.rb +5 -5
- data/lib/lifx/gateway_connection.rb +12 -8
- data/lib/lifx/light.rb +4 -4
- data/lib/lifx/network_context.rb +14 -6
- data/lib/lifx/observable.rb +31 -15
- data/lib/lifx/routing_manager.rb +9 -2
- data/lib/lifx/routing_table.rb +8 -2
- data/lib/lifx/site.rb +12 -6
- data/lib/lifx/tag_manager.rb +4 -2
- data/lib/lifx/thread.rb +11 -0
- data/lib/lifx/timers.rb +9 -1
- data/lib/lifx/transport.rb +6 -3
- data/lib/lifx/transport/tcp.rb +13 -7
- data/lib/lifx/transport/udp.rb +7 -5
- data/lib/lifx/transport_manager.rb +7 -2
- data/lib/lifx/transport_manager/lan.rb +17 -11
- data/lib/lifx/version.rb +1 -1
- data/spec/integration/client_spec.rb +1 -1
- data/spec/routing_manager_spec.rb +1 -1
- data/spec/routing_table_spec.rb +21 -0
- data/spec/transport/udp_spec.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c4d3a3b49f4182b136607335b3439a6d8c475af4
|
4
|
+
data.tar.gz: 5119e5d44ca2c1649a9f4226678dc1c3c04900c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76282a8c2b04cf4f0c0b199532d2847b97eacf7f8313c246c9aedafbf1cf6d35b02d9c75e75d472bb4f41a278988b92aae63cace417e5902a9e84095161f62f2
|
7
|
+
data.tar.gz: 0b81b9d0165ce833a8436bb597a5f6398ebf4cebee892f02116a6af9a7450b851c782639c9c077b8672bd3b836cf1f6be03e7dfb219ca02f3255165b12311355
|
data/CHANGES.md
CHANGED
data/bin/lifx-snoop
CHANGED
@@ -27,7 +27,7 @@ end
|
|
27
27
|
|
28
28
|
begin
|
29
29
|
light_udp = LIFX::Transport::UDP.new('0.0.0.0', 56700)
|
30
|
-
light_udp.add_observer(self) do |message: nil, ip: nil, transport: nil|
|
30
|
+
light_udp.add_observer(self, :message_received) do |message: nil, ip: nil, transport: nil|
|
31
31
|
if matchers.all? { |m| message.to_s =~ m }
|
32
32
|
puts "#{Time.now.iso8601(5)} BROADCAST: #{ip} #{message}"
|
33
33
|
end
|
@@ -35,7 +35,7 @@ begin
|
|
35
35
|
light_udp.listen
|
36
36
|
|
37
37
|
peer_udp = LIFX::Transport::UDP.new('0.0.0.0', 56750)
|
38
|
-
peer_udp.add_observer(self) do |message: nil, ip: nil, transport: nil|
|
38
|
+
peer_udp.add_observer(self, :message_received) do |message: nil, ip: nil, transport: nil|
|
39
39
|
if matchers.all? { |m| message.to_s =~ m }
|
40
40
|
puts "#{Time.now.iso8601(5)} PEER: #{ip} #{message}"
|
41
41
|
end
|
data/lib/lifx.rb
CHANGED
@@ -7,6 +7,8 @@ require "lifx/required_keyword_arguments"
|
|
7
7
|
require "lifx/utilities"
|
8
8
|
require "lifx/logging"
|
9
9
|
|
10
|
+
require "lifx/thread"
|
11
|
+
|
10
12
|
require "lifx/protocol/payload"
|
11
13
|
%w(device light sensor wan wifi message).each { |f| require "lifx/protocol/#{f}" }
|
12
14
|
require "lifx/protocol/type"
|
data/lib/lifx/color.rb
CHANGED
@@ -19,7 +19,7 @@ module LIFX
|
|
19
19
|
|
20
20
|
# Helper to create a white {Color}
|
21
21
|
# @param brightness: [Float] Valid range: `0..1`
|
22
|
-
# @param kelvin: [Integer] Valid range: `2500..
|
22
|
+
# @param kelvin: [Integer] Valid range: `2500..9000`
|
23
23
|
# @return [Color]
|
24
24
|
def white(brightness: 1.0, kelvin: DEFAULT_KELVIN)
|
25
25
|
Color.new(0, 0, brightness, kelvin)
|
@@ -37,7 +37,7 @@ module LIFX
|
|
37
37
|
extend Colors
|
38
38
|
UINT16_MAX = 65535
|
39
39
|
KELVIN_MIN = 2500
|
40
|
-
KELVIN_MAX =
|
40
|
+
KELVIN_MAX = 9000
|
41
41
|
|
42
42
|
class << self
|
43
43
|
# Helper method to create from HSB/HSV
|
@@ -54,7 +54,7 @@ module LIFX
|
|
54
54
|
# @param hue [Float] Valid range: `0..360`
|
55
55
|
# @param saturation [Float] Valid range: `0..1`
|
56
56
|
# @param brightness [Float] Valid range: `0..1`
|
57
|
-
# @param kelvin [Integer] Valid range: `2500..
|
57
|
+
# @param kelvin [Integer] Valid range: `2500..9000`
|
58
58
|
# @return [Color]
|
59
59
|
def hsbk(hue, saturation, brightness, kelvin)
|
60
60
|
new(hue, saturation, brightness, kelvin)
|
@@ -150,7 +150,7 @@ module LIFX
|
|
150
150
|
end
|
151
151
|
|
152
152
|
# Returns a new Color with the kelvin changed while keeping other attributes
|
153
|
-
# @param kelvin [Integer] Kelvin. `2500..
|
153
|
+
# @param kelvin [Integer] Kelvin. `2500..9000`
|
154
154
|
# @return [Color]
|
155
155
|
def with_kelvin(kelvin)
|
156
156
|
Color.new(hue, saturation, brightness, kelvin)
|
@@ -184,7 +184,7 @@ module LIFX
|
|
184
184
|
conditions = []
|
185
185
|
|
186
186
|
conditions << (((hue - other.hue).abs < (threshold * 360)) || begin
|
187
|
-
# FIXME: Surely there's a better way.
|
187
|
+
# FIXME: Surely there's a better way.
|
188
188
|
hues = [hue, other.hue].sort
|
189
189
|
hues[0] += 360
|
190
190
|
(hues[0] - hues[1]).abs < (threshold * 360)
|
@@ -66,13 +66,10 @@ module LIFX
|
|
66
66
|
@tcp_attempts += 1
|
67
67
|
logger.info("#{self}: Establishing connection to #{ip}:#{port}")
|
68
68
|
@tcp_transport = Transport::TCP.new(ip, port)
|
69
|
-
@tcp_transport.add_observer(self) do |message: nil, ip: nil, transport: nil|
|
70
|
-
notify_observers(message: message, ip: ip, transport: @tcp_transport)
|
69
|
+
@tcp_transport.add_observer(self, :message_received) do |message: nil, ip: nil, transport: nil|
|
70
|
+
notify_observers(:message_received, message: message, ip: ip, transport: @tcp_transport)
|
71
71
|
end
|
72
72
|
@tcp_transport.listen
|
73
|
-
at_exit do
|
74
|
-
@tcp_transport.close if @tcp_transport
|
75
|
-
end
|
76
73
|
end
|
77
74
|
|
78
75
|
def write(message)
|
@@ -80,7 +77,9 @@ module LIFX
|
|
80
77
|
end
|
81
78
|
|
82
79
|
def close
|
83
|
-
@threads.each
|
80
|
+
@threads.each do |thr|
|
81
|
+
thr.abort
|
82
|
+
end
|
84
83
|
[@tcp_transport, @udp_transport].compact.each(&:close)
|
85
84
|
end
|
86
85
|
|
@@ -118,8 +117,7 @@ module LIFX
|
|
118
117
|
def initialize_write_queue
|
119
118
|
@queue = SizedQueue.new(MAXIMUM_QUEUE_LENGTH)
|
120
119
|
@last_write = Time.now
|
121
|
-
Thread.
|
122
|
-
Thread.new do
|
120
|
+
Thread.start do
|
123
121
|
loop do
|
124
122
|
if !connected?
|
125
123
|
sleep 0.1
|
@@ -174,5 +172,11 @@ module LIFX
|
|
174
172
|
false
|
175
173
|
end
|
176
174
|
|
175
|
+
def observer_callback_definition
|
176
|
+
{
|
177
|
+
message_received: -> (message: nil, ip: nil, transport: nil) {}
|
178
|
+
}
|
179
|
+
end
|
180
|
+
|
177
181
|
end
|
178
182
|
end
|
data/lib/lifx/light.rb
CHANGED
@@ -76,7 +76,7 @@ module LIFX
|
|
76
76
|
# @return [Color] Color
|
77
77
|
def color(refresh: false, fetch: true)
|
78
78
|
@color = nil if refresh
|
79
|
-
send_message!(Protocol::Light::Get.new, wait_for: Protocol::Light::
|
79
|
+
send_message!(Protocol::Light::Get.new, wait_for: Protocol::Light::State) if fetch && !@color
|
80
80
|
@color
|
81
81
|
end
|
82
82
|
|
@@ -86,7 +86,7 @@ module LIFX
|
|
86
86
|
# @return [String, nil] Label
|
87
87
|
def label(refresh: false, fetch: true)
|
88
88
|
@label = nil if refresh
|
89
|
-
send_message!(Protocol::Light::Get.new, wait_for: Protocol::Light::
|
89
|
+
send_message!(Protocol::Light::Get.new, wait_for: Protocol::Light::State) if fetch && !@label
|
90
90
|
@label
|
91
91
|
end
|
92
92
|
|
@@ -158,7 +158,7 @@ module LIFX
|
|
158
158
|
# @return [:unknown, :off, :on] Light power state
|
159
159
|
def power(refresh: false, fetch: true)
|
160
160
|
@power = nil if refresh
|
161
|
-
send_message!(Protocol::
|
161
|
+
send_message!(Protocol::Light::Get.new, wait_for: Protocol::Light::State) if !@power && fetch
|
162
162
|
case @power
|
163
163
|
when nil
|
164
164
|
:unknown
|
@@ -331,7 +331,7 @@ module LIFX
|
|
331
331
|
def tags
|
332
332
|
context.tags_for_device(self)
|
333
333
|
end
|
334
|
-
|
334
|
+
|
335
335
|
# Returns a nice string representation of the Light
|
336
336
|
# @return [String]
|
337
337
|
def to_s
|
data/lib/lifx/network_context.rb
CHANGED
@@ -4,12 +4,16 @@ require 'lifx/routing_manager'
|
|
4
4
|
require 'lifx/tag_manager'
|
5
5
|
require 'lifx/light'
|
6
6
|
require 'lifx/protocol_path'
|
7
|
+
require 'lifx/timers'
|
8
|
+
|
9
|
+
require 'weakref'
|
7
10
|
|
8
11
|
module LIFX
|
9
12
|
class NetworkContext
|
10
13
|
include Logging
|
11
14
|
include Utilities
|
12
15
|
include RequiredKeywordArguments
|
16
|
+
include Timers
|
13
17
|
extend Forwardable
|
14
18
|
|
15
19
|
# NetworkContext stores lights and ties together TransportManager, TagManager and RoutingManager
|
@@ -19,14 +23,15 @@ module LIFX
|
|
19
23
|
@devices = {}
|
20
24
|
|
21
25
|
@transport_manager = transport_manager
|
22
|
-
@transport_manager.context = self
|
23
|
-
@transport_manager.add_observer(self) do |message: nil, ip: nil, transport: nil|
|
26
|
+
@transport_manager.context = WeakRef.new(self)
|
27
|
+
@transport_manager.add_observer(self, :message_received) do |message: nil, ip: nil, transport: nil|
|
24
28
|
handle_message(message, ip, transport)
|
25
29
|
end
|
26
30
|
|
27
31
|
reset!
|
28
32
|
|
29
33
|
@threads = []
|
34
|
+
@threads << initialize_timer_thread
|
30
35
|
end
|
31
36
|
|
32
37
|
def discover
|
@@ -44,9 +49,12 @@ module LIFX
|
|
44
49
|
|
45
50
|
def stop
|
46
51
|
@transport_manager.stop
|
52
|
+
stop_timers
|
47
53
|
@threads.each do |thread|
|
48
|
-
|
54
|
+
thread.abort
|
55
|
+
thread.join
|
49
56
|
end
|
57
|
+
@threads = nil
|
50
58
|
end
|
51
59
|
|
52
60
|
# Sends a message to their destination(s)
|
@@ -84,7 +92,7 @@ module LIFX
|
|
84
92
|
if within_sync?
|
85
93
|
raise "You cannot nest sync"
|
86
94
|
end
|
87
|
-
messages = Thread.
|
95
|
+
messages = Thread.start do
|
88
96
|
Thread.current[:sync_enabled] = true
|
89
97
|
Thread.current[:sync_messages] = messages = []
|
90
98
|
block.call
|
@@ -94,11 +102,11 @@ module LIFX
|
|
94
102
|
|
95
103
|
time = nil
|
96
104
|
try_until -> { time } do
|
97
|
-
light =
|
105
|
+
light = lights.alive.sample
|
98
106
|
time = light && light.time
|
99
107
|
end
|
100
108
|
|
101
|
-
delay = (messages.count + 1) * (1.0 / message_rate)
|
109
|
+
delay = (messages.count + 1) * (1.0 / @transport_manager.message_rate)
|
102
110
|
at_time = ((time.to_f + delay) * 1_000_000_000).to_i
|
103
111
|
messages.each do |m|
|
104
112
|
m.at_time = at_time
|
data/lib/lifx/observable.rb
CHANGED
@@ -1,36 +1,52 @@
|
|
1
|
+
require 'weakref'
|
2
|
+
|
1
3
|
module LIFX
|
2
4
|
# @private
|
3
5
|
module Observable
|
4
6
|
class ObserverCallbackMismatch < ArgumentError; end
|
5
|
-
|
6
|
-
|
7
|
+
class ObserverCallbackNotFound < ArgumentError; end
|
8
|
+
|
9
|
+
def add_observer(obj, type, &callback)
|
10
|
+
if !callback_type_exists?(type)
|
11
|
+
raise ObserverCallbackNotFound.new
|
12
|
+
end
|
13
|
+
if !callback_has_required_keys?(type, callback)
|
7
14
|
raise ObserverCallbackMismatch.new
|
8
15
|
end
|
9
|
-
observers[obj] = callback
|
16
|
+
observers[type][WeakRef.new(obj)] = callback
|
10
17
|
end
|
11
18
|
|
12
|
-
def remove_observer(obj)
|
13
|
-
observers.delete(obj)
|
19
|
+
def remove_observer(obj, type)
|
20
|
+
observers[type].delete(obj)
|
14
21
|
end
|
15
22
|
|
16
|
-
def
|
17
|
-
observers.
|
23
|
+
def remove_observers
|
24
|
+
observers.clear
|
25
|
+
end
|
26
|
+
|
27
|
+
def notify_observers(type, **args)
|
28
|
+
observers[type].each do |_, callback|
|
18
29
|
callback.call(**args)
|
19
30
|
end
|
20
31
|
end
|
21
32
|
|
22
|
-
def
|
23
|
-
|
33
|
+
def callback_type_exists?(type)
|
34
|
+
!!observer_callback_definition[type]
|
35
|
+
end
|
36
|
+
|
37
|
+
def callback_has_required_keys?(type, callback)
|
38
|
+
(required_keys_for_callback(type) - required_keys_in_proc(callback)).empty?
|
24
39
|
end
|
25
40
|
|
26
41
|
def observer_callback_definition
|
27
|
-
|
42
|
+
{}
|
28
43
|
end
|
29
44
|
|
30
|
-
def required_keys_for_callback
|
31
|
-
@_required_keys_for_callback ||=
|
32
|
-
|
33
|
-
|
45
|
+
def required_keys_for_callback(type)
|
46
|
+
@_required_keys_for_callback ||= {}
|
47
|
+
@_required_keys_for_callback[type] ||= begin
|
48
|
+
return [] if !observer_callback_definition[type]
|
49
|
+
required_keys_in_proc(observer_callback_definition[type])
|
34
50
|
end
|
35
51
|
end
|
36
52
|
|
@@ -41,7 +57,7 @@ module LIFX
|
|
41
57
|
end
|
42
58
|
|
43
59
|
def observers
|
44
|
-
@_observers ||= {}
|
60
|
+
@_observers ||= Hash.new { |h, k| h[k] = {} }
|
45
61
|
end
|
46
62
|
end
|
47
63
|
end
|
data/lib/lifx/routing_manager.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'lifx/routing_table'
|
2
2
|
require 'lifx/tag_table'
|
3
3
|
require 'lifx/utilities'
|
4
|
+
require 'weakref'
|
4
5
|
|
5
6
|
module LIFX
|
6
7
|
# @private
|
@@ -13,11 +14,16 @@ module LIFX
|
|
13
14
|
|
14
15
|
attr_reader :context, :tag_table, :routing_table
|
15
16
|
|
17
|
+
STALE_ROUTING_TABLE_PURGE_INTERVAL = 60
|
18
|
+
|
16
19
|
def initialize(context: required!(:context))
|
17
|
-
@context = context
|
20
|
+
@context = WeakRef.new(context)
|
18
21
|
@routing_table = RoutingTable.new
|
19
22
|
@tag_table = TagTable.new
|
20
23
|
@last_refresh_seen = {}
|
24
|
+
@context.timers.every(STALE_ROUTING_TABLE_PURGE_INTERVAL) do
|
25
|
+
routing_table.clear_stale_entries
|
26
|
+
end
|
21
27
|
end
|
22
28
|
|
23
29
|
def resolve_target(target)
|
@@ -85,8 +91,9 @@ module LIFX
|
|
85
91
|
@routing_table.update_table(site_id: message.site_id,
|
86
92
|
device_id: message.device_id,
|
87
93
|
tag_ids: tag_ids_from_field(message.payload.tags))
|
94
|
+
when Protocol::Device::StatePanGateway, Protocol::Device::StatePower
|
95
|
+
@routing_table.update_table(site_id: message.site_id, device_id: message.device_id)
|
88
96
|
end
|
89
|
-
@routing_table.update_table(site_id: message.site_id, device_id: message.device_id)
|
90
97
|
end
|
91
98
|
|
92
99
|
MINIMUM_REFRESH_INTERVAL = 20
|
data/lib/lifx/routing_table.rb
CHANGED
@@ -7,10 +7,10 @@ module LIFX
|
|
7
7
|
@device_site_mapping = entries
|
8
8
|
end
|
9
9
|
|
10
|
-
def update_table(site_id: site_id, device_id: device_id, tag_ids: nil)
|
10
|
+
def update_table(site_id: site_id, device_id: device_id, tag_ids: nil, last_seen: Time.now)
|
11
11
|
device_mapping = @device_site_mapping[device_id] ||= Entry.new(site_id, device_id, [])
|
12
12
|
device_mapping.site_id = site_id
|
13
|
-
device_mapping.last_seen =
|
13
|
+
device_mapping.last_seen = last_seen
|
14
14
|
device_mapping.tag_ids = tag_ids if tag_ids
|
15
15
|
end
|
16
16
|
|
@@ -30,5 +30,11 @@ module LIFX
|
|
30
30
|
def entries
|
31
31
|
@device_site_mapping.values
|
32
32
|
end
|
33
|
+
|
34
|
+
def clear_stale_entries(threshold: 60 * 5)
|
35
|
+
@device_site_mapping.reject! do |device_id, entry|
|
36
|
+
entry.last_seen < Time.now - threshold
|
37
|
+
end
|
38
|
+
end
|
33
39
|
end
|
34
40
|
end
|
data/lib/lifx/site.rb
CHANGED
@@ -11,7 +11,7 @@ module LIFX
|
|
11
11
|
include Logging
|
12
12
|
include Observable
|
13
13
|
include RequiredKeywordArguments
|
14
|
-
|
14
|
+
|
15
15
|
attr_reader :id, :gateways, :tag_manager
|
16
16
|
|
17
17
|
def initialize(id: required!(:id))
|
@@ -38,8 +38,8 @@ module LIFX
|
|
38
38
|
@gateways_mutex.synchronize do
|
39
39
|
@gateways[message.device_id] ||= GatewayConnection.new
|
40
40
|
@gateways[message.device_id].handle_message(message, ip, transport)
|
41
|
-
@gateways[message.device_id].add_observer(self) do |**args|
|
42
|
-
notify_observers(**args)
|
41
|
+
@gateways[message.device_id].add_observer(self, :message_received) do |**args|
|
42
|
+
notify_observers(:message_received, **args)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -48,12 +48,12 @@ module LIFX
|
|
48
48
|
|
49
49
|
def flush(**options)
|
50
50
|
@gateways.values.map do |gateway|
|
51
|
-
Thread.
|
51
|
+
Thread.start do
|
52
52
|
gateway.flush(**options)
|
53
53
|
end
|
54
54
|
end.each(&:join)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def to_s
|
58
58
|
%Q{#<LIFX::Site id=#{id}>}
|
59
59
|
end
|
@@ -61,13 +61,19 @@ module LIFX
|
|
61
61
|
|
62
62
|
def stop
|
63
63
|
@threads.each do |thread|
|
64
|
-
|
64
|
+
thread.abort
|
65
65
|
end
|
66
66
|
@gateways.values.each do |gateway|
|
67
67
|
gateway.close
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
def observer_callback_definition
|
72
|
+
{
|
73
|
+
message_received: -> (message: nil, ip: nil, transport: nil) {}
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
71
77
|
|
72
78
|
protected
|
73
79
|
|
data/lib/lifx/tag_manager.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'weakref'
|
2
|
+
|
1
3
|
module LIFX
|
2
4
|
# @api private
|
3
5
|
# @private
|
@@ -15,7 +17,7 @@ module LIFX
|
|
15
17
|
class TagLimitReached < StandardError; end
|
16
18
|
|
17
19
|
def initialize(context: required!(:context), tag_table: required!(:tag_table))
|
18
|
-
@context = context
|
20
|
+
@context = WeakRef.new(context)
|
19
21
|
@tag_table = tag_table
|
20
22
|
end
|
21
23
|
|
@@ -83,7 +85,7 @@ module LIFX
|
|
83
85
|
end
|
84
86
|
end
|
85
87
|
end
|
86
|
-
|
88
|
+
|
87
89
|
protected
|
88
90
|
|
89
91
|
VALID_TAG_IDS = (0...64).to_a.freeze
|
data/lib/lifx/thread.rb
ADDED
data/lib/lifx/timers.rb
CHANGED
@@ -5,13 +5,21 @@ module LIFX
|
|
5
5
|
protected
|
6
6
|
def initialize_timer_thread
|
7
7
|
timers.after(1) {} # Just so timers.wait doesn't complain when there's no timer
|
8
|
-
Thread.
|
8
|
+
@timer_thread = Thread.start do
|
9
9
|
loop do
|
10
10
|
timers.wait
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
def stop_timers
|
16
|
+
timers.each(&:cancel)
|
17
|
+
if @timer_thread
|
18
|
+
@timer_thread.abort
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
public
|
15
23
|
def timers
|
16
24
|
@timers ||= ::Timers.new
|
17
25
|
end
|
data/lib/lifx/transport.rb
CHANGED
@@ -5,7 +5,7 @@ module LIFX
|
|
5
5
|
class Transport
|
6
6
|
include Logging
|
7
7
|
include Observable
|
8
|
-
|
8
|
+
|
9
9
|
attr_reader :host, :port
|
10
10
|
|
11
11
|
def initialize(host, port, ignore_unpackable_messages: true)
|
@@ -23,7 +23,7 @@ module LIFX
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def close
|
26
|
-
|
26
|
+
remove_observers
|
27
27
|
end
|
28
28
|
|
29
29
|
def to_s
|
@@ -32,7 +32,10 @@ module LIFX
|
|
32
32
|
alias_method :inspect, :to_s
|
33
33
|
|
34
34
|
def observer_callback_definition
|
35
|
-
|
35
|
+
{
|
36
|
+
message_received: -> (message: nil, ip: nil, transport: nil) {},
|
37
|
+
disconnected: -> {}
|
38
|
+
}
|
36
39
|
end
|
37
40
|
end
|
38
41
|
end
|
data/lib/lifx/transport/tcp.rb
CHANGED
@@ -13,7 +13,7 @@ module LIFX
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def connected?
|
16
|
-
@socket && !@socket.closed?
|
16
|
+
!!(@socket && !@socket.closed?)
|
17
17
|
end
|
18
18
|
|
19
19
|
CONNECT_TIMEOUT = 3
|
@@ -31,17 +31,23 @@ module LIFX
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def close
|
34
|
+
super
|
34
35
|
return if !@socket
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
if !@socket.closed?
|
37
|
+
@socket.close
|
38
|
+
notify_observers(:disconnected)
|
39
|
+
end
|
38
40
|
@socket = nil
|
41
|
+
if @listener
|
42
|
+
@listener.abort
|
43
|
+
end
|
44
|
+
@listener = nil
|
39
45
|
end
|
40
46
|
|
41
47
|
HEADER_SIZE = 8
|
42
48
|
def listen
|
43
49
|
return if @listener
|
44
|
-
@listener = Thread.
|
50
|
+
@listener = Thread.start do
|
45
51
|
while @socket do
|
46
52
|
begin
|
47
53
|
header_data = @socket.recv(HEADER_SIZE, Socket::MSG_PEEK)
|
@@ -49,8 +55,8 @@ module LIFX
|
|
49
55
|
size = header.msg_size
|
50
56
|
data = @socket.recv(size)
|
51
57
|
message = Message.unpack(data)
|
52
|
-
|
53
|
-
notify_observers(message: message, ip: host, transport: self)
|
58
|
+
|
59
|
+
notify_observers(:message_received, {message: message, ip: host, transport: self})
|
54
60
|
rescue Message::UnpackError
|
55
61
|
if Config.log_invalid_messages
|
56
62
|
logger.info("#{self}: Exception occured while decoding message - #{ex}")
|
data/lib/lifx/transport/udp.rb
CHANGED
@@ -28,9 +28,8 @@ module LIFX
|
|
28
28
|
if @listener
|
29
29
|
raise "Socket already being listened to"
|
30
30
|
end
|
31
|
-
|
32
|
-
Thread.
|
33
|
-
@listener = Thread.new do
|
31
|
+
|
32
|
+
@listener = Thread.start do
|
34
33
|
reader = UDPSocket.new
|
35
34
|
reader.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
|
36
35
|
reader.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEPORT, true) if Socket.const_defined?('SO_REUSEPORT')
|
@@ -39,7 +38,7 @@ module LIFX
|
|
39
38
|
begin
|
40
39
|
bytes, (_, _, ip, _) = reader.recvfrom(128)
|
41
40
|
message = Message.unpack(bytes)
|
42
|
-
notify_observers(message: message, ip: ip, transport: self)
|
41
|
+
notify_observers(:message_received, {message: message, ip: ip, transport: self})
|
43
42
|
rescue Message::UnpackError
|
44
43
|
if Config.log_invalid_messages
|
45
44
|
logger.warn("#{self}: Unrecognised bytes: #{bytes.bytes.map { |b| '%02x ' % b }.join}")
|
@@ -50,10 +49,13 @@ module LIFX
|
|
50
49
|
end
|
51
50
|
|
52
51
|
def close
|
53
|
-
|
52
|
+
super
|
54
53
|
return if !@socket
|
55
54
|
@socket.close
|
56
55
|
@socket = nil
|
56
|
+
if @listener
|
57
|
+
@listener.abort
|
58
|
+
end
|
57
59
|
end
|
58
60
|
|
59
61
|
protected
|
@@ -24,10 +24,15 @@ module LIFX
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def stop
|
27
|
-
|
27
|
+
@context = nil
|
28
|
+
remove_observers
|
28
29
|
end
|
29
30
|
|
30
|
-
|
31
|
+
def observer_callback_definition
|
32
|
+
{
|
33
|
+
message_received: -> (message: nil, ip: nil, transport: nil) {}
|
34
|
+
}
|
35
|
+
end
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|
@@ -21,7 +21,7 @@ module LIFX
|
|
21
21
|
|
22
22
|
def flush(**options)
|
23
23
|
@sites.values.map do |site|
|
24
|
-
Thread.
|
24
|
+
Thread.start do
|
25
25
|
site.flush(**options)
|
26
26
|
end
|
27
27
|
end.each(&:join)
|
@@ -31,8 +31,7 @@ module LIFX
|
|
31
31
|
DISCOVERY_INTERVAL = 15 # seconds
|
32
32
|
def discover
|
33
33
|
stop_discovery
|
34
|
-
Thread.
|
35
|
-
@discovery_thread = Thread.new do
|
34
|
+
@discovery_thread = Thread.start do
|
36
35
|
@last_request_seen = Time.at(0)
|
37
36
|
message = Message.new(path: ProtocolPath.new(tagged: true), payload: Protocol::Device::GetPanGateway.new)
|
38
37
|
logger.info("Discovering gateways on #{@bind_ip}:#{@port}")
|
@@ -49,12 +48,19 @@ module LIFX
|
|
49
48
|
end
|
50
49
|
|
51
50
|
def stop_discovery
|
52
|
-
|
51
|
+
if @discovery_thread
|
52
|
+
@discovery_thread.abort
|
53
|
+
end
|
53
54
|
end
|
54
55
|
|
55
56
|
def stop
|
57
|
+
super
|
56
58
|
stop_discovery
|
57
|
-
|
59
|
+
stop_timers
|
60
|
+
@threads.each do |thr|
|
61
|
+
thr.abort
|
62
|
+
end
|
63
|
+
@peer_transport.close
|
58
64
|
@transport.close
|
59
65
|
@sites.values.each do |site|
|
60
66
|
site.stop
|
@@ -152,17 +158,17 @@ module LIFX
|
|
152
158
|
|
153
159
|
def create_broadcast_transport
|
154
160
|
@transport = Transport::UDP.new(@send_ip, @port)
|
155
|
-
@transport.add_observer(self) do |message: nil, ip: nil, transport: nil|
|
161
|
+
@transport.add_observer(self, :message_received) do |message: nil, ip: nil, transport: nil|
|
156
162
|
handle_broadcast_message(message, ip, @transport)
|
157
|
-
notify_observers(message: message, ip: ip, transport: transport)
|
163
|
+
notify_observers(:message_received, message: message, ip: ip, transport: transport)
|
158
164
|
end
|
159
165
|
@transport.listen(ip: @bind_ip)
|
160
166
|
end
|
161
167
|
|
162
168
|
def create_peer_transport
|
163
169
|
@peer_transport = Transport::UDP.new('255.255.255.255', @peer_port)
|
164
|
-
@peer_transport.add_observer(self) do |message: nil, ip: nil, transport: nil|
|
165
|
-
notify_observers(message: message, ip: ip, transport: transport)
|
170
|
+
@peer_transport.add_observer(self, :message_received) do |message: nil, ip: nil, transport: nil|
|
171
|
+
notify_observers(:message_received, message: message, ip: ip, transport: transport)
|
166
172
|
end
|
167
173
|
@peer_transport.listen(ip: @bind_ip)
|
168
174
|
end
|
@@ -174,8 +180,8 @@ module LIFX
|
|
174
180
|
when Protocol::Device::StatePanGateway
|
175
181
|
if !@sites.has_key?(message.path.site_id)
|
176
182
|
@sites[message.path.site_id] = Site.new(id: message.path.site_id)
|
177
|
-
@sites[message.path.site_id].add_observer(self) do |**args|
|
178
|
-
notify_observers(**args)
|
183
|
+
@sites[message.path.site_id].add_observer(self, :message_received) do |**args|
|
184
|
+
notify_observers(:message_received, **args)
|
179
185
|
end
|
180
186
|
end
|
181
187
|
@sites[message.path.site_id].handle_message(message, ip, transport)
|
data/lib/lifx/version.rb
CHANGED
@@ -19,7 +19,7 @@ module LIFX
|
|
19
19
|
sleep 1
|
20
20
|
|
21
21
|
msgs = []
|
22
|
-
udp.add_observer(self) do |message: nil, ip: nil, transport: nil|
|
22
|
+
udp.add_observer(self, :message_received) do |message: nil, ip: nil, transport: nil|
|
23
23
|
msgs << message if message.payload.is_a?(Protocol::Light::SetWaveform)
|
24
24
|
end
|
25
25
|
udp.listen
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
module LIFX
|
4
4
|
describe RoutingManager do
|
5
5
|
describe '#tags_for_device_id' do
|
6
|
-
subject(:manager) { RoutingManager.new(context: double) }
|
6
|
+
subject(:manager) { RoutingManager.new(context: double(timers: double(every: double))) }
|
7
7
|
|
8
8
|
before do
|
9
9
|
['Some label', 'Another label', 'Much label'].each_with_index do |lbl, i|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LIFX
|
4
|
+
describe RoutingTable do
|
5
|
+
describe '#clear_stale_entries' do
|
6
|
+
subject(:table) { RoutingTable.new }
|
7
|
+
|
8
|
+
before do
|
9
|
+
table.update_table(site_id: 'site', device_id: 'stale device', last_seen: Time.now - 305)
|
10
|
+
table.update_table(site_id: 'site', device_id: 'recent device', last_seen: Time.now)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'clears only entries older than 5 minutes' do
|
14
|
+
expect(table.entries.count).to eq(2)
|
15
|
+
table.clear_stale_entries
|
16
|
+
expect(table.entries.count).to eq(1)
|
17
|
+
expect(table.entries.first.device_id).to eq('recent device')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/spec/transport/udp_spec.rb
CHANGED
@@ -24,7 +24,7 @@ module LIFX
|
|
24
24
|
let(:socket) { UDPSocket.new }
|
25
25
|
let(:messages) { [] }
|
26
26
|
before do
|
27
|
-
udp.add_observer(self) do |message: nil, ip: nil, transport: nil|
|
27
|
+
udp.add_observer(self, :message_received) do |message: nil, ip: nil, transport: nil|
|
28
28
|
messages << message
|
29
29
|
end
|
30
30
|
udp.listen
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lifx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jack Chen (chendo)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bindata
|
@@ -152,6 +152,7 @@ files:
|
|
152
152
|
- lib/lifx/tag_manager.rb
|
153
153
|
- lib/lifx/tag_table.rb
|
154
154
|
- lib/lifx/target.rb
|
155
|
+
- lib/lifx/thread.rb
|
155
156
|
- lib/lifx/timers.rb
|
156
157
|
- lib/lifx/transport.rb
|
157
158
|
- lib/lifx/transport/tcp.rb
|
@@ -170,6 +171,7 @@ files:
|
|
170
171
|
- spec/message_spec.rb
|
171
172
|
- spec/protocol_path_spec.rb
|
172
173
|
- spec/routing_manager_spec.rb
|
174
|
+
- spec/routing_table_spec.rb
|
173
175
|
- spec/spec_helper.rb
|
174
176
|
- spec/transport/udp_spec.rb
|
175
177
|
- spec/transport_spec.rb
|
@@ -209,6 +211,7 @@ test_files:
|
|
209
211
|
- spec/message_spec.rb
|
210
212
|
- spec/protocol_path_spec.rb
|
211
213
|
- spec/routing_manager_spec.rb
|
214
|
+
- spec/routing_table_spec.rb
|
212
215
|
- spec/spec_helper.rb
|
213
216
|
- spec/transport/udp_spec.rb
|
214
217
|
- spec/transport_spec.rb
|