omq 0.11.0 → 0.12.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.
@@ -12,9 +12,10 @@ module OMQ
12
12
  # @param engine [Engine]
13
13
  #
14
14
  def initialize(engine)
15
- @engine = engine
16
- @recv_queue = Async::LimitedQueue.new(engine.options.recv_hwm)
17
- @tasks = []
15
+ @engine = engine
16
+ @recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
17
+ @tasks = []
18
+ @state = :ready # :ready or :waiting_reply
18
19
  init_round_robin(engine)
19
20
  end
20
21
 
@@ -22,6 +23,7 @@ module OMQ
22
23
  #
23
24
  attr_reader :recv_queue, :send_queue
24
25
 
26
+
25
27
  # @param connection [Connection]
26
28
  #
27
29
  def connection_added(connection)
@@ -29,6 +31,7 @@ module OMQ
29
31
  signal_connection_available
30
32
  update_direct_pipe
31
33
  task = @engine.start_recv_pump(connection, @recv_queue) do |msg|
34
+ @state = :ready
32
35
  msg.first&.empty? ? msg[1..] : msg
33
36
  end
34
37
  @tasks << task if task
@@ -45,6 +48,8 @@ module OMQ
45
48
  # @param parts [Array<String>]
46
49
  #
47
50
  def enqueue(parts)
51
+ raise SocketError, "REQ socket expects send/recv/send/recv order" unless @state == :ready
52
+ @state = :waiting_reply
48
53
  enqueue_round_robin(parts)
49
54
  end
50
55
 
@@ -12,6 +12,9 @@ module OMQ
12
12
  # their #initialize.
13
13
  #
14
14
  module RoundRobin
15
+ # @return [Boolean] true when the send pump is idle (not sending a batch)
16
+ def send_pump_idle? = @send_pump_idle
17
+
15
18
  private
16
19
 
17
20
 
@@ -23,7 +26,7 @@ module OMQ
23
26
  @connections = []
24
27
  @cycle = @connections.cycle
25
28
  @connection_available = Async::Promise.new
26
- @send_queue = Async::LimitedQueue.new(engine.options.send_hwm)
29
+ @send_queue = Routing.build_queue(engine.options.send_hwm, :block)
27
30
  @send_pump_started = false
28
31
  @send_pump_idle = true
29
32
  @direct_pipe = nil
@@ -90,13 +93,6 @@ module OMQ
90
93
  def transform_send(parts) = parts
91
94
 
92
95
 
93
- # Starts the background send pump that dequeues messages
94
- # and dispatches them round-robin across connections.
95
- #
96
- # @return [Boolean] true when the send pump is idle (not sending a batch)
97
- def send_pump_idle? = @send_pump_idle
98
-
99
-
100
96
  def start_send_pump
101
97
  @send_pump_started = true
102
98
  @tasks << @engine.spawn_pump_task(annotation: "send pump") do
@@ -144,14 +140,11 @@ module OMQ
144
140
  @written << conn
145
141
  rescue *CONNECTION_LOST
146
142
  @engine.connection_lost(conn)
147
- # Flush what we've written so far
148
143
  @written.each do |c|
149
144
  c.flush
150
145
  rescue *CONNECTION_LOST
151
- # will be cleaned up
152
146
  end
153
147
  @written.clear
154
- # Fall back to send_with_retry for this and remaining
155
148
  send_with_retry(parts)
156
149
  batch[(i + 1)..].each { |p| send_with_retry(p) }
157
150
  return
@@ -160,7 +153,6 @@ module OMQ
160
153
  @written.each do |conn|
161
154
  conn.flush
162
155
  rescue *CONNECTION_LOST
163
- # will be cleaned up
164
156
  end
165
157
  end
166
158
  end
@@ -15,8 +15,8 @@ module OMQ
15
15
  #
16
16
  def initialize(engine)
17
17
  @engine = engine
18
- @recv_queue = Async::LimitedQueue.new(engine.options.recv_hwm)
19
- @send_queue = Async::LimitedQueue.new(engine.options.send_hwm)
18
+ @recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
19
+ @send_queue = Routing.build_queue(engine.options.send_hwm, :block)
20
20
  @connections_by_identity = {}
21
21
  @identity_by_connection = {}
22
22
  @tasks = []
@@ -13,7 +13,7 @@ module OMQ
13
13
  def initialize(engine)
