hakuban 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,13 @@
1
1
  require 'set'
2
+ require 'ostruct'
2
3
 
3
4
  require_relative './ffi.rb'
4
5
 
5
6
  #TODO: explicit drops?
6
7
  #TODO: privative methods
8
+ #TODO: error classes
9
+
10
+ #AutoPointers use proc-wrapped calls because they segfault sometimes when used with FFI::method(:xxx) (why?)
7
11
 
8
12
  module Hakuban
9
13
 
@@ -28,26 +32,73 @@ module Hakuban
28
32
  end
29
33
 
30
34
 
35
+ @@logger_initialized = false
36
+
37
+ def self.logger_initialize(default_level, skip_if_already_initialized = false)
38
+ if @@logger_initialized and !skip_if_already_initialized
39
+ raise "Logger already initialized. This can't be done more than once. Make sure logger_initialize is called before any LocalNode gets constructed."
40
+ end
41
+ if not @@logger_initialized
42
+ raise "Invalid default log level string" if FFI::hakuban_logger_initialize(default_level) != 0
43
+ @@logger_initialized = true
44
+ end
45
+ end
46
+
47
+
31
48
  class LocalNode
32
49
 
33
50
  #TODO: explicit drop
34
51
 
35
52
  attr_reader :local_node_pointer #todo: hide
36
53
 
37
- def initialize(name=nil)
38
- result = FFI::hakuban_local_node_new(name || "local")
54
+ def initialize(name: nil)
55
+ @default_serializer = lambda { |data_type, data|
56
+ [["JSON"]+data_type, JSON.dump(data)]
57
+ }
58
+ @default_deserializer = lambda { |data_type, data|
59
+ raise "Expected JSON serialized data, got: #{dat_type}" if data_type[0] != "JSON"
60
+ [data_type[1..-1], JSON.load(data)]
61
+ }
62
+ Hakuban::logger_initialize("hakuban=warn", true)
63
+ result = FFI::hakuban_local_node_new(name || File.basename(caller_locations(0..1)[1].path))
39
64
  Hakuban::raise_if_error(result)
40
65
  @local_node_pointer = ::FFI::AutoPointer.new(result[:local_node_pointer], FFI::method(:hakuban_local_node_drop))
41
66
  end
42
67
 
68
+ def with_default_serializer(&block)
69
+ @default_serializer = block
70
+ self
71
+ end
72
+
73
+ def with_default_deserializer(&block)
74
+ @default_deserializer = block
75
+ self
76
+ end
77
+
78
+ def default_serializer(&block)
79
+ if block_given?
80
+ @default_serializer = block
81
+ else
82
+ @default_serializer
83
+ end
84
+ end
85
+
86
+ def default_deserializer(&block)
87
+ if block_given?
88
+ @default_deserializer = block
89
+ else
90
+ @default_deserializer
91
+ end
92
+ end
93
+
43
94
  def object(tags, descriptor)
44
95
  #TODO: accept real descriptor too
45
- ObjectBuilder.new(self, ObjectDescriptor.new(tags,descriptor))
96
+ ObjectBuilder.new(self, ObjectDescriptor.new(tags,descriptor), @default_serializer, @default_deserializer)
46
97
  end
47
98
 
48
99
  def tag(descriptor)
49
100
  #TODO: accept real descriptor too
50
- TagBuilder.new(self, TagDescriptor.new(descriptor))
101
+ TagBuilder.new(self, TagDescriptor.new(descriptor), @default_serializer, @default_deserializer)
51
102
  end
52
103
 
53
104
  end
@@ -55,16 +106,24 @@ module Hakuban
55
106
 
56
107
  class ObjectBuilder
57
108
 
58
- def initialize(store, descriptor)
59
- @store, @descriptor = store, descriptor
109
+ def initialize(store, descriptor, serializer, deserializer)
110
+ @store, @descriptor, @serializer, @deserializer = store, descriptor, serializer, deserializer
60
111
  end
61
112
 
62
113
  def observe
