omq 0.28.2 → 0.28.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4fdf548893d2ef3a060964a37aba4c6e7b28ef375376a98d1d609e8495801bf9
4
- data.tar.gz: 3e0f418d932b6d1575dfeeae27b90faf70cddd1dcceeb47b82e9792164044e5c
3
+ metadata.gz: 4a7d2541a2f4b738d4afc495979d3d9a6d36eb7dba15c16b69715a818d8a98c7
4
+ data.tar.gz: 5237a3a57df244d8576565600192b056d74f9cc1538c613816906f19703a11e3
5
5
  SHA512:
6
- metadata.gz: 9310c7e4c955c5157a161032f93faadf9acc4a7beb0c20caf47470881de1a439354a728278016e79e16c9bd83eb2c1d99ebd5be6c9fef5f465a5b909c331328e
7
- data.tar.gz: 48053e2af3a4a5925ff8adaacac87345dbf32dbceaa418035a945fa047752dd30d6dd0422a5947583b245aba754c04ae89e6e9415ee308cfbd4dbfa6b4c8e536
6
+ metadata.gz: 6aab453842918ebec2116dd070ad83b79a82d410cd55f6c4f198e1fce8e06cc5b050f7a3b01baadb3d09249d489ad9c9236dff9d07c5a2e26b0e3781d7c44f75
7
+ data.tar.gz: ef4e5e965f0aa20f9037e5bd7e782ac5fcce5bb1b939b3bf7f5b35c546ac8395a4b96670a67d0086fd0a0f201a8d3050efdb769c2f23f120316d4528607c64bc
data/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.28.4] - 2026-07-30
6
+
7
+ ### Fixed
8
+
9
+ - Exposed `conflate` through the public socket option accessors.
10
+
11
+ ## [0.28.3] - 2026-07-30
12
+
13
+ ### Added
14
+
15
+ - Made `inproc://` a compatibility alias for `ruby://` when no backend or
16
+ plugin registers a real `inproc` transport.
17
+ - Lazy-load the Rust backend from `omq/backend/rust`, matching
18
+ `omq/backend/libzmq`.
19
+
20
+ ### Removed
21
+
22
+ - Removed the old `omq/rust` backend load path.
23
+ - Removed the old `omq/ffi` backend load path and `backend: :ffi` alias.
24
+
5
25
  ## 0.28.2 - 2026-07-28
6
26
 
7
27
  ### Fixed
data/README.md CHANGED
@@ -34,8 +34,9 @@ walkthrough of every major pattern with working code.
34
34
  knife for ØMQ. `gem install omq-cli`
35
35
  - **Every socket pattern**: req/rep, pub/sub, push/pull, dealer/router,
36
36
  xpub/xsub, pair, and all draft types
37
- - **Every transport**: tcp, ipc (Unix domain sockets), inproc (in-process
38
- queues)
37
+ - **Every transport**: tcp, ipc (Unix domain sockets), ruby/inproc
38
+ (in-process queues). `inproc://` aliases `ruby://` unless a backend
39
+ provides native inproc
39
40
  - **Async-native**: built on fibers, non-blocking from the ground up
40
41
  - **Works outside Async too**: a shared IO thread handles sockets for callers
41
42
  that aren't inside a reactor, so simple scripts just work
@@ -214,6 +215,16 @@ echo "hello" | omq req -c tcp://localhost:5555
214
215
 