14
14
  @engine = engine
15
15
  @connections = []
16
- @recv_queue = Async::LimitedQueue.new(engine.options.recv_hwm)
16
+ @recv_queue = Routing.build_queue(engine.options.recv_hwm, engine.options.on_mute)
17
17
  @subscriptions = Set.new
18
18
  @tasks = []
19
19
  end
@@ -26,7 +26,6 @@ module OMQ
26
26
  #
27
27
  def connection_added(connection)
28
28
  @connections << connection
29
- # Send existing subscriptions to new peer
30
29
  @subscriptions.each do |prefix|
31
30
  connection.send_command(Protocol::ZMTP::Codec::Command.subscribe(prefix))
32
31
  end
@@ -15,7 +15,7 @@ module OMQ
15
15
  #
16
16
  def initialize(engine)
17
17
  @engine = engine
18
- @recv_queue = Async::LimitedQueue.new(engine.options.recv_hwm)
18
+ @recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
19
19
  @tasks = []
20
20
  init_fan_out(engine)
21
21
  end
@@ -14,8 +14,8 @@ module OMQ
14
14
  def initialize(engine)
15
15
  @engine = engine
16
16
  @connections = []
17
- @recv_queue = Async::LimitedQueue.new(engine.options.recv_hwm)
18
- @send_queue = Async::LimitedQueue.new(engine.options.send_hwm)
17
+ @recv_queue = Routing.build_queue(engine.options.recv_hwm, engine.options.on_mute)
18
+ @send_queue = Routing.build_queue(engine.options.send_hwm, :block)
19
19
  @tasks = []
20
20
  @send_pump_started = false
21
21
  @send_pump_idle = true
data/lib/omq/routing.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require "async"
4
4
  require "async/queue"
5
5
  require "async/limited_queue"
6
+ require_relative "drop_queue"
6
7
 
7
8
  module OMQ
8
9
  # Routing strategies for each ZMQ socket type.
@@ -14,6 +15,42 @@ module OMQ
14
15
  # Shared frozen empty binary string to avoid repeated allocations.
15
16
  EMPTY_BINARY = "".b.freeze
16
17
 
18
+ # Plugin registry for socket types not built into omq.
19
+ # Populated by sister gems via +Routing.register+.
20
+ #
21
+ @registry = {}
22
+
23
+ class << self
24
+ # Registers a routing strategy class for a socket type.
25
+ # Called by omq-draft (and other plugins) at require time.
26
+ #
27
+ # @param socket_type [Symbol] e.g. :RADIO, :CLIENT
28
+ # @param strategy_class [Class]
29
+ #
30
+ def register(socket_type, strategy_class)
31
+ @registry[socket_type] = strategy_class
32
+ end
33
+ end
34
+
35
+ # Builds a send or recv queue based on the mute strategy.
36
+ #
37
+ # @param hwm [Integer] high water mark
38
+ # @param on_mute [Symbol] :block, :drop_newest, or :drop_oldest
39
+ # @return [Async::LimitedQueue, DropQueue]
40
+ #
41
+ def self.build_queue(hwm, on_mute)
42
+ return Async::Queue.new if hwm.nil? || hwm == 0
43
+
44
+ case on_mute
45
+ when :block
46
+ Async::LimitedQueue.new(hwm)
47
+ when :drop_newest, :drop_oldest
48
+ DropQueue.new(hwm, strategy: on_mute)
49
+ else
50
+ raise ArgumentError, "unknown on_mute strategy: #{on_mute.inspect}"
51
+ end
52
+ end
53
+
17
54
  # Drains all available messages from +queue+ into +batch+ without
18
55
  # blocking. Call after the initial blocking dequeue.
19
56
  #
@@ -49,17 +86,10 @@ module OMQ
49
86
  when :SUB then Sub
50
87
  when :XPUB then XPub
51
88
  when :XSUB then XSub
52
- when :PUSH then Push
53
- when :PULL then Pull
54
- when :CLIENT then Client
55
- when :SERVER then Server
56
- when :RADIO then Radio
57
- when :DISH then Dish
58
- when :SCATTER then Scatter
59
- when :GATHER then Gather
60
- when :PEER then Peer
61
- when :CHANNEL then Channel
62
- else raise ArgumentError, "unknown socket type: #{socket_type}"
89
+ when :PUSH then Push
90
+ when :PULL then Pull
91
+ else
92
+ @registry[socket_type] or raise ArgumentError, "unknown socket type: #{socket_type.inspect}"
63
93
  end
64
94
  end
65
95
  end
data/lib/omq/socket.rb CHANGED
@@ -36,8 +36,8 @@ module OMQ
36
36
  :heartbeat_ttl, :heartbeat_ttl=,
37
37
  :heartbeat_timeout, :heartbeat_timeout=,
38
38
  :max_message_size, :max_message_size=,
39
- :mechanism, :mechanism=,
40
- :tls_context, :tls_context=
39
+ :on_mute, :on_mute=,
40
+ :mechanism, :mechanism=
41
41
 
42
42
 
43
43
  # Creates a new socket and binds it to the given endpoint.
@@ -141,6 +141,46 @@ module OMQ
141
141
  end
142
142
 
143
143
 
144
+ # Yields lifecycle events for this socket.
145
+ #
146
+ # Spawns a background fiber that reads from an internal event queue.
147
+ # The block receives {MonitorEvent} instances until the socket is
148
+ # closed or the returned task is stopped.
149
+ #
150
+ # @yield [event] called for each lifecycle event
151
+ # @yieldparam event [MonitorEvent]
152
+ # @return [Async::Task] the monitor task (call +#stop+ to end early)
153
+ #
154
+ # @example
155
+ # task = socket.monitor do |event|
156
+ # case event
157
+ # in type: :connected, endpoint:
158
+ # puts "peer up: #{endpoint}"
159
+ # in type: :disconnected, endpoint:
160
+ # puts "peer down: #{endpoint}"
161
+ # end
162
+ # end
163
+ # # later:
164
+ # task.stop
165
+ #
166
+ def monitor(&block)
167
+ ensure_parent_task
168
+ queue = Async::Queue.new
169
+ @engine.monitor_queue = queue
170
+ Reactor.run do
171
+ @engine.parent_task.async(transient: true, annotation: "monitor") do
172
+ while (event = queue.dequeue)
173
+ block.call(event)
174
+ end
175
+ rescue Async::Stop
176
+ ensure
177
+ @engine.monitor_queue = nil
178
+ block.call(MonitorEvent.new(type: :monitor_stopped))
179
+ end
180
+ end
181
+ end
182
+
183
+
144
184
  # Disable auto-reconnect for connected endpoints.
145
185
  def reconnect_enabled=(val)
146
186
  @engine.reconnect_enabled = val
@@ -226,13 +266,14 @@ module OMQ
226
266
  #
227
267
  def _init_engine(socket_type, linger:, send_hwm: nil, recv_hwm: nil,
228
268
  send_timeout: nil, recv_timeout: nil, conflate: false,
229
- backend: nil)
269
+ on_mute: nil, backend: nil)
230
270
  @options = Options.new(linger: linger)
231
271
  @options.send_hwm = send_hwm if send_hwm
232
272
  @options.recv_hwm = recv_hwm if recv_hwm
233
273
  @options.send_timeout = send_timeout if send_timeout
234
274
  @options.recv_timeout = recv_timeout if recv_timeout
235
275
  @options.conflate = conflate
276
+ @options.on_mute = on_mute if on_mute
236
277
  @recv_buffer = []
237
278
  @recv_mutex = Mutex.new
238
279
  @engine = case backend
@@ -118,11 +118,12 @@ module OMQ
118
118
  "incompatible socket types: #{client_type} cannot connect to #{server_type}"
119
119
  end
120
120
 
121
- # Only PUB/SUB-family types exchange commands (SUBSCRIBE/CANCEL)
122
- # over inproc. All other types use only the direct recv queue
123
- # bypass for data, so no internal queues are needed.
121
+ # PUB/SUB-family types exchange commands (SUBSCRIBE/CANCEL)
122
+ # over inproc. QoS >= 1 needs command queues for ACK/NACK.
124
123
  needs_commands = COMMAND_TYPES.include?(client_type) ||
125
- COMMAND_TYPES.include?(server_type)
124
+ COMMAND_TYPES.include?(server_type) ||
125
+ client_engine.options.qos >= 1 ||
126
+ server_engine.options.qos >= 1
126
127
 
127
128
  if needs_commands
128
129
  a_to_b = Async::Queue.new
