omq 0.11.0 → 0.13.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +143 -0
  3. data/README.md +3 -1
  4. data/lib/omq/drop_queue.rb +54 -0
  5. data/lib/omq/engine/connection_setup.rb +47 -0
  6. data/lib/omq/engine/heartbeat.rb +40 -0
  7. data/lib/omq/engine/reconnect.rb +56 -0
  8. data/lib/omq/engine/recv_pump.rb +76 -0
  9. data/lib/omq/engine.rb +145 -371
  10. data/lib/omq/monitor_event.rb +16 -0
  11. data/lib/omq/options.rb +5 -3
  12. data/lib/omq/pub_sub.rb +9 -8
  13. data/lib/omq/routing/conn_send_pump.rb +36 -0
  14. data/lib/omq/routing/dealer.rb +8 -10
  15. data/lib/omq/routing/fair_queue.rb +144 -0
  16. data/lib/omq/routing/fair_recv.rb +27 -0
  17. data/lib/omq/routing/fan_out.rb +116 -63
  18. data/lib/omq/routing/pair.rb +39 -20
  19. data/lib/omq/routing/pub.rb +5 -7
  20. data/lib/omq/routing/pull.rb +5 -4
  21. data/lib/omq/routing/push.rb +3 -10
  22. data/lib/omq/routing/rep.rb +31 -51
  23. data/lib/omq/routing/req.rb +15 -12
  24. data/lib/omq/routing/round_robin.rb +82 -72
  25. data/lib/omq/routing/router.rb +23 -48
  26. data/lib/omq/routing/sub.rb +8 -6
  27. data/lib/omq/routing/xpub.rb +8 -4
  28. data/lib/omq/routing/xsub.rb +43 -27
  29. data/lib/omq/routing.rb +44 -11
  30. data/lib/omq/socket.rb +46 -5
  31. data/lib/omq/transport/inproc/direct_pipe.rb +162 -0
  32. data/lib/omq/transport/inproc.rb +37 -200
  33. data/lib/omq/transport/ipc.rb +16 -4
  34. data/lib/omq/transport/tcp.rb +31 -8
  35. data/lib/omq/version.rb +1 -1
  36. data/lib/omq.rb +5 -19
  37. metadata +11 -16
  38. data/lib/omq/channel.rb +0 -14
  39. data/lib/omq/client_server.rb +0 -37
  40. data/lib/omq/peer.rb +0 -26
  41. data/lib/omq/radio_dish.rb +0 -74
  42. data/lib/omq/routing/channel.rb +0 -83
  43. data/lib/omq/routing/client.rb +0 -56
  44. data/lib/omq/routing/dish.rb +0 -78
  45. data/lib/omq/routing/gather.rb +0 -46
  46. data/lib/omq/routing/peer.rb +0 -101
  47. data/lib/omq/routing/radio.rb +0 -150
  48. data/lib/omq/routing/scatter.rb +0 -82
  49. data/lib/omq/routing/server.rb +0 -101
  50. data/lib/omq/scatter_gather.rb +0 -23
  51. data/lib/omq/single_frame.rb +0 -18
  52. data/lib/omq/transport/tls.rb +0 -146
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "async"
4
4
  require "async/queue"
5
+ require_relative "inproc/direct_pipe"
5
6
 
6
7
  module OMQ
7
8
  module Transport
@@ -54,25 +55,7 @@ module OMQ
54
55
  #
55
56
  def connect(endpoint, engine)
56
57
  bound_engine = @mutex.synchronize { @registry[endpoint] }
57
-
58
- unless bound_engine
59
- # Endpoint not bound yet. Wait with timeout derived from
60
- # reconnect_interval. If it doesn't appear, silently return —
61
- # matching ZMQ 4.x behavior where inproc connect to an
62
- # unbound endpoint succeeds but messages go nowhere.
63
- # A background task retries periodically.
64
- ri = engine.options.reconnect_interval
65
- timeout = ri.is_a?(Range) ? ri.begin : ri
66
- promise = Async::Promise.new
67
- @mutex.synchronize { @waiters[endpoint] << promise }
68
- unless promise.wait?(timeout: timeout)
69
- @mutex.synchronize { @waiters[endpoint].delete(promise) }
70
- start_connect_retry(endpoint, engine)
71
- return
72
- end
73
- bound_engine = @mutex.synchronize { @registry[endpoint] }
74
- end
75
-
58
+ bound_engine ||= await_bind(endpoint, engine) or return
76
59
  establish_link(engine, bound_engine, endpoint)
77
60
  end
78
61
 
