hakuban 0.5.1 → 0.6.1
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/MIT-LICENSE +20 -0
- data/bin/hakuban-observer +56 -0
- data/bin/hakuban-thread-engine +45 -0
- data/lib/hakuban/async.rb +45 -0
- data/lib/hakuban/engine.rb +44 -0
- data/lib/hakuban/ffi.rb +36 -18
- data/lib/hakuban/hakuban.rb +175 -295
- data/lib/hakuban/manager.rb +259 -0
- data/lib/hakuban/thread.rb +44 -0
- data/lib/hakuban/version.rb +1 -1
- data/lib/hakuban.rb +3 -0
- metadata +21 -22
- data/.gitignore +0 -12
- data/.rspec +0 -3
- data/Gemfile +0 -6
- data/LICENSE.txt +0 -21
- data/bin/console +0 -15
- data/bin/setup +0 -8
- data/examples/all-top-managed.rb +0 -46
- data/examples/all-top-simple.rb +0 -26
- data/examples/cpu-usage.rb +0 -16
- data/hakuban.gemspec +0 -36
data/lib/hakuban/hakuban.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'set'
|
2
|
+
require 'ostruct'
|
2
3
|
|
3
4
|
require_relative './ffi.rb'
|
4
5
|
|
@@ -6,6 +7,7 @@ require_relative './ffi.rb'
|
|
6
7
|
#TODO: privative methods
|
7
8
|
#TODO: error classes
|
8
9
|
|
10
|
+
#AutoPointers use proc-wrapped calls because they segfault sometimes when used with FFI::method(:xxx) (why?)
|
9
11
|
|
10
12
|
module Hakuban
|
11
13
|
|
@@ -49,21 +51,54 @@ module Hakuban
|
|
49
51
|
|
50
52
|
attr_reader :local_node_pointer #todo: hide
|
51
53
|
|
52
|
-
def initialize(name
|
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: #{data_type}" if data_type[0] != "JSON"
|
60
|
+
[data_type[1..-1], JSON.load(data)]
|
61
|
+
}
|
53
62
|
Hakuban::logger_initialize("hakuban=warn", true)
|
54
63
|
result = FFI::hakuban_local_node_new(name || File.basename(caller_locations(0..1)[1].path))
|
55
64
|
Hakuban::raise_if_error(result)
|
56
65
|
@local_node_pointer = ::FFI::AutoPointer.new(result[:local_node_pointer], FFI::method(:hakuban_local_node_drop))
|
57
66
|
end
|
58
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
|
+
|
59
94
|
def object(tags, descriptor)
|
60
95
|
#TODO: accept real descriptor too
|
61
|
-
ObjectBuilder.new(self, ObjectDescriptor.new(tags,descriptor))
|
96
|
+
ObjectBuilder.new(self, ObjectDescriptor.new(tags,descriptor), @default_serializer, @default_deserializer)
|
62
97
|
end
|
63
98
|
|
64
99
|
def tag(descriptor)
|
65
100
|
#TODO: accept real descriptor too
|
66
|
-
TagBuilder.new(self, TagDescriptor.new(descriptor))
|
101
|
+
TagBuilder.new(self, TagDescriptor.new(descriptor), @default_serializer, @default_deserializer)
|
67
102
|
end
|
68
103
|
|
69
104
|
end
|
@@ -71,16 +106,24 @@ module Hakuban
|
|
71
106
|
|
72
107
|
class ObjectBuilder
|
73
108
|
|
74
|
-
def initialize(store, descriptor)
|
75
|
-
@store, @descriptor = store, descriptor
|
109
|
+
def initialize(store, descriptor, serializer, deserializer)
|
110
|
+
@store, @descriptor, @serializer, @deserializer = store, descriptor, serializer, deserializer
|
76
111
|
end
|
77
112
|
|
78
113
|
def observe
|
79
|
-
ObjectObserve.new(@store, @descriptor)
|
114
|
+
ObjectObserve.new(@store, @descriptor, @deserializer)
|
80
115
|
end
|
81
116
|
|
82
117
|
def expose
|
83
|
-
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
|
84
127
|
end
|
85
128
|
|
86
129
|
end
|
@@ -88,16 +131,24 @@ module Hakuban
|
|
88
131
|
|
89
132
|
class TagBuilder
|
90
133
|
|
91
|
-
def initialize(store, descriptor)
|
92
|
-
@store, @descriptor = store, descriptor
|
134
|
+
def initialize(store, descriptor, serializer, deserializer)
|
135
|
+
@store, @descriptor, @serializer, @deserializer = store, descriptor, serializer, deserializer
|
93
136
|
end
|
94
137
|
|
95
138
|
def observe
|
96
|
-
TagObserve.new(@store, @descriptor)
|
139
|
+
TagObserve.new(@store, @descriptor, @deserializer)
|
97
140
|
end
|
98
141
|
|
99
142
|
def expose
|
100
|
-
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
|
101
152
|
end
|
102
153
|
|
103
154
|
end
|
@@ -107,15 +158,16 @@ module Hakuban
|
|
107
158
|
attr_reader :tags, :json
|
108
159
|
|
109
160
|
def initialize(tags,json)
|
110
|
-
@tags
|
161
|
+
@tags = Set.new(tags.map { |tag| tag.kind_of?(TagDescriptor) ? tag : TagDescriptor.new(tag) })
|
162
|
+
@json = json
|
111
163
|
end
|
112
164
|
|
113
165
|
def to_ffi
|
114
|
-
FFI::FFIObjectDescriptor.construct(@tags, @json)
|
166
|
+
FFI::FFIObjectDescriptor.construct(@tags.map(&:json), @json)
|
115
167
|
end
|
116
168
|
|
117
169
|
def self.from_ffi(ffi)
|
118
|
-
ObjectDescriptor.new(ffi.tags, ffi.json)
|
170
|
+
ObjectDescriptor.new(ffi.tags.map{ |tag| TagDescriptor.new(tag) }, ffi.json)
|
119
171
|
end
|
120
172
|
|
121
173
|
def ==(other)
|
@@ -163,68 +215,59 @@ module Hakuban
|
|
163
215
|
end
|
164
216
|
|
165
217
|
|
166
|
-
class
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
@callback = EventQueue.generate_callback(@queue, prefix)
|
171
|
-
@registered_callback_pointer = ::FFI::AutoPointer.new(
|
172
|
-
register_method.call(pointer, @callback, ::FFI::Pointer::NULL),
|
173
|
-
EventQueue.generate_unregister(unregister_method, @callback)
|
174
|
-
)
|
175
|
-
#puts "Allocated callback pointer: #{@registered_callback_pointer}"
|
176
|
-
#puts "Allocated callback queue: #{@events}"
|
177
|
-
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
|
178
222
|
|
179
|
-
|
180
|
-
|
181
|
-
|
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|
|
182
226
|
action = Hakuban::action_int_to_symbol(ffi_action)
|
183
227
|
descriptor = ObjectDescriptor.from_ffi(ffi_descriptor)
|
184
|
-
|
228
|
+
callback.call(descriptor, action)
|
185
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
|
+
)
|
186
234
|
end
|
187
235
|
|
188
|
-
def
|
189
|
-
|
190
|
-
|
191
|
-
callback # probably not needed, but I want to be sure this is captured
|
192
|
-
unregister_method.call(pointer)
|
193
|
-
}
|
236
|
+
def callback_unregister
|
237
|
+
@callback_pointer.free
|
238
|
+
@callback_pointer = nil
|
194
239
|
end
|
195
240
|
|
196
|
-
|
241
|
+
def drop
|
242
|
+
@events_pointer.free
|
243
|
+
@events_pointer = nil
|
244
|
+
end
|
197
245
|
|
246
|
+
end
|
198
247
|
|
199
248
|
class ObjectObserve
|
200
249
|
|
201
250
|
attr_reader :descriptor
|
202
251
|
|
203
|
-
def initialize(local_node, descriptor)
|
204
|
-
@local_node, @descriptor = local_node, descriptor
|
252
|
+
def initialize(local_node, descriptor, deserializer)
|
253
|
+
@local_node, @descriptor, @deserializer = local_node, descriptor, deserializer
|
205
254
|
result = FFI::hakuban_object_observe_new(@local_node.local_node_pointer, descriptor.to_ffi)
|
206
255
|
Hakuban::raise_if_error(result)
|
207
|
-
@object_observe_pointer = ::FFI::AutoPointer.new(result[:object_observe_pointer], FFI::
|
208
|
-
@queues = {}
|
256
|
+
@object_observe_pointer = ::FFI::AutoPointer.new(result[:object_observe_pointer], proc { |ptr| FFI::hakuban_object_observe_drop(ptr) })
|
209
257
|
end
|
210
258
|
|
211
259
|
def object_state
|
212
260
|
raise "Attempt to use after 'drop'" if not @object_observe_pointer
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
queue,
|
219
|
-
prefix,
|
220
|
-
FFI::method(:hakuban_object_observe_changes_callback_register),
|
221
|
-
@object_observe_pointer,
|
222
|
-
FFI::method(:hakuban_object_callback_unregister)
|
223
|
-
)
|
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
|
224
266
|
end
|
225
267
|
|
226
|
-
def
|
227
|
-
@
|
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))
|
228
271
|
end
|
229
272
|
|
230
273
|
def inspect
|
@@ -234,13 +277,10 @@ module Hakuban
|
|
234
277
|
def drop
|
235
278
|
@object_observe_pointer.free
|
236
279
|
@object_observe_pointer = nil
|
237
|
-
@queues.clear
|
238
280
|
end
|
239
281
|
|
240
|
-
def
|
241
|
-
|
242
|
-
manager.contract = self
|
243
|
-
manager
|
282
|
+
def dropped?
|
283
|
+
@object_observe_pointer.nil?
|
244
284
|
end
|
245
285
|
|
246
286
|
end
|
@@ -250,40 +290,38 @@ module Hakuban
|
|
250
290
|
|
251
291
|
attr_reader :descriptor
|
252
292
|
|
253
|
-
def initialize(local_node, descriptor)
|
254
|
-
@local_node, @descriptor = local_node, descriptor
|
293
|
+
def initialize(local_node, descriptor, serializer)
|
294
|
+
@local_node, @descriptor, @serializer = local_node, descriptor, serializer
|
255
295
|
result = FFI::hakuban_object_expose_new(@local_node.local_node_pointer, descriptor.to_ffi)
|
256
296
|
Hakuban::raise_if_error(result)
|
257
297
|
@object_expose_pointer = ::FFI::AutoPointer.new(result[:object_expose_pointer], FFI::method(:hakuban_object_expose_drop))
|
258
|
-
@queues = {}
|
259
298
|
end
|
260
299
|
|
261
|
-
def set_object_state(version, data_type,
|
300
|
+
def set_object_state(version, data, data_type: [], assignment: 0)
|
262
301
|
raise "Attempt to use after 'drop'" if not @object_expose_pointer
|
263
|
-
|
264
|
-
|
265
|
-
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)
|
266
304
|
Hakuban::raise_if_error(result)
|
267
305
|
result[:changed] == 1
|
268
306
|
end
|
269
307
|
|
270
|
-
def
|
308
|
+
def assignment
|
271
309
|
raise "Attempt to use after 'drop'" if not @object_expose_pointer
|
272
|
-
FFI::
|
310
|
+
FFI::hakuban_object_expose_assignment(@object_expose_pointer)
|
273
311
|
end
|
274
312
|
|
275
|
-
def
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
)
|
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)
|
283
320
|
end
|
284
321
|
|
285
|
-
def
|
286
|
-
@
|
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))
|
287
325
|
end
|
288
326
|
|
289
327
|
def inspect
|
@@ -293,13 +331,10 @@ module Hakuban
|
|
293
331
|
def drop
|
294
332
|
@object_expose_pointer.free
|
295
333
|
@object_expose_pointer = nil
|
296
|
-
@queues.clear
|
297
334
|
end
|
298
335
|
|
299
|
-
def
|
300
|
-
|
301
|
-
manager.contract = self
|
302
|
-
manager
|
336
|
+
def dropped?
|
337
|
+
@object_expose_pointer.nil?
|
303
338
|
end
|
304
339
|
|
305
340
|
end
|
@@ -307,25 +342,41 @@ module Hakuban
|
|
307
342
|
|
308
343
|
class ObjectObserveState
|
309
344
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
@raw_state = raw_state
|
314
|
-
@synchronized = (raw_state[:synchronized] == 1)
|
315
|
-
@data_type = raw_state[:data_type].read_array_of_pointer(raw_state[:data_type_length]).map { |string| string.read_string() }
|
316
|
-
@data_version = raw_state[:version].read_array_of_type(::FFI::TYPE_INT64, :read_int64, raw_state[:version_length]) if not raw_state[:version].null?
|
317
|
-
@data = MessagePack.unpack(raw_state[:raw].read_string_length(raw_state[:raw_length])) if not raw_state[:raw].null?
|
318
|
-
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))
|
319
348
|
end
|
320
349
|
|
321
|
-
def ObjectObserveState.finalize(
|
350
|
+
def ObjectObserveState.finalize(state)
|
322
351
|
proc { |_|
|
323
|
-
FFI::hakuban_object_observe_state_return(
|
352
|
+
FFI::hakuban_object_observe_state_return(state)
|
324
353
|
}
|
325
354
|
end
|
326
355
|
|
327
356
|
def version
|
328
|
-
@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)
|
329
380
|
end
|
330
381
|
|
331
382
|
def inspect
|
@@ -339,12 +390,11 @@ module Hakuban
|
|
339
390
|
|
340
391
|
attr_reader :descriptor
|
341
392
|
|
342
|
-
def initialize(local_node, descriptor)
|
343
|
-
@local_node, @descriptor = local_node, descriptor
|
393
|
+
def initialize(local_node, descriptor, deserializer)
|
394
|
+
@local_node, @descriptor, @deserializer = local_node, descriptor, deserializer
|
344
395
|
result = FFI::hakuban_tag_observe_new(@local_node.local_node_pointer, @descriptor.to_ffi)
|
345
396
|
Hakuban::raise_if_error(result)
|
346
397
|
@tag_observe_pointer = ::FFI::AutoPointer.new(result[:tag_observe_pointer], FFI::method(:hakuban_tag_observe_drop))
|
347
|
-
@queues = {}
|
348
398
|
end
|
349
399
|
|
350
400
|
def object_descriptors
|
@@ -360,37 +410,21 @@ module Hakuban
|
|
360
410
|
result = FFI::hakuban_tag_observe_object_state_borrow(@tag_observe_pointer, object_descriptor.to_ffi)
|
361
411
|
return nil if result[:error] == 4
|
362
412
|
Hakuban::raise_if_error(result)
|
363
|
-
ObjectObserveState.new(result[:state])
|
364
|
-
end
|
365
|
-
|
366
|
-
def send_events_to(*params)
|
367
|
-
self.send_objects_events_to(*params)
|
368
|
-
end
|
369
|
-
|
370
|
-
def send_objects_events_to(queue, *prefix)
|
371
|
-
@queues[queue] = EventQueue.new(
|
372
|
-
queue,
|
373
|
-
prefix,
|
374
|
-
FFI::method(:hakuban_tag_observe_objects_changes_callback_register),
|
375
|
-
@tag_observe_pointer,
|
376
|
-
FFI::method(:hakuban_object_callback_unregister)
|
377
|
-
)
|
413
|
+
ObjectObserveState.new(result[:state], @deserializer)
|
378
414
|
end
|
379
415
|
|
380
|
-
def
|
381
|
-
@
|
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))
|
382
419
|
end
|
383
420
|
|
384
421
|
def drop
|
385
422
|
@tag_observe_pointer.free
|
386
423
|
@tag_observe_pointer = nil
|
387
|
-
@queues.clear
|
388
424
|
end
|
389
425
|
|
390
|
-
def
|
391
|
-
|
392
|
-
manager.contract = self
|
393
|
-
manager
|
426
|
+
def dropped?
|
427
|
+
@tag_observe_pointer.nil?
|
394
428
|
end
|
395
429
|
|
396
430
|
end
|
@@ -400,12 +434,11 @@ module Hakuban
|
|
400
434
|
|
401
435
|
attr_reader :descriptor
|
402
436
|
|
403
|
-
def initialize(local_node, descriptor)
|
404
|
-
@local_node, @descriptor = local_node, descriptor
|
437
|
+
def initialize(local_node, descriptor, serializer)
|
438
|
+
@local_node, @descriptor, @serializer = local_node, descriptor, serializer
|
405
439
|
result = FFI::hakuban_tag_expose_new(@local_node.local_node_pointer, descriptor.to_ffi)
|
406
440
|
Hakuban::raise_if_error(result)
|
407
441
|
@tag_expose_pointer = ::FFI::AutoPointer.new(result[:tag_expose_pointer], FFI::method(:hakuban_tag_expose_drop))
|
408
|
-
@queues = {}
|
409
442
|
end
|
410
443
|
|
411
444
|
def object_descriptors
|
@@ -416,43 +449,41 @@ module Hakuban
|
|
416
449
|
ret
|
417
450
|
end
|
418
451
|
|
419
|
-
def set_object_state(object_descriptor, version, data_type,
|
452
|
+
def set_object_state(object_descriptor, version, data, data_type: [], assignment: 0)
|
420
453
|
raise "Attempt to use after 'drop'" if not @tag_expose_pointer
|
421
|
-
|
422
|
-
|
423
|
-
result = FFI::hakuban_tag_expose_object_state(@tag_expose_pointer, object_descriptor.to_ffi, FFI::FFIObjectExposeState.construct(version,
|
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)
|
424
457
|
Hakuban::raise_if_error(result)
|
425
458
|
result[:changed] == 1
|
426
459
|
end
|
427
460
|
|
428
|
-
def
|
429
|
-
|
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)
|
430
464
|
end
|
431
465
|
|
432
|
-
def
|
433
|
-
|
434
|
-
queue,
|
435
|
-
prefix,
|
436
|
-
FFI::method(:hakuban_tag_expose_objects_changes_callback_register),
|
437
|
-
@tag_expose_pointer,
|
438
|
-
FFI::method(:hakuban_object_callback_unregister)
|
439
|
-
)
|
466
|
+
def assigned?(object_descriptor)
|
467
|
+
assignment(object_descriptor) > 0
|
440
468
|
end
|
441
469
|
|
442
|
-
def
|
443
|
-
@
|
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)
|
473
|
+
end
|
474
|
+
|
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))
|
444
478
|
end
|
445
479
|
|
446
480
|
def drop
|
447
481
|
@tag_expose_pointer.free
|
448
482
|
@tag_expose_pointer = nil
|
449
|
-
@queues.clear
|
450
483
|
end
|
451
484
|
|
452
|
-
def
|
453
|
-
|
454
|
-
manager.contract = self
|
455
|
-
manager
|
485
|
+
def dropped?
|
486
|
+
@tag_expose_pointer.nil?
|
456
487
|
end
|
457
488
|
|
458
489
|
end
|
@@ -487,12 +518,6 @@ module Hakuban
|
|
487
518
|
@websocket_connector_pointer = ::FFI::AutoPointer.new(result[:websocket_connector_pointer], WebsocketConnector.generate_drop)
|
488
519
|
end
|
489
520
|
|
490
|
-
def start(local_node)
|
491
|
-
@local_node = local_node
|
492
|
-
FFI::hakuban_tokio_websocket_connector_start(Tokio.pointer, @websocket_connector_pointer, @local_node.local_node_pointer)
|
493
|
-
self
|
494
|
-
end
|
495
|
-
|
496
521
|
def self.generate_drop
|
497
522
|
proc { |pointer|
|
498
523
|
FFI::hakuban_tokio_websocket_connector_drop(Tokio.pointer, pointer)
|
@@ -502,149 +527,4 @@ module Hakuban
|
|
502
527
|
end
|
503
528
|
|
504
529
|
|
505
|
-
# convenience utils
|
506
|
-
|
507
|
-
#TODO: replace this mess (<Hash, dynamic mixings) with some "deref"
|
508
|
-
class ObjectManager < Hash
|
509
|
-
|
510
|
-
module ObservedObjectManager
|
511
|
-
def descriptor; self.values.first.descriptor; end
|
512
|
-
def state; self.values.first.state; end
|
513
|
-
def data; self.values.first.data; end
|
514
|
-
def version; self.values.first.verison; end
|
515
|
-
def synchronized; self.values.first.synchronized; end
|
516
|
-
def construct_object(contract, descriptor); ObservedObject.new(contract, descriptor); end
|
517
|
-
end
|
518
|
-
|
519
|
-
module ExposedObjectManager
|
520
|
-
def descriptor; self.values.first.descriptor; end
|
521
|
-
def state=(params); self.values.first.state = params; end
|
522
|
-
def data=(params); self.values.first.data = params; end
|
523
|
-
def state_set(params); self.values.first.state_set(params); end
|
524
|
-
def data_set(params); self.values.first.data_set(params); end
|
525
|
-
def construct_object(contract, descriptor); ExposedObject.new(contract, descriptor); end
|
526
|
-
end
|
527
|
-
|
528
|
-
module ObservedTagManager
|
529
|
-
def construct_object(contract, descriptor); ObservedObject.new(contract, descriptor); end
|
530
|
-
end
|
531
|
-
|
532
|
-
module ExposedTagManager
|
533
|
-
def construct_object(contract, descriptor); ExposedObject.new(contract, descriptor); end
|
534
|
-
end
|
535
|
-
|
536
|
-
attr_reader :objects, :contract
|
537
|
-
|
538
|
-
def contract=(contract)
|
539
|
-
raise "You can't change contracts, sorry." if @contract
|
540
|
-
@contract = contract
|
541
|
-
case @contract.class.name
|
542
|
-
when "Hakuban::ObjectObserve" then singleton_class.include(ObservedObjectManager)
|
543
|
-
when "Hakuban::ObjectExpose" then singleton_class.include(ExposedObjectManager)
|
544
|
-
when "Hakuban::TagObserve" then singleton_class.include(ObservedTagManager)
|
545
|
-
when "Hakuban::TagExpose" then singleton_class.include(ExposedTagManager)
|
546
|
-
else raise
|
547
|
-
end
|
548
|
-
|
549
|
-
@queue = Queue.new
|
550
|
-
@contract.send_events_to(@queue, :object)
|
551
|
-
if @contract.kind_of?(ObjectObserve) or @contract.kind_of?(ObjectExpose)
|
552
|
-
event, param, descriptor = @queue.pop
|
553
|
-
raise if event != :object or param != :insert or not descriptor
|
554
|
-
self[descriptor] = self.construct_object(@contract, descriptor)
|
555
|
-
end
|
556
|
-
|
557
|
-
@thread = Thread.new {
|
558
|
-
loop {
|
559
|
-
event,param,descriptor = @queue.shift
|
560
|
-
case [event, param]
|
561
|
-
when [:control, :quit]
|
562
|
-
break
|
563
|
-
when [:object, :insert]
|
564
|
-
self[descriptor] = construct_object(@contract, descriptor)
|
565
|
-
object_insert(self[descriptor])
|
566
|
-
when [:object, :change]
|
567
|
-
object_change(self[descriptor])
|
568
|
-
when [:object, :remove]
|
569
|
-
object_remove(delete(descriptor))
|
570
|
-
end
|
571
|
-
}
|
572
|
-
}
|
573
|
-
end
|
574
|
-
|
575
|
-
|
576
|
-
def object_insert(object)
|
577
|
-
# noop default
|
578
|
-
end
|
579
|
-
|
580
|
-
def object_change(object)
|
581
|
-
# noop default
|
582
|
-
end
|
583
|
-
|
584
|
-
def object_remove(object)
|
585
|
-
# noop default
|
586
|
-
end
|
587
|
-
|
588
|
-
|
589
|
-
def drop
|
590
|
-
@contract.stop_sending_objects_events_to(@queue)
|
591
|
-
@queue.push [:control, :quit]
|
592
|
-
@thread.join
|
593
|
-
@queue, @contract, @thread, @objects = nil, nil, nil, {}
|
594
|
-
end
|
595
|
-
|
596
|
-
|
597
|
-
class ManagedObject
|
598
|
-
attr_reader :contract, :descriptor
|
599
|
-
def initialize(contract, descriptor)
|
600
|
-
@contract, @descriptor = contract, descriptor
|
601
|
-
end
|
602
|
-
end
|
603
|
-
|
604
|
-
#TODO: remove the arity thing...
|
605
|
-
class ObservedObject < ManagedObject
|
606
|
-
def state
|
607
|
-
if @contract.method(:object_state).arity == 1
|
608
|
-
@contract.object_state(@descriptor)
|
609
|
-
else
|
610
|
-
@contract.object_state
|
611
|
-
end
|
612
|
-
end
|
613
|
-
def data
|
614
|
-
if @contract.method(:object_state).arity == 1
|
615
|
-
@contract.object_state(@descriptor)&.data
|
616
|
-
else
|
617
|
-
@contract.object_state&.data
|
618
|
-
end
|
619
|
-
end
|
620
|
-
end
|
621
|
-
|
622
|
-
class ExposedObject < ManagedObject
|
623
|
-
def state_set(state)
|
624
|
-
if @contract.method(:set_object_state).arity == 4
|
625
|
-
@contract.set_object_state(@descriptor, *state)
|
626
|
-
else
|
627
|
-
@contract.set_object_state(*state)
|
628
|
-
end
|
629
|
-
end
|
630
|
-
def state=(state)
|
631
|
-
state_set(state)
|
632
|
-
end
|
633
|
-
def data_set(value)
|
634
|
-
timestamp = Time.new.to_f
|
635
|
-
if @contract.method(:set_object_state).arity == 4
|
636
|
-
@contract.set_object_state(@descriptor,[1, timestamp.floor, ((timestamp - timestamp.floor)*1000000000).floor, 0],[],value)
|
637
|
-
else
|
638
|
-
@contract.set_object_state([1, timestamp.floor, ((timestamp - timestamp.floor)*1000000000).floor, 0],[],value)
|
639
|
-
end
|
640
|
-
end
|
641
|
-
def data=(value)
|
642
|
-
data_set(value)
|
643
|
-
end
|
644
|
-
end
|
645
|
-
end
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
530
|
end
|