63
- ObjectObserve.new(@store, @descriptor)
114
+ ObjectObserve.new(@store, @descriptor, @deserializer)
64
115
  end
65
116
 
66
117
  def expose
67
- ObjectExpose.new(@store, @descriptor)
118
+ ObjectExpose.new(@store, @descriptor, @serializer)
119
+ end
120
+
121
+ def with_serializer(&block)
122
+ @serializer = block
123
+ end
124
+
125
+ def with_deserializer(&block)
126
+ @deserializer = block
68
127
  end
69
128
 
70
129
  end
@@ -72,16 +131,24 @@ module Hakuban
72
131
 
73
132
  class TagBuilder
74
133
 
75
- def initialize(store, descriptor)
76
- @store, @descriptor = store, descriptor
134
+ def initialize(store, descriptor, serializer, deserializer)
135
+ @store, @descriptor, @serializer, @deserializer = store, descriptor, serializer, deserializer
77
136
  end
78
137
 
79
138
  def observe
80
- TagObserve.new(@store, @descriptor)
139
+ TagObserve.new(@store, @descriptor, @deserializer)
81
140
  end
82
141
 
83
142
  def expose
84
- TagExpose.new(@store, @descriptor)
143
+ TagExpose.new(@store, @descriptor, @serializer)
144
+ end
145
+
146
+ def with_serializer(&block)
147
+ @serializer = block
148
+ end
149
+
150
+ def with_deserializer(&block)
151
+ @deserializer = block
85
152
  end
86
153
 
87
154
  end
@@ -91,15 +158,16 @@ module Hakuban
91
158
  attr_reader :tags, :json
92
159
 
93
160
  def initialize(tags,json)
94
- @tags, @json = Set.new(tags), json
161
+ @tags = Set.new(tags.map { |tag| tag.kind_of?(TagDescriptor) ? tag : TagDescriptor.new(tag) })
162
+ @json = json
95
163
  end
96
164
 
97
165
  def to_ffi
98
- FFI::FFIObjectDescriptor.construct(@tags, @json)
166
+ FFI::FFIObjectDescriptor.construct(@tags.map(&:json), @json)
99
167
  end
100
168
 
101
169
  def self.from_ffi(ffi)
102
- ObjectDescriptor.new(ffi.tags, ffi.json)
170
+ ObjectDescriptor.new(ffi.tags.map{ |tag| TagDescriptor.new(tag) }, ffi.json)
103
171
  end
104
172
 
105
173
  def ==(other)
@@ -111,6 +179,11 @@ module Hakuban
111
179
  def hash
112
180
  [@tags.hash, @json.hash].hash
113
181
  end
182
+
183
+ def inspect
184
+ "#<ObjectDescriptor @tags={%s}, @json=%p>"%[self.tags.map(&:inspect).join(","), self.json]
185
+ end
186
+
114
187
  end
115
188
 
116
189
 
@@ -142,68 +215,59 @@ module Hakuban
142
215
  end
143
216
 
144
217
 
145
- class EventQueue
146
-
147
- def initialize(queue, prefix, register_method, pointer, unregister_method)
148
- @queue = queue
149
- @callback = EventQueue.generate_callback(@queue, prefix)
150
- @registered_callback_pointer = ::FFI::AutoPointer.new(
151
- register_method.call(pointer, @callback, ::FFI::Pointer::NULL),
152
- EventQueue.generate_unregister(unregister_method, @callback)
153
- )
154
- #puts "Allocated callback pointer: #{@registered_callback_pointer}"
155
- #puts "Allocated callback queue: #{@events}"
156
- end
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
157
222
 
158
- def self.generate_callback(queue, prefix)
159
- proc { |_userdata, ffi_descriptor, ffi_action|
160
- #puts "Callback for queue: #{queue}"
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|
161
226
  action = Hakuban::action_int_to_symbol(ffi_action)
162
227
  descriptor = ObjectDescriptor.from_ffi(ffi_descriptor)
163
- queue << prefix + [action, descriptor]
228
+ callback.call(descriptor, action)
164
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
+ )
165
234
  end
166
235
 
167
- def self.generate_unregister(unregister_method, callback)
168
- proc { |pointer|
169
- #puts "Dropping callback pointer: #{pointer}"
170
- callback # probably not needed, but I want to be sure this is captured
171
- unregister_method.call(pointer)
172
- }
236
+ def callback_unregister
237
+ @callback_pointer.free
238
+ @callback_pointer = nil
173
239
  end
174
240
 
175
- end
241
+ def drop
242
+ @events_pointer.free
243
+ @events_pointer = nil
244
+ end
176
245
 
246
+ end
177
247
 
178
248
  class ObjectObserve
179
249
 
180
250
  attr_reader :descriptor
181
251
 
182
- def initialize(local_node, descriptor)
183
- @local_node, @descriptor = local_node, descriptor
252
+ def initialize(local_node, descriptor, deserializer)
253
+ @local_node, @descriptor, @deserializer = local_node, descriptor, deserializer
184
254
  result = FFI::hakuban_object_observe_new(@local_node.local_node_pointer, descriptor.to_ffi)
185
255
  Hakuban::raise_if_error(result)
186
- @object_observe_pointer = ::FFI::AutoPointer.new(result[:object_observe_pointer], FFI::method(:hakuban_object_observe_drop))
187
- @queues = {}
256
+ @object_observe_pointer = ::FFI::AutoPointer.new(result[:object_observe_pointer], proc { |ptr| FFI::hakuban_object_observe_drop(ptr) })
188
257
  end
189
258
 
190
259
  def object_state
191
260
  raise "Attempt to use after 'drop'" if not @object_observe_pointer
192
- ObjectObserveState.new(FFI::hakuban_object_observe_state_borrow(@object_observe_pointer))
193
- end
194
-
195
- def send_events_to(queue, *prefix)
196
- @queues[queue] = EventQueue.new(
197
- queue,
198
- prefix,
199
- FFI::method(:hakuban_object_observe_changes_callback_register),
200
- @object_observe_pointer,
201
- FFI::method(:hakuban_object_callback_unregister)
202
- )
261
+ if (state_ptr = FFI::hakuban_object_observe_state_borrow(@object_observe_pointer)).null?
262
+ nil
263
+ else
264
+ ObjectObserveState.new(state_ptr, @deserializer)
265
+ end
203
266
  end
204
267
 
205
- def stop_sending_objects_events_to(queue)
206
- @queues.delete(queue)
268
+ def events
269
+ raise "Attempt to use after 'drop'" if not @object_observe_pointer
270
+ ObjectDescriptorEvents.new(FFI::hakuban_object_observe_events_get(@object_observe_pointer))
207
271
  end
208
272
 
209
273
  def inspect
@@ -213,12 +277,10 @@ module Hakuban
213
277
  def drop
214
278
  @object_observe_pointer.free
215
279
  @object_observe_pointer = nil
216
- @queues.values.each { |pointer| pointer.free }
217
- @queues.clear
218
280
  end
219
281
 
220
- def manage(object_class, *object_constructor_params)
221
- object_class::new(self, @descriptor, *object_constructor_params)
282
+ def dropped?
283
+ @object_observe_pointer.nil?
222
284
  end
223
285
 
224
286
  end
@@ -228,51 +290,51 @@ module Hakuban
228
290
 
229
291
  attr_reader :descriptor
230
292
 
231
- def initialize(local_node, descriptor)
232
- @local_node, @descriptor = local_node, descriptor
293
+ def initialize(local_node, descriptor, serializer)
294
+ @local_node, @descriptor, @serializer = local_node, descriptor, serializer
233
295
  result = FFI::hakuban_object_expose_new(@local_node.local_node_pointer, descriptor.to_ffi)
234
296
  Hakuban::raise_if_error(result)
235
297
  @object_expose_pointer = ::FFI::AutoPointer.new(result[:object_expose_pointer], FFI::method(:hakuban_object_expose_drop))
236
- @queues = {}
237
298
  end