@@ -112,41 +95,51 @@ module OMQ
112
95
  def establish_link(client_engine, server_engine, endpoint)
113
96
  client_type = client_engine.socket_type
114
97
  server_type = server_engine.socket_type
115
-
116
98
  unless Protocol::ZMTP::VALID_PEERS[client_type]&.include?(server_type)
117
99
  raise Protocol::ZMTP::Error,
118
100
  "incompatible socket types: #{client_type} cannot connect to #{server_type}"
119
101
  end
102
+ needs_cmds = needs_commands?(client_engine, server_engine, client_type, server_type)
103
+ client_pipe, server_pipe = make_pipe_pair(client_engine, server_engine, client_type, server_type, needs_cmds)
104
+ client_engine.connection_ready(client_pipe, endpoint: endpoint)
105
+ server_engine.connection_ready(server_pipe, endpoint: endpoint)
106
+ end
120
107
 
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.
124
- needs_commands = COMMAND_TYPES.include?(client_type) ||
125
- COMMAND_TYPES.include?(server_type)
108
+ def needs_commands?(ce, se, ct, st)
109
+ COMMAND_TYPES.include?(ct) || COMMAND_TYPES.include?(st) ||
110
+ ce.options.qos >= 1 || se.options.qos >= 1
111
+ end
126
112
 
127
- if needs_commands
113
+ def make_pipe_pair(ce, se, ct, st, needs_cmds)
114
+ if needs_cmds
128
115
  a_to_b = Async::Queue.new
129
116
  b_to_a = Async::Queue.new
130
117
  end
118
+ client = DirectPipe.new(send_queue: needs_cmds ? a_to_b : nil,
119
+ receive_queue: needs_cmds ? b_to_a : nil,
120
+ peer_identity: se.options.identity, peer_type: st.to_s)
121
+ server = DirectPipe.new(send_queue: needs_cmds ? b_to_a : nil,
122
+ receive_queue: needs_cmds ? a_to_b : nil,
123
+ peer_identity: ce.options.identity, peer_type: ct.to_s)
124
+ client.peer = server
125
+ server.peer = client
126
+ [client, server]
127
+ end
131
128
 
132
- client_pipe = DirectPipe.new(
133
- send_queue: needs_commands ? a_to_b : nil,
134
- receive_queue: needs_commands ? b_to_a : nil,
135
- peer_identity: server_engine.options.identity,
136
- peer_type: server_type.to_s,
137
- )
138
- server_pipe = DirectPipe.new(
139
- send_queue: needs_commands ? b_to_a : nil,
140
- receive_queue: needs_commands ? a_to_b : nil,
141
- peer_identity: client_engine.options.identity,
142
- peer_type: client_type.to_s,
143
- )
144
-
145
- client_pipe.peer = server_pipe
146
- server_pipe.peer = client_pipe
147
-
148
- client_engine.connection_ready(client_pipe, endpoint: endpoint)
149
- server_engine.connection_ready(server_pipe, endpoint: endpoint)
129
+ def await_bind(endpoint, engine)
130
+ # Endpoint not bound yet — wait briefly then start background retry.
131
+ # Matches ZMQ 4.x: connect to unbound inproc succeeds silently.
132
+ ri = engine.options.reconnect_interval
133
+ timeout = ri.is_a?(Range) ? ri.begin : ri
134
+ promise = Async::Promise.new
135
+ @mutex.synchronize { @waiters[endpoint] << promise }
136
+ if promise.wait?(timeout: timeout)
137
+ @mutex.synchronize { @registry[endpoint] }
138
+ else
139
+ @mutex.synchronize { @waiters[endpoint].delete(promise) }
140
+ start_connect_retry(endpoint, engine)
141
+ nil
142
+ end
150
143
  end
151
144
 
152
145
 
@@ -194,162 +187,6 @@ module OMQ
194
187
  end
195
188
  end
196
189
 
