hakuban 0.6.5 → 0.7.0
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/bin/{hakuban-thread-engine → hakuban-engine} +7 -6
- data/bin/hakuban-observer +39 -35
- data/lib/hakuban/contract.rb +196 -0
- data/lib/hakuban/descriptor.rb +90 -0
- data/lib/hakuban/engine.rb +3 -3
- data/lib/hakuban/exchange.rb +75 -0
- data/lib/hakuban/ffi-object.rb +132 -0
- data/lib/hakuban/ffi.rb +217 -141
- data/lib/hakuban/logger.rb +16 -0
- data/lib/hakuban/object_state.rb +106 -0
- data/lib/hakuban/object_state_sink.rb +64 -0
- data/lib/hakuban/object_state_stream.rb +39 -0
- data/lib/hakuban/stream.rb +119 -0
- data/lib/hakuban/tokio-websocket-connector.rb +32 -0
- data/lib/hakuban/version.rb +1 -1
- data/lib/hakuban.rb +21 -6
- metadata +29 -10
- data/lib/hakuban/async.rb +0 -38
- data/lib/hakuban/event-queue.rb +0 -75
- data/lib/hakuban/hakuban.rb +0 -545
- data/lib/hakuban/manager.rb +0 -398
- data/lib/hakuban/thread.rb +0 -35
data/lib/hakuban/ffi.rb
CHANGED
@@ -1,174 +1,250 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'ffi'
|
3
|
+
require 'hakuban/ffi-object'
|
3
4
|
|
4
5
|
|
5
|
-
# all functions which can trigger synchronuous callbacks, and those which wait on rust locks are "blocking: true" to avoid deadlock on GIL
|
6
6
|
module Hakuban::FFI
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
class
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
class
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
class FFITagObserveResult < FFI::Struct
|
21
|
-
layout :error, :uint8, :tag_observe_pointer, :pointer
|
22
|
-
end
|
23
|
-
|
24
|
-
class FFITagExposeResult < FFI::Struct
|
25
|
-
layout :error, :uint8, :tag_expose_pointer, :pointer
|
26
|
-
end
|
27
|
-
|
28
|
-
class FFIObjectObserveStateGetVersionResult < FFI::Struct
|
29
|
-
layout :version_length, :size_t, :version_elements, :pointer
|
30
|
-
end
|
8
|
+
extend FFI::Library
|
9
|
+
ffi_lib 'hakuban'
|
10
|
+
|
11
|
+
|
12
|
+
class FFIError < Exception; end
|
13
|
+
class FFIErrorInvalidString < FFIError; end
|
14
|
+
class FFIErrorInvalidJSON < FFIError; end
|
15
|
+
class FFIErrorInvalidURL < FFIError; end
|
16
|
+
class FFIErrorInvalidLogLevel < FFIError; end
|
17
|
+
class FFIErrorUnknownError < FFIError; end
|
31
18
|
|
32
|
-
class
|
33
|
-
layout :
|
19
|
+
class FFIResultStatus < FFI::Struct
|
20
|
+
layout :id, :uint8
|
21
|
+
ENUM = [:Ok, :Pending, :NotAvailable, :InvalidString, :InvalidJSON, :InvalidURL, :InvalidLogLevel, :UnknownError]
|
22
|
+
|
23
|
+
def to_sym
|
24
|
+
ENUM[self[:id]]
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_exception
|
28
|
+
Hakuban::FFI::const_get("FFIError"+ENUM[self[:id]].to_s)
|
29
|
+
end
|
34
30
|
end
|
35
31
|
|
36
|
-
|
37
|
-
|
32
|
+
|
33
|
+
class FFIResult < FFI::Struct
|
34
|
+
FFIResultStatus::ENUM.each { |sym|
|
35
|
+
define_method(("is_"+sym.to_s+"?").to_sym) {
|
36
|
+
FFIResultStatus::ENUM[self[:status][:id]] == sym
|
37
|
+
}
|
38
|
+
}
|
38
39
|
end
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
state[:version].write_array_of_int64(version)
|
49
|
-
state[:data_type_length] = data_type.size
|
50
|
-
state[:data_type] = FFI::MemoryPointer.new(:pointer, data_type.size)
|
51
|
-
state.data_type_strings = data_type.map {|string| FFI::MemoryPointer.from_string(string)}
|
52
|
-
state[:data_type].write_array_of_pointer(state.data_type_strings)
|
53
|
-
state[:raw] = FFI::MemoryPointer.from_string(data)
|
54
|
-
state[:raw_length] = data.size
|
55
|
-
state
|
41
|
+
|
42
|
+
class FFIResultWithNothing < FFIResult
|
43
|
+
layout :status, FFIResultStatus
|
44
|
+
|
45
|
+
def unwrap
|
46
|
+
return nil if self[:status].to_sym == :NotAvailable
|
47
|
+
raise self[:status].to_exception if self[:status].to_sym != :Ok
|
48
|
+
nil
|
56
49
|
end
|
57
50
|
end
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
51
|
+
|
52
|
+
|
53
|
+
class FFIResultWithPointer < FFIResult
|
54
|
+
layout :status, FFIResultStatus, :pointer, :pointer
|
55
|
+
|
56
|
+
def unwrap
|
57
|
+
return nil if self[:status].to_sym == :NotAvailable
|
58
|
+
raise self[:status].to_exception if self[:status].to_sym != :Ok
|
59
|
+
self[:pointer]
|
60
|
+
end
|
65
61
|
end
|
66
62
|
|
67
|
-
class FFITagObserveObjectStateBorrowResult < FFI::Struct
|
68
|
-
layout :error, :uint8, :state, :pointer
|
69
|
-
end
|
70
63
|
|
71
|
-
class
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
def
|
76
|
-
|
64
|
+
class Callbacks
|
65
|
+
|
66
|
+
attr_reader :waker
|
67
|
+
|
68
|
+
def initialize
|
69
|
+
@queues = {}
|
70
|
+
@queues_sequence = 0
|
71
|
+
@queues_mutex = Mutex.new
|
72
|
+
@waker = proc { |pointer|
|
73
|
+
queue_id = pointer.address
|
74
|
+
@queues_mutex.synchronize {
|
75
|
+
@queues[queue_id]&.each { |queue|
|
76
|
+
queue << :wake
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
77
80
|
end
|
78
|
-
|
79
|
-
def
|
80
|
-
|
81
|
+
|
82
|
+
def register_queue(queue)
|
83
|
+
@queues_mutex.synchronize {
|
84
|
+
@queues_sequence = (@queues_sequence+1) % 2**32
|
85
|
+
queue_id = @queues_sequence
|
86
|
+
(@queues[queue_id] ||= Set.new) << queue
|
87
|
+
queue_id
|
88
|
+
}
|
81
89
|
end
|
82
|
-
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
descriptor[:tags].write_array_of_pointer(descriptor.tags_strings)
|
89
|
-
descriptor[:json] = FFI::MemoryPointer.from_string(JSON.dump(json))
|
90
|
-
descriptor
|
90
|
+
|
91
|
+
def unregister_queue(queue_id)
|
92
|
+
@queues_mutex.synchronize {
|
93
|
+
@queues[queue_id].delete(queue_id)
|
94
|
+
@queues.delete(queue_id) if @queues[queue_id].empty?
|
95
|
+
}
|
91
96
|
end
|
92
|
-
|
93
97
|
end
|
98
|
+
|
94
99
|
|
95
|
-
class
|
96
|
-
layout :
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
100
|
+
class FFIFutureReturningNothing < FFI::Struct
|
101
|
+
layout :pointer, :pointer
|
102
|
+
|
103
|
+
@@callbacks = Callbacks.new
|
104
|
+
|
105
|
+
def self.create_and_await(owner)
|
106
|
+
Thread.handle_interrupt(Object => :never) {
|
107
|
+
begin
|
108
|
+
queue = queue_id = drop_locked = pointer = nil
|
109
|
+
Thread.handle_interrupt(Object => :immediate) {
|
110
|
+
queue = Queue.new
|
111
|
+
queue_id = @@callbacks.register_queue(queue)
|
112
|
+
drop_locked = owner.drop_lock(queue)
|
113
|
+
return nil if !pointer = owner.with_pointer { |pointer| yield pointer }
|
114
|
+
loop {
|
115
|
+
result = owner.with_pointer { Hakuban::FFI::hakuban_future_returning_nothing_poll(pointer[:pointer],@@callbacks.waker,::FFI::Pointer.new(queue_id)) }
|
116
|
+
return result if not result.is_Pending?
|
117
|
+
# Currently the only future returning nothing is guaranteed to complete at first poll
|
118
|
+
# :unreachable:
|
119
|
+
raise Hakuban::FFIObject::PointerAlreadyDropped if queue.pop == :dropping
|
120
|
+
# :unreachable:
|
121
|
+
}
|
122
|
+
}
|
123
|
+
ensure
|
124
|
+
Hakuban::FFI::hakuban_future_returning_nothing_drop(pointer[:pointer]) if pointer
|
125
|
+
owner.drop_release(queue) if drop_locked
|
126
|
+
@@callbacks.unregister_queue(queue_id)
|
127
|
+
end
|
128
|
+
}
|
106
129
|
end
|
107
|
-
|
108
130
|
end
|
109
|
-
|
110
|
-
|
111
|
-
class
|
112
|
-
layout :
|
113
|
-
|
114
|
-
|
115
|
-
|
131
|
+
|
132
|
+
|
133
|
+
class FFIFutureReturningPointer < FFI::Struct
|
134
|
+
layout :pointer, :pointer
|
135
|
+
|
136
|
+
@@callbacks = Callbacks.new
|
137
|
+
|
138
|
+
def self.create_and_await(owner)
|
139
|
+
Thread.handle_interrupt(Object => :never) {
|
140
|
+
begin
|
141
|
+
queue = queue_id = drop_locked = pointer = nil
|
142
|
+
Thread.handle_interrupt(Object => :immediate) {
|
143
|
+
queue = Queue.new
|
144
|
+
queue_id = @@callbacks.register_queue(queue)
|
145
|
+
drop_locked = owner.drop_lock(queue)
|
146
|
+
return nil if !pointer = owner.with_pointer { |pointer| yield pointer }
|
147
|
+
loop {
|
148
|
+
result = owner.with_pointer { Hakuban::FFI::hakuban_future_returning_pointer_poll(pointer[:pointer],@@callbacks.waker,::FFI::Pointer.new(queue_id)) }
|
149
|
+
return result if not result.is_Pending?
|
150
|
+
raise Hakuban::FFIObject::PointerAlreadyDropped if queue.pop == :dropping
|
151
|
+
}
|
152
|
+
}
|
153
|
+
ensure
|
154
|
+
Hakuban::FFI::hakuban_future_returning_pointer_drop(pointer[:pointer]) if pointer
|
155
|
+
owner.drop_release(queue) if drop_locked
|
156
|
+
@@callbacks.unregister_queue(queue_id)
|
157
|
+
end
|
158
|
+
}
|
116
159
|
end
|
117
160
|
end
|
161
|
+
|
162
|
+
|
163
|
+
class FFIArray < FFI::Struct
|
164
|
+
layout :length, :size_t, :pointer, :pointer
|
165
|
+
end
|
118
166
|
|
119
167
|
|
120
|
-
|
168
|
+
# Every function which can cause a wake() has to be "blocking: true".
|
169
|
+
# Otherwise they are very likely to deadlock on GVL and other locks acquired by RemoteExchange on incomming message.
|
170
|
+
# FIXME: way too many functions are marked as blocking here
|
121
171
|
|
122
|
-
|
172
|
+
callback :waker, [ :pointer ], :void
|
123
173
|
|
124
|
-
|
125
|
-
#callback :tag_callback, [ :pointer, FFITagDescriptor.by_value, :uint8 ], :void
|
126
|
-
|
127
|
-
attach_function :hakuban_local_node_new, [ :string ], FFILocalNodeNewResult.by_value
|
128
|
-
attach_function :hakuban_local_node_drop, [ :pointer ], :void, blocking: true
|
129
|
-
|
130
|
-
attach_function :hakuban_object_observe_new, [ :pointer, FFIObjectDescriptor.by_value ], FFIObjectObserveResult.by_value, blocking: true
|
131
|
-
attach_function :hakuban_object_observe_drop, [ :pointer ], :void, blocking: true
|
132
|
-
attach_function :hakuban_object_observe_state_borrow, [ :pointer ], :pointer, blocking: true
|
133
|
-
attach_function :hakuban_object_observe_events_get, [ :pointer ], :pointer, blocking: true
|
134
|
-
|
135
|
-
attach_function :hakuban_object_expose_new, [ :pointer, FFIObjectDescriptor.by_value], FFIObjectExposeResult.by_value, blocking: true
|
136
|
-
attach_function :hakuban_object_expose_drop, [ :pointer ], :void, blocking: true
|
137
|
-
attach_function :hakuban_object_expose_state, [ :pointer, FFIObjectExposeState.by_value, :uint64 ], FFIObjectExposeStateResult.by_value, blocking: true
|
138
|
-
attach_function :hakuban_object_expose_assignment, [ :pointer ], :uint64, blocking: true
|
139
|
-
attach_function :hakuban_object_expose_desynchronize, [ :pointer, :uint64 ], :void, blocking: true
|
140
|
-
attach_function :hakuban_object_expose_events_get, [ :pointer ], :pointer, blocking: true
|
141
|
-
|
142
|
-
attach_function :hakuban_tag_observe_new, [ :pointer, FFITagDescriptor.by_value ], FFITagObserveResult.by_value, blocking: true
|
143
|
-
attach_function :hakuban_tag_observe_drop, [ :pointer ], :void, blocking: true
|
144
|
-
attach_function :hakuban_tag_observe_object_descriptors_borrow, [ :pointer ], FFIObjectDescriptors.by_value, blocking: true
|
145
|
-
attach_function :hakuban_tag_observe_object_state_borrow, [ :pointer, FFIObjectDescriptor.by_value ], FFITagObserveObjectStateBorrowResult.by_value, blocking: true
|
146
|
-
attach_function :hakuban_tag_observe_events_get, [ :pointer ], :pointer, blocking: true
|
147
|
-
|
148
|
-
attach_function :hakuban_tag_expose_new, [ :pointer, FFITagDescriptor.by_value ], FFITagExposeResult.by_value, blocking: true
|
149
|
-
attach_function :hakuban_tag_expose_drop, [ :pointer ], :void, blocking: true
|
150
|
-
attach_function :hakuban_tag_expose_object_descriptors_borrow, [ :pointer ], FFIObjectDescriptors.by_value, blocking: true
|
151
|
-
attach_function :hakuban_tag_expose_object_state, [ :pointer, FFIObjectDescriptor.by_value, FFIObjectExposeState.by_value, :uint64 ], FFIObjectExposeStateResult.by_value, blocking: true
|
152
|
-
attach_function :hakuban_tag_expose_object_assignment, [ :pointer, FFIObjectDescriptor.by_value ], :uint64, blocking: true
|
153
|
-
attach_function :hakuban_tag_expose_object_desynchronize, [ :pointer, FFIObjectDescriptor.by_value, :uint64 ], :void, blocking: true
|
154
|
-
attach_function :hakuban_tag_expose_events_get, [ :pointer ], :pointer, blocking: true
|
155
|
-
|
156
|
-
attach_function :hakuban_object_observe_state_get_synchronized, [ :pointer ], :uint64
|
157
|
-
attach_function :hakuban_object_observe_state_get_data_version, [ :pointer ], FFIObjectObserveStateGetVersionResult.by_value
|
158
|
-
attach_function :hakuban_object_observe_state_get_data_type, [ :pointer ], FFIObjectObserveStateGetDataTypeResult.by_value
|
159
|
-
attach_function :hakuban_object_observe_state_get_data, [ :pointer ], FFIObjectObserveStateGetDataResult.by_value
|
160
|
-
|
161
|
-
attach_function :hakuban_object_descriptor_events_callback_register, [ :pointer, :object_callback, :pointer ], :pointer, blocking: true
|
162
|
-
attach_function :hakuban_object_descriptor_events_callback_unregister, [ :pointer ], :void, blocking: true
|
163
|
-
attach_function :hakuban_object_descriptor_events_return, [ :pointer ], :void, blocking: true
|
164
|
-
|
165
|
-
attach_function :hakuban_object_observe_state_return, [ :pointer ], :void
|
166
|
-
attach_function :hakuban_object_descriptors_return, [ FFIObjectDescriptors.by_value ], :void
|
174
|
+
attach_function :hakuban_logger_initialize, [ :string ], FFIResultWithNothing.by_value
|
167
175
|
|
168
|
-
attach_function :
|
169
|
-
attach_function :
|
170
|
-
attach_function :
|
176
|
+
attach_function :hakuban_local_exchange_new, [ :string ], FFIResultWithPointer.by_value
|
177
|
+
attach_function :hakuban_local_exchange_drop, [ :pointer ], :void
|
178
|
+
attach_function :hakuban_local_exchange_clone, [ :pointer ], :pointer
|
171
179
|
|
172
|
-
attach_function :
|
180
|
+
attach_function :hakuban_tokio_init_multi_thread, [ :size_t ], :pointer
|
181
|
+
attach_function :hakuban_tokio_websocket_connector_new, [ :pointer, :pointer, :string ], FFIResultWithPointer.by_value
|
182
|
+
attach_function :hakuban_tokio_websocket_connector_drop, [ :pointer ], :void, blocking: true
|
183
|
+
|
184
|
+
attach_function :hakuban_object_observe_contract_new, [ :pointer, :pointer ], :pointer, blocking: true
|
185
|
+
attach_function :hakuban_object_observe_contract_drop, [ :pointer ], :void, blocking: true
|
186
|
+
attach_function :hakuban_object_observe_contract_terminate, [ :pointer ], :void, blocking: true
|
187
|
+
attach_function :hakuban_object_observe_contract_next, [ :pointer ], FFIFutureReturningPointer.by_value, blocking: true
|
188
|
+
attach_function :hakuban_object_observe_contract_ready, [ :pointer ], FFIResultWithPointer.by_value, blocking: true
|
189
|
+
|
190
|
+
attach_function :hakuban_object_expose_contract_new, [ :pointer, :pointer ], :pointer, blocking: true
|
191
|
+
attach_function :hakuban_object_expose_contract_drop, [ :pointer ], :void, blocking: true
|
192
|
+
attach_function :hakuban_object_expose_contract_terminate, [ :pointer ], :void, blocking: true
|
193
|
+
attach_function :hakuban_object_expose_contract_next, [ :pointer ], FFIFutureReturningPointer.by_value, blocking: true
|
194
|
+
attach_function :hakuban_object_expose_contract_ready, [ :pointer ], FFIResultWithPointer.by_value, blocking: true
|
195
|
+
|
196
|
+
attach_function :hakuban_tag_observe_contract_new, [ :pointer, :pointer ], :pointer, blocking: true
|
197
|
+
attach_function :hakuban_tag_observe_contract_drop, [ :pointer ], :void, blocking: true
|
198
|
+
attach_function :hakuban_tag_observe_contract_terminate, [ :pointer ], :void, blocking: true
|
199
|
+
attach_function :hakuban_tag_observe_contract_next, [ :pointer ], FFIFutureReturningPointer.by_value, blocking: true
|
200
|
+
attach_function :hakuban_tag_observe_contract_ready, [ :pointer ], FFIArray.by_value, blocking: true
|
201
|
+
|
202
|
+
attach_function :hakuban_tag_expose_contract_new, [ :pointer, :pointer ], :pointer, blocking: true
|
203
|
+
attach_function :hakuban_tag_expose_contract_drop, [ :pointer ], :void, blocking: true
|
204
|
+
attach_function :hakuban_tag_expose_contract_terminate, [ :pointer ], :void, blocking: true
|
205
|
+
attach_function :hakuban_tag_expose_contract_next, [ :pointer ], FFIFutureReturningPointer.by_value, blocking: true
|
206
|
+
attach_function :hakuban_tag_expose_contract_ready, [ :pointer ], FFIArray.by_value, blocking: true
|
207
|
+
|
208
|
+
attach_function :hakuban_object_state_stream_drop, [ :pointer ], :void, blocking: true
|
209
|
+
attach_function :hakuban_object_state_stream_next, [ :pointer ], FFIFutureReturningPointer.by_value, blocking: true
|
210
|
+
attach_function :hakuban_object_state_stream_current, [ :pointer ], FFIResultWithPointer.by_value
|
211
|
+
attach_function :hakuban_object_state_stream_descriptor, [ :pointer ], :pointer
|
212
|
+
|
213
|
+
attach_function :hakuban_object_state_sink_drop, [ :pointer ], :void, blocking: true
|
214
|
+
attach_function :hakuban_object_state_sink_next, [ :pointer ], FFIFutureReturningPointer.by_value, blocking: true
|
215
|
+
attach_function :hakuban_object_state_sink_send, [ :pointer, :pointer ], FFIFutureReturningNothing.by_value, blocking: true
|
216
|
+
attach_function :hakuban_object_state_sink_current, [ :pointer ], FFIResultWithPointer.by_value, blocking: true
|
217
|
+
attach_function :hakuban_object_state_sink_descriptor, [ :pointer ], :pointer
|
218
|
+
attach_function :hakuban_object_state_sink_desynchronize, [ :pointer ], :void, blocking: true
|
219
|
+
|
220
|
+
attach_function :hakuban_object_state_sink_params_drop, [ :pointer ], :void
|
221
|
+
attach_function :hakuban_object_state_sink_params_clone, [ :pointer ], :pointer
|
222
|
+
|
223
|
+
attach_function :hakuban_object_state_new, [ :size_t, :pointer, :size_t, :pointer, :size_t, :pointer, :uint64 ], FFIResultWithPointer.by_value
|
224
|
+
attach_function :hakuban_object_state_drop, [ :pointer ], :void
|
225
|
+
attach_function :hakuban_object_state_clone, [ :pointer ], :pointer
|
226
|
+
attach_function :hakuban_object_state_data, [ :pointer ], FFIArray.by_value
|
227
|
+
attach_function :hakuban_object_state_format, [ :pointer ], FFIArray.by_value
|
228
|
+
attach_function :hakuban_object_state_version, [ :pointer ], FFIArray.by_value
|
229
|
+
attach_function :hakuban_object_state_synchronized_ago, [ :pointer ], :uint64
|
230
|
+
|
231
|
+
attach_function :hakuban_tag_descriptor_new, [ :string ], FFIResultWithPointer.by_value
|
232
|
+
attach_function :hakuban_tag_descriptor_drop, [ :pointer ], :void
|
233
|
+
attach_function :hakuban_tag_descriptor_clone, [ :pointer ], :pointer
|
234
|
+
attach_function :hakuban_tag_descriptor_json, [ :pointer ], :string
|
235
|
+
|
236
|
+
attach_function :hakuban_object_descriptor_new, [ :string, :size_t, :pointer ], FFIResultWithPointer.by_value
|
237
|
+
attach_function :hakuban_object_descriptor_drop, [ :pointer ], :void
|
238
|
+
attach_function :hakuban_object_descriptor_clone, [ :pointer ], :pointer
|
239
|
+
attach_function :hakuban_object_descriptor_json, [ :pointer ], :string
|
240
|
+
attach_function :hakuban_object_descriptor_tags, [ :pointer ], FFIArray.by_value
|
241
|
+
|
242
|
+
attach_function :hakuban_future_returning_nothing_drop, [ :pointer ], :void, blocking: true
|
243
|
+
attach_function :hakuban_future_returning_pointer_drop, [ :pointer ], :void, blocking: true
|
244
|
+
attach_function :hakuban_future_returning_nothing_poll, [ :pointer, :waker, :pointer ], FFIResultWithNothing.by_value, blocking: true
|
245
|
+
attach_function :hakuban_future_returning_pointer_poll, [ :pointer, :waker, :pointer ], FFIResultWithPointer.by_value, blocking: true
|
246
|
+
|
247
|
+
attach_function :hakuban_array_drop, [ FFIArray.by_value ], :void
|
173
248
|
|
174
249
|
end
|
250
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Hakuban
|
2
|
+
|
3
|
+
@@logger_initialized = false
|
4
|
+
|
5
|
+
def self.logger_initialize(default_level, skip_if_already_initialized: false)
|
6
|
+
Hakuban::hakuban_initialize
|
7
|
+
if @@logger_initialized and !skip_if_already_initialized
|
8
|
+
raise "Logger already initialized. This can't be done more than once. Make sure logger_initialize is called before any LocalExchange gets constructed."
|
9
|
+
end
|
10
|
+
if not @@logger_initialized
|
11
|
+
raise "Invalid default log level string" if ! FFI::hakuban_logger_initialize(default_level).is_Ok?
|
12
|
+
@@logger_initialized = true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'hakuban/ffi-object.rb'
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
module Hakuban
|
6
|
+
|
7
|
+
class ObjectState < FFIObject
|
8
|
+
|
9
|
+
class WrongFormatError < Exception; end
|
10
|
+
|
11
|
+
def initialize(data, version: nil, format: nil, synchronized_us_ago: 0, &block)
|
12
|
+
if version.nil?
|
13
|
+
timestamp = Time.new
|
14
|
+
version = [0, timestamp.to_i, timestamp.nsec]
|
15
|
+
end
|
16
|
+
@version = version
|
17
|
+
@format = [format || []].flatten
|
18
|
+
@synchronized_us_ago = synchronized_us_ago
|
19
|
+
@data = data
|
20
|
+
@pointer = false
|
21
|
+
@mutex = Mutex.new
|
22
|
+
self.do_and_drop_or_return(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def with_pointer
|
27
|
+
@mutex.synchronize {
|
28
|
+
raise PointerAlreadyDropped if dropped?
|
29
|
+
if @pointer == false
|
30
|
+
Hakuban::hakuban_initialize
|
31
|
+
version_pointer = ::FFI::MemoryPointer.new(:int64, @version.size)
|
32
|
+
version_pointer.write_array_of_int64(@version)
|
33
|
+
format_pointer = ::FFI::MemoryPointer.new(:pointer, @format.size)
|
34
|
+
format_strings = format.map {|string| ::FFI::MemoryPointer.from_string(string)}
|
35
|
+
format_pointer.write_array_of_pointer(format_strings)
|
36
|
+
data_pointer = ::FFI::MemoryPointer.from_string(@data)
|
37
|
+
pointer = FFI::hakuban_object_state_new(@version.size, version_pointer, @format.size, format_pointer, @data.bytesize, data_pointer, @synchronized_us_ago).unwrap
|
38
|
+
initialize_pointer(pointer, :hakuban_object_state_drop, :hakuban_object_state_clone)
|
39
|
+
end
|
40
|
+
yield ::FFI::Pointer.new(@pointer)
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
private_class_method def self.from_ffi_pointer(pointer)
|
46
|
+
new_instance = allocate
|
47
|
+
new_instance.send(:initialize_pointer, pointer, :hakuban_object_state_drop, :hakuban_object_state_clone)
|
48
|
+
new_instance
|
49
|
+
end
|
50
|
+
|
51
|
+
def data
|
52
|
+
return @data if defined? @data
|
53
|
+
array = with_pointer { |pointer| FFI::hakuban_object_state_data(pointer) }
|
54
|
+
#array[:data_bytes].read_array_of_char(array[:length]) #.pack('c*').clone()
|
55
|
+
@data = array[:pointer].read_string(array[:length]).clone()
|
56
|
+
end
|
57
|
+
|
58
|
+
def format
|
59
|
+
return @format if defined? @format
|
60
|
+
array = with_pointer { |pointer| FFI::hakuban_object_state_format(pointer) }
|
61
|
+
@format = array[:pointer].read_array_of_pointer(array[:length]).map { |string| string.read_string().clone() }
|
62
|
+
end
|
63
|
+
|
64
|
+
def version
|
65
|
+
return @version if defined? @version
|
66
|
+
array = with_pointer { |pointer| FFI::hakuban_object_state_version(pointer) }
|
67
|
+
@version = array[:pointer].read_array_of_int64(array[:length])
|
68
|
+
end
|
69
|
+
|
70
|
+
def synchronized_us_ago
|
71
|
+
return @synchronized_us_ago if defined? @synchronized_us_ago
|
72
|
+
@synchronized_us_ago = with_pointer { |pointer| FFI::hakuban_object_state_synchronized_ago(pointer) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def with_data(data)
|
76
|
+
ObjectState.new(data, version: version, format: format, synchronized_us_ago: synchronized_us_ago)
|
77
|
+
end
|
78
|
+
|
79
|
+
def with_version(version)
|
80
|
+
ObjectState.new(data, version: version, format: format, synchronized_us_ago: synchronized_us_ago)
|
81
|
+
end
|
82
|
+
|
83
|
+
def with_format(format)
|
84
|
+
ObjectState.new(data, version: version, format: format, synchronized_us_ago: synchronized_us_ago)
|
85
|
+
end
|
86
|
+
|
87
|
+
def with_synchronized_us_ago(synchronized_us_ago)
|
88
|
+
ObjectState.new(data, version: version, format: format, synchronized_us_ago: synchronized_us_ago)
|
89
|
+
end
|
90
|
+
|
91
|
+
def json_deserialize
|
92
|
+
raise WrongFormatError if format[-1] != "JSON"
|
93
|
+
ObjectState.new(JSON.parse(data), version: version, format: format[0...-1], synchronized_us_ago: synchronized_us_ago)
|
94
|
+
end
|
95
|
+
|
96
|
+
def json_serialize
|
97
|
+
ObjectState.new(JSON.dump(data), version: version, format: format+["JSON"], synchronized_us_ago: synchronized_us_ago)
|
98
|
+
end
|
99
|
+
|
100
|
+
def inspect
|
101
|
+
"#<ObjectState @synchronized=%p @version=%p>"%[synchronized_us_ago, version]
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'hakuban/ffi-object.rb'
|
2
|
+
require 'hakuban/stream.rb'
|
3
|
+
|
4
|
+
|
5
|
+
module Hakuban
|
6
|
+
|
7
|
+
class ObjectStateSink < FFIObject
|
8
|
+
|
9
|
+
private_class_method :new
|
10
|
+
|
11
|
+
def initialize(pointer)
|
12
|
+
initialize_pointer(pointer, :hakuban_object_state_sink_drop, nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
include Stream
|
17
|
+
|
18
|
+
|
19
|
+
def next(&block)
|
20
|
+
return nil if ! pointer = FFI::FFIFutureReturningPointer.create_and_await(self) { |pointer| FFI::hakuban_object_state_sink_next(pointer) }.unwrap
|
21
|
+
ObjectStateSinkParams.send(:new, pointer).do_and_drop_or_return(&block)
|
22
|
+
rescue FFIObject::PointerAlreadyDropped
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def current(&block)
|
27
|
+
return nil if ! pointer = with_pointer { |pointer| FFI::hakuban_object_state_sink_current(pointer) }.unwrap
|
28
|
+
ObjectStateSinkParams.send(:new, pointer).do_and_drop_or_return(&block)
|
29
|
+
rescue FFIObject::PointerAlreadyDropped
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def send(object_state)
|
34
|
+
FFI::FFIFutureReturningNothing.create_and_await(self) { |pointer|
|
35
|
+
object_state.with_pointer { |object_state_pointer| FFI::hakuban_object_state_sink_send(pointer, object_state_pointer) }
|
36
|
+
}.unwrap
|
37
|
+
rescue FFIObject::PointerAlreadyDropped
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def descriptor
|
42
|
+
Hakuban::ObjectDescriptor.send(:from_ffi_pointer, with_pointer { |pointer| FFI::hakuban_object_state_sink_descriptor(pointer) })
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def desynchronize
|
47
|
+
with_pointer { |pointer| FFI::hakuban_object_state_sink_desynchronize(pointer) }
|
48
|
+
rescue FFIObject::PointerAlreadyDropped
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
class ObjectStateSinkParams < FFIObject
|
54
|
+
|
55
|
+
private_class_method :new
|
56
|
+
|
57
|
+
def initialize(pointer)
|
58
|
+
initialize_pointer(pointer, :hakuban_object_state_sink_params_drop, :hakuban_object_state_sink_params_clone)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'hakuban/ffi-object.rb'
|
2
|
+
require 'hakuban/stream.rb'
|
3
|
+
|
4
|
+
|
5
|
+
module Hakuban
|
6
|
+
|
7
|
+
class ObjectStateStream < FFIObject
|
8
|
+
|
9
|
+
private_class_method :new
|
10
|
+
|
11
|
+
def initialize(pointer)
|
12
|
+
initialize_pointer(pointer, :hakuban_object_state_stream_drop, nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
include Stream
|
17
|
+
|
18
|
+
|
19
|
+
def next(&block)
|
20
|
+
return nil if ! pointer = FFI::FFIFutureReturningPointer.create_and_await(self) { |pointer| FFI::hakuban_object_state_stream_next(pointer) }.unwrap
|
21
|
+
ObjectState.send(:from_ffi_pointer, pointer).do_and_drop_or_return(&block)
|
22
|
+
rescue FFIObject::PointerAlreadyDropped
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def current(&block)
|
27
|
+
return nil if ! pointer = with_pointer { |pointer| FFI::hakuban_object_state_stream_current(pointer) }.unwrap
|
28
|
+
ObjectState.send(:from_ffi_pointer, pointer).do_and_drop_or_return(&block)
|
29
|
+
rescue FFIObject::PointerAlreadyDropped
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def descriptor
|
34
|
+
Hakuban::ObjectDescriptor.send(:from_ffi_pointer, with_pointer { |pointer| FFI::hakuban_object_state_stream_descriptor(pointer) })
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|