238
299
 
239
- def set_object_state(version, data_type, data)
300
+ def set_object_state(version, data, data_type: [], assignment: 0)
240
301
  raise "Attempt to use after 'drop'" if not @object_expose_pointer
241
- data_type = ["MessagePack"] + data_type
242
- serialized = MessagePack.pack(data)
243
- result = FFI::hakuban_object_expose_state(@object_expose_pointer, FFI::FFIObjectExposeState.construct(version, data_type, serialized))
302
+ serialized_data_type, serialized_data = @serializer.call(data_type, data)
303
+ result = FFI::hakuban_object_expose_state(@object_expose_pointer, FFI::FFIObjectExposeState.construct(version, serialized_data_type, serialized_data), assignment)
244
304
  Hakuban::raise_if_error(result)
245
305
  result[:changed] == 1
246
306
  end
247
307
 
248
- def assigned
308
+ def assignment
249
309
  raise "Attempt to use after 'drop'" if not @object_expose_pointer
250
- FFI::hakuban_object_expose_assigned(@object_expose_pointer) == 1
310
+ FFI::hakuban_object_expose_assignment(@object_expose_pointer)
251
311
  end
252
312
 
253
- def send_events_to(queue, *prefix)
254
- @queues[queue] = EventQueue.new(
255
- queue,
256
- prefix,
257
- FFI::method(:hakuban_object_expose_changes_callback_register),
258
- @object_expose_pointer,
259
- FFI::method(:hakuban_object_callback_unregister)
260
- )
313
+ def assigned?
314
+ assignment > 0
315
+ end
316
+
317
+ def desynchronize(assignment)
318
+ raise "Attempt to use after 'drop'" if not @object_expose_pointer
319
+ FFI::hakuban_object_expose_desynchronize(@object_expose_pointer, assignment)
261
320
  end
262
321
 
263
- def stop_sending_objects_events_to(queue)
264
- @queues.delete(queue)
322
+ def events
323
+ raise "Attempt to use after 'drop'" if not @object_expose_pointer
324
+ ObjectDescriptorEvents.new(FFI::hakuban_object_expose_events_get(@object_expose_pointer))
325
+ end
326
+
327
+ def inspect
328
+ "#<ObjectExpose #{@descriptor}>"
265
329
  end
266
330
 
267
331
  def drop
268
332
  @object_expose_pointer.free
269
333
  @object_expose_pointer = nil
270
- @queues.values.each { |pointer| pointer.free }
271
- @queues.clear
272
334
  end
273
335
 
274
- def manage(object_class, *object_constructor_params)
275
- object_class::new(self, @descriptor, *object_constructor_params)
336
+ def dropped?
337
+ @object_expose_pointer.nil?
276
338
  end
277
339
 
278
340
  end
@@ -280,29 +342,45 @@ module Hakuban
280
342
 
281
343
  class ObjectObserveState
282
344
 
283
- attr_reader :data, :data_type, :data_version
284
-
285
- def initialize(raw_state)
286
- @raw_state = raw_state
287
- @synchronized = (raw_state[:synchronized] == 1)
288
- @data_type = raw_state[:data_type].read_array_of_pointer(raw_state[:data_type_length]).map { |string| string.read_string() }
289
- @data_version = raw_state[:version].read_array_of_type(::FFI::TYPE_INT64, :read_int64, raw_state[:version_length]) if not raw_state[:version].null?
290
- @data = MessagePack.unpack(raw_state[:raw].read_string_length(raw_state[:raw_length])) if not raw_state[:raw].null?
291
- ObjectSpace.define_finalizer(self, ObjectObserveState.finalize(@raw_state))
345
+ def initialize(state, deserializer)
346
+ @state, @deserializer = state, deserializer
347
+ ObjectSpace.define_finalizer(self, ObjectObserveState.finalize(@state))
292
348
  end
293
349
 