197
- # A direct in-process pipe that transfers Ruby arrays through queues.
198
- #
199
- # Implements the same interface as Connection so routing strategies
200
- # can use it transparently.
201
- #
202
- # When a routing strategy sets {#direct_recv_queue} on a pipe,
203
- # {#send_message} enqueues directly into the peer's recv queue,
204
- # bypassing the intermediate pipe queues and the recv pump task.
205
- # This reduces inproc from 3 queue hops to 2 (send_queue →
206
- # recv_queue), eliminating the internal pipe queue in between.
207
- #
208
- class DirectPipe
209
- # @return [String] peer's socket type
210
- #
211
- attr_reader :peer_socket_type
212
-
213
-
214
- # @return [String] peer's identity
215
- #
216
- attr_reader :peer_identity
217
-
218
-
219
- # @return [DirectPipe, nil] the other end of this pipe pair
220
- #
221
- attr_accessor :peer
222
-
223
-
224
- # @return [Async::LimitedQueue, nil] when set, {#send_message}
225
- # enqueues directly here instead of using the internal queue
226
- #
227
- attr_reader :direct_recv_queue
228
-
229
-
230
- # @return [Proc, nil] optional transform applied before
231
- # enqueuing into {#direct_recv_queue}
232
- #
233
- attr_accessor :direct_recv_transform
234
-
235
-
236
- # @param send_queue [Async::Queue, nil] outgoing command queue
237
- # (nil for non-PUB/SUB types that don't exchange commands)
238
- # @param receive_queue [Async::Queue, nil] incoming command queue
239
- # @param peer_identity [String]
240
- # @param peer_type [String]
241
- #
242
- def initialize(send_queue: nil, receive_queue: nil, peer_identity:, peer_type:)
243
- @send_queue = send_queue
244
- @receive_queue = receive_queue
245
- @peer_identity = peer_identity || "".b
246
- @peer_socket_type = peer_type
247
- @closed = false
248
- @peer = nil
249
- @direct_recv_queue = nil
250
- @direct_recv_transform = nil
251
- @pending_direct = nil
252
- end
253
-
254
-
255
- # Sets the direct recv queue. Drains any messages that were
256
- # buffered before the queue was available.
257
- #
258
- def direct_recv_queue=(queue)
259
- @direct_recv_queue = queue
260
- if queue && @pending_direct
261
- @pending_direct.each do |msg|
262
- queue.enqueue(msg)
263
- end
264
- @pending_direct = nil
265
- end
266
- end
267
-
268
-
269
- # Sends a multi-frame message.
270
- #
271
- # When {#direct_recv_queue} is set (inproc fast path), the
272
- # message is delivered directly to the peer's recv queue,
273
- # skipping the internal pipe queues and the recv pump.
274
- #
275
- # @param parts [Array<String>]
276
- # @return [void]
277
- #
278
- def send_message(parts)
279
- raise IOError, "closed" if @closed
280
- if @direct_recv_queue
281
- msg = @direct_recv_transform ? @direct_recv_transform.call(parts).freeze : parts
282
- @direct_recv_queue.enqueue(msg)
283
- elsif @send_queue
284
- @send_queue.enqueue(parts)
285
- else
286
- msg = @direct_recv_transform ? @direct_recv_transform.call(parts).freeze : parts
287
- (@pending_direct ||= []) << msg
288
- end
289
- end
290
-
291
-
292
- alias write_message send_message
293
-
294
-
295
- # No-op — inproc has no IO buffer to flush.
296
- #
297
- # @return [void]
298
- #
299
- def flush = nil
300
-
301
-
302
- # Receives a multi-frame message.
303
- #
304
- # @return [Array<String>]
305
- # @raise [EOFError] if closed
306
- #
307
- def receive_message
308
- msg = @receive_queue.dequeue
309
- raise EOFError, "connection closed" if msg.nil?
310
- msg
311
- end
312
-
313
-
314
- # Sends a command via the internal command queue.
315
- # Only available for PUB/SUB-family pipes.
316
- #
317
- # @param command [Protocol::ZMTP::Codec::Command]
318
- # @return [void]
319
- #
320
- def send_command(command)
321
- raise IOError, "closed" if @closed
322
- @send_queue.enqueue([:command, command])
323
- end
324
-
325
-
326
- # Reads one command frame from the internal command queue.
327
- # Used by PUB/XPUB subscription listeners.
328
- #
329
- # @return [Protocol::ZMTP::Codec::Frame]
330
- #
331
- def read_frame
332
- loop do
333
- item = @receive_queue.dequeue
334
- raise EOFError, "connection closed" if item.nil?
335
- if item.is_a?(Array) && item.first == :command
336
- cmd = item[1]
337
- return Protocol::ZMTP::Codec::Frame.new(cmd.to_body, command: true)
338
- end
339
- end
340
- end
341
-
342
-
343
- # Closes this pipe end.
344
- #
345
- # @return [void]
346
- #
347
- def close
348
- return if @closed
349
- @closed = true
350
- @send_queue&.enqueue(nil) # close sentinel
351
- end
352
- end
353
190
  end
354
191
  end
355
192
  end
@@ -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.13.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.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger
@@ -65,49 +65,44 @@ 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/engine/connection_setup.rb
71
+ - lib/omq/engine/heartbeat.rb
72
+ - lib/omq/engine/reconnect.rb
73
+ - lib/omq/engine/recv_pump.rb
74
+ - lib/omq/monitor_event.rb
71
75
  - lib/omq/options.rb
