omq-rs 0.1.0 → 0.1.2
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 +16 -0
- data/DEVELOPMENT.md +170 -0
- data/README.md +11 -24
- data/ext/omq_rs_native/Cargo.toml +3 -3
- data/ext/omq_rs_native/src/socket.rs +4 -2
- data/lib/omq/rs/socket.rb +145 -15
- data/lib/omq/rs/version.rb +1 -1
- data/lib/omq/rs.rb +1 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ace7dd4c9d05f6cba6ed58941ed30038c131c3de0a246395baf2b932ac76fa25
|
|
4
|
+
data.tar.gz: 4c6fdc8bd3543f98c01979ba2cabe4460a6c435d92c91b969b7a6bc0e6b7fdd0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ff6a09ddfa0c2c1cddad4a369509ed59085143cd5abb208e506a216f5d6c6977db2a4c77384db602f0cd193be1ab4b69b17f4f0b25f31b9a88d236093e415918
|
|
7
|
+
data.tar.gz: a0e77ee6fc098846c4e8e40035ebed72d059cbcbb249c4f264954407cc5fde6ba7f1b3b0294752ad33069e261235269e2c0a87c889636b5b8b04374e31b73f7e
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.1.2] - 2026-09-01
|
|
6
|
+
|
|
7
|
+
- Route `Socket#try_recv` directly through the native nonblocking receive path.
|
|
8
|
+
- Avoid Ruby-side batch array churn in hot polling loops.
|
|
9
|
+
|
|
10
|
+
## [0.1.1] - 2026-08-23
|
|
11
|
+
|
|
12
|
+
- Document the full public API and publish the RubyDoc documentation link.
|
|
13
|
+
- Reject unknown socket options instead of silently ignoring misspellings.
|
|
14
|
+
- Make peer, subscriber, and monitor waits stop cleanly when a socket closes.
|
|
15
|
+
- Release the CURVE auth-worker mutex before joining its thread during close.
|
|
16
|
+
- Add mixed transport, protocol, lifecycle, and resource soak coverage.
|
|
17
|
+
- Require `omq-proto` 0.26.1 and `omq-tokio` 0.21.4.
|
|
18
|
+
|
|
19
|
+
## [0.1.0] - 2026-08-20
|
|
20
|
+
|
|
5
21
|
- Add standalone `omq-rs` Ruby binding with all 20 OMQ socket types.
|
|
6
22
|
- Add PLAIN and CURVE sockets, Z85 key generation, CURVE client authentication,
|
|
7
23
|
and pyzmq CURVE interoperability.
|
data/DEVELOPMENT.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# omq-rs development
|
|
2
|
+
|
|
3
|
+
Run commands from the repository root unless a section changes directory.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Ruby 3.3 or newer with Bundler.
|
|
8
|
+
- Rust 1.93 or newer with Cargo, rustfmt, and Clippy.
|
|
9
|
+
- Python with pyzmq for the Python interoperability tests.
|
|
10
|
+
- CZMQ and libzmq development files for cztop interoperability and both
|
|
11
|
+
benchmark baselines.
|
|
12
|
+
|
|
13
|
+
Install the Ruby dependencies:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
cd bindings/ruby
|
|
17
|
+
bundle install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Build and test
|
|
21
|
+
|
|
22
|
+
Run the normal binding test pass from the repository root:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
./scripts/test-ruby.sh
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Select a Ruby executable explicitly with `OMQ_RUBY`:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
OMQ_RUBY=/path/to/ruby ./scripts/test-ruby.sh
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The equivalent commands from the binding directory are:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
cd bindings/ruby
|
|
38
|
+
bundle exec rake
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Compile once, then run one test file:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
bundle exec rake compile
|
|
45
|
+
bundle exec ruby -Ilib:test test/test_features.rb
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The suite covers socket patterns, options, transports, CURVE, PLAIN,
|
|
49
|
+
compression, monitors, Fiber schedulers, Ractors, lifecycle behavior, and
|
|
50
|
+
pyzmq interoperability. pyzmq tests skip when pyzmq is unavailable. cztop
|
|
51
|
+
tests skip when CZMQ or cztop is unavailable. Ractor tests require Ruby 4.
|
|
52
|
+
|
|
53
|
+
## Soak tests
|
|
54
|
+
|
|
55
|
+
Run the mixed transport, security, compression, churn, and resource soak:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
bindings/ruby/scripts/soak.sh 1h
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The duration accepts `s`, `m`, `h`, or `d`. The test reports progress, RSS,
|
|
62
|
+
file descriptors, and Ruby thread counts. It fails on message corruption,
|
|
63
|
+
stalls, or sustained resource growth.
|
|
64
|
+
|
|
65
|
+
`scripts/test-all.sh` includes the Ruby pass in the full repository test run.
|
|
66
|
+
|
|
67
|
+
## Static checks
|
|
68
|
+
|
|
69
|
+
Run the same native checks as CI:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
cargo fmt --manifest-path bindings/ruby/Cargo.toml --all --check
|
|
73
|
+
cargo clippy --manifest-path bindings/ruby/Cargo.toml \
|
|
74
|
+
--all-targets --all-features -- -D warnings
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Check Ruby syntax:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
find bindings/ruby/lib bindings/ruby/test bindings/ruby/scripts \
|
|
81
|
+
-name '*.rb' -print0 | xargs -0 -n1 ruby -cw
|
|
82
|
+
ruby -cw bindings/ruby/Rakefile
|
|
83
|
+
ruby -cw bindings/ruby/omq-rs.gemspec
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Check public YARD coverage from `bindings/ruby` after installing YARD:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
yard stats --no-save --no-cache --list-undoc --no-private \
|
|
90
|
+
'lib/**/*.rb' 'lib/*.rb'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Benchmarks
|
|
94
|
+
|
|
95
|
+
Run benchmarks on an otherwise idle machine. The harness starts separate Ruby
|
|
96
|
+
processes over TCP. PUSH/PULL throughput covers 16 B through 32 KiB. REQ/REP
|
|
97
|
+
mean latency covers 16 B through 4 KiB. The default run keeps the median of three
|
|
98
|
+
rounds for each implementation, pattern, and message size. Throughput uses a
|
|
99
|
+
0.5 second warmup and 2.5 second measurement window. Latency uses a 0.5 second
|
|
100
|
+
warmup and 1.5 second measurement window.
|
|
101
|
+
|
|
102
|
+
From the binding directory:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
cd bindings/ruby
|
|
106
|
+
bundle exec rake compile
|
|
107
|
+
bundle exec ruby -Ilib scripts/update_perf.rb
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The default run benchmarks `omq-rs`. It includes cztop when CZMQ is available
|
|
111
|
+
and ffi-rzmq when libzmq is available. Missing baselines are skipped.
|
|
112
|
+
|
|
113
|
+
Useful controls:
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
bundle exec ruby -Ilib scripts/update_perf.rb --quick
|
|
117
|
+
bundle exec ruby -Ilib scripts/update_perf.rb --impl omq-rs,cztop,ffi-rzmq
|
|
118
|
+
bundle exec ruby -Ilib scripts/update_perf.rb --patterns pushpull,reqrep
|
|
119
|
+
bundle exec ruby -Ilib scripts/update_perf.rb --sizes 16,128,1024,4096
|
|
120
|
+
bundle exec ruby -Ilib scripts/update_perf.rb --rounds 5
|
|
121
|
+
bundle exec ruby -Ilib scripts/update_perf.rb --duration 2.5 --warmup-duration 0.5
|
|
122
|
+
bundle exec ruby -Ilib scripts/update_perf.rb --latency-duration 1.5 --latency-warmup-duration 0.5
|
|
123
|
+
bundle exec ruby -Ilib scripts/update_perf.rb --no-record
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`--quick` runs one round at 128 B and 1 KiB without recording results or
|
|
127
|
+
rewriting the chart.
|
|
128
|
+
|
|
129
|
+
## Chart generation
|
|
130
|
+
|
|
131
|
+
Benchmark rows append to:
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
~/.cache/omq-rs/bindings.jsonl
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Regenerate the SVG from the latest cached row for each implementation,
|
|
138
|
+
pattern, and message size:
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
cd bindings/ruby
|
|
142
|
+
bundle exec ruby -Ilib scripts/update_perf.rb --chart-only
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The output is `bindings/ruby/doc/charts/bindings.svg`. Its hardware subtitle
|
|
146
|
+
comes from the repository-root `.chart_hw` file:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
prefix=Linux VM on a 2018 Mac Mini
|
|
150
|
+
postfix=6 cores, performance governor, turbo off
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`.chart_hw` is local-only and gitignored.
|
|
154
|
+
|
|
155
|
+
## Packaging and release
|
|
156
|
+
|
|
157
|
+
Build the source gem from the binding directory:
|
|
158
|
+
|
|
159
|
+
```sh
|
|
160
|
+
cd bindings/ruby
|
|
161
|
+
bundle exec rake build
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The gem is written to `bindings/ruby/pkg/`. Publication runs only through
|
|
165
|
+
`.github/workflows/release-rubygems.yml` using RubyGems trusted publishing.
|
|
166
|
+
The release tag must match the gem version:
|
|
167
|
+
|
|
168
|
+
```text
|
|
169
|
+
ruby-v<VERSION>
|
|
170
|
+
```
|
data/README.md
CHANGED
|
@@ -7,6 +7,16 @@ synchronous; its waits cooperate with an installed `Fiber.scheduler`.
|
|
|
7
7
|
MRI 3.3+, MRI 4.0+, and TruffleRuby are supported. TruffleRuby 34 does not
|
|
8
8
|
provide Ruby's `Fiber.scheduler` API, so waits block the calling thread there.
|
|
9
9
|
|
|
10
|
+
## Performance
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
The binding benchmark uses separate Ruby processes over TCP and compares
|
|
15
|
+
`omq-rs` with [cztop](https://github.com/paddor/cztop), which calls CZMQ and
|
|
16
|
+
libzmq through FFI, and [ffi-rzmq](https://github.com/chuckremes/ffi-rzmq),
|
|
17
|
+
which calls libzmq directly through FFI. See [DEVELOPMENT.md](DEVELOPMENT.md)
|
|
18
|
+
for methodology and regeneration commands.
|
|
19
|
+
|
|
10
20
|
## Install
|
|
11
21
|
|
|
12
22
|
```sh
|
|
@@ -131,30 +141,7 @@ TCP endpoints; no preparation call is required.
|
|
|
131
141
|
|
|
132
142
|
## Development
|
|
133
143
|
|
|
134
|
-
|
|
135
|
-
bundle install
|
|
136
|
-
bundle exec rake
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Performance
|
|
140
|
-
|
|
141
|
-