@@ -301,13 +302,30 @@ module OMQ
301
302
 
302
303
  # Receives a multi-frame message.
303
304
  #
305
+ # When a block is given, command items ([:command, cmd]) are
306
+ # yielded as command frames — matching the Protocol::ZMTP::Connection
307
+ # interface. Without a block, commands are silently skipped if
308
+ # the pipe has command queues.
309
+ #
304
310
  # @return [Array<String>]
305
311
  # @raise [EOFError] if closed
306
312
  #
307
313
  def receive_message
308
- msg = @receive_queue.dequeue
309
- raise EOFError, "connection closed" if msg.nil?
310
- msg
314
+ loop do
315
+ item = @receive_queue.dequeue
316
+ raise EOFError, "connection closed" if item.nil?
317
+
318
+ if item.is_a?(Array) && item.first == :command
319
+ if block_given?
320
+ cmd = item[1]
321
+ frame = Protocol::ZMTP::Codec::Frame.new(cmd.to_body, command: true)
322
+ yield frame
323
+ end
324
+ next
325
+ end
326
+
327
+ return item
328
+ end
311
329
  end
312
330
 
313
331
 
@@ -92,12 +92,24 @@ module OMQ
92
92
  end
93
93
 
94
94
 
95
- # Registers the accept loop task owned by the engine.
95
+ # Spawns an accept loop task under +parent_task+.
96
+ # Yields an IO::Stream-wrapped client socket for each accepted connection.
96
97
  #
97
- # @param task [Async::Task]
98
+ # @param parent_task [Async::Task]
99
+ # @yieldparam io [IO::Stream::Buffered]
98
100
  #
99
- def accept_task=(task)
100
- @task = task
101
+ def start_accept_loops(parent_task, &on_accepted)
102
+ @task = parent_task.async(transient: true, annotation: "ipc accept #{@endpoint}") do
103
+ loop do
104
+ client = @server.accept
105
+ Async::Task.current.defer_stop { on_accepted.call(IO::Stream::Buffered.wrap(client)) }
106
+ end
107
+ rescue Async::Stop
108
+ rescue IOError
109
+ # server closed
110
+ ensure
111
+ @server.close rescue nil
112
+ end
101
113
  end
102
114
 
103
115
 
@@ -17,7 +17,7 @@ module OMQ
17
17
  # @return [Listener]
18
18
  #
19
19
  def bind(endpoint, engine)
20
- host, port = parse_endpoint(endpoint)
20
+ host, port = self.parse_endpoint(endpoint)
21
21
  host = "0.0.0.0" if host == "*"
22
22
 
23
23
  addrs = Addrinfo.getaddrinfo(host, port, nil, :STREAM, nil, ::Socket::AI_PASSIVE)
@@ -43,14 +43,23 @@ module OMQ
43
43
  # @param engine [Engine]
44
44
  # @return [void]
45
45
  #
46
+ # Validates that the endpoint's host can be resolved.
47
+ #
48
+ # @param endpoint [String]
49
+ # @return [void]
50
+ #
51
+ def validate_endpoint!(endpoint)
52
+ host, _port = parse_endpoint(endpoint)
53
+ Addrinfo.getaddrinfo(host, nil, nil, :STREAM) if host
54
+ end
55
+
56
+
46
57
  def connect(endpoint, engine)
47
- host, port = parse_endpoint(endpoint)
58
+ host, port = self.parse_endpoint(endpoint)
48
59
  sock = TCPSocket.new(host, port)
49
60
  engine.handle_connected(IO::Stream::Buffered.wrap(sock), endpoint: endpoint)
50
61
  end
51
62
 
52
- private
53
-
54
63
  # Parses a TCP endpoint URI into host and port.
55
64
  #
56
65
  # @param endpoint [String]
@@ -90,12 +99,26 @@ module OMQ
90
99
  end
91
100
 
92
101
 
93
- # Registers accept loop tasks owned by the engine.
102
+ # Spawns accept loop tasks under +parent_task+.
103
+ # Yields an IO::Stream-wrapped client socket for each accepted connection.
94
104
  #
95
- # @param tasks [Array<Async::Task>]
105
+ # @param parent_task [Async::Task]
106
+ # @yieldparam io [IO::Stream::Buffered]
96
107
  #