294
- def ObjectObserveState.finalize(raw_state)
350
+ def ObjectObserveState.finalize(state)
295
351
  proc { |_|
296
- FFI::hakuban_object_observe_state_return(raw_state)
352
+ FFI::hakuban_object_observe_state_return(state)
297
353
  }
298
354
  end
299
355
 
300
356
  def version
301
- @data_version
357
+ return @data_version if @data_version
358
+ ffi_version = FFI::hakuban_object_observe_state_get_data_version(@state)
359
+ @data_version = ffi_version[:version_elements].read_array_of_type(::FFI::TYPE_INT64, :read_int64, ffi_version[:version_length])
360
+ end
361
+
362
+ def data
363
+ return @data if @data
364
+ ffi_data = FFI::hakuban_object_observe_state_get_data(@state)
365
+ ffi_data_type = FFI::hakuban_object_observe_state_get_data_type(@state)
366
+ serialized_data_type = ffi_data_type[:type_elements].read_array_of_pointer(ffi_data_type[:type_length]).map { |string| string.read_string() }
367
+ @data_type, @data = @deserializer.call(serialized_data_type, ffi_data[:data_bytes].read_string_length(ffi_data[:data_length]))
368
+ @data
369
+ end
370
+
371
+ def data_type
372
+ return @data_type if @data_type
373
+ data
374
+ @data_type
375
+ end
376
+
377
+ def synchronized
378
+ return @synchronized if @synchronized
379
+ @synchronized = FFI::hakuban_object_observe_state_get_synchronized(@state)
302
380
  end
303
381
 
304
382
  def inspect
305
- "#<ObjectObserveState version=#{@data_version}>"
383
+ "#<ObjectObserveState @synchronized=%p @version=%p>"%[@synchronized, @data_version]
306
384
  end
307
385
 
308
386
  end
@@ -312,12 +390,11 @@ module Hakuban
312
390
 
313
391
  attr_reader :descriptor
314
392
 
315
- def initialize(local_node, descriptor)
316
- @local_node, @descriptor = local_node, descriptor
393
+ def initialize(local_node, descriptor, deserializer)
394
+ @local_node, @descriptor, @deserializer = local_node, descriptor, deserializer
317
395
  result = FFI::hakuban_tag_observe_new(@local_node.local_node_pointer, @descriptor.to_ffi)
318
396
  Hakuban::raise_if_error(result)
319
397
  @tag_observe_pointer = ::FFI::AutoPointer.new(result[:tag_observe_pointer], FFI::method(:hakuban_tag_observe_drop))
320
- @queues = {}
321
398
  end
322
399
 
323
400
  def object_descriptors
@@ -333,36 +410,21 @@ module Hakuban
333
410
  result = FFI::hakuban_tag_observe_object_state_borrow(@tag_observe_pointer, object_descriptor.to_ffi)
334
411
  return nil if result[:error] == 4
335
412
  Hakuban::raise_if_error(result)
336
- ObjectObserveState.new(result[:state])
413
+ ObjectObserveState.new(result[:state], @deserializer)
337
414
  end
338
415
 
339
- def send_events_to(*params)
340
- self.send_objects_events_to(*params)
341
- end
342
-
343
- def send_objects_events_to(queue, *prefix)
344
- @queues[queue] = EventQueue.new(
345
- queue,
346
- prefix,
347
- FFI::method(:hakuban_tag_observe_objects_changes_callback_register),
348
- @tag_observe_pointer,
349
- FFI::method(:hakuban_object_callback_unregister)
350
- )
351
- end
352
-
353
- def stop_sending_objects_events_to(queue)
354
- @queues.delete(queue)
416
+ def events
417
+ raise "Attempt to use after 'drop'" if not @tag_observe_pointer
418
+ ObjectDescriptorEvents.new(FFI::hakuban_tag_observe_events_get(@tag_observe_pointer))
355
419
  end
356
420
 
357
421
  def drop
358
422
  @tag_observe_pointer.free
359
423
  @tag_observe_pointer = nil
360
- @queues.values.each { |pointer| pointer.free }
361
- @queues.clear
362
424
  end
363
425
 
