hakuban 0.6.0 → 0.6.3
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 +4 -4
- data/lib/hakuban/async.rb +11 -24
- data/lib/hakuban/event-queue.rb +75 -0
- data/lib/hakuban/hakuban.rb +56 -41
- data/lib/hakuban/manager.rb +191 -53
- data/lib/hakuban/thread.rb +9 -22
- data/lib/hakuban/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6822f983334fd24d18385b13f77352026609b85e2f386760b00bae8e60e53cb
|
4
|
+
data.tar.gz: e90301ced5b302e23fcc4c3da3d59c9ac32bf9e22d472272ff43bdb8ad78eadc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22eb5c5b3223bd25d7b3dea31f52134f9a71a07a1fcdf06e4d6077dc27df689e57a9e92cb059919f283f8708bfbe26e9ed679cdaeee7631d1203eedc4254aa85
|
7
|
+
data.tar.gz: e39db8ea279d53883c61333768928aca255891e105dfb27e82e6ddc88f73a1128fe0b9972da59921074479272ed7baf32b0317dc933bebef1664568414469e8c
|
data/lib/hakuban/async.rb
CHANGED
@@ -5,41 +5,28 @@ require 'async'
|
|
5
5
|
module Hakuban
|
6
6
|
|
7
7
|
class AsyncObjectManager < ObjectManager
|
8
|
+
|
8
9
|
def async_run
|
9
10
|
Async { yield }
|
10
11
|
end
|
11
12
|
|
12
|
-
def async_join(
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
|
18
|
-
class ObjectObserve
|
19
|
-
def async(&block)
|
20
|
-
AsyncObjectManager.new(self, ObservedObject, block)
|
13
|
+
def async_join(task)
|
14
|
+
task.wait
|
21
15
|
end
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
class ObjectExpose
|
26
|
-
def async(&block)
|
27
|
-
AsyncObjectManager.new(self, ExposedObject, block)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
16
|
|
32
|
-
|
33
|
-
|
34
|
-
AsyncObjectManager.new(self, ObservedObject, block)
|
17
|
+
def async_stop(task)
|
18
|
+
task.stop
|
35
19
|
end
|
20
|
+
|
36
21
|
end
|
37
22
|
|
38
23
|
|
39
|
-
class
|
40
|
-
|
41
|
-
|
24
|
+
class ObjectManagerBuilder
|
25
|
+
|
26
|
+
def with_async(&block)
|
27
|
+
build(AsyncObjectManager, block)
|
42
28
|
end
|
29
|
+
|
43
30
|
end
|
44
31
|
|
45
32
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#TODO: rebuild to handle event squashing on rust side
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
|
6
|
+
module Hakuban
|
7
|
+
|
8
|
+
class Event < OpenStruct; end
|
9
|
+
|
10
|
+
class ObjectDescriptorCallbackEventQueue
|
11
|
+
|
12
|
+
def initialize(pointer)
|
13
|
+
@events_pointer = ::FFI::AutoPointer.new(pointer, proc { |ptr| FFI.hakuban_object_descriptor_events_return(ptr) })
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# WARNING: this callback may be run from a separate, non-ruby, thread
|
18
|
+
def callback_register(&callback)
|
19
|
+
ffi_callback = proc { |_userdata, ffi_descriptor, ffi_action|
|
20
|
+
action = Hakuban::action_int_to_symbol(ffi_action)
|
21
|
+
descriptor = ObjectDescriptor.from_ffi(ffi_descriptor)
|
22
|
+
callback.call(descriptor, action)
|
23
|
+
}
|
24
|
+
@callback_pointer = ::FFI::AutoPointer.new(
|
25
|
+
FFI::hakuban_object_descriptor_events_callback_register(@events_pointer, ffi_callback, ::FFI::Pointer::NULL),
|
26
|
+
proc { |ptr| FFI::hakuban_object_descriptor_events_callback_unregister(ptr) }
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def callback_unregister
|
32
|
+
@callback_pointer.free
|
33
|
+
@callback_pointer = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def drop
|
38
|
+
@events_pointer.free
|
39
|
+
@events_pointer = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
class ObjectDescriptorEventQueue
|
46
|
+
|
47
|
+
def initialize(contract)
|
48
|
+
@contract = contract
|
49
|
+
@queue = Queue.new
|
50
|
+
@ffi_callback = proc { |descriptor, action|
|
51
|
+
@queue << Hakuban::Event.new(action: action, descriptor: descriptor)
|
52
|
+
}
|
53
|
+
@ffi_events = @contract.new_callback_event_queue
|
54
|
+
@ffi_events.callback_register(&@ffi_callback)
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
#def push(event)
|
59
|
+
# @queue << event
|
60
|
+
#end
|
61
|
+
|
62
|
+
|
63
|
+
def next_event; next_change; end
|
64
|
+
def next_change
|
65
|
+
@queue.pop
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def close
|
70
|
+
@queue.close
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
data/lib/hakuban/hakuban.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'ostruct'
|
3
3
|
|
4
|
-
require_relative './
|
4
|
+
require_relative './event-queue.rb'
|
5
5
|
|
6
6
|
#TODO: explicit drops?
|
7
7
|
#TODO: privative methods
|
@@ -32,9 +32,14 @@ module Hakuban
|
|
32
32
|
end
|
33
33
|
|
34
34
|
|
35
|
+
def self.hakuban_initialize
|
36
|
+
require_relative './ffi.rb'
|
37
|
+
end
|
38
|
+
|
35
39
|
@@logger_initialized = false
|
36
40
|
|
37
41
|
def self.logger_initialize(default_level, skip_if_already_initialized = false)
|
42
|
+
::Hakuban::hakuban_initialize
|
38
43
|
if @@logger_initialized and !skip_if_already_initialized
|
39
44
|
raise "Logger already initialized. This can't be done more than once. Make sure logger_initialize is called before any LocalNode gets constructed."
|
40
45
|
end
|
@@ -52,11 +57,12 @@ module Hakuban
|
|
52
57
|
attr_reader :local_node_pointer #todo: hide
|
53
58
|
|
54
59
|
def initialize(name: nil)
|
60
|
+
::Hakuban::hakuban_initialize
|
55
61
|
@default_serializer = lambda { |data_type, data|
|
56
62
|
[["JSON"]+data_type, JSON.dump(data)]
|
57
63
|
}
|
58
64
|
@default_deserializer = lambda { |data_type, data|
|
59
|
-
raise "Expected JSON serialized data, got: #{
|
65
|
+
raise "Expected JSON serialized data, got: #{data_type}" if data_type[0] != "JSON"
|
60
66
|
[data_type[1..-1], JSON.load(data)]
|
61
67
|
}
|
62
68
|
Hakuban::logger_initialize("hakuban=warn", true)
|
@@ -215,36 +221,6 @@ module Hakuban
|
|
215
221
|
end
|
216
222
|
|
217
223
|
|
218
|
-
class ObjectDescriptorEvents
|
219
|
-
def initialize(pointer)
|
220
|
-
@events_pointer = ::FFI::AutoPointer.new(pointer, proc { |ptr| FFI.hakuban_object_descriptor_events_return(ptr) })
|
221
|
-
end
|
222
|
-
|
223
|
-
# WARNING: this callback may be run from a separate, non-ruby, thread
|
224
|
-
def callback_register(&callback)
|
225
|
-
ffi_callback = proc { |_userdata, ffi_descriptor, ffi_action|
|
226
|
-
action = Hakuban::action_int_to_symbol(ffi_action)
|
227
|
-
descriptor = ObjectDescriptor.from_ffi(ffi_descriptor)
|
228
|
-
callback.call(descriptor, action)
|
229
|
-
}
|
230
|
-
@callback_pointer = ::FFI::AutoPointer.new(
|
231
|
-
FFI::hakuban_object_descriptor_events_callback_register(@events_pointer, ffi_callback, ::FFI::Pointer::NULL),
|
232
|
-
proc { |ptr| FFI::hakuban_object_descriptor_events_callback_unregister(ptr) }
|
233
|
-
)
|
234
|
-
end
|
235
|
-
|
236
|
-
def callback_unregister
|
237
|
-
@callback_pointer.free
|
238
|
-
@callback_pointer = nil
|
239
|
-
end
|
240
|
-
|
241
|
-
def drop
|
242
|
-
@events_pointer.free
|
243
|
-
@events_pointer = nil
|
244
|
-
end
|
245
|
-
|
246
|
-
end
|
247
|
-
|
248
224
|
class ObjectObserve
|
249
225
|
|
250
226
|
attr_reader :descriptor
|
@@ -253,6 +229,7 @@ module Hakuban
|
|
253
229
|
@local_node, @descriptor, @deserializer = local_node, descriptor, deserializer
|
254
230
|
result = FFI::hakuban_object_observe_new(@local_node.local_node_pointer, descriptor.to_ffi)
|
255
231
|
Hakuban::raise_if_error(result)
|
232
|
+
@queues = []
|
256
233
|
@object_observe_pointer = ::FFI::AutoPointer.new(result[:object_observe_pointer], proc { |ptr| FFI::hakuban_object_observe_drop(ptr) })
|
257
234
|
end
|
258
235
|
|
@@ -265,9 +242,16 @@ module Hakuban
|
|
265
242
|
end
|
266
243
|
end
|
267
244
|
|
268
|
-
def
|
245
|
+
def new_callback_event_queue
|
246
|
+
raise "Attempt to use after 'drop'" if not @object_observe_pointer
|
247
|
+
ObjectDescriptorCallbackEventQueue.new(FFI::hakuban_object_observe_events_get(@object_observe_pointer))
|
248
|
+
end
|
249
|
+
|
250
|
+
def new_event_queue
|
269
251
|
raise "Attempt to use after 'drop'" if not @object_observe_pointer
|
270
|
-
|
252
|
+
queue = ObjectDescriptorEventQueue.new(self)
|
253
|
+
@queues << queue
|
254
|
+
queue
|
271
255
|
end
|
272
256
|
|
273
257
|
def inspect
|
@@ -277,6 +261,8 @@ module Hakuban
|
|
277
261
|
def drop
|
278
262
|
@object_observe_pointer.free
|
279
263
|
@object_observe_pointer = nil
|
264
|
+
@queues.each(&:close) #is this atomic?
|
265
|
+
@queues.clear
|
280
266
|
end
|
281
267
|
|
282
268
|
def dropped?
|
@@ -294,6 +280,7 @@ module Hakuban
|
|
294
280
|
@local_node, @descriptor, @serializer = local_node, descriptor, serializer
|
295
281
|
result = FFI::hakuban_object_expose_new(@local_node.local_node_pointer, descriptor.to_ffi)
|
296
282
|
Hakuban::raise_if_error(result)
|
283
|
+
@queues = []
|
297
284
|
@object_expose_pointer = ::FFI::AutoPointer.new(result[:object_expose_pointer], FFI::method(:hakuban_object_expose_drop))
|
298
285
|
end
|
299
286
|
|
@@ -319,9 +306,16 @@ module Hakuban
|
|
319
306
|
FFI::hakuban_object_expose_desynchronize(@object_expose_pointer, assignment)
|
320
307
|
end
|
321
308
|
|
322
|
-
def
|
309
|
+
def new_callback_event_queue
|
323
310
|
raise "Attempt to use after 'drop'" if not @object_expose_pointer
|
324
|
-
|
311
|
+
ObjectDescriptorCallbackEventQueue.new(FFI::hakuban_object_expose_events_get(@object_expose_pointer))
|
312
|
+
end
|
313
|
+
|
314
|
+
def new_event_queue
|
315
|
+
raise "Attempt to use after 'drop'" if not @object_expose_pointer
|
316
|
+
queue = ObjectDescriptorEventQueue.new(self)
|
317
|
+
@queues << queue
|
318
|
+
queue
|
325
319
|
end
|
326
320
|
|
327
321
|
def inspect
|
@@ -331,7 +325,8 @@ module Hakuban
|
|
331
325
|
def drop
|
332
326
|
@object_expose_pointer.free
|
333
327
|
@object_expose_pointer = nil
|
334
|
-
|
328
|
+
@queues.each(&:close) #is this atomic?
|
329
|
+
@queues.clear end
|
335
330
|
|
336
331
|
def dropped?
|
337
332
|
@object_expose_pointer.nil?
|
@@ -394,6 +389,7 @@ module Hakuban
|
|
394
389
|
@local_node, @descriptor, @deserializer = local_node, descriptor, deserializer
|
395
390
|
result = FFI::hakuban_tag_observe_new(@local_node.local_node_pointer, @descriptor.to_ffi)
|
396
391
|
Hakuban::raise_if_error(result)
|
392
|
+
@queues = []
|
397
393
|
@tag_observe_pointer = ::FFI::AutoPointer.new(result[:tag_observe_pointer], FFI::method(:hakuban_tag_observe_drop))
|
398
394
|
end
|
399
395
|
|
@@ -413,14 +409,23 @@ module Hakuban
|
|
413
409
|
ObjectObserveState.new(result[:state], @deserializer)
|
414
410
|
end
|
415
411
|
|
416
|
-
def
|
412
|
+
def new_callback_event_queue
|
417
413
|
raise "Attempt to use after 'drop'" if not @tag_observe_pointer
|
418
|
-
|
414
|
+
ObjectDescriptorCallbackEventQueue.new(FFI::hakuban_tag_observe_events_get(@tag_observe_pointer))
|
415
|
+
end
|
416
|
+
|
417
|
+
def new_event_queue
|
418
|
+
raise "Attempt to use after 'drop'" if not @tag_observe_pointer
|
419
|
+
queue = ObjectDescriptorEventQueue.new(self)
|
420
|
+
@queues << queue
|
421
|
+
queue
|
419
422
|
end
|
420
423
|
|
421
424
|
def drop
|
422
425
|
@tag_observe_pointer.free
|
423
426
|
@tag_observe_pointer = nil
|
427
|
+
@queues.each(&:close) #is this atomic?
|
428
|
+
@queues.clear
|
424
429
|
end
|
425
430
|
|
426
431
|
def dropped?
|
@@ -438,6 +443,7 @@ module Hakuban
|
|
438
443
|
@local_node, @descriptor, @serializer = local_node, descriptor, serializer
|
439
444
|
result = FFI::hakuban_tag_expose_new(@local_node.local_node_pointer, descriptor.to_ffi)
|
440
445
|
Hakuban::raise_if_error(result)
|
446
|
+
@queues = []
|
441
447
|
@tag_expose_pointer = ::FFI::AutoPointer.new(result[:tag_expose_pointer], FFI::method(:hakuban_tag_expose_drop))
|
442
448
|
end
|
443
449
|
|
@@ -472,14 +478,23 @@ module Hakuban
|
|
472
478
|
FFI::hakuban_tag_expose_object_desynchronize(@tag_expose_pointer, object_descriptor.to_ffi, assignment)
|
473
479
|
end
|
474
480
|
|
475
|
-
def
|
481
|
+
def new_callback_event_queue
|
482
|
+
raise "Attempt to use after 'drop'" if not @tag_expose_pointer
|
483
|
+
ObjectDescriptorCallbackEventQueue.new(FFI::hakuban_tag_expose_events_get(@tag_expose_pointer))
|
484
|
+
end
|
485
|
+
|
486
|
+
def new_event_queue
|
476
487
|
raise "Attempt to use after 'drop'" if not @tag_expose_pointer
|
477
|
-
|
488
|
+
queue = ObjectDescriptorEventQueue.new(self)
|
489
|
+
@queues << queue
|
490
|
+
queue
|
478
491
|
end
|
479
492
|
|
480
493
|
def drop
|
481
494
|
@tag_expose_pointer.free
|
482
495
|
@tag_expose_pointer = nil
|
496
|
+
@queues.each(&:close) #is this atomic?
|
497
|
+
@queues.clear
|
483
498
|
end
|
484
499
|
|
485
500
|
def dropped?
|
data/lib/hakuban/manager.rb
CHANGED
@@ -6,16 +6,55 @@ require 'ostruct'
|
|
6
6
|
|
7
7
|
module Hakuban
|
8
8
|
|
9
|
+
class ObjectManagerBuilder
|
10
|
+
|
11
|
+
def initialize(contract)
|
12
|
+
@contract = contract
|
13
|
+
@on_exception_policy = :retry
|
14
|
+
@retry_backoff = [0.01, 0.1, 1.0, 10.0]
|
15
|
+
@terminate_on_deactivation = false
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def on_exception(policy)
|
20
|
+
@on_exception_policy = policy
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def terminate_on_deactivation
|
26
|
+
@terminate_on_deactivation = true
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def retry_backoff(*times)
|
32
|
+
@retry_backoff = times.flatten
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def build(manager_class, block)
|
38
|
+
raise "don't use build() directly, use .with_thread {} or .with_async {} instead" if not manager_class
|
39
|
+
manager_class.new(@contract, block, @retry_backoff, @terminate_on_deactivation, @on_exception_policy)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
|
9
45
|
class ObjectManager
|
10
46
|
|
11
47
|
attr_reader :contract
|
12
48
|
|
13
49
|
class Event < OpenStruct; end
|
50
|
+
class HandlerException < OpenStruct; end
|
14
51
|
|
15
|
-
def initialize(contract,
|
52
|
+
def initialize(contract, block, retry_backoff, terminate_on_deactivation, on_exception_policy)
|
16
53
|
@contract = contract
|
17
|
-
|
18
|
-
@
|
54
|
+
object_class = @contract.class.const_get(:ManagedObject)
|
55
|
+
@objects_mutex = Mutex.new
|
56
|
+
@existing_objects = {} #TODO: turn this into a WeakMap, to keep object if external code still holds reference to it
|
57
|
+
@active_objects = {}
|
19
58
|
@event_queue = Queue.new
|
20
59
|
|
21
60
|
# This callback gets called from a separate thread, with no async reactor running.
|
@@ -23,60 +62,119 @@ module Hakuban
|
|
23
62
|
@ffi_callback = proc { |descriptor, action|
|
24
63
|
@event_queue << Event.new(action: action, descriptor: descriptor)
|
25
64
|
}
|
26
|
-
@ffi_events = @contract.
|
65
|
+
@ffi_events = @contract.new_callback_event_queue
|
27
66
|
@ffi_events.callback_register(&@ffi_callback)
|
28
67
|
|
29
68
|
@async = async_run {
|
30
|
-
while event = @event_queue.shift
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
69
|
+
while @event_queue and event = @event_queue.shift
|
70
|
+
@objects_mutex.synchronize {
|
71
|
+
case event.action
|
72
|
+
when :insert, :change, :remove, :stopped, :timer
|
73
|
+
object = @existing_objects[event.descriptor] ||= object_class.new(@contract, event.descriptor)
|
74
|
+
if !object.running and object.async
|
75
|
+
error = async_join(object.async)
|
76
|
+
object.async = nil
|
77
|
+
if object.last_exception_at
|
78
|
+
interval_since_last_exception = Time.new - object.last_exception_at
|
79
|
+
heal_multiplier = 10.0
|
80
|
+
object.current_delay_index -= (interval_since_last_exception / (retry_backoff[-1]*heal_multiplier)).floor
|
81
|
+
object.current_delay_index = 0 if object.current_delay_index < 0
|
82
|
+
end
|
83
|
+
if error.kind_of? HandlerException
|
84
|
+
case on_exception_policy
|
85
|
+
when :raise
|
86
|
+
raise error.exception
|
87
|
+
when :retry
|
88
|
+
object.last_exception_at = Time.new
|
89
|
+
object.earliest_next_run = Time.new + retry_backoff[object.current_delay_index]
|
90
|
+
lambda_sleep_time = object.earliest_next_run - Time.new
|
91
|
+
lambda_descriptor = event.descriptor
|
92
|
+
async_run {
|
93
|
+
sleep lambda_sleep_time
|
94
|
+
@event_queue << Event.new(action: :timer, descriptor: lambda_descriptor) if @event_queue
|
95
|
+
} #TODO: do we have to join this?
|
96
|
+
object.current_delay_index += 1 if object.current_delay_index < retry_backoff.size - 1
|
97
|
+
#when :ignore_failing_descriptor
|
98
|
+
#when :drop_contract
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
if object.check_active
|
103
|
+
if block and !object.running and (!object.earliest_next_run or Time.new >= object.earliest_next_run)
|
104
|
+
descriptor_for_lambda = event.descriptor
|
105
|
+
object.running = true
|
106
|
+
object.async = async_run do
|
107
|
+
object.run(block)
|
108
|
+
rescue Async::Stop
|
109
|
+
nil
|
110
|
+
rescue Exception => e
|
111
|
+
$stderr.puts "Exception in hakuban manager lambda: #{e}"
|
112
|
+
$stderr.puts "Contract: "+@contract.inspect
|
113
|
+
$stderr.puts "Descriptor: "+descriptor_for_lambda.inspect
|
114
|
+
$stderr.puts "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
|
115
|
+
HandlerException.new(exception: e) # exception has to wrapped here to stop async from throwing on join
|
116
|
+
ensure
|
117
|
+
object.running = false
|
118
|
+
@event_queue << Event.new(action: :stopped, descriptor: descriptor_for_lambda) if @event_queue
|
119
|
+
end
|
120
|
+
end
|
121
|
+
@active_objects[event.descriptor] ||= object
|
122
|
+
object.change
|
123
|
+
else
|
124
|
+
@active_objects.delete(event.descriptor)
|
125
|
+
if object.running
|
126
|
+
object.stop
|
127
|
+
async_stop(object.async) if terminate_on_deactivation
|
128
|
+
else
|
129
|
+
@existing_objects.delete(event.descriptor)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
when :drop
|
133
|
+
@ffi_events.callback_unregister
|
134
|
+
@active_objects.clear
|
135
|
+
@existing_objects.dup.each { |descriptor, object|
|
136
|
+
if object.running
|
137
|
+
object.stop
|
138
|
+
async_stop(object.async) if terminate_on_deactivation
|
139
|
+
else
|
140
|
+
@existing_objects.delete(descriptor)
|
141
|
+
end
|
49
142
|
}
|
143
|
+
while @existing_objects.size > 0
|
144
|
+
event = @event_queue.shift
|
145
|
+
@existing_objects.delete(event.descriptor) if event.action == :stopped
|
146
|
+
end
|
147
|
+
@event_queue.clear
|
148
|
+
@contract.drop
|
149
|
+
@contract, @event_queue = nil, nil
|
150
|
+
break
|
50
151
|
end
|
51
|
-
|
52
|
-
raise if not @running_handlers[event.descriptor]
|
53
|
-
@running_handlers.delete(event.descriptor)
|
54
|
-
@event_queue << Event.new(action: :handler_start, descriptor: event.descriptor) if @objects[event.descriptor]
|
55
|
-
when :drop
|
56
|
-
@ffi_events.callback_unregister
|
57
|
-
@objects.values.each { |object| object.do_change(:remove) }
|
58
|
-
while @running_handlers.size > 0
|
59
|
-
event = @event_queue.shift
|
60
|
-
@running_handlers.delete(event.descriptor) if event.action == :handler_finished
|
61
|
-
end
|
62
|
-
@event_queue.clear
|
63
|
-
@objects.clear
|
64
|
-
@contract.drop
|
65
|
-
@contract, @event_queue = nil, nil
|
66
|
-
break
|
67
|
-
end
|
152
|
+
}
|
68
153
|
end
|
69
154
|
}
|
70
155
|
end
|
71
156
|
|
72
|
-
|
73
|
-
def
|
157
|
+
|
158
|
+
def objects
|
159
|
+
@objects_mutex.synchronize {
|
160
|
+
@active_objects.dup
|
161
|
+
}
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
def object
|
166
|
+
@objects_mutex.synchronize {
|
167
|
+
@active_objects.values.first
|
168
|
+
}
|
169
|
+
end
|
170
|
+
|
74
171
|
|
75
172
|
def drop
|
76
173
|
drop_nonblock
|
77
174
|
async_join(@async)
|
78
175
|
end
|
79
176
|
|
177
|
+
|
80
178
|
def drop_nonblock
|
81
179
|
if @contract
|
82
180
|
@event_queue << Event.new(action: :drop)
|
@@ -86,20 +184,20 @@ module Hakuban
|
|
86
184
|
|
87
185
|
|
88
186
|
|
89
|
-
class
|
187
|
+
class ManagedObjectBase
|
90
188
|
|
91
|
-
attr_reader :descriptor
|
189
|
+
attr_reader :descriptor
|
190
|
+
attr_accessor :running, :async, :last_exception_at, :current_delay_index, :earliest_next_run
|
92
191
|
|
93
192
|
|
94
193
|
def initialize(contract, descriptor)
|
95
194
|
@contract,@descriptor = contract, descriptor
|
96
195
|
@changes = Queue.new
|
97
|
-
@
|
196
|
+
@current_delay_index = 0
|
98
197
|
end
|
99
198
|
|
100
199
|
|
101
200
|
def run(handler)
|
102
|
-
@handler_already_run = true
|
103
201
|
handler.call(self)
|
104
202
|
end
|
105
203
|
|
@@ -109,23 +207,27 @@ module Hakuban
|
|
109
207
|
loop {
|
110
208
|
case @changes.shift
|
111
209
|
when :change then return true
|
112
|
-
when :
|
210
|
+
when :stop then return false
|
113
211
|
end
|
114
212
|
}
|
115
213
|
end
|
116
214
|
|
117
215
|
|
118
|
-
def
|
119
|
-
@changes.push(change)
|
216
|
+
def change
|
217
|
+
@changes.push(:change)
|
120
218
|
end
|
121
219
|
|
220
|
+
def stop
|
221
|
+
@changes.push(:stop)
|
222
|
+
end
|
223
|
+
|
122
224
|
end
|
123
225
|
|
124
226
|
|
125
227
|
|
126
228
|
class ObjectObserve
|
127
229
|
|
128
|
-
class
|
230
|
+
class ManagedObject < ManagedObjectBase
|
129
231
|
|
130
232
|
def state
|
131
233
|
@contract.object_state
|
@@ -135,6 +237,15 @@ module Hakuban
|
|
135
237
|
@contract.object_state&.data
|
136
238
|
end
|
137
239
|
|
240
|
+
def check_active
|
241
|
+
!!state
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
def manage
|
248
|
+
ObjectManagerBuilder.new(self)
|
138
249
|
end
|
139
250
|
|
140
251
|
end
|
@@ -142,7 +253,7 @@ module Hakuban
|
|
142
253
|
|
143
254
|
class ObjectExpose
|
144
255
|
|
145
|
-
class
|
256
|
+
class ManagedObject < ManagedObjectBase
|
146
257
|
|
147
258
|
def initialize(contract, descriptor)
|
148
259
|
super(contract, descriptor)
|
@@ -185,6 +296,15 @@ module Hakuban
|
|
185
296
|
set_data(value)
|
186
297
|
end
|
187
298
|
|
299
|
+
def check_active
|
300
|
+
assigned?
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
|
305
|
+
|
306
|
+
def manage
|
307
|
+
ObjectManagerBuilder.new(self)
|
188
308
|
end
|
189
309
|
|
190
310
|
end
|
@@ -192,7 +312,7 @@ module Hakuban
|
|
192
312
|
|
193
313
|
class TagObserve
|
194
314
|
|
195
|
-
class
|
315
|
+
class ManagedObject < ManagedObjectBase
|
196
316
|
|
197
317
|
def state
|
198
318
|
@contract.object_state(@descriptor)
|
@@ -202,6 +322,15 @@ module Hakuban
|
|
202
322
|
@contract.object_state(@descriptor)&.data
|
203
323
|
end
|
204
324
|
|
325
|
+
def check_active
|
326
|
+
!!state
|
327
|
+
end
|
328
|
+
|
329
|
+
end
|
330
|
+
|
331
|
+
|
332
|
+
def manage
|
333
|
+
ObjectManagerBuilder.new(self)
|
205
334
|
end
|
206
335
|
|
207
336
|
end
|
@@ -209,7 +338,7 @@ module Hakuban
|
|
209
338
|
|
210
339
|
class TagExpose
|
211
340
|
|
212
|
-
class
|
341
|
+
class ManagedObject < ManagedObjectBase
|
213
342
|
|
214
343
|
def initialize(contract, descriptor)
|
215
344
|
super(contract, descriptor)
|
@@ -252,6 +381,15 @@ module Hakuban
|
|
252
381
|
set_data(value)
|
253
382
|
end
|
254
383
|
|
384
|
+
def check_active
|
385
|
+
assigned?
|
386
|
+
end
|
387
|
+
|
388
|
+
end
|
389
|
+
|
390
|
+
|
391
|
+
def manage
|
392
|
+
ObjectManagerBuilder.new(self)
|
255
393
|
end
|
256
394
|
|
257
395
|
end
|
data/lib/hakuban/thread.rb
CHANGED
@@ -4,41 +4,28 @@ require 'hakuban/manager'
|
|
4
4
|
module Hakuban
|
5
5
|
|
6
6
|
class ThreadObjectManager < ObjectManager
|
7
|
+
|
7
8
|
def async_run
|
8
9
|
Thread.new { yield }
|
9
10
|
end
|
10
11
|
|
11
12
|
def async_join(thread)
|
12
|
-
thread.
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
|
17
|
-
class ObjectObserve
|
18
|
-
def thread(&block)
|
19
|
-
ThreadObjectManager.new(self, ObservedObject, block)
|
13
|
+
thread.value
|
20
14
|
end
|
21
|
-
end
|
22
|
-
|
23
15
|
|
24
|
-
|
25
|
-
|
26
|
-
ThreadObjectManager.new(self, ExposedObject, block)
|
16
|
+
def async_stop(thread)
|
17
|
+
thread.kill
|
27
18
|
end
|
19
|
+
|
28
20
|
end
|
29
21
|
|
30
22
|
|
31
|
-
class
|
32
|
-
|
33
|
-
|
23
|
+
class ObjectManagerBuilder
|
24
|
+
|
25
|
+
def with_thread(&block)
|
26
|
+
build(ThreadObjectManager, block)
|
34
27
|
end
|
35
|
-
end
|
36
28
|
|
37
|
-
|
38
|
-
class TagExpose
|
39
|
-
def thread(&block)
|
40
|
-
ThreadObjectManager.new(self, ExposedObject, block)
|
41
|
-
end
|
42
29
|
end
|
43
30
|
|
44
31
|
end
|
data/lib/hakuban/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hakuban
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yunta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -83,6 +83,7 @@ files:
|
|
83
83
|
- lib/hakuban.rb
|
84
84
|
- lib/hakuban/async.rb
|
85
85
|
- lib/hakuban/engine.rb
|
86
|
+
- lib/hakuban/event-queue.rb
|
86
87
|
- lib/hakuban/ffi.rb
|
87
88
|
- lib/hakuban/hakuban.rb
|
88
89
|
- lib/hakuban/manager.rb
|