97
- def accept_tasks=(tasks)
98
- @tasks = tasks
108
+ def start_accept_loops(parent_task, &on_accepted)
109
+ @tasks = @servers.map do |server|
110
+ parent_task.async(transient: true, annotation: "tcp accept #{@endpoint}") do
111
+ loop do
112
+ client = server.accept
113
+ Async::Task.current.defer_stop { on_accepted.call(IO::Stream::Buffered.wrap(client)) }
114
+ end
115
+ rescue Async::Stop
116
+ rescue IOError
117
+ # server closed
118
+ ensure
119
+ server.close rescue nil
120
+ end
121
+ end
99
122
  end
100
123
 
101
124
 
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.11.0"
4
+ VERSION = "0.12.0"
5
5
  end
data/lib/omq.rb CHANGED
@@ -8,9 +8,9 @@
8
8
 
9
9
  require "protocol/zmtp"
10
10
  require "io/stream"
11
- require "openssl"
12
11
 
13
12
  require_relative "omq/version"
13
+ require_relative "omq/monitor_event"
14
14
 
15
15
  module OMQ
16
16
  # Raised when an internal pump task crashes unexpectedly.
@@ -19,6 +19,8 @@ module OMQ
19
19
  class SocketDeadError < RuntimeError; end
20
20
 
21
21
  # Errors raised when a peer disconnects or resets the connection.
22
+ # Not frozen at load time — transport plugins append to this before
23
+ # the first bind/connect, which freezes both arrays.
22
24
  CONNECTION_LOST = [
23
25
  EOFError,
24
26
  IOError,
@@ -27,8 +29,7 @@ module OMQ
27
29
  Errno::ECONNABORTED,
28
30
  Errno::ENOTCONN,
29
31
  IO::Stream::ConnectionResetError,
30
- OpenSSL::SSL::SSLError,
31
- ].freeze
32
+ ]
32
33
 
33
34
  # Errors raised when a peer cannot be reached.
34
35
  CONNECTION_FAILED = [
@@ -38,13 +39,12 @@ module OMQ
38
39
  Errno::EHOSTUNREACH,
39
40
  Errno::ENETUNREACH,
40
41
  Socket::ResolutionError,
41
- ].freeze
42
+ ]
42
43
  end
43
44
 
44
45
  # Transport
45
46
  require_relative "omq/transport/inproc"
46
47
  require_relative "omq/transport/tcp"
47
- require_relative "omq/transport/tls"
48
48
  require_relative "omq/transport/ipc"
49
49
 
50
50
  # Core
@@ -64,15 +64,6 @@ require_relative "omq/routing/xpub"
64
64
  require_relative "omq/routing/xsub"
65
65
  require_relative "omq/routing/push"
66
66
  require_relative "omq/routing/pull"
67
- require_relative "omq/routing/scatter"
68
- require_relative "omq/routing/gather"
69
- require_relative "omq/routing/channel"
70
- require_relative "omq/routing/client"
71
- require_relative "omq/routing/server"
72
- require_relative "omq/routing/radio"
73
- require_relative "omq/routing/dish"
74
- require_relative "omq/routing/peer"
75
- require_relative "omq/single_frame"
76
67
  require_relative "omq/engine"
77
68
  require_relative "omq/queue_interface"
78
69
  require_relative "omq/readable"
@@ -85,11 +76,6 @@ require_relative "omq/router_dealer"
85
76
  require_relative "omq/pub_sub"
86
77
  require_relative "omq/push_pull"
87
78
  require_relative "omq/pair"
88
- require_relative "omq/scatter_gather"
89
- require_relative "omq/channel"
90
- require_relative "omq/client_server"
91
- require_relative "omq/radio_dish"
92
- require_relative "omq/peer"
93
79
 
94
80
  # For the purists.
95
81
  ØMQ = OMQ
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.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger
@@ -65,49 +65,36 @@ files:
65
65
  - LICENSE
66
66
  - README.md
67
67
  - lib/omq.rb
68
- - lib/omq/channel.rb
69
- - lib/omq/client_server.rb
68
+ - lib/omq/drop_queue.rb
70
69
  - lib/omq/engine.rb
70
+ - lib/omq/monitor_event.rb
71
71
  - lib/omq/options.rb
72
72
  - lib/omq/pair.rb
73
- - lib/omq/peer.rb
74
73
  - lib/omq/pub_sub.rb