364
- def manage(object_class, *object_constructor_params)
365
- ObjectManager::new(self, object_class, *object_constructor_params)
426
+ def dropped?
427
+ @tag_observe_pointer.nil?
366
428
  end
367
429
 
368
430
  end
@@ -372,12 +434,11 @@ module Hakuban
372
434
 
373
435
  attr_reader :descriptor
374
436
 
375
- def initialize(local_node, descriptor)
376
- @local_node, @descriptor = local_node, descriptor
437
+ def initialize(local_node, descriptor, serializer)
438
+ @local_node, @descriptor, @serializer = local_node, descriptor, serializer
377
439
  result = FFI::hakuban_tag_expose_new(@local_node.local_node_pointer, descriptor.to_ffi)
378
440
  Hakuban::raise_if_error(result)
379
441
  @tag_expose_pointer = ::FFI::AutoPointer.new(result[:tag_expose_pointer], FFI::method(:hakuban_tag_expose_drop))
380
- @queues = {}
381
442
  end
382
443
 
383
444
  def object_descriptors
@@ -388,42 +449,41 @@ module Hakuban
388
449
  ret
389
450
  end
390
451
 
391
- def set_object_state(object_descriptor, version, data_type, data)
452
+ def set_object_state(object_descriptor, version, data, data_type: [], assignment: 0)
392
453
  raise "Attempt to use after 'drop'" if not @tag_expose_pointer
393
- data_type = ["MessagePack"] + data_type
394
- serialized = MessagePack.pack(data)
395
- result = FFI::hakuban_tag_expose_object_state(@tag_expose_pointer, object_descriptor.to_ffi, FFI::FFIObjectExposeState.construct(version, data_type, serialized))
454
+ raise if not version #TODO: replace this by type check
455
+ serialized_data_type, serialized_data = @serializer.call(data_type, data)
456
+ result = FFI::hakuban_tag_expose_object_state(@tag_expose_pointer, object_descriptor.to_ffi, FFI::FFIObjectExposeState.construct(version, serialized_data_type, serialized_data), assignment)
396
457
  Hakuban::raise_if_error(result)
397
458
  result[:changed] == 1
398
459
  end
399
460
 
400
- def send_events_to(*params)
401
- self.send_objects_events_to(*params)
461
+ def assignment(object_descriptor)
462
+ raise "Attempt to use after 'drop'" if not @tag_expose_pointer
463
+ FFI::hakuban_tag_expose_object_assignment(@tag_expose_pointer, object_descriptor.to_ffi)
402
464
  end
403
465
 
404
- def send_objects_events_to(queue, *prefix)
405
- @queues[queue] = EventQueue.new(
406
- queue,
407
- prefix,
408
- FFI::method(:hakuban_tag_expose_objects_changes_callback_register),
409
- @tag_expose_pointer,
410
- FFI::method(:hakuban_object_callback_unregister)
411
- )
466
+ def assigned?(object_descriptor)
467
+ assignment(object_descriptor) > 0
468
+ end
469
+
470
+ def desynchronize(object_descriptor, assignment)
471
+ raise "Attempt to use after 'drop'" if not @tag_expose_pointer
472
+ FFI::hakuban_tag_expose_object_desynchronize(@tag_expose_pointer, object_descriptor.to_ffi, assignment)
412
473
  end
413
474
 
414
- def stop_sending_objects_events_to(queue)
415
- @queues.delete(queue)
475
+ def events
476
+ raise "Attempt to use after 'drop'" if not @tag_expose_pointer
477
+ ObjectDescriptorEvents.new(FFI::hakuban_tag_expose_events_get(@tag_expose_pointer))
416
478
  end
417
479
 
418
480
  def drop
419
481
  @tag_expose_pointer.free
420
482
  @tag_expose_pointer = nil
421
- @queues.values.each { |pointer| pointer.free }
422
- @queues.clear
423
483
  end
424
484
 
425
- def manage(object_class, *object_constructor_params)
426
- ObjectManager::new(self, object_class, *object_constructor_params)
485
+ def dropped?
486
+ @tag_expose_pointer.nil?
427
487
  end
