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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 80450f20193ebd24bb8f0b55e9e822be3a0271d26aa1c41954fe09a23c02a62d
4
- data.tar.gz: 56a74e6c21534550ef484ae58ede825fd6690f847d45245c57be3271943d77bb
3
+ metadata.gz: e6822f983334fd24d18385b13f77352026609b85e2f386760b00bae8e60e53cb
4
+ data.tar.gz: e90301ced5b302e23fcc4c3da3d59c9ac32bf9e22d472272ff43bdb8ad78eadc
5
5
  SHA512:
6
- metadata.gz: 9a67bad1007498001d0550abd1eab1827d155fe6b6f25ee94aa08149bd054090bc9d0b37e1767eb03b7b7971216643e4c7dd396f7ef7cc20420ea7b54fbebdea
7
- data.tar.gz: 5f3d377665666e3cada421c1140c3a8e8b00e84564b61a6c29991560b45615846dfbddce318b212b2d386d9f3b84737b59a7fccc5c4068661da1b366032b8c6d
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(async)
13
- async.wait
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
- class TagObserve
33
- def async(&block)
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 TagExpose
40
- def async(&block)
41
- AsyncObjectManager.new(self, ExposedObject, block)
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
@@ -1,7 +1,7 @@
1
1
  require 'set'
2
2
  require 'ostruct'
3
3
 
4
- require_relative './ffi.rb'
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: #{dat_type}" if data_type[0] != "JSON"
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 events
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
- ObjectDescriptorEvents.new(FFI::hakuban_object_observe_events_get(@object_observe_pointer))
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 events
309
+ def new_callback_event_queue
323
310
  raise "Attempt to use after 'drop'" if not @object_expose_pointer
324
- ObjectDescriptorEvents.new(FFI::hakuban_object_expose_events_get(@object_expose_pointer))
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
- end
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 events
412
+ def new_callback_event_queue
417
413
  raise "Attempt to use after 'drop'" if not @tag_observe_pointer
418
- ObjectDescriptorEvents.new(FFI::hakuban_tag_observe_events_get(@tag_observe_pointer))
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 events
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
- ObjectDescriptorEvents.new(FFI::hakuban_tag_expose_events_get(@tag_expose_pointer))
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?
@@ -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, object_class, block)
52
+ def initialize(contract, block, retry_backoff, terminate_on_deactivation, on_exception_policy)
16
53
  @contract = contract
17
- @objects = {}
18
- @running_handlers = {}
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.events
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
- case event.action
32
- when :insert
33
- raise if @objects[event.descriptor]
34
- @objects[event.descriptor] = object_class.new(@contract, event.descriptor)
35
- @event_queue << Event.new(action: :handler_start, descriptor: event.descriptor) if block
36
- when :change
37
- raise if not @objects[event.descriptor]
38
- @objects[event.descriptor].do_change(:change)
39
- when :remove
40
- raise if not @objects[event.descriptor]
41
- @objects[event.descriptor].do_change(:remove)
42
- @objects.delete(event.descriptor)
43
- when :handler_start
44
- if (object = @objects[event.descriptor]) and !object.handler_already_run and !@running_handlers[event.descriptor]
45
- descriptor_for_lambda = event.descriptor
46
- @running_handlers[event.descriptor] = async_run {
47
- object.run(block)
48
- @event_queue << Event.new(action: :handler_finished, descriptor: descriptor_for_lambda) if @event_queue
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
- when :handler_finished
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
- def objects; @objects; end
73
- def object; @objects.values.first; end
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 ManagedObject
187
+ class ManagedObjectBase
90
188
 
91
- attr_reader :descriptor, :async, :handler_already_run
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
- @handler_already_run = false
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 :remove then return false
210
+ when :stop then return false
113
211
  end
114
212
  }
115
213
  end
116
214
 
117
215
 
118
- def do_change(change)
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 ObservedObject < ManagedObject
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 ExposedObject < ManagedObject
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 ObservedObject < ManagedObject
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 ExposedObject < ManagedObject
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
@@ -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.join
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
- class ObjectExpose
25
- def thread(&block)
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 TagObserve
32
- def thread(&block)
33
- ThreadObjectManager.new(self, ObservedObject, block)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hakuban
4
- VERSION = "0.6.0"
4
+ VERSION = "0.6.3"
5
5
  end
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.0
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-01-16 00:00:00.000000000 Z
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