75
74
  - lib/omq/push_pull.rb
76
75
  - lib/omq/queue_interface.rb
77
- - lib/omq/radio_dish.rb
78
76
  - lib/omq/reactor.rb
79
77
  - lib/omq/readable.rb
80
78
  - lib/omq/req_rep.rb
81
79
  - lib/omq/router_dealer.rb
82
80
  - lib/omq/routing.rb
83
- - lib/omq/routing/channel.rb
84
- - lib/omq/routing/client.rb
85
81
  - lib/omq/routing/dealer.rb
86
- - lib/omq/routing/dish.rb
87
82
  - lib/omq/routing/fan_out.rb
88
- - lib/omq/routing/gather.rb
89
83
  - lib/omq/routing/pair.rb
90
- - lib/omq/routing/peer.rb
91
84
  - lib/omq/routing/pub.rb
92
85
  - lib/omq/routing/pull.rb
93
86
  - lib/omq/routing/push.rb
94
- - lib/omq/routing/radio.rb
95
87
  - lib/omq/routing/rep.rb
96
88
  - lib/omq/routing/req.rb
97
89
  - lib/omq/routing/round_robin.rb
98
90
  - lib/omq/routing/router.rb
99
- - lib/omq/routing/scatter.rb
100
- - lib/omq/routing/server.rb
101
91
  - lib/omq/routing/sub.rb
102
92
  - lib/omq/routing/xpub.rb
103
93
  - lib/omq/routing/xsub.rb
104
- - lib/omq/scatter_gather.rb
105
- - lib/omq/single_frame.rb
106
94
  - lib/omq/socket.rb
107
95
  - lib/omq/transport/inproc.rb
108
96
  - lib/omq/transport/ipc.rb
109
97
  - lib/omq/transport/tcp.rb
110
- - lib/omq/transport/tls.rb
111
98
  - lib/omq/version.rb
112
99
  - lib/omq/writable.rb
113
100
  homepage: https://github.com/zeromq/omq
data/lib/omq/channel.rb DELETED
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OMQ
4
- class CHANNEL < Socket
5
- include Readable
6
- include Writable
7
- include SingleFrame
8
-
9
- def initialize(endpoints = nil, linger: 0, backend: nil)
10
- _init_engine(:CHANNEL, linger: linger, backend: backend)
11
- _attach(endpoints, default: :connect)
12
- end
13
- end
14
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OMQ
4
- class CLIENT < Socket
5
- include Readable
6
- include Writable
7
- include SingleFrame
8
-
9
- def initialize(endpoints = nil, linger: 0, backend: nil)
10
- _init_engine(:CLIENT, linger: linger, backend: backend)
11
- _attach(endpoints, default: :connect)
12
- end
13
- end
14
-
15
- class SERVER < Socket
16
- include Readable
17
- include Writable
18
- include SingleFrame
19
-
20
- def initialize(endpoints = nil, linger: 0, backend: nil)
21
- _init_engine(:SERVER, linger: linger, backend: backend)
22
- _attach(endpoints, default: :bind)
23
- end
24
-
25
- # Sends a message to a specific peer by routing ID.
26
- #
27
- # @param routing_id [String] 4-byte routing ID
28
- # @param message [String] message body
29
- # @return [self]
30
- #
31
- def send_to(routing_id, message)
32
- parts = [routing_id.b.freeze, message.b.freeze]
33
- with_timeout(@options.write_timeout) { @engine.enqueue_send(parts) }
34
- self
35
- end
36
- end
37
- end
data/lib/omq/peer.rb DELETED
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OMQ
4
- class PEER < Socket
5
- include Readable
6
- include Writable
7
- include SingleFrame
8
-
9
- def initialize(endpoints = nil, linger: 0, backend: nil)
10
- _init_engine(:PEER, linger: linger, backend: backend)
11
- _attach(endpoints, default: :connect)
12
- end
13
-
14
- # Sends a message to a specific peer by routing ID.
15
- #
16
- # @param routing_id [String] 4-byte routing ID
17
- # @param message [String] message body
18
- # @return [self]
19
- #
20
- def send_to(routing_id, message)
21
- parts = [routing_id.b.freeze, message.b.freeze]
22
- with_timeout(@options.write_timeout) { @engine.enqueue_send(parts) }
23
- self
24
- end
25
- end
26
- end