72
76
  - lib/omq/pair.rb
73
- - lib/omq/peer.rb
74
77
  - lib/omq/pub_sub.rb
75
78
  - lib/omq/push_pull.rb
76
79
  - lib/omq/queue_interface.rb
77
- - lib/omq/radio_dish.rb
78
80
  - lib/omq/reactor.rb
79
81
  - lib/omq/readable.rb
80
82
  - lib/omq/req_rep.rb
81
83
  - lib/omq/router_dealer.rb
82
84
  - lib/omq/routing.rb
83
- - lib/omq/routing/channel.rb
84
- - lib/omq/routing/client.rb
85
+ - lib/omq/routing/conn_send_pump.rb
85
86
  - lib/omq/routing/dealer.rb
86
- - lib/omq/routing/dish.rb
87
+ - lib/omq/routing/fair_queue.rb
88
+ - lib/omq/routing/fair_recv.rb
87
89
  - lib/omq/routing/fan_out.rb
88
- - lib/omq/routing/gather.rb
89
90
  - lib/omq/routing/pair.rb
90
- - lib/omq/routing/peer.rb
91
91
  - lib/omq/routing/pub.rb
92
92
  - lib/omq/routing/pull.rb
93
93
  - lib/omq/routing/push.rb
94
- - lib/omq/routing/radio.rb
95
94
  - lib/omq/routing/rep.rb
96
95
  - lib/omq/routing/req.rb
97
96
  - lib/omq/routing/round_robin.rb
98
97
  - lib/omq/routing/router.rb
99
- - lib/omq/routing/scatter.rb
100
- - lib/omq/routing/server.rb
101
98
  - lib/omq/routing/sub.rb
102
99
  - lib/omq/routing/xpub.rb
103
100
  - lib/omq/routing/xsub.rb
104
- - lib/omq/scatter_gather.rb
105
- - lib/omq/single_frame.rb
106
101
  - lib/omq/socket.rb
107
102
  - lib/omq/transport/inproc.rb
103
+ - lib/omq/transport/inproc/direct_pipe.rb
108
104
  - lib/omq/transport/ipc.rb
109
105
  - lib/omq/transport/tcp.rb
110
- - lib/omq/transport/tls.rb
111
106
  - lib/omq/version.rb
112
107
  - lib/omq/writable.rb
113
108
  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
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OMQ
4
- class RADIO < Socket
5
- include Writable
6
-
7
- def initialize(endpoints = nil, linger: 0, conflate: false, backend: nil)
8
- _init_engine(:RADIO, linger: linger, conflate: conflate, backend: backend)
9
- _attach(endpoints, default: :bind)
10
- end
11
-
12
- # Publishes a message to a group.
13
- #
14
- # @param group [String] group name
15
- # @param body [String] message body
16
- # @return [self]
17
- #
18
- def publish(group, body)
19
- with_timeout(@options.write_timeout) do
20
- @engine.enqueue_send([group.b.freeze, body.b.freeze])
21
- end
22
- self
23
- end
24
-
25
- # Sends a message to a group.
26
- #
27
- # @param message [String] message body (requires group: kwarg)
28
- # @param group [String] group name
29
- # @return [self]
30
- #
31
- def send(message, group: nil)
32
- raise ArgumentError, "RADIO requires a group (use group: kwarg, publish, or << [group, body])" unless group
33
- publish(group, message)
34
- end
35
-
36
- # Sends a message to a group via [group, body] array.
37
- #
38
- # @param message [Array<String>] [group, body]
39
- # @return [self]
40
- #
41
- def <<(message)
42
- raise ArgumentError, "RADIO requires [group, body] array" unless message.is_a?(Array) && message.size == 2
43
- publish(message[0], message[1])
44
- end
45
- end
46
-
47
- class DISH < Socket
48
- include Readable
49
-
50
- def initialize(endpoints = nil, linger: 0, group: nil, backend: nil)
51
- _init_engine(:DISH, linger: linger, backend: backend)
52
- _attach(endpoints, default: :connect)
53
- join(group) if group
54
- end
55
-
56
- # Joins a group.
57
- #
58
- # @param group [String]
59
- # @return [void]
60
- #
61
- def join(group)
62
- @engine.routing.join(group)
63
- end
64
-
65
- # Leaves a group.
66
- #
67
- # @param group [String]
68
- # @return [void]
69
- #
70
- def leave(group)
71
- @engine.routing.leave(group)
72
- end
73
- end
74
- end