428
488
 
429
489
  end
@@ -452,104 +512,19 @@ module Hakuban
452
512
 
453
513
  #TODO: drop
454
514
 
455
- def initialize(url)
456
- result = FFI::hakuban_tokio_websocket_connector_new(Tokio.pointer, url)
515
+ def initialize(local_node, url)
516
+ result = FFI::hakuban_tokio_websocket_connector_new(Tokio.pointer, local_node.local_node_pointer, url)
457
517
  Hakuban::raise_if_error(result)
458
- @websocket_connector_pointer = result[:websocket_connector_pointer]
518
+ @websocket_connector_pointer = ::FFI::AutoPointer.new(result[:websocket_connector_pointer], WebsocketConnector.generate_drop)
459
519
  end
460
520
 
461
- def start(local_node)
462
- @local_node = local_node
463
- FFI::hakuban_tokio_websocket_connector_start(Tokio.pointer, @websocket_connector_pointer, @local_node.local_node_pointer)
464
- self
465
- end
466
-
467
- end
468
-
469
-
470
- # convenience utils
471
-
472
- class ObjectManager
473
-
474
- attr_reader :objects, :contract
475
-
476
- def initialize(contract, object_class, *object_constructor_params)
477
- @contract = contract
478
- @objects = {}
479
- @queue = Queue.new
480
- contract.send_events_to(@queue, :object)
481
- @thread = Thread.new {
482
- loop {
483
- event = @queue.shift
484
- case event[0..1]
485
- when [:control, :quit]
486
- break
487
- when [:object, :insert]
488
- @objects[event[2]] = object_class.new(@contract, event[2], *object_constructor_params)
489
- when [:object, :change]
490
- @objects[event[2]].change if @objects[event[2]].respond_to?(:change)
491
- when [:object, :remove]
492
- raise if not deleted = @objects.delete(event[2])
493
- deleted.drop if deleted.respond_to?(:drop)
494
- end
495
- }
521
+ def self.generate_drop
522
+ proc { |pointer|
523
+ FFI::hakuban_tokio_websocket_connector_drop(Tokio.pointer, pointer)
496
524
  }
497
525
  end
498
526
 
499
- def drop
500
- @contract.stop_sending_objects_events_to(@queue)
501
- @queue.push [:control, :quit]
502
- @thread.join
503
- @queue, @contract, @thread, @objects = nil, nil, nil, {}
504
- end
505
-
506
-
507
- class ManagedObject
508
- attr_reader :contract, :descriptor
509
- def initialize(contract, descriptor)
510
- @contract, @descriptor = contract, descriptor
511
- end
512
- end
513
-
514
-
515
- #TODO: fix the arity thing...
516
- module ObservedObject
517
- def state
518
- if @contract.method(:object_state).arity == 1
519
- @contract.object_state(@descriptor)
520
- else
521
- @contract.object_state
522
- end
523
- end
524
- def data
525
- if @contract.method(:object_state).arity == 1
526
- @contract.object_state(@descriptor)&.data
527
- else
528
- @contract.object_state&.data
529
- end
530
- end
531
- end
532
-
533
- module ExposedObject
534
- def state=(state)
535
- if @contract.method(:set_object_state).arity == 4
536
- @contract.set_object_state(@descriptor, *state)
537
- else
538
- @contract.set_object_state(*state)
539
- end
540
- end
541
- def data=(value)
542
- timestamp = Time.new.to_f.floor
543
- if @contract.method(:set_object_state).arity == 4
544
- @contract.set_object_state(@descriptor,[1, timestamp.floor, ((timestamp - timestamp.floor)*1000000000).floor, 0],[],value)
545
- else
546
- @contract.set_object_state([1, timestamp.floor, ((timestamp - timestamp.floor)*1000000000).floor, 0],[],value)
547
- end
548
- end
549
- end
550
527
  end
551
528
 
552
529
 
553
-
554
-
555
530
  end