|
|
142
|
-
|
|
143
|
-
The binding benchmark uses separate Ruby processes over TCP and compares
|
|
144
|
-
`omq-rs` with [cztop](https://github.com/paddor/cztop), which calls CZMQ and
|
|
145
|
-
libzmq through FFI, and [ffi-rzmq](https://github.com/chuckremes/ffi-rzmq),
|
|
146
|
-
which calls libzmq directly through FFI. Install CZMQ and libzmq to include
|
|
147
|
-
both baselines.
|
|
148
|
-
|
|
149
|
-
```sh
|
|
150
|
-
ruby -Ilib scripts/update_perf.rb
|
|
151
|
-
ruby -Ilib scripts/update_perf.rb --quick
|
|
152
|
-
ruby -Ilib scripts/update_perf.rb --chart-only
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Rows append to `~/.cache/omq-rs/bindings.jsonl`. The generated chart is
|
|
156
|
-
`doc/charts/bindings.svg`. `--quick` only runs a smoke benchmark and does not
|
|
157
|
-
write results or a chart.
|
|
144
|
+
Build, test, benchmark, and release instructions: [DEVELOPMENT.md](DEVELOPMENT.md).
|
|
158
145
|
|
|
159
146
|
## License
|
|
160
147
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "omq_rs_native"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.2"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
rust-version = "1.93"
|
|
6
6
|
license = "ISC"
|
|
@@ -20,8 +20,8 @@ zstd = ["omq-tokio/zstd"]
|
|
|
20
20
|
ws = ["omq-tokio/ws"]
|
|
21
21
|
|
|
22
22
|
[dependencies]
|
|
23
|
-
omq-proto = { version = ">=0.26.
|
|
24
|
-
omq-tokio = { version = ">=0.21.
|
|
23
|
+
omq-proto = { version = ">=0.26.1, <0.28.0", default-features = false }
|
|
24
|
+
omq-tokio = { version = ">=0.21.4, <0.23.0", default-features = false }
|
|
25
25
|
yring = { version = "=0.3.14", features = ["async"] }
|
|
26
26
|
|
|
27
27
|
bytes = "1.12.0"
|
|
@@ -198,7 +198,8 @@ fn set_curve_authenticator(
|
|
|
198
198
|
}
|
|
199
199
|
drop(options_guard);
|
|
200
200
|
|
|
201
|
-
|
|
201
|
+
let previous = rb_self.auth_worker.lock().unwrap().take();
|
|
202
|
+
if let Some(previous) = previous {
|
|
202
203
|
previous.stop();
|
|
203
204
|
}
|
|
204
205
|
*rb_self.auth_worker.lock().unwrap() = worker;
|
|
@@ -774,7 +775,8 @@ unsafe extern "C" fn rust_socket_leave(rb_self: VALUE, group: VALUE) -> VALUE {
|
|
|
774
775
|
fn rust_socket_close_impl(rb_self: &RustSocket, wait_for_auth_worker: bool) {
|
|
775
776
|
rb_self.closed.store(true, Ordering::Relaxed);
|
|
776
777
|
#[cfg(feature = "curve")]
|
|
777
|
-
|
|
778
|
+
let worker = rb_self.auth_worker.lock().unwrap().take();
|
|
779
|
+
if let Some(worker) = worker {
|
|
778
780
|
if wait_for_auth_worker {
|
|
779
781
|
worker.stop();
|
|
780
782
|
} else {
|
data/lib/omq/rs/socket.rb
CHANGED
|
@@ -18,6 +18,69 @@ module OMQ
|
|
|
18
18
|
# @api private
|
|
19
19
|
SINGLE_FRAME_TYPES = %i[client server scatter gather channel].freeze
|
|
20
20
|
|
|
21
|
+
# @api private
|
|
22
|
+
SOCKET_OPTIONS = %w[
|
|
23
|
+
workload_profile
|
|
24
|
+
send_hwm
|
|
25
|
+
recv_hwm
|
|
26
|
+
recv_rate_limit
|
|
27
|
+
recv_ip_rate_limit
|
|
28
|
+
|
|
29
|
+
linger
|
|
30
|
+
identity
|
|
31
|
+
router_mandatory
|
|
32
|
+
conflate
|
|
33
|
+
|
|
34
|
+
heartbeat_interval
|
|
35
|
+
heartbeat_ttl
|
|
36
|
+
heartbeat_timeout
|
|
37
|
+
handshake_timeout
|
|
38
|
+
max_pending_handshakes
|
|
39
|
+
|
|
40
|
+
max_message_size
|
|
41
|
+
sndbuf
|
|
42
|
+
rcvbuf
|
|
43
|
+
large_message_threshold
|
|
44
|
+
arena_threshold
|
|
45
|
+
transmit_slot_cap
|
|
46
|
+
|
|
47
|
+
xpub_nodrop
|
|
48
|
+
reconnect_stop_conn_refused
|
|
49
|
+
on_mute
|
|
50
|
+
reconnect_interval
|
|
51
|
+
reconnect_interval_min
|
|
52
|
+
reconnect_interval_max
|
|
53
|
+
|
|
54
|
+
compression_dict
|
|
55
|
+
compression_auto_train
|
|
56
|
+
compression_threshold
|
|
57
|
+
compression_level
|
|
58
|
+
compression_dict_capacity
|
|
59
|
+
max_recv_dict_size
|
|
60
|
+
compression_offload_threshold
|
|
61
|
+
|
|
62
|
+
mechanism_type
|
|
63
|
+
mechanism_server
|
|
64
|
+
mechanism_public_key
|
|
65
|
+
mechanism_secret_key
|
|
66
|
+
mechanism_server_key
|
|
67
|
+
mechanism_username
|
|
68
|
+
mechanism_password
|
|
69
|
+
|
|
70
|
+
curve_server
|
|
71
|
+
curve_publickey
|
|
72
|
+
curve_public_key
|
|
73
|
+
curve_secretkey
|
|
74
|
+
curve_secret_key
|
|
75
|
+
curve_serverkey
|
|
76
|
+
curve_server_key
|
|
77
|
+
|
|
78
|
+
plain_server
|
|
79
|
+
plain_username
|
|
80
|
+
plain_password
|
|
81
|
+
].freeze
|
|
82
|
+
private_constant :ROUTED_TYPES, :SINGLE_FRAME_TYPES, :SOCKET_OPTIONS
|
|
83
|
+
|
|
21
84
|
# CURVE peer metadata passed to callable authenticators.
|
|
22
85
|
#
|
|
23
86
|
# @!attribute [r] public_key
|
|
@@ -34,11 +97,13 @@ module OMQ
|
|
|
34
97
|
Native.io_threads
|
|
35
98
|
end
|
|
36
99
|
|
|
37
|
-
# Sets number of OMQ.rs IO threads
|
|
100
|
+
# Sets number of OMQ.rs IO threads before the shared runtime starts.
|
|
38
101
|
#
|
|
39
102
|
# @param count [Integer] positive IO thread count
|
|
40
103
|
# @return [Integer] assigned count
|
|
41
104
|
# @raise [ArgumentError] if +count+ is not positive
|
|
105
|
+
# @note Set this before materializing any socket. It does not resize a
|
|
106
|
+
# running runtime.
|
|
42
107
|
def io_threads=(count)
|
|
43
108
|
count = Integer(count)
|
|
44
109
|
raise ArgumentError, "io_threads must be positive" unless count.positive?
|
|
@@ -139,7 +204,9 @@ module OMQ
|
|
|
139
204
|
def each
|
|
140
205
|
return enum_for(__method__) unless block_given?
|
|
141
206
|
|
|
142
|
-
|
|
207
|
+
while (event = recv)
|
|
208
|
+
yield event
|
|
209
|
+
end
|
|
143
210
|
rescue IOError
|
|
144
211
|
raise unless @socket.closed?
|
|
145
212
|
end
|
|
@@ -156,8 +223,53 @@ module OMQ
|
|
|
156
223
|
# @param send_timeout [Numeric, nil] send timeout in seconds
|
|
157
224
|
# @param curve_auth [Array<String>, #call, nil] CURVE allowlist or authenticator
|
|
158
225
|
# @param options [Hash] native OMQ.rs socket options
|
|
226
|
+
# @option options [Symbol] :workload_profile +:throughput+ or +:latency+
|
|
227
|
+
# @option options [Integer] :send_hwm outbound message capacity
|
|
228
|
+
# @option options [Integer] :recv_hwm inbound message capacity
|
|
229
|
+
# @option options [Hash] :recv_rate_limit per-connection
|
|
230
|
+
# +:messages_per_second+ (or +:rate+) and +:burst+
|
|
231
|
+
# @option options [Hash] :recv_ip_rate_limit per-IP
|
|
232
|
+
# +:messages_per_second+ (or +:rate+) and +:burst+
|
|
233
|
+
# @option options [Numeric] :linger close linger in seconds; positive
|
|
234
|
+
# infinity waits forever
|
|
235
|
+
# @option options [String] :identity ZMTP socket identity
|
|
236
|
+
# @option options [Boolean] :router_mandatory reject unroutable sends
|
|
237
|
+
# @option options [Boolean] :conflate retain only latest received message
|
|
238
|
+
# @option options [Numeric] :heartbeat_interval heartbeat period in seconds
|
|
239
|
+
# @option options [Numeric] :heartbeat_ttl remote heartbeat TTL in seconds
|
|
240
|
+
# @option options [Numeric] :heartbeat_timeout peer timeout in seconds
|
|
241
|
+
# @option options [Numeric] :handshake_timeout handshake timeout in seconds
|
|
242
|
+
# @option options [Integer] :max_pending_handshakes inbound handshake limit
|
|
243
|
+
# @option options [Integer] :max_message_size maximum received message bytes
|
|
244
|
+
# @option options [Integer] :sndbuf kernel send buffer bytes
|
|
245
|
+
# @option options [Integer] :rcvbuf kernel receive buffer bytes
|
|
246
|
+
# @option options [Integer] :large_message_threshold receive buffer threshold
|
|
247
|
+
# @option options [Integer] :arena_threshold contiguous frame arena threshold
|
|
248
|
+
# @option options [Integer] :transmit_slot_cap per-peer transmit bytes
|
|
249
|
+
# @option options [Boolean] :xpub_nodrop block instead of dropping on mute
|
|
250
|
+
# @option options [Boolean] :reconnect_stop_conn_refused stop refused reconnects
|
|
251
|
+
# @option options [Symbol] :on_mute +:block+, +:drop_newest+, or +:drop_oldest+
|
|
252
|
+
# @option options [Numeric] :reconnect_interval fixed reconnect delay in seconds
|
|
253
|
+
# @option options [Numeric] :reconnect_interval_min minimum backoff in seconds
|
|
254
|
+
# @option options [Numeric] :reconnect_interval_max maximum backoff in seconds
|
|
255
|
+
# @option options [String] :compression_dict compression dictionary bytes
|
|
256
|
+
# @option options [Boolean] :compression_auto_train train a zstd dictionary
|
|
257
|
+
# @option options [Integer] :compression_threshold minimum bytes to compress
|
|
258
|
+
# @option options [Integer] :compression_level zstd compression level
|
|
259
|
+
# @option options [Integer] :compression_dict_capacity trained dictionary bytes
|
|
260
|
+
# @option options [Integer] :max_recv_dict_size received dictionary byte limit
|
|
261
|
+
# @option options [Integer] :compression_offload_threshold offload threshold;
|
|
262
|
+
# negative disables offloading
|
|
263
|
+
# @option options [Symbol] :mechanism_type +:null+, +:plain+, or +:curve+
|
|
264
|
+
# @option options [Boolean] :plain_server enable PLAIN server mode
|
|
265
|
+
# @option options [String] :plain_username PLAIN client username
|
|
266
|
+
# @option options [String] :plain_password PLAIN client password
|
|
267
|
+
# @option options [Boolean] :curve_server enable CURVE server mode
|
|
268
|
+
# @option options [String] :curve_publickey local raw or Z85 public key
|
|
269
|
+
# @option options [String] :curve_secretkey local raw or Z85 secret key
|
|
270
|
+
# @option options [String] :curve_serverkey CURVE server raw or Z85 public key
|
|
159
271
|
# @return [Socket]
|
|
160
|
-
# @raise [ArgumentError] if an option is invalid
|
|
272
|
+
# @raise [ArgumentError] if an option is unknown or invalid
|
|
161
273
|
def initialize(recv_timeout: nil, send_timeout: nil, curve_auth: nil, **options)
|
|
162
274
|
socket_type = self.class.const_get(:SOCKET_TYPE, false)
|
|
163
275
|
@socket_type = socket_type.to_s.downcase.to_sym
|
|
@@ -167,7 +279,6 @@ module OMQ
|
|
|
167
279
|
|
|
168
280
|
@recv_timeout = recv_timeout
|
|
169
281
|
@send_timeout = send_timeout
|
|
170
|
-
@recv_batch = []
|
|
171
282
|
@request_waiting = false
|
|
172
283
|
@reply_ready = false
|
|
173
284
|
@native = Native::Socket.new(@socket_type.to_s.upcase)
|
|
@@ -176,6 +287,8 @@ module OMQ
|
|
|
176
287
|
@materialized = false
|
|
177
288
|
@recv_io = nil
|
|
178
289
|
@send_io = nil
|
|
290
|
+
@peer_connected = false
|
|
291
|
+
@subscriber_joined = false
|
|
179
292
|
set_curve_auth(curve_auth) unless curve_auth.nil?
|
|
180
293
|
end
|
|
181
294
|
|
|
@@ -228,7 +341,7 @@ module OMQ
|
|
|
228
341
|
@native.peer_info(routing_id)
|
|
229
342
|
end
|
|
230
343
|
|
|
231
|
-
# Configures CURVE client
|
|
344
|
+
# Configures CURVE client authorization on a server before materialization.
|
|
232
345
|
#
|
|
233
346
|
# @param authenticator [Array<String>, #call, nil] public-key allowlist,
|
|
234
347
|
# callable receiving {MechanismPeerInfo}, or +nil+ to allow valid clients
|
|
@@ -326,18 +439,11 @@ module OMQ
|
|
|
326
439
|
# @return [Array<String, Integer>, nil] next message, or +nil+ if none is ready
|
|
327
440
|
def try_recv
|
|
328
441
|
ensure_materialized
|
|
329
|
-
unless @recv_batch.empty?
|
|
330
|
-
message = @recv_batch.shift
|
|
331
|
-
received!
|
|
332
|
-
return message
|
|
333
|
-
end
|
|
334
442
|
|
|
335
443
|
message = if ROUTED_TYPES.include?(@socket_type)
|
|
336
444
|
@native.try_recv_routed
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
@recv_batch = batch
|
|
340
|
-
first
|
|
445
|
+
else
|
|
446
|
+
@native.try_recv
|
|
341
447
|
end
|
|
342
448
|
received! if message
|
|
343
449
|
message
|
|
@@ -430,9 +536,16 @@ module OMQ
|
|
|
430
536
|
# @param timeout [Numeric, nil] maximum wait in seconds
|
|
431
537
|
# @return [Socket] self
|
|
432
538
|
# @raise [IO::TimeoutError] if timeout expires
|
|
539
|
+
# @raise [IOError] if socket closes first
|
|
433
540
|
def wait_for_peer(timeout: nil)
|
|
541
|
+
raise IOError, "socket closed" if closed?
|
|
542
|
+
return self if @peer_connected
|
|
543
|
+
|
|
434
544
|
ensure_materialized
|
|
435
545
|
wait_for_native_fd(@native.peer_connected_fd, timeout, "peer connection timed out")
|
|
546
|
+
raise IOError, "socket closed" if closed?
|
|
547
|
+
|
|
548
|
+
@peer_connected = true
|
|
436
549
|
self
|
|
437
550
|
end
|
|
438
551
|
|
|
@@ -441,9 +554,16 @@ module OMQ
|
|
|
441
554
|
# @param timeout [Numeric, nil] maximum wait in seconds
|
|
442
555
|
# @return [Socket] self
|
|
443
556
|
# @raise [IO::TimeoutError] if timeout expires
|
|
557
|
+
# @raise [IOError] if socket closes first
|
|
444
558
|
def wait_for_subscriber(timeout: nil)
|
|
559
|
+
raise IOError, "socket closed" if closed?
|
|
560
|
+
return self if @subscriber_joined
|
|
561
|
+
|
|
445
562
|
ensure_materialized
|
|
446
563
|
wait_for_native_fd(@native.subscriber_joined_fd, timeout, "subscriber timed out")
|
|
564
|
+
raise IOError, "socket closed" if closed?
|
|
565
|
+
|
|
566
|
+
@subscriber_joined = true
|
|
447
567
|
self
|
|
448
568
|
end
|
|
449
569
|
|
|
@@ -471,6 +591,8 @@ module OMQ
|
|
|
471
591
|
# @return [Hash, nil]
|
|
472
592
|
# @raise [IO::TimeoutError] if timeout expires
|
|
473
593
|
def monitor_event(timeout: @recv_timeout)
|
|
594
|
+
return if closed?
|
|
595
|
+
|
|
474
596
|
ensure_materialized
|
|
475
597
|
event = @native.try_recv_monitor
|
|
476
598
|
return event if event
|
|
@@ -483,6 +605,8 @@ module OMQ
|
|
|
483
605
|
#
|
|
484
606
|
# @return [Hash, nil]
|
|
485
607
|
def try_monitor_event
|
|
608
|
+
return if closed?
|
|
609
|
+
|
|
486
610
|
ensure_materialized
|
|
487
611
|
@native.try_recv_monitor
|
|
488
612
|
end
|
|
@@ -532,11 +656,17 @@ module OMQ
|
|
|
532
656
|
end
|
|
533
657
|
|
|
534
658
|
def normalize_options(options)
|
|
535
|
-
options.to_h do |key, value|
|
|
659
|
+
normalized = options.to_h do |key, value|
|
|
536
660
|
value = value.to_s if value.is_a?(Symbol)
|
|
537
661
|
value = value.transform_keys(&:to_s) if value.is_a?(Hash)
|
|
538
662
|
[key.to_s, value]
|
|
539
663
|
end
|
|
664
|
+
unknown = normalized.keys - SOCKET_OPTIONS
|
|
665
|
+
unless unknown.empty?
|
|
666
|
+
raise ArgumentError, "unknown socket option#{"s" if unknown.length > 1}: #{unknown.sort.join(", ")}"
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
normalized
|
|
540
670
|
end
|
|
541
671
|
|
|
542
672
|
def validate_send_parts!(parts)
|
data/lib/omq/rs/version.rb
CHANGED
data/lib/omq/rs.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: omq-rs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrik Wenger
|
|
@@ -33,6 +33,7 @@ extensions:
|
|
|
33
33
|
extra_rdoc_files: []
|
|
34
34
|
files:
|
|
35
35
|
- CHANGELOG.md
|
|
36
|
+
- DEVELOPMENT.md
|
|
36
37
|
- LICENSE
|
|
37
38
|
- README.md
|
|
38
39
|
- ext/omq_rs_native/Cargo.toml
|
|
@@ -56,6 +57,7 @@ licenses:
|
|
|
56
57
|
metadata:
|
|
57
58
|
source_code_uri: https://github.com/paddor/omq.rs/tree/main/bindings/ruby
|
|
58
59
|
changelog_uri: https://github.com/paddor/omq.rs/tree/main/bindings/ruby/CHANGELOG.md
|
|
60
|
+
documentation_uri: https://www.rubydoc.info/gems/omq-rs
|
|
59
61
|
rubygems_mfa_required: 'true'
|
|
60
62
|
rdoc_options: []
|
|
61
63
|
require_paths:
|