omq-cli 0.3.1 → 0.5.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 +69 -0
- data/README.md +10 -7
- data/lib/omq/cli/base_runner.rb +38 -2
- data/lib/omq/cli/cli_parser.rb +43 -10
- data/lib/omq/cli/config.rb +5 -3
- data/lib/omq/cli/pipe.rb +52 -12
- data/lib/omq/cli/socket_setup.rb +15 -3
- data/lib/omq/cli/version.rb +1 -1
- data/lib/omq/cli.rb +24 -23
- metadata +45 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5f3ca44a806e32560f7cd0d7381f0aecd670e475659c5329853c2596e114dc22
|
|
4
|
+
data.tar.gz: b14444d22ccad4e1209d4aaf7102cf4065450bb9892eca8498cdbd90d865936d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 53ce8979e26384cd35cd0ee6e1cb57d24f10e25c4a27e81063d5c6436d2d109bbf6f1aa9eee362d97bf8e75b82f9780c27482414a70b163b452c9a5349582d4e
|
|
7
|
+
data.tar.gz: 6cfc6975d43a04198d89759c406e3068a72224206a265dc13976db8617ba3df3a2b39629c791f139b5b180db693453c1bbc271da9cd041caa78aaddd3c9f9989
|
data/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,78 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.2 — 2026-04-07
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Guard async-debug behind `OMQ_DEV`** — the Gemfile still caused the
|
|
8
|
+
openssl conflict on CI even after removing it from the gemspec.
|
|
9
|
+
|
|
10
|
+
## 0.5.1 — 2026-04-07
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Move async-debug from runtime to dev dependency** — async-debug depends on
|
|
15
|
+
`openssl >= 3.0` which conflicts with Ruby's default openssl gem on CI.
|
|
16
|
+
Now only loaded when `OMQ_DEBUG_URI` is set, with a `LoadError` guard and
|
|
17
|
+
install hint.
|
|
18
|
+
|
|
19
|
+
## 0.5.0 — 2026-04-07
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **rbnacl, zstd-ruby, and msgpack are now fixed dependencies** —
|
|
24
|
+
no more runtime detection or conditional test guards.
|
|
25
|
+
- **`--curve-crypto` renamed to `--crypto`** — applies to CURVE and future
|
|
26
|
+
mechanisms (e.g. BLAKE3ZMQ). Env var renamed from `OMQ_CURVE_CRYPTO` to
|
|
27
|
+
`OMQ_CRYPTO`.
|
|
28
|
+
- **CURVE requires system libsodium** — rbnacl is bundled but needs libsodium
|
|
29
|
+
installed (`apt install libsodium-dev` / `brew install libsodium`). nuckle
|
|
30
|
+
(pure Ruby) is available via `--crypto nuckle` but marked as DANGEROUS.
|
|
31
|
+
|
|
32
|
+
### Removed
|
|
33
|
+
|
|
34
|
+
- **`has_zstd` / `has_msgpack` config fields** — no longer needed since both
|
|
35
|
+
gems are fixed dependencies.
|
|
36
|
+
|
|
37
|
+
## 0.4.0 — 2026-04-07
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- **`--sndbuf` / `--rcvbuf` options** — set `SO_SNDBUF` and `SO_RCVBUF` kernel
|
|
42
|
+
buffer sizes. Accepts plain bytes or suffixed values (`4K`, `1M`).
|
|
43
|
+
- **Pipe FIFO ordering system test** — verifies sequential source batches are
|
|
44
|
+
never interleaved through a pipe.
|
|
45
|
+
- **Pipe producer-first system test** — verifies messages are delivered when
|
|
46
|
+
the producer finishes before the consumer connects.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- **Message traces moved to monitor events** — `-vvv` traces now use
|
|
51
|
+
`Socket#monitor(verbose: true)` instead of inline `trace_send`/`trace_recv`
|
|
52
|
+
calls, ensuring correct ordering with connection lifecycle events.
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- **Test helper `make_config`** — added missing `send_hwm`, `recv_hwm`,
|
|
57
|
+
`sndbuf`, `rcvbuf` fields and changed `verbose` default from `false` to `0`.
|
|
58
|
+
|
|
3
59
|
## 0.3.1 — 2026-04-07
|
|
4
60
|
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- **`--send-hwm` / `--recv-hwm` options** — set send and receive high water
|
|
64
|
+
marks from the command line (default 1000, 0 = unbounded).
|
|
65
|
+
- **`OMQ_DEBUG` env var** — starts async-debug web UI on
|
|
66
|
+
`https://localhost:5050` (or custom port via `OMQ_DEBUG=PORT`).
|
|
67
|
+
- **Multi-level verbosity** — `-v` prints endpoints, `-vv` logs all
|
|
68
|
+
connection events (connect/disconnect/retry/timeout) via socket monitor,
|
|
69
|
+
`-vvv` also traces first 10 bytes of every sent/received message.
|
|
70
|
+
|
|
5
71
|
### Fixed
|
|
6
72
|
|
|
73
|
+
- **`omq pipe` slow reconnection** — sequential `peer_connected.wait` calls
|
|
74
|
+
blocked receiving until both PULL and PUSH peers connected in order. Now
|
|
75
|
+
waits concurrently using `Kernel#Barrier`.
|
|
7
76
|
- **`-i` on recv-only sockets** — `pull -i 0.2` rate-limits receiving to
|
|
8
77
|
one message every 200 ms using `Async::Loop.quantized`. Works on all
|
|
9
78
|
recv-only socket types (pull, sub, gather, dish).
|
data/README.md
CHANGED
|
@@ -352,22 +352,25 @@ omq keygen
|
|
|
352
352
|
# OMQ_SERVER_PUBLIC='...'
|
|
353
353
|
# OMQ_SERVER_SECRET='...'
|
|
354
354
|
|
|
355
|
-
omq keygen --
|
|
355
|
+
omq keygen --crypto nuckle # pure Ruby backend (DANGEROUS — not audited)
|
|
356
356
|
```
|
|
357
357
|
|
|
358
358
|
Export the vars, then use `--curve-server` (server) or `--curve-server-key` (client).
|
|
359
359
|
|
|
360
360
|
## CURVE encryption
|
|
361
361
|
|
|
362
|
-
End-to-end encryption using CurveZMQ. Requires
|
|
363
|
-
- **rbnacl** (recommended) — wraps libsodium, fast and audited. `gem install rbnacl`
|
|
364
|
-
- **nuckle** — pure Ruby, no system dependencies, not audited. `gem install nuckle`
|
|
362
|
+
End-to-end encryption using CurveZMQ. Requires system libsodium:
|
|
365
363
|
|
|
366
|
-
|
|
364
|
+
```sh
|
|
365
|
+
apt install libsodium-dev # Debian/Ubuntu
|
|
366
|
+
brew install libsodium # macOS
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
To use nuckle (pure Ruby, DANGEROUS — not audited) instead:
|
|
367
370
|
|
|
368
371
|
```sh
|
|
369
|
-
omq rep -b tcp://:5555 --echo --curve-server --
|
|
370
|
-
# or:
|
|
372
|
+
omq rep -b tcp://:5555 --echo --curve-server --crypto nuckle
|
|
373
|
+
# or: OMQ_CRYPTO=nuckle omq rep -b tcp://:5555 --echo --curve-server
|
|
371
374
|
```
|
|
372
375
|
|
|
373
376
|
```sh
|
data/lib/omq/cli/base_runner.rb
CHANGED
|
@@ -25,6 +25,7 @@ module OMQ
|
|
|
25
25
|
# @return [void]
|
|
26
26
|
def call(task)
|
|
27
27
|
setup_socket
|
|
28
|
+
start_event_monitor if config.verbose >= 2
|
|
28
29
|
maybe_start_transient_monitor(task)
|
|
29
30
|
sleep(config.delay) if config.delay && config.recv_only?
|
|
30
31
|
wait_for_peer if needs_peer_wait?
|
|
@@ -63,7 +64,7 @@ module OMQ
|
|
|
63
64
|
|
|
64
65
|
|
|
65
66
|
def attach_endpoints
|
|
66
|
-
SocketSetup.attach(@sock, config, verbose: config.verbose)
|
|
67
|
+
SocketSetup.attach(@sock, config, verbose: config.verbose >= 1)
|
|
67
68
|
end
|
|
68
69
|
|
|
69
70
|
|
|
@@ -424,7 +425,42 @@ module OMQ
|
|
|
424
425
|
|
|
425
426
|
|
|
426
427
|
def log(msg)
|
|
427
|
-
$stderr.
|
|
428
|
+
$stderr.write("#{msg}\n") if config.verbose >= 1
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
# -vv: log connect/disconnect/retry/timeout events via Socket#monitor
|
|
433
|
+
# -vvv: also log message sent/received traces
|
|
434
|
+
def start_event_monitor
|
|
435
|
+
verbose = config.verbose >= 3
|
|
436
|
+
@sock.monitor(verbose: verbose) do |event|
|
|
437
|
+
case event.type
|
|
438
|
+
when :message_sent
|
|
439
|
+
$stderr.write("omq: >> #{msg_preview(event.detail[:parts])}\n")
|
|
440
|
+
when :message_received
|
|
441
|
+
$stderr.write("omq: << #{msg_preview(event.detail[:parts])}\n")
|
|
442
|
+
else
|
|
443
|
+
ep = event.endpoint ? " #{event.endpoint}" : ""
|
|
444
|
+
detail = event.detail ? " #{event.detail}" : ""
|
|
445
|
+
$stderr.write("omq: #{event.type}#{ep}#{detail}\n")
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def msg_preview(parts)
|
|
452
|
+
parts.map { |p| preview_bytes(p) }.join(" | ")
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def preview_bytes(str)
|
|
457
|
+
bytes = str.b
|
|
458
|
+
preview = bytes[0, 10].gsub(/[^[:print:]]/, ".")
|
|
459
|
+
if bytes.bytesize > 10
|
|
460
|
+
"#{preview}... (#{bytes.bytesize}B)"
|
|
461
|
+
else
|
|
462
|
+
preview
|
|
463
|
+
end
|
|
428
464
|
end
|
|
429
465
|
end
|
|
430
466
|
end
|
data/lib/omq/cli/cli_parser.rb
CHANGED
|
@@ -213,20 +213,24 @@ module OMQ
|
|
|
213
213
|
linger: 5,
|
|
214
214
|
reconnect_ivl: nil,
|
|
215
215
|
heartbeat_ivl: nil,
|
|
216
|
+
send_hwm: nil,
|
|
217
|
+
recv_hwm: nil,
|
|
218
|
+
sndbuf: nil,
|
|
219
|
+
rcvbuf: nil,
|
|
216
220
|
conflate: false,
|
|
217
221
|
compress: false,
|
|
218
222
|
send_expr: nil,
|
|
219
223
|
recv_expr: nil,
|
|
220
224
|
parallel: nil,
|
|
221
225
|
transient: false,
|
|
222
|
-
verbose:
|
|
226
|
+
verbose: 0,
|
|
223
227
|
quiet: false,
|
|
224
228
|
echo: false,
|
|
225
229
|
scripts: [],
|
|
226
230
|
recv_maxsz: nil,
|
|
227
231
|
curve_server: false,
|
|
228
232
|
curve_server_key: nil,
|
|
229
|
-
|
|
233
|
+
crypto: nil,
|
|
230
234
|
}.freeze
|
|
231
235
|
|
|
232
236
|
|
|
@@ -244,12 +248,9 @@ module OMQ
|
|
|
244
248
|
end
|
|
245
249
|
|
|
246
250
|
|
|
247
|
-
# Validates that
|
|
251
|
+
# Validates option combinations that depend on socket type.
|
|
248
252
|
#
|
|
249
253
|
def self.validate_gems!(config)
|
|
250
|
-
abort "--msgpack requires the msgpack gem" if config.format == :msgpack && !config.has_msgpack
|
|
251
|
-
abort "--compress requires the zstd-ruby gem" if config.compress && !config.has_zstd
|
|
252
|
-
|
|
253
254
|
if config.recv_only? && (config.data || config.file)
|
|
254
255
|
abort "--data/--file not valid for #{config.type_name} (receive-only)"
|
|
255
256
|
end
|
|
@@ -336,6 +337,10 @@ module OMQ
|
|
|
336
337
|
}
|
|
337
338
|
o.on("--heartbeat-ivl SECS", Float, "ZMTP heartbeat interval (detects dead peers)") { |v| opts[:heartbeat_ivl] = v }
|
|
338
339
|
o.on("--recv-maxsz COUNT", Integer, "Max inbound message size in bytes (larger messages dropped)") { |v| opts[:recv_maxsz] = v }
|
|
340
|
+
o.on("--send-hwm N", Integer, "Send high water mark (default 1000, 0=unbounded)") { |v| opts[:send_hwm] = v }
|
|
341
|
+
o.on("--recv-hwm N", Integer, "Recv high water mark (default 1000, 0=unbounded)") { |v| opts[:recv_hwm] = v }
|
|
342
|
+
o.on("--sndbuf N", "SO_SNDBUF kernel buffer size (e.g. 4K, 1M)") { |v| opts[:sndbuf] = parse_byte_size(v) }
|
|
343
|
+
o.on("--rcvbuf N", "SO_RCVBUF kernel buffer size (e.g. 4K, 1M)") { |v| opts[:rcvbuf] = parse_byte_size(v) }
|
|
339
344
|
|
|
340
345
|
o.separator "\nDelivery:"
|
|
341
346
|
o.on("--conflate", "Keep only last message per subscriber (PUB/RADIO)") { opts[:conflate] = true }
|
|
@@ -355,15 +360,16 @@ module OMQ
|
|
|
355
360
|
opts[:parallel] = v || Etc.nprocessors
|
|
356
361
|
}
|
|
357
362
|
|
|
358
|
-
o.separator "\nCURVE encryption (requires
|
|
363
|
+
o.separator "\nCURVE encryption (requires system libsodium):"
|
|
359
364
|
o.on("--curve-server", "Enable CURVE as server (generates keypair)") { opts[:curve_server] = true }
|
|
360
365
|
o.on("--curve-server-key KEY", "Enable CURVE as client (server's Z85 public key)") { |v| opts[:curve_server_key] = v }
|
|
361
|
-
o.on("--
|
|
366
|
+
o.on("--crypto BACKEND", "Crypto backend: rbnacl (default) or nuckle (pure Ruby, DANGEROUS)") { |v| opts[:crypto] = v }
|
|
367
|
+
o.separator " Install libsodium: apt install libsodium-dev / brew install libsodium"
|
|
362
368
|
o.separator " Env vars: OMQ_SERVER_KEY (client), OMQ_SERVER_PUBLIC + OMQ_SERVER_SECRET (server)"
|
|
363
|
-
o.separator "
|
|
369
|
+
o.separator " OMQ_CRYPTO (backend: rbnacl or nuckle)"
|
|
364
370
|
|
|
365
371
|
o.separator "\nOther:"
|
|
366
|
-
o.on("-v", "--verbose", "
|
|
372
|
+
o.on("-v", "--verbose", "Verbosity: -v endpoints, -vv events, -vvv messages") { opts[:verbose] += 1 }
|
|
367
373
|
o.on("-q", "--quiet", "Suppress message output") { opts[:quiet] = true }
|
|
368
374
|
o.on( "--transient", "Exit when all peers disconnect") { opts[:transient] = true }
|
|
369
375
|
o.on("-V", "--version") {
|
|
@@ -413,6 +419,25 @@ module OMQ
|
|
|
413
419
|
end
|
|
414
420
|
|
|
415
421
|
|
|
422
|
+
# Parses a byte size string with optional K/M suffix.
|
|
423
|
+
#
|
|
424
|
+
# @param str [String] e.g. "4096", "4K", "1M"
|
|
425
|
+
# @return [Integer] size in bytes
|
|
426
|
+
#
|
|
427
|
+
def parse_byte_size(str)
|
|
428
|
+
case str
|
|
429
|
+
when /\A(\d+)[kK]\z/
|
|
430
|
+
$1.to_i * 1024
|
|
431
|
+
when /\A(\d+)[mM]\z/
|
|
432
|
+
$1.to_i * 1024 * 1024
|
|
433
|
+
when /\A\d+\z/
|
|
434
|
+
str.to_i
|
|
435
|
+
else
|
|
436
|
+
abort "invalid byte size: #{str} (use e.g. 4096, 4K, 1M)"
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
|
|
416
441
|
# Validates option combinations, aborting on invalid combos.
|
|
417
442
|
#
|
|
418
443
|
# @param opts [Hash] parsed options from {#parse}
|
|
@@ -464,6 +489,14 @@ module OMQ
|
|
|
464
489
|
(opts[:connects] + opts[:binds]).each do |url|
|
|
465
490
|
abort "inproc not supported, use tcp:// or ipc://" if url.include?("inproc://")
|
|
466
491
|
end
|
|
492
|
+
|
|
493
|
+
all_urls = if type_name == "pipe"
|
|
494
|
+
(opts[:in_endpoints] + opts[:out_endpoints] + opts[:endpoints]).map(&:url)
|
|
495
|
+
else
|
|
496
|
+
opts[:connects] + opts[:binds]
|
|
497
|
+
end
|
|
498
|
+
dups = all_urls.tally.select { |_, n| n > 1 }.keys
|
|
499
|
+
abort "duplicate endpoint: #{dups.first}" if dups.any?
|
|
467
500
|
end
|
|
468
501
|
end
|
|
469
502
|
end
|
data/lib/omq/cli/config.rb
CHANGED
|
@@ -38,6 +38,10 @@ module OMQ
|
|
|
38
38
|
:linger,
|
|
39
39
|
:reconnect_ivl,
|
|
40
40
|
:heartbeat_ivl,
|
|
41
|
+
:send_hwm,
|
|
42
|
+
:recv_hwm,
|
|
43
|
+
:sndbuf,
|
|
44
|
+
:rcvbuf,
|
|
41
45
|
:conflate,
|
|
42
46
|
:compress,
|
|
43
47
|
:send_expr,
|
|
@@ -51,9 +55,7 @@ module OMQ
|
|
|
51
55
|
:recv_maxsz,
|
|
52
56
|
:curve_server,
|
|
53
57
|
:curve_server_key,
|
|
54
|
-
:
|
|
55
|
-
:has_msgpack,
|
|
56
|
-
:has_zstd,
|
|
58
|
+
:crypto,
|
|
57
59
|
:stdin_is_tty,
|
|
58
60
|
) do
|
|
59
61
|
# @return [Boolean] true if this socket type only sends
|
data/lib/omq/cli/pipe.rb
CHANGED
|
@@ -42,7 +42,7 @@ module OMQ
|
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
def attach_endpoints(sock, endpoints)
|
|
45
|
-
SocketSetup.attach_endpoints(sock, endpoints)
|
|
45
|
+
SocketSetup.attach_endpoints(sock, endpoints, verbose: config.verbose >= 1)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
|
|
@@ -58,9 +58,12 @@ module OMQ
|
|
|
58
58
|
)
|
|
59
59
|
compile_expr
|
|
60
60
|
@sock = @pull # for eval instance_exec
|
|
61
|
+
start_event_monitors if config.verbose >= 2
|
|
61
62
|
with_timeout(config.timeout) do
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
Barrier do |barrier|
|
|
64
|
+
barrier.async(annotation: "wait push peer") { @push.peer_connected.wait }
|
|
65
|
+
barrier.async(annotation: "wait pull peer") { @pull.peer_connected.wait }
|
|
66
|
+
end
|
|
64
67
|
end
|
|
65
68
|
setup_sequential_transient(task)
|
|
66
69
|
@sock.instance_exec(&@recv_begin_proc) if @recv_begin_proc
|
|
@@ -72,17 +75,21 @@ module OMQ
|
|
|
72
75
|
end
|
|
73
76
|
|
|
74
77
|
|
|
75
|
-
def
|
|
78
|
+
def apply_socket_options(sock)
|
|
76
79
|
sock.reconnect_interval = config.reconnect_ivl if config.reconnect_ivl
|
|
77
80
|
sock.heartbeat_interval = config.heartbeat_ivl if config.heartbeat_ivl
|
|
81
|
+
sock.send_hwm = config.send_hwm if config.send_hwm
|
|
82
|
+
sock.recv_hwm = config.recv_hwm if config.recv_hwm
|
|
83
|
+
sock.sndbuf = config.sndbuf if config.sndbuf
|
|
84
|
+
sock.rcvbuf = config.rcvbuf if config.rcvbuf
|
|
78
85
|
end
|
|
79
86
|
|
|
80
87
|
|
|
81
88
|
def build_pull_push(pull_opts, push_opts, in_eps, out_eps)
|
|
82
89
|
pull = OMQ::PULL.new(**pull_opts)
|
|
83
90
|
push = OMQ::PUSH.new(**push_opts)
|
|
84
|
-
|
|
85
|
-
|
|
91
|
+
apply_socket_options(pull)
|
|
92
|
+
apply_socket_options(push)
|
|
86
93
|
attach_endpoints(pull, in_eps)
|
|
87
94
|
attach_endpoints(push, out_eps)
|
|
88
95
|
[pull, push]
|
|
@@ -107,7 +114,10 @@ module OMQ
|
|
|
107
114
|
break if parts.nil?
|
|
108
115
|
parts = @fmt.decompress(parts)
|
|
109
116
|
parts = eval_recv_expr(parts)
|
|
110
|
-
|
|
117
|
+
if parts && !parts.empty?
|
|
118
|
+
out = @fmt.compress(parts)
|
|
119
|
+
@push.send(out)
|
|
120
|
+
end
|
|
111
121
|
i += 1
|
|
112
122
|
break if n && n > 0 && i >= n
|
|
113
123
|
end
|
|
@@ -143,9 +153,11 @@ module OMQ
|
|
|
143
153
|
|
|
144
154
|
def wait_for_pairs(pairs)
|
|
145
155
|
with_timeout(config.timeout) do
|
|
146
|
-
|
|
147
|
-
push
|
|
148
|
-
|
|
156
|
+
Barrier do |barrier|
|
|
157
|
+
pairs.each do |pull, push|
|
|
158
|
+
barrier.async(annotation: "wait push peer") { push.peer_connected.wait }
|
|
159
|
+
barrier.async(annotation: "wait pull peer") { pull.peer_connected.wait }
|
|
160
|
+
end
|
|
149
161
|
end
|
|
150
162
|
end
|
|
151
163
|
end
|
|
@@ -245,7 +257,7 @@ module OMQ
|
|
|
245
257
|
workers.each do |w|
|
|
246
258
|
w.value
|
|
247
259
|
rescue Ractor::RemoteError => e
|
|
248
|
-
$stderr.
|
|
260
|
+
$stderr.write("omq: Ractor error: #{e.cause&.message || e.message}\n")
|
|
249
261
|
end
|
|
250
262
|
end
|
|
251
263
|
|
|
@@ -277,7 +289,35 @@ module OMQ
|
|
|
277
289
|
|
|
278
290
|
|
|
279
291
|
def log(msg)
|
|
280
|
-
$stderr.
|
|
292
|
+
$stderr.write("#{msg}\n") if config.verbose >= 1
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def start_event_monitors
|
|
297
|
+
verbose = config.verbose >= 3
|
|
298
|
+
[@pull, @push].each do |sock|
|
|
299
|
+
sock.monitor(verbose: verbose) do |event|
|
|
300
|
+
case event.type
|
|
301
|
+
when :message_sent
|
|
302
|
+
$stderr.write("omq: >> #{msg_preview(event.detail[:parts])}\n")
|
|
303
|
+
when :message_received
|
|
304
|
+
$stderr.write("omq: << #{msg_preview(event.detail[:parts])}\n")
|
|
305
|
+
else
|
|
306
|
+
ep = event.endpoint ? " #{event.endpoint}" : ""
|
|
307
|
+
detail = event.detail ? " #{event.detail}" : ""
|
|
308
|
+
$stderr.write("omq: #{event.type}#{ep}#{detail}\n")
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def msg_preview(parts)
|
|
316
|
+
parts.map { |p|
|
|
317
|
+
bytes = p.b
|
|
318
|
+
preview = bytes[0, 10].gsub(/[^[:print:]]/, ".")
|
|
319
|
+
bytes.bytesize > 10 ? "#{preview}... (#{bytes.bytesize}B)" : preview
|
|
320
|
+
}.join(" | ")
|
|
281
321
|
end
|
|
282
322
|
end
|
|
283
323
|
end
|
data/lib/omq/cli/socket_setup.rb
CHANGED
|
@@ -15,6 +15,10 @@ module OMQ
|
|
|
15
15
|
sock.recv_timeout = config.timeout if config.timeout
|
|
16
16
|
sock.send_timeout = config.timeout if config.timeout
|
|
17
17
|
sock.max_message_size = config.recv_maxsz if config.recv_maxsz
|
|
18
|
+
sock.send_hwm = config.send_hwm if config.send_hwm
|
|
19
|
+
sock.recv_hwm = config.recv_hwm if config.recv_hwm
|
|
20
|
+
sock.sndbuf = config.sndbuf if config.sndbuf
|
|
21
|
+
sock.rcvbuf = config.rcvbuf if config.rcvbuf
|
|
18
22
|
sock.reconnect_interval = config.reconnect_ivl if config.reconnect_ivl
|
|
19
23
|
sock.heartbeat_interval = config.heartbeat_ivl if config.heartbeat_ivl
|
|
20
24
|
sock.identity = config.identity if config.identity
|
|
@@ -40,8 +44,16 @@ module OMQ
|
|
|
40
44
|
# Bind/connect +sock+ from an Array of Endpoint objects.
|
|
41
45
|
# Used by PipeRunner, which works with structured endpoint lists.
|
|
42
46
|
#
|
|
43
|
-
def self.attach_endpoints(sock, endpoints)
|
|
44
|
-
endpoints.each
|
|
47
|
+
def self.attach_endpoints(sock, endpoints, verbose: false)
|
|
48
|
+
endpoints.each do |ep|
|
|
49
|
+
if ep.bind?
|
|
50
|
+
sock.bind(ep.url)
|
|
51
|
+
$stderr.puts "Bound to #{sock.last_endpoint}" if verbose
|
|
52
|
+
else
|
|
53
|
+
sock.connect(ep.url)
|
|
54
|
+
$stderr.puts "Connecting to #{ep.url}" if verbose
|
|
55
|
+
end
|
|
56
|
+
end
|
|
45
57
|
end
|
|
46
58
|
|
|
47
59
|
|
|
@@ -66,7 +78,7 @@ module OMQ
|
|
|
66
78
|
|
|
67
79
|
return unless server_key_z85 || server_mode
|
|
68
80
|
|
|
69
|
-
crypto = CLI.load_curve_crypto(config.
|
|
81
|
+
crypto = CLI.load_curve_crypto(config.crypto || ENV["OMQ_CRYPTO"], verbose: config.verbose >= 1)
|
|
70
82
|
require "protocol/zmtp/mechanism/curve"
|
|
71
83
|
|
|
72
84
|
if server_key_z85
|
data/lib/omq/cli/version.rb
CHANGED
data/lib/omq/cli.rb
CHANGED
|
@@ -122,12 +122,12 @@ module OMQ
|
|
|
122
122
|
verbose = false
|
|
123
123
|
while (arg = argv.shift)
|
|
124
124
|
case arg
|
|
125
|
-
when "--
|
|
125
|
+
when "--crypto"
|
|
126
126
|
crypto_name = argv.shift
|
|
127
127
|
when "-v", "--verbose"
|
|
128
128
|
verbose = true
|
|
129
129
|
when "-h", "--help"
|
|
130
|
-
puts "Usage: omq keygen [--
|
|
130
|
+
puts "Usage: omq keygen [--crypto rbnacl|nuckle] [-v]\n\n" \
|
|
131
131
|
"Generates a CURVE keypair for persistent server identity.\n" \
|
|
132
132
|
"Output: Z85-encoded env vars for use with --curve-server."
|
|
133
133
|
exit
|
|
@@ -135,7 +135,7 @@ module OMQ
|
|
|
135
135
|
abort "omq keygen: unknown option: #{arg}"
|
|
136
136
|
end
|
|
137
137
|
end
|
|
138
|
-
crypto_name ||= ENV["
|
|
138
|
+
crypto_name ||= ENV["OMQ_CRYPTO"]
|
|
139
139
|
|
|
140
140
|
crypto = load_curve_crypto(crypto_name, verbose: verbose)
|
|
141
141
|
require "protocol/zmtp/mechanism/curve"
|
|
@@ -166,11 +166,11 @@ module OMQ
|
|
|
166
166
|
require "rbnacl"
|
|
167
167
|
RbNaCl
|
|
168
168
|
rescue LoadError
|
|
169
|
-
abort "CURVE requires
|
|
170
|
-
"
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"
|
|
169
|
+
abort "CURVE requires libsodium. Install it:\n" \
|
|
170
|
+
" apt install libsodium-dev # Debian/Ubuntu\n" \
|
|
171
|
+
" brew install libsodium # macOS\n" \
|
|
172
|
+
"Or use nuckle (pure Ruby, DANGEROUS — not audited):\n" \
|
|
173
|
+
" --crypto nuckle"
|
|
174
174
|
end
|
|
175
175
|
else
|
|
176
176
|
abort "Unknown CURVE crypto backend: #{name}. Use 'rbnacl' or 'nuckle'."
|
|
@@ -204,11 +204,23 @@ module OMQ
|
|
|
204
204
|
trap("INT") { Process.exit!(0) }
|
|
205
205
|
trap("TERM") { Process.exit!(0) }
|
|
206
206
|
|
|
207
|
-
Console.logger = Console::Logger.new(Console::Output::Null.new) unless config.verbose
|
|
207
|
+
Console.logger = Console::Logger.new(Console::Output::Null.new) unless config.verbose >= 1
|
|
208
|
+
|
|
209
|
+
debug_ep = nil
|
|
210
|
+
|
|
211
|
+
if ENV["OMQ_DEBUG_URI"]
|
|
212
|
+
begin
|
|
213
|
+
require "async/debug"
|
|
214
|
+
debug_ep = Async::HTTP::Endpoint.parse ENV["OMQ_DEBUG_URI"]
|
|
215
|
+
rescue LoadError
|
|
216
|
+
abort "OMQ_DEBUG_URI requires the async-debug gem: gem install async-debug"
|
|
217
|
+
end
|
|
218
|
+
end
|
|
208
219
|
|
|
209
220
|
if config.type_name.nil?
|
|
210
221
|
Object.include(OMQ) unless Object.include?(OMQ)
|
|
211
|
-
Async do
|
|
222
|
+
Async annotation: 'omq' do
|
|
223
|
+
Async::Debug.serve(endpoint: debug_ep) if debug_ep
|
|
212
224
|
config.scripts.each { |s| load_script(s) }
|
|
213
225
|
rescue => e
|
|
214
226
|
$stderr.puts "omq: #{e.message}"
|
|
@@ -219,7 +231,8 @@ module OMQ
|
|
|
219
231
|
|
|
220
232
|
runner_class, socket_sym = RUNNER_MAP.fetch(config.type_name)
|
|
221
233
|
|
|
222
|
-
Async do |task|
|
|
234
|
+
Async annotation: "omq #{config.type_name}" do |task|
|
|
235
|
+
Async::Debug.serve(endpoint: debug_ep) if debug_ep
|
|
223
236
|
config.scripts.each { |s| load_script(s) }
|
|
224
237
|
runner = if socket_sym
|
|
225
238
|
runner_class.new(config, OMQ.const_get(socket_sym))
|
|
@@ -256,18 +269,6 @@ module OMQ
|
|
|
256
269
|
opts = CliParser.parse(argv)
|
|
257
270
|
CliParser.validate!(opts)
|
|
258
271
|
|
|
259
|
-
opts[:has_msgpack] = begin
|
|
260
|
-
require "msgpack"
|
|
261
|
-
true
|
|
262
|
-
rescue LoadError
|
|
263
|
-
false
|
|
264
|
-
end
|
|
265
|
-
opts[:has_zstd] = begin
|
|
266
|
-
require "zstd-ruby"
|
|
267
|
-
true
|
|
268
|
-
rescue LoadError
|
|
269
|
-
false
|
|
270
|
-
end
|
|
271
272
|
opts[:stdin_is_tty] = $stdin.tty?
|
|
272
273
|
|
|
273
274
|
Ractor.make_shareable(Config.new(**opts))
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: omq-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrik Wenger
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '0.
|
|
18
|
+
version: '0.15'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '0.
|
|
25
|
+
version: '0.15'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: omq-ractor
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -107,6 +107,48 @@ dependencies:
|
|
|
107
107
|
- - "~>"
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
109
|
version: '0.1'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: msgpack
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0'
|
|
117
|
+
type: :runtime
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
124
|
+
- !ruby/object:Gem::Dependency
|
|
125
|
+
name: rbnacl
|
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - "~>"
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '7.0'
|
|
131
|
+
type: :runtime
|
|
132
|
+
prerelease: false
|
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - "~>"
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '7.0'
|
|
138
|
+
- !ruby/object:Gem::Dependency
|
|
139
|
+
name: zstd-ruby
|
|
140
|
+
requirement: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - ">="
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: '0'
|
|
145
|
+
type: :runtime
|
|
146
|
+
prerelease: false
|
|
147
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
148
|
+
requirements:
|
|
149
|
+
- - ">="
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: '0'
|
|
110
152
|
description: Command-line tool for sending and receiving ZeroMQ messages on any socket
|
|
111
153
|
type (REQ/REP, PUB/SUB, PUSH/PULL, DEALER/ROUTER, and all draft types). Supports
|
|
112
154
|
Ruby eval (-e/-E), script handlers (-r), pipe virtual socket with Ractor parallelism,
|