omq-backend-rust 0.2.0 → 0.3.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/CHANGELOG.md +29 -0
- data/README.md +30 -7
- data/lib/omq/backend/rust.rb +14 -7
- data/lib/omq/rust/engine.rb +89 -112
- data/lib/omq/rust/java/engine.rb +664 -0
- data/lib/omq/rust/java/platform.rb +95 -0
- data/lib/omq/rust/version.rb +13 -1
- metadata +17 -22
- data/Cargo.toml +0 -3
- data/ext/omq_backend_rust/Cargo.toml +0 -33
- data/ext/omq_backend_rust/build.rs +0 -23
- data/ext/omq_backend_rust/extconf.rb +0 -8
- data/ext/omq_backend_rust/src/error.rs +0 -16
- data/ext/omq_backend_rust/src/lib.rs +0 -51
- data/ext/omq_backend_rust/src/notify.rs +0 -69
- data/ext/omq_backend_rust/src/options.rs +0 -220
- data/ext/omq_backend_rust/src/rb.rs +0 -433
- data/ext/omq_backend_rust/src/runtime.rs +0 -439
- data/ext/omq_backend_rust/src/socket.rs +0 -707
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ed979a32dfef182642cb03dba149e36843c9e37fed1e75032c439b35d769d145
|
|
4
|
+
data.tar.gz: bd80cf78e629a3b4af1bec1ec6646ea9df635be16c096b1a9d597aed05918d79
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fe616024d998eeae83b17b81bfedba2e49bc542a16b8fb6a4f13df4e6a21f768603e497276817c722a5dd1308c54979ad6b615af0d944d692f2faf78c9c77efc
|
|
7
|
+
data.tar.gz: be283792e7d988030b6d13859b206e10c6c8ae355285809a9282ff40c7b14ae4a7b35fa908a24a3e5daa122040c82073c7f022569d163ce451b80ebb8d37faa5
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.3.1] - 2026-10-15
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Resolve RADIO subscriber readiness on `join_received` monitor events.
|
|
10
|
+
- Reject unsupported security mechanisms instead of silently using NULL.
|
|
11
|
+
- Forward CURVE authenticators on MRI, TruffleRuby, and JRuby, preserving the
|
|
12
|
+
Ruby `PeerInfo` and crypto public-key types.
|
|
13
|
+
- Reject JRuby authenticator configuration when the OMQ.java callback classes
|
|
14
|
+
are missing from the JVM classpath.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Require `omq-rs >= 0.2.5` for native authentication callbacks and REQ/REP
|
|
19
|
+
fixes: reject unrelated REQ replies and bodyless REP requests, and preserve
|
|
20
|
+
REP reply destinations across prefetched requests and disconnects.
|
|
21
|
+
|
|
22
|
+
## [0.3.0] - 2026-08-26
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- Added JRuby support through OMQ.java Maven artifacts for Linux x86_64,
|
|
27
|
+
macOS aarch64, macOS x86_64, and Windows x86_64.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Replaced the private MRI/TruffleRuby native extension with the first-class
|
|
32
|
+
`omq-rs` binding.
|
|
33
|
+
|
|
5
34
|
## [0.2.0] - 2026-08-08
|
|
6
35
|
|
|
7
36
|
### Added
|
data/README.md
CHANGED
|
@@ -6,12 +6,19 @@
|
|
|
6
6
|
[](https://www.ruby-lang.org)
|
|
7
7
|
|
|
8
8
|
Rust-backed engine for [OMQ](https://github.com/zeromq/omq.rb). Same socket API,
|
|
9
|
-
but networking runs
|
|
10
|
-
|
|
9
|
+
but networking runs through the first-class
|
|
10
|
+
[omq-rs](https://github.com/paddor/omq.rs/tree/main/bindings/ruby) binding on
|
|
11
|
+
MRI and TruffleRuby, or through OMQ.java on JRuby.
|
|
11
12
|
|
|
12
13
|
## Install
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
The `omq-rs >= 0.2.5` dependency compiles OMQ.rs during installation on MRI
|
|
16
|
+
and TruffleRuby. This minimum includes the REQ/REP envelope and reply-routing
|
|
17
|
+
fixes in `omq-tokio` 0.28.1 and `omq-proto` 0.32.1.
|
|
18
|
+
|
|
19
|
+
JRuby uses OMQ.java on Java 25 or newer. The Java gem selects the
|
|
20
|
+
matching OMQ.java artifact on Linux x86_64, macOS aarch64, macOS x86_64, and
|
|
21
|
+
Windows x86_64.
|
|
15
22
|
|
|
16
23
|
```ruby
|
|
17
24
|
# Gemfile
|
|
@@ -44,8 +51,7 @@ ensure
|
|
|
44
51
|
end
|
|
45
52
|
```
|
|
46
53
|
|
|
47
|
-
|
|
48
|
-
Mix backends freely within the same process.
|
|
54
|
+
Select a backend per socket to exchange ZMTP messages with Ruby and other peers.
|
|
49
55
|
|
|
50
56
|
## Supported socket types
|
|
51
57
|
|
|
@@ -58,6 +64,23 @@ SCATTER/GATHER, CHANNEL.
|
|
|
58
64
|
- **NULL** (default)
|
|
59
65
|
- **CURVE** (CurveZMQ, via [Nuckle](https://github.com/paddor/nuckle))
|
|
60
66
|
|
|
67
|
+
CURVE authenticators receive `Protocol::ZMTP::PeerInfo`, including a public key
|
|
68
|
+
from the configured crypto backend. As with the Ruby engine, the identity is
|
|
69
|
+
empty during authentication.
|
|
70
|
+
|
|
71
|
+
On JRuby, OMQ.java 0.3.0's JNI callback threads require the platform jar on the
|
|
72
|
+
JVM `CLASSPATH`. For example:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
CLASSPATH="$HOME/.m2/repository/io/github/paddor/omq-java/0.3.0/omq-java-0.3.0-linux-x86_64.jar" jruby app.rb
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Without it, configuring a CURVE authenticator raises `ArgumentError` before
|
|
79
|
+
opening a connection. CURVE without an authenticator does not need this workaround.
|
|
80
|
+
|
|
81
|
+
PLAIN and custom mechanisms raise `ArgumentError` before binding, connecting,
|
|
82
|
+
or sending. They are not supported by this adapter.
|
|
83
|
+
|
|
61
84
|
## Compressed transports
|
|
62
85
|
|
|
63
86
|
The Rust backend supports `lz4+tcp://` and `zstd+tcp://`. Compression
|
|
@@ -73,8 +96,8 @@ the first `bind` or `connect` for a Rust-backed socket.
|
|
|
73
96
|
## Development
|
|
74
97
|
|
|
75
98
|
```sh
|
|
76
|
-
|
|
77
|
-
|
|
99
|
+
OMQ_RS_PATH=/path/to/omq.rs/bindings/ruby bundle install
|
|
100
|
+
OMQ_RS_PATH=/path/to/omq.rs/bindings/ruby bundle exec rake
|
|
78
101
|
```
|
|
79
102
|
|
|
80
103
|
## License
|
data/lib/omq/backend/rust.rb
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "omq"
|
|
4
|
-
require_relative "../rust/omq_backend_rust"
|
|
5
4
|
require_relative "../rust/version"
|
|
6
|
-
require_relative "../rust/engine"
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
if RUBY_ENGINE == "jruby"
|
|
7
|
+
require_relative "../rust/java/engine"
|
|
8
|
+
else
|
|
9
|
+
require "omq/rs"
|
|
10
|
+
require_relative "../rust/engine"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
if RUBY_ENGINE == "jruby"
|
|
14
|
+
module OMQ
|
|
15
|
+
module Rust
|
|
16
|
+
@io_threads = 1
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
class << self
|
|
19
|
+
attr_accessor :io_threads
|
|
20
|
+
end
|
|
14
21
|
end
|
|
15
22
|
end
|
|
16
23
|
end
|
data/lib/omq/rust/engine.rb
CHANGED
|
@@ -27,8 +27,10 @@ module OMQ
|
|
|
27
27
|
@materialized = false
|
|
28
28
|
@recv_sentinels = 0
|
|
29
29
|
@compression_options = {}
|
|
30
|
-
|
|
31
|
-
@
|
|
30
|
+
@socket = nil
|
|
31
|
+
@monitor_task = nil
|
|
32
|
+
@monitor_watching = false
|
|
33
|
+
@had_peer = false
|
|
32
34
|
|
|
33
35
|
@routing = RoutingStub.new(self)
|
|
34
36
|
end
|
|
@@ -55,7 +57,7 @@ module OMQ
|
|
|
55
57
|
capture_parent_task(parent: parent)
|
|
56
58
|
apply_endpoint_options!(opts)
|
|
57
59
|
ensure_materialized
|
|
58
|
-
resolved = @
|
|
60
|
+
resolved = @socket.bind(endpoint)
|
|
59
61
|
URI.parse(resolved)
|
|
60
62
|
end
|
|
61
63
|
|
|
@@ -64,54 +66,39 @@ module OMQ
|
|
|
64
66
|
capture_parent_task(parent: parent)
|
|
65
67
|
apply_endpoint_options!(opts)
|
|
66
68
|
ensure_materialized
|
|
67
|
-
@
|
|
69
|
+
@socket.connect(endpoint)
|
|
68
70
|
URI.parse(endpoint)
|
|
69
71
|
end
|
|
70
72
|
|
|
71
73
|
|
|
72
74
|
def disconnect(endpoint)
|
|
73
|
-
@
|
|
75
|
+
@socket.disconnect(endpoint)
|
|
74
76
|
end
|
|
75
77
|
|
|
76
78
|
|
|
77
79
|
def unbind(endpoint)
|
|
78
|
-
@
|
|
80
|
+
@socket.unbind(endpoint)
|
|
79
81
|
end
|
|
80
82
|
|
|
81
83
|
|
|
82
84
|
def enqueue_send(parts)
|
|
83
85
|
ensure_materialized
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
@send_signal_r ||= io_for_native_fd(@native.send_fd)
|
|
88
|
-
loop do
|
|
89
|
-
result = @native.enqueue_send(parts)
|
|
90
|
-
return if result == :ok
|
|
91
|
-
|
|
92
|
-
@send_signal_r.wait_readable
|
|
93
|
-
@send_signal_r.read_nonblock(256, exception: false)
|
|
94
|
-
end
|
|
86
|
+
@socket.send(normalize_outgoing(parts))
|
|
87
|
+
nil
|
|
95
88
|
end
|
|
96
89
|
|
|
97
90
|
|
|
98
91
|
def dequeue_recv
|
|
99
92
|
ensure_materialized
|
|
100
93
|
|
|
101
|
-
|
|
102
|
-
return @recv_batch.shift
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
msg = try_recv_batch
|
|
94
|
+
msg = try_recv
|
|
106
95
|
return msg if msg
|
|
107
96
|
|
|
108
97
|
return take_recv_sentinel if @recv_sentinels.positive?
|
|
109
98
|
|
|
110
99
|
loop do
|
|
111
|
-
@
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
msg = try_recv_batch
|
|
100
|
+
@socket.wait_readable
|
|
101
|
+
msg = try_recv
|
|
115
102
|
return msg if msg
|
|
116
103
|
|
|
117
104
|
return take_recv_sentinel if @recv_sentinels.positive?
|
|
@@ -121,7 +108,7 @@ module OMQ
|
|
|
121
108
|
|
|
122
109
|
def dequeue_recv_sentinel
|
|
123
110
|
@recv_sentinels += 1
|
|
124
|
-
@
|
|
111
|
+
@socket.wake_recv if @materialized
|
|
125
112
|
nil
|
|
126
113
|
end
|
|
127
114
|
|
|
@@ -134,9 +121,8 @@ module OMQ
|
|
|
134
121
|
@all_peers_gone.resolve(nil) unless @all_peers_gone.resolved?
|
|
135
122
|
@subscriber_joined.resolve(nil) unless @subscriber_joined.resolved?
|
|
136
123
|
FdWatcher.unwatch_owner(self) unless Reactor.native_fiber_scheduler?
|
|
137
|
-
@
|
|
138
|
-
|
|
139
|
-
close_io_wrapper(@send_signal_r)
|
|
124
|
+
@socket&.close
|
|
125
|
+
@monitor_task&.stop
|
|
140
126
|
end
|
|
141
127
|
|
|
142
128
|
|
|
@@ -179,19 +165,10 @@ module OMQ
|
|
|
179
165
|
return if @materialized
|
|
180
166
|
|
|
181
167
|
capture_parent_task unless @parent_task
|
|
182
|
-
|
|
183
|
-
@
|
|
184
|
-
@
|
|
185
|
-
|
|
186
|
-
@materialized = true
|
|
187
|
-
|
|
188
|
-
@routing.replay_pending(@native)
|
|
189
|
-
|
|
190
|
-
spawn_lifecycle_watcher(@native.peer_connected_fd, @peer_connected)
|
|
191
|
-
spawn_lifecycle_watcher(@native.all_peers_gone_fd, @all_peers_gone)
|
|
192
|
-
spawn_lifecycle_watcher(@native.subscriber_joined_fd, @subscriber_joined)
|
|
193
|
-
|
|
194
|
-
start_monitor_forwarder if @monitor_queue
|
|
168
|
+
@socket = OMQ::Rust.socket(@socket_type, **extract_options.transform_keys(&:to_sym))
|
|
169
|
+
@materialized = true
|
|
170
|
+
@routing.replay_pending(@socket)
|
|
171
|
+
start_monitor_forwarder
|
|
195
172
|
end
|
|
196
173
|
|
|
197
174
|
|
|
@@ -201,89 +178,82 @@ module OMQ
|
|
|
201
178
|
end
|
|
202
179
|
|
|
203
180
|
|
|
204
|
-
def
|
|
205
|
-
|
|
206
|
-
return unless
|
|
181
|
+
def try_recv
|
|
182
|
+
message = @socket.try_recv
|
|
183
|
+
return unless message
|
|
184
|
+
return message unless @socket_type.to_sym == :SERVER
|
|
207
185
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
msg
|
|
186
|
+
routing_id, *parts = message
|
|
187
|
+
[[routing_id].pack("N"), *parts]
|
|
211
188
|
end
|
|
212
189
|
|
|
213
190
|
|
|
214
|
-
def
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
rescue IOError, Errno::EBADF
|
|
221
|
-
ensure
|
|
222
|
-
close_io_wrapper(io)
|
|
223
|
-
end
|
|
224
|
-
else
|
|
225
|
-
FdWatcher.watch_once(fd, owner: self) do
|
|
226
|
-
promise.resolve(true) unless promise.resolved? || @closed
|
|
227
|
-
end
|
|
191
|
+
def normalize_outgoing(parts)
|
|
192
|
+
return parts unless @socket_type.to_sym == :SERVER
|
|
193
|
+
|
|
194
|
+
routing_id, *body = parts
|
|
195
|
+
unless routing_id.is_a?(String) && routing_id.bytesize == 4
|
|
196
|
+
raise ArgumentError, "SERVER routing ID must be a 4-byte String"
|
|
228
197
|
end
|
|
198
|
+
[routing_id.unpack1("N"), *body]
|
|
229
199
|
end
|
|
230
200
|
|
|
231
201
|
|
|
232
202
|
def start_monitor_forwarder
|
|
203
|
+
return if @monitor_task || @monitor_watching
|
|
204
|
+
|
|
233
205
|
if Reactor.native_fiber_scheduler?
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
until @closed
|
|
237
|
-
monitor_io.wait_readable
|
|
238
|
-
monitor_io.read_nonblock(256, exception: false)
|
|
239
|
-
while (data = @native.try_recv_monitor)
|
|
240
|
-
track_connection_event(data)
|
|
241
|
-
@monitor_queue.enqueue(MonitorEvent.new(**data))
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
rescue IOError, Errno::EBADF
|
|
245
|
-
ensure
|
|
246
|
-
close_io_wrapper(monitor_io)
|
|
206
|
+
@monitor_task = @parent_task.async(transient: true, annotation: "rust-monitor") do
|
|
207
|
+
monitor_loop
|
|
247
208
|
end
|
|
248
209
|
else
|
|
249
|
-
|
|
210
|
+
@monitor_watching = true
|
|
211
|
+
FdWatcher.watch_loop(@socket.monitor_fd, owner: self) do |io|
|
|
250
212
|
io.read_nonblock(256, exception: false)
|
|
251
|
-
while (data = @
|
|
252
|
-
|
|
253
|
-
@monitor_queue.enqueue(MonitorEvent.new(**data))
|
|
213
|
+
while (data = @socket.try_monitor_event)
|
|
214
|
+
handle_monitor_event(data)
|
|
254
215
|
end
|
|
216
|
+
@socket.monitor_fd unless @closed
|
|
255
217
|
end
|
|
256
218
|
end
|
|
257
219
|
end
|
|
258
220
|
|
|
259
221
|
|
|
260
|
-
def
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
222
|
+
def monitor_loop
|
|
223
|
+
until @closed
|
|
224
|
+
data = @socket.monitor.recv
|
|
225
|
+
break unless data
|
|
264
226
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
rescue IOError, SystemCallError
|
|
227
|
+
handle_monitor_event(data)
|
|
228
|
+
end
|
|
229
|
+
rescue IOError, Errno::EBADF
|
|
230
|
+
raise unless @closed
|
|
270
231
|
end
|
|
271
232
|
|
|
272
233
|
|
|
273
|
-
def
|
|
274
|
-
|
|
275
|
-
|
|
234
|
+
def handle_monitor_event(data)
|
|
235
|
+
type = data.fetch(:event)
|
|
236
|
+
endpoint = data[:endpoint]
|
|
237
|
+
connection_id = data[:connection_id]
|
|
276
238
|
|
|
277
|
-
case
|
|
239
|
+
case type
|
|
278
240
|
when :handshake_succeeded
|
|
241
|
+
@had_peer = true
|
|
279
242
|
@connections[connection_id || Object.new] = true
|
|
243
|
+
@peer_connected.resolve(true) unless @peer_connected.resolved?
|
|
280
244
|
when :disconnected
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
@connections.shift
|
|
245
|
+
connection_id ? @connections.delete(connection_id) : @connections.shift
|
|
246
|
+
if @had_peer && @connections.empty? && !@all_peers_gone.resolved?
|
|
247
|
+
@all_peers_gone.resolve(true)
|
|
285
248
|
end
|
|
249
|
+
when :subscribe_received, :join_received
|
|
250
|
+
@subscriber_joined.resolve(true) unless @subscriber_joined.resolved?
|
|
286
251
|
end
|
|
252
|
+
|
|
253
|
+
return unless @monitor_queue
|
|
254
|
+
|
|
255
|
+
detail = data.except(:event, :endpoint)
|
|
256
|
+
@monitor_queue.enqueue(MonitorEvent.new(type:, endpoint:, detail: detail.empty? ? nil : detail))
|
|
287
257
|
end
|
|
288
258
|
|
|
289
259
|
|
|
@@ -402,14 +372,12 @@ module OMQ
|
|
|
402
372
|
|
|
403
373
|
def extract_mechanism(h)
|
|
404
374
|
mech = @options.mechanism
|
|
405
|
-
|
|
406
|
-
when Protocol::ZMTP::Mechanism::Null
|
|
375
|
+
if mech.nil? || mech.instance_of?(Protocol::ZMTP::Mechanism::Null)
|
|
407
376
|
h["mechanism_type"] = "null"
|
|
377
|
+
elsif defined?(Protocol::ZMTP::Mechanism::Curve) && mech.instance_of?(Protocol::ZMTP::Mechanism::Curve)
|
|
378
|
+
extract_curve_mechanism(h, mech)
|
|
408
379
|
else
|
|
409
|
-
|
|
410
|
-
if klass&.include?("Curve")
|
|
411
|
-
extract_curve_mechanism(h, mech)
|
|
412
|
-
end
|
|
380
|
+
raise ArgumentError, "Rust backend does not support security mechanism #{mech.class}"
|
|
413
381
|
end
|
|
414
382
|
end
|
|
415
383
|
|
|
@@ -427,6 +395,15 @@ module OMQ
|
|
|
427
395
|
srv_key = mech.instance_variable_get(:@server_public)
|
|
428
396
|
h["mechanism_server_key"] = srv_key.to_s.b if srv_key
|
|
429
397
|
end
|
|
398
|
+
|
|
399
|
+
if (authenticator = mech.instance_variable_get(:@authenticator))
|
|
400
|
+
require "protocol/zmtp/z85"
|
|
401
|
+
crypto = mech.instance_variable_get(:@crypto)
|
|
402
|
+
h["curve_auth"] = lambda do |peer|
|
|
403
|
+
public_key = crypto::PublicKey.new(Protocol::ZMTP::Z85.decode(peer.public_key))
|
|
404
|
+
authenticator.call(Protocol::ZMTP::PeerInfo.new(public_key: public_key, identity: ""))
|
|
405
|
+
end
|
|
406
|
+
end
|
|
430
407
|
end
|
|
431
408
|
|
|
432
409
|
|
|
@@ -444,9 +421,9 @@ module OMQ
|
|
|
444
421
|
|
|
445
422
|
|
|
446
423
|
def subscribe(prefix)
|
|
447
|
-
|
|
424
|
+
socket = @engine.instance_variable_get(:@socket)
|
|
448
425
|
if @engine.instance_variable_get(:@materialized)
|
|
449
|
-
|
|
426
|
+
socket.subscribe(prefix.b)
|
|
450
427
|
else
|
|
451
428
|
@pending_subscribe << prefix.b
|
|
452
429
|
end
|
|
@@ -454,14 +431,14 @@ module OMQ
|
|
|
454
431
|
|
|
455
432
|
|
|
456
433
|
def unsubscribe(prefix)
|
|
457
|
-
@engine.instance_variable_get(:@
|
|
434
|
+
@engine.instance_variable_get(:@socket).unsubscribe(prefix.b)
|
|
458
435
|
end
|
|
459
436
|
|
|
460
437
|
|
|
461
438
|
def join(group)
|
|
462
|
-
|
|
439
|
+
socket = @engine.instance_variable_get(:@socket)
|
|
463
440
|
if @engine.instance_variable_get(:@materialized)
|
|
464
|
-
|
|
441
|
+
socket.join(group)
|
|
465
442
|
else
|
|
466
443
|
@pending_join << group
|
|
467
444
|
end
|
|
@@ -469,14 +446,14 @@ module OMQ
|
|
|
469
446
|
|
|
470
447
|
|
|
471
448
|
def leave(group)
|
|
472
|
-
@engine.instance_variable_get(:@
|
|
449
|
+
@engine.instance_variable_get(:@socket).leave(group)
|
|
473
450
|
end
|
|
474
451
|
|
|
475
452
|
|
|
476
|
-
def replay_pending(
|
|
477
|
-
@pending_subscribe.each { |p|
|
|
453
|
+
def replay_pending(socket)
|
|
454
|
+
@pending_subscribe.each { |p| socket.subscribe(p) }
|
|
478
455
|
@pending_subscribe.clear
|
|
479
|
-
@pending_join.each { |g|
|
|
456
|
+
@pending_join.each { |g| socket.join(g) }
|
|
480
457
|
@pending_join.clear
|
|
481
458
|
end
|
|
482
459
|
end
|