hakuban 0.6.0 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
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