hakuban 0.6.4 → 0.7.0

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