215
216
  See the [omq-cli README](https://github.com/paddor/omq-cli) for full documentation.
216
217
 
218
+ ## Optional Rust backend
219
+
220
+ Install `omq-backend-rust` for a Rust/omq-tokio backend. Same socket API,
221
+ but connection handling runs in native code on a Tokio runtime.
222
+
223
+ ```ruby
224
+ require "omq/backend/rust"
225
+ push = OMQ::PUSH.new(backend: :rust)
226
+ ```
227
+
217
228
  ## Optional libzmq backend
218
229
 
219
230
  Install `omq-backend-libzmq` for a Ruby 4.0+ libzmq backend. Same socket
@@ -227,8 +238,7 @@ push = OMQ::PUSH.new(backend: :libzmq)
227
238
  ```
228
239
 
229
240
  Requires the `ffi` gem and a system libzmq 4.x. `ffi` is not a runtime
230
- dependency of `omq`. The old `require "omq/ffi"` and `backend: :ffi`
231
- names still work.
241
+ dependency of `omq`.
232
242
 
233
243
  ## Companion Gems
234
244
 
data/lib/omq/engine.rb CHANGED
@@ -192,8 +192,8 @@ module OMQ
192
192
  def bind(endpoint, parent: nil, **opts)
193
193
  OMQ.freeze_for_ractors!
194
194
  capture_parent_task(parent: parent)
195
- transport = transport_for(endpoint)
196
- listener = transport.listener(endpoint, self, **opts)
195
+ endpoint, transport = resolve_endpoint(endpoint)
196
+ listener = transport.listener(endpoint, self, **opts)
197
197
 
198
198
  start_accept_loops(listener)
199
199
 
@@ -214,15 +214,14 @@ module OMQ
214
214
  def connect(endpoint, parent: nil, **opts)
215
215
  OMQ.freeze_for_ractors!
216
216
  capture_parent_task(parent: parent)
217
- validate_endpoint!(endpoint)
217
+ endpoint, transport = resolve_endpoint(endpoint)
218
+ validate_endpoint!(endpoint, transport)
218
219
 
219
220
  if endpoint.start_with?("ruby://")
220
221
  # Ruby in-process connect is synchronous and instant — no Dialer
221
- transport = transport_for(endpoint)
222
222
  transport.connect(endpoint, self, **opts)
223
223
  @dialers[endpoint] = :ruby # sentinel for reconnect intent
224
224
  else
225
- transport = transport_for(endpoint)
226
225
  @dialers[endpoint] = transport.dialer(endpoint, self, **opts)
227
226
  emit_monitor_event(:connect_delayed, endpoint: endpoint)
228
227
  schedule_reconnect(endpoint, delay: 0)
@@ -239,6 +238,7 @@ module OMQ
239
238
  # @return [void]
240
239
  #
241
240
  def disconnect(endpoint)
241
+ endpoint = canonical_endpoint(endpoint)
242
242
  @dialers.delete(endpoint)
243
243
  close_connections_at(endpoint)
244
244
  end
@@ -251,6 +251,7 @@ module OMQ
251
251
  # @return [void]
252
252
  #
253
253
  def unbind(endpoint)
254
+ endpoint = canonical_endpoint(endpoint)
254
255
  listener = @listeners.delete(endpoint) or return
255
256
 
256
257
  listener.stop
@@ -608,8 +609,8 @@ module OMQ
608
609
  # @raise [ArgumentError] if the scheme is not registered
609
610
  #
610
611
  def transport_for(endpoint)
611
- scheme = endpoint[/\A([^:]+):\/\//, 1]
612
- transport = self.class.transports[scheme]
612
+ scheme = scheme_for(endpoint)
613
+ transport = registered_transport(scheme)
613
614
 
614
615
  unless transport
615
616
  raise ArgumentError, "unsupported transport: #{endpoint}"
@@ -701,15 +702,65 @@ module OMQ
701
702
  # @param endpoint [String]
702
703
  # @raise [ArgumentError] if the transport rejects the endpoint
703
704
  #
704
- def validate_endpoint!(endpoint)
705
- transport = transport_for(endpoint)
706
-
705
+ def validate_endpoint!(endpoint, transport)
707
706
  if transport.respond_to?(:validate_endpoint!)
708
707
  transport.validate_endpoint!(endpoint)
709
708
  end
710
709
  end
711
710
 
712
711
 
712
+ # Resolves transport aliases before the endpoint is stored in
713
+ # listener, dialer, or connection maps.
714
+ #
715
+ # @param endpoint [String]
716
+ # @return [Array(String, Module)]
717
+ #
718
+ def resolve_endpoint(endpoint)
719
+ transport = transport_for(endpoint)
720
+ if transport.respond_to?(:canonical_endpoint)
721
+ endpoint = transport.canonical_endpoint(endpoint)
722
+ end
723
+
724
+ [endpoint, transport]
725
+ end
726
+
727
+
728
+ # Best-effort normalization for disconnect/unbind. Unknown schemes
729
+ # stay as-is so those calls remain no-ops instead of raising.
730
+ #
731
+ # @param endpoint [String]
732
+ # @return [String]
733
+ #
734
+ def canonical_endpoint(endpoint)
735
+ transport = registered_transport(scheme_for(endpoint))
736
+ return endpoint unless transport&.respond_to?(:canonical_endpoint)
737
+
738
+ transport.canonical_endpoint(endpoint)
739
+ end
740
+
741
+
742
+ # Looks up a registered transport. If no real inproc transport is
743
+ # registered, inproc:// falls back to the Ruby in-process transport.
744
+ #
745
+ # @param scheme [String, nil]
746
+ # @return [Module, nil]
747
+ #
748
+ def registered_transport(scheme)
749
+ self.class.transports[scheme] ||
750
+ (scheme == "inproc" ? self.class.transports["ruby"] : nil)
751
+ end
752
+
753
+
754
+ # Extracts the URI scheme from an endpoint.
755
+ #
756
+ # @param endpoint [String]
757
+ # @return [String, nil]
758
+ #
759
+ def scheme_for(endpoint)
760
+ endpoint[/\A([^:]+):\/\//, 1]
761
+ end
762
+
763
+
713
764
  # Starts the listener's accept loops on the socket-level barrier
714
765
  # and routes accepted IOs through {#handle_accepted}.
715
766
  #
data/lib/omq/socket.rb CHANGED
@@ -55,6 +55,7 @@ module OMQ
55
55
  :write_timeout, :write_timeout=,
56
56
  :router_mandatory, :router_mandatory=,
57
57
  :router_mandatory?,
58
+ :conflate, :conflate=,
58
59
  :reconnect_interval, :reconnect_interval=,
59
60
  :heartbeat_interval, :heartbeat_interval=,
60
61
  :heartbeat_ttl, :heartbeat_ttl=,
@@ -330,8 +331,7 @@ module OMQ
330
331
  def require_backend(name)
331
332
  path = case name
332
333
  when :libzmq then "omq/backend/libzmq"
333
- when :ffi then "omq/ffi"
334
- when :rust then "omq/rust"
334
+ when :rust then "omq/backend/rust"
335
335
  end
336
336
  return unless path
337
337
 
@@ -13,8 +13,8 @@ module OMQ
13
13
  # serialization. Parts are already frozen by Writable#send, so the
14
14
  # receiver sees the same immutable contract as ZMTP transports.
15
15
  #
16
- # The inproc:// scheme is reserved for native backends (FFI/libzmq,
17
- # Rust/omq-tokio) which have their own in-process registries.
16
+ # inproc:// is treated as a compatibility alias by the Ruby backend
17
+ # unless a backend or plugin registers a real inproc transport.
18
18
  #
19
19
  module Inproc
20
20
  Engine.transports["ruby"] = self
@@ -38,6 +38,17 @@ module OMQ
38
38
  attr_reader :registry
39
39
 
40
40
 
41
+ # Canonicalizes compatibility aliases so ruby:// and inproc://
42
+ # share the same in-process endpoint namespace.
43
+ #
44
+ # @param endpoint [String]
45
+ # @return [String]
46
+ #
47
+ def canonical_endpoint(endpoint)
48
+ endpoint.sub(/\Ainproc:\/\//, "ruby://")
49
+ end
50
+
51
+
41
52
  # Creates a bound inproc listener.
42
53
  #
43
54
  # @param endpoint [String] e.g. "ruby://my-endpoint"
@@ -46,6 +57,8 @@ module OMQ
46
57
  # @raise [ArgumentError] if endpoint is already bound
47
58
  #
48
59
  def listener(endpoint, engine, **)
60
+ endpoint = canonical_endpoint(endpoint)
61
+
49
62
  @mutex.synchronize do
50
63
  if @registry.key?(endpoint)
51
64
  raise ArgumentError, "endpoint already bound: #{endpoint}"
@@ -68,6 +81,7 @@ module OMQ
68
81
  # @return [void]
69
82
  #
70
83
  def connect(endpoint, engine, **)
84
+ endpoint = canonical_endpoint(endpoint)
71
85
  bound_engine = @mutex.synchronize { @registry[endpoint] }
72
86
  bound_engine ||= await_bind(endpoint, engine) or return
73
87
  establish_link(engine, bound_engine, endpoint)
@@ -80,6 +94,7 @@ module OMQ
80
94
  # @return [void]
81
95
  #
82
96
  def unbind(endpoint)
97
+ endpoint = canonical_endpoint(endpoint)
83
98
  @mutex.synchronize { @registry.delete(endpoint) }
84
99
  end
85
100
 
data/lib/omq/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OMQ
4
- VERSION = "0.28.2"
4
+ VERSION = "0.28.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.28.2
4
+ version: 0.28.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger