omq 0.22.0 → 0.23.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +139 -0
- data/README.md +17 -21
- data/lib/omq/channel.rb +35 -0
- data/lib/omq/client_server.rb +72 -0
- data/lib/omq/constants.rb +68 -0
- data/lib/omq/engine/connection_lifecycle.rb +11 -3
- data/lib/omq/engine/heartbeat.rb +3 -4
- data/lib/omq/engine/maintenance.rb +4 -5
- data/lib/omq/engine/reconnect.rb +12 -11
- data/lib/omq/engine/recv_pump.rb +3 -4
- data/lib/omq/engine/socket_lifecycle.rb +26 -9
- data/lib/omq/engine.rb +196 -85
- data/lib/omq/peer.rb +49 -0
- data/lib/omq/pub_sub.rb +2 -2
- data/lib/omq/radio_dish.rb +122 -0
- data/lib/omq/reactor.rb +14 -5
- data/lib/omq/routing/channel.rb +110 -0
- data/lib/omq/routing/client.rb +70 -0
- data/lib/omq/routing/conn_send_pump.rb +12 -10
- data/lib/omq/routing/dealer.rb +1 -13
- data/lib/omq/routing/dish.rb +94 -0
- data/lib/omq/routing/fan_out.rb +14 -13
- data/lib/omq/routing/gather.rb +60 -0
- data/lib/omq/routing/pair.rb +7 -24
- data/lib/omq/routing/peer.rb +95 -0
- data/lib/omq/routing/pub.rb +0 -11
- data/lib/omq/routing/pull.rb +1 -13
- data/lib/omq/routing/push.rb +1 -10
- data/lib/omq/routing/radio.rb +187 -0
- data/lib/omq/routing/rep.rb +10 -20
- data/lib/omq/routing/req.rb +5 -17
- data/lib/omq/routing/round_robin.rb +17 -18
- data/lib/omq/routing/router.rb +3 -17
- data/lib/omq/routing/scatter.rb +77 -0
- data/lib/omq/routing/server.rb +90 -0
- data/lib/omq/routing/sub.rb +1 -13
- data/lib/omq/routing/xpub.rb +0 -11
- data/lib/omq/routing/xsub.rb +6 -23
- data/lib/omq/routing.rb +5 -2
- data/lib/omq/scatter_gather.rb +56 -0
- data/lib/omq/socket.rb +8 -23
- data/lib/omq/transport/inproc/direct_pipe.rb +17 -15
- data/lib/omq/transport/inproc.rb +11 -3
- data/lib/omq/transport/ipc.rb +41 -13
- data/lib/omq/transport/tcp.rb +59 -23
- data/lib/omq/transport/udp.rb +281 -0
- data/lib/omq/version.rb +1 -1
- data/lib/omq.rb +9 -64
- metadata +16 -2
- data/lib/omq/monitor_event.rb +0 -16
data/lib/omq/transport/tcp.rb
CHANGED
|
@@ -9,14 +9,17 @@ module OMQ
|
|
|
9
9
|
# TCP transport using Ruby sockets with Async.
|
|
10
10
|
#
|
|
11
11
|
module TCP
|
|
12
|
+
Engine.transports["tcp"] = self
|
|
13
|
+
|
|
14
|
+
|
|
12
15
|
class << self
|
|
13
|
-
#
|
|
16
|
+
# Creates a bound TCP listener.
|
|
14
17
|
#
|
|
15
18
|
# @param endpoint [String] e.g. "tcp://127.0.0.1:5555" or "tcp://*:0"
|
|
16
19
|
# @param engine [Engine]
|
|
17
20
|
# @return [Listener]
|
|
18
21
|
#
|
|
19
|
-
def
|
|
22
|
+
def listener(endpoint, engine, **)
|
|
20
23
|
host, port = self.parse_endpoint(endpoint)
|
|
21
24
|
lookup_host = normalize_bind_host(host)
|
|
22
25
|
|
|
@@ -34,6 +37,17 @@ module OMQ
|
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
|
|
40
|
+
# Creates a TCP dialer for an endpoint.
|
|
41
|
+
#
|
|
42
|
+
# @param endpoint [String] e.g. "tcp://127.0.0.1:5555"
|
|
43
|
+
# @param engine [Engine]
|
|
44
|
+
# @return [Dialer]
|
|
45
|
+
#
|
|
46
|
+
def dialer(endpoint, engine, **)
|
|
47
|
+
Dialer.new(endpoint, engine)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
|
|
37
51
|
# Validates that the endpoint's host can be resolved.
|
|
38
52
|
#
|
|
39
53
|
# @param endpoint [String]
|
|
@@ -46,21 +60,6 @@ module OMQ
|
|
|
46
60
|
end
|
|
47
61
|
|
|
48
62
|
|
|
49
|
-
# Connects to a TCP endpoint.
|
|
50
|
-
#
|
|
51
|
-
# @param endpoint [String] e.g. "tcp://127.0.0.1:5555"
|
|
52
|
-
# @param engine [Engine]
|
|
53
|
-
# @return [void]
|
|
54
|
-
#
|
|
55
|
-
def connect(endpoint, engine)
|
|
56
|
-
host, port = self.parse_endpoint(endpoint)
|
|
57
|
-
host = normalize_connect_host(host)
|
|
58
|
-
sock = ::Socket.tcp(host, port, connect_timeout: connect_timeout(engine.options))
|
|
59
|
-
apply_buffer_sizes(sock, engine.options)
|
|
60
|
-
engine.handle_connected(IO::Stream::Buffered.wrap(sock), endpoint: endpoint)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
|
|
64
63
|
# Normalizes the bind host:
|
|
65
64
|
# "*" → nil (dual-stack wildcard via AI_PASSIVE)
|
|
66
65
|
# "" / nil / "localhost" → loopback_host (::1 on IPv6-capable hosts, else 127.0.0.1)
|
|
@@ -142,6 +141,42 @@ module OMQ
|
|
|
142
141
|
end
|
|
143
142
|
|
|
144
143
|
|
|
144
|
+
# A TCP dialer — stateful factory for outgoing connections.
|
|
145
|
+
#
|
|
146
|
+
# Created once per {Engine#connect}, stored in +@dialers[endpoint]+.
|
|
147
|
+
# Reconnect calls {#connect} directly — no transport lookup or opts
|
|
148
|
+
# replay needed.
|
|
149
|
+
#
|
|
150
|
+
class Dialer
|
|
151
|
+
# @return [String] the endpoint this dialer connects to
|
|
152
|
+
#
|
|
153
|
+
attr_reader :endpoint
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# @param endpoint [String] e.g. "tcp://127.0.0.1:5555"
|
|
157
|
+
# @param engine [Engine]
|
|
158
|
+
#
|
|
159
|
+
def initialize(endpoint, engine)
|
|
160
|
+
@endpoint = endpoint
|
|
161
|
+
@engine = engine
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
# Establishes a TCP connection to the endpoint.
|
|
166
|
+
#
|
|
167
|
+
# @return [void]
|
|
168
|
+
#
|
|
169
|
+
def connect
|
|
170
|
+
host, port = TCP.parse_endpoint(@endpoint)
|
|
171
|
+
host = TCP.normalize_connect_host(host)
|
|
172
|
+
sock = ::Socket.tcp(host, port, connect_timeout: TCP.connect_timeout(@engine.options))
|
|
173
|
+
TCP.apply_buffer_sizes(sock, @engine.options)
|
|
174
|
+
@engine.handle_connected(IO::Stream::Buffered.wrap(sock), endpoint: @endpoint)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
|
|
145
180
|
# A bound TCP listener.
|
|
146
181
|
#
|
|
147
182
|
class Listener
|
|
@@ -168,7 +203,7 @@ module OMQ
|
|
|
168
203
|
@servers = servers
|
|
169
204
|
@port = port
|
|
170
205
|
@engine = engine
|
|
171
|
-
@
|
|
206
|
+
@barrier = nil
|
|
172
207
|
end
|
|
173
208
|
|
|
174
209
|
|
|
@@ -179,10 +214,11 @@ module OMQ
|
|
|
179
214
|
# @yieldparam io [IO::Stream::Buffered]
|
|
180
215
|
#
|
|
181
216
|
def start_accept_loops(parent_task)
|
|
182
|
-
@
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
217
|
+
@barrier = Async::Barrier.new(parent: parent_task)
|
|
218
|
+
|
|
219
|
+
@servers.each do |server|
|
|
220
|
+
annotation = "tcp accept #{server.local_address.inspect_sockaddr}"
|
|
221
|
+
@barrier.async(transient: true, annotation:) do
|
|
186
222
|
loop do
|
|
187
223
|
client, _addr = server.accept
|
|
188
224
|
TCP.apply_buffer_sizes(client, @engine.options)
|
|
@@ -207,7 +243,7 @@ module OMQ
|
|
|
207
243
|
# @return [void]
|
|
208
244
|
#
|
|
209
245
|
def stop
|
|
210
|
-
@
|
|
246
|
+
@barrier&.stop
|
|
211
247
|
@servers.each { |s| s.close rescue nil }
|
|
212
248
|
end
|
|
213
249
|
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "socket"
|
|
4
|
+
require "uri"
|
|
5
|
+
require "set"
|
|
6
|
+
|
|
7
|
+
module OMQ
|
|
8
|
+
module Transport
|
|
9
|
+
# UDP transport for RADIO/DISH sockets.
|
|
10
|
+
#
|
|
11
|
+
# Connectionless, datagram-based. No ZMTP handshake.
|
|
12
|
+
# DISH binds and receives; RADIO connects and sends.
|
|
13
|
+
#
|
|
14
|
+
# Wire format per datagram:
|
|
15
|
+
# flags (1 byte = 0x01) | group_size (1 byte) | group (n bytes) | body
|
|
16
|
+
#
|
|
17
|
+
module UDP
|
|
18
|
+
Engine.transports["udp"] = self
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
MAX_DATAGRAM_SIZE = 65507
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
# Creates a bound UDP listener for a DISH socket.
|
|
25
|
+
#
|
|
26
|
+
# @param endpoint [String] e.g. "udp://*:5555" or "udp://127.0.0.1:5555"
|
|
27
|
+
# @param engine [Engine]
|
|
28
|
+
# @return [Listener]
|
|
29
|
+
#
|
|
30
|
+
def listener(endpoint, engine, **)
|
|
31
|
+
host, port = parse_endpoint(endpoint)
|
|
32
|
+
host = "0.0.0.0" if host == "*"
|
|
33
|
+
socket = UDPSocket.new
|
|
34
|
+
socket.bind(host, port)
|
|
35
|
+
Listener.new(endpoint, socket, engine)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Creates a UDP dialer for a RADIO socket.
|
|
40
|
+
#
|
|
41
|
+
# @param endpoint [String] e.g. "udp://127.0.0.1:5555"
|
|
42
|
+
# @param engine [Engine]
|
|
43
|
+
# @return [Dialer]
|
|
44
|
+
#
|
|
45
|
+
def dialer(endpoint, engine, **)
|
|
46
|
+
Dialer.new(endpoint, engine)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# @param endpoint [String]
|
|
51
|
+
# @return [Array(String, Integer)]
|
|
52
|
+
#
|
|
53
|
+
def parse_endpoint(endpoint)
|
|
54
|
+
uri = URI.parse(endpoint)
|
|
55
|
+
[uri.hostname, uri.port]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# Encodes a group + body into a UDP datagram.
|
|
60
|
+
#
|
|
61
|
+
# @param group [String]
|
|
62
|
+
# @param body [String]
|
|
63
|
+
# @return [String] binary datagram
|
|
64
|
+
#
|
|
65
|
+
def encode_datagram(group, body)
|
|
66
|
+
g = group.b
|
|
67
|
+
b = body.b
|
|
68
|
+
[0x01, g.bytesize].pack("CC") + g + b
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Decodes a UDP datagram into [group, body].
|
|
73
|
+
#
|
|
74
|
+
# @param data [String] raw datagram bytes
|
|
75
|
+
# @return [Array(String, String), nil] nil if malformed
|
|
76
|
+
#
|
|
77
|
+
def decode_datagram(data)
|
|
78
|
+
return nil if data.bytesize < 2
|
|
79
|
+
return nil unless data.getbyte(0) & 0x01 == 0x01
|
|
80
|
+
gs = data.getbyte(1)
|
|
81
|
+
return nil if data.bytesize < 2 + gs
|
|
82
|
+
group = data.byteslice(2, gs)
|
|
83
|
+
body = data.byteslice(2 + gs, data.bytesize - 2 - gs)
|
|
84
|
+
[group, body]
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# A UDP dialer — registers a single RadioConnection with the engine.
|
|
90
|
+
#
|
|
91
|
+
# UDP is connectionless; #connect is a one-shot registration.
|
|
92
|
+
# The reconnect loop will break out after the first successful call.
|
|
93
|
+
#
|
|
94
|
+
class Dialer
|
|
95
|
+
# @return [String] the endpoint this dialer sends to
|
|
96
|
+
#
|
|
97
|
+
attr_reader :endpoint
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# @param endpoint [String]
|
|
101
|
+
# @param engine [Engine]
|
|
102
|
+
#
|
|
103
|
+
def initialize(endpoint, engine)
|
|
104
|
+
@endpoint = endpoint
|
|
105
|
+
@engine = engine
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# Registers a RadioConnection with the engine.
|
|
110
|
+
#
|
|
111
|
+
# @return [void]
|
|
112
|
+
#
|
|
113
|
+
def connect
|
|
114
|
+
host, port = UDP.parse_endpoint(@endpoint)
|
|
115
|
+
socket = UDPSocket.new
|
|
116
|
+
conn = RadioConnection.new(socket, host, port)
|
|
117
|
+
@engine.connection_ready(conn, endpoint: @endpoint)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# Outgoing UDP connection for RADIO sockets.
|
|
124
|
+
#
|
|
125
|
+
# Intentionally does not implement #read_frame — this signals
|
|
126
|
+
# Routing::Radio to skip the group listener and use ANY_GROUPS.
|
|
127
|
+
#
|
|
128
|
+
class RadioConnection
|
|
129
|
+
# @param socket [UDPSocket]
|
|
130
|
+
# @param host [String]
|
|
131
|
+
# @param port [Integer]
|
|
132
|
+
#
|
|
133
|
+
def initialize(socket, host, port)
|
|
134
|
+
@socket = socket
|
|
135
|
+
@host = host
|
|
136
|
+
@port = port
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# Encodes and sends a datagram.
|
|
141
|
+
#
|
|
142
|
+
# @param parts [Array<String>] [group, body]
|
|
143
|
+
#
|
|
144
|
+
def write_message(parts)
|
|
145
|
+
group, body = parts
|
|
146
|
+
datagram = UDP.encode_datagram(group.to_s, body.to_s)
|
|
147
|
+
@socket.send(datagram, 0, @host, @port)
|
|
148
|
+
rescue Errno::ECONNREFUSED, Errno::ENETUNREACH
|
|
149
|
+
# UDP fire-and-forget — drop silently
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
alias send_message write_message
|
|
153
|
+
|
|
154
|
+
# No-op; UDP datagrams are sent immediately.
|
|
155
|
+
def flush
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# Whether this connection uses CURVE encryption.
|
|
160
|
+
#
|
|
161
|
+
# @return [Boolean] always false
|
|
162
|
+
def curve?
|
|
163
|
+
false
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# Closes the underlying UDP socket.
|
|
168
|
+
def close
|
|
169
|
+
@socket.close rescue nil
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# Incoming UDP connection for DISH sockets.
|
|
175
|
+
#
|
|
176
|
+
# Tracks joined groups locally. JOIN/LEAVE commands from the
|
|
177
|
+
# DISH routing strategy are intercepted via #send_command and
|
|
178
|
+
# never transmitted on the wire.
|
|
179
|
+
#
|
|
180
|
+
class DishConnection
|
|
181
|
+
# @param socket [UDPSocket] bound socket
|
|
182
|
+
#
|
|
183
|
+
def initialize(socket)
|
|
184
|
+
@socket = socket
|
|
185
|
+
@groups = Set.new
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# Receives one matching datagram, blocking until available.
|
|
190
|
+
#
|
|
191
|
+
# Async-safe: rescues IO::WaitReadable and yields to the
|
|
192
|
+
# fiber scheduler via #wait_readable.
|
|
193
|
+
#
|
|
194
|
+
# @return [Array<String>] [group, body], both binary-frozen
|
|
195
|
+
#
|
|
196
|
+
def receive_message
|
|
197
|
+
loop do
|
|
198
|
+
data, = @socket.recvfrom_nonblock(MAX_DATAGRAM_SIZE)
|
|
199
|
+
parts = UDP.decode_datagram(data)
|
|
200
|
+
next unless parts
|
|
201
|
+
group, body = parts
|
|
202
|
+
next unless @groups.include?(group.b)
|
|
203
|
+
return [group.b.freeze, body.b.freeze]
|
|
204
|
+
rescue IO::WaitReadable
|
|
205
|
+
@socket.wait_readable
|
|
206
|
+
retry
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# Handles JOIN/LEAVE commands locally; nothing is sent on the wire.
|
|
212
|
+
#
|
|
213
|
+
# @param cmd [Protocol::ZMTP::Codec::Command]
|
|
214
|
+
#
|
|
215
|
+
def send_command(cmd)
|
|
216
|
+
case cmd.name
|
|
217
|
+
when "JOIN"
|
|
218
|
+
@groups << cmd.data.b.freeze
|
|
219
|
+
when "LEAVE"
|
|
220
|
+
@groups.delete(cmd.data.b)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# Whether this connection uses CURVE encryption.
|
|
226
|
+
#
|
|
227
|
+
# @return [Boolean] always false
|
|
228
|
+
def curve?
|
|
229
|
+
false
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# Closes the underlying UDP socket.
|
|
234
|
+
def close
|
|
235
|
+
@socket.close rescue nil
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
# Bound UDP listener for DISH sockets.
|
|
241
|
+
#
|
|
242
|
+
# Unlike TCP/IPC listeners, there is no accept loop — a single
|
|
243
|
+
# DishConnection is registered directly with the engine, bypassing
|
|
244
|
+
# the ZMTP handshake path.
|
|
245
|
+
#
|
|
246
|
+
class Listener
|
|
247
|
+
# @return [String] bound endpoint
|
|
248
|
+
#
|
|
249
|
+
attr_reader :endpoint
|
|
250
|
+
|
|
251
|
+
# @param endpoint [String]
|
|
252
|
+
# @param socket [UDPSocket]
|
|
253
|
+
# @param engine [Engine]
|
|
254
|
+
#
|
|
255
|
+
def initialize(endpoint, socket, engine)
|
|
256
|
+
@endpoint = endpoint
|
|
257
|
+
@socket = socket
|
|
258
|
+
@engine = engine
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# Registers a DishConnection with the engine.
|
|
263
|
+
# The on_accepted block is intentionally ignored — no ZMTP handshake.
|
|
264
|
+
#
|
|
265
|
+
# @param parent_task [Async::Task] (unused)
|
|
266
|
+
#
|
|
267
|
+
def start_accept_loops(parent_task, &_on_accepted)
|
|
268
|
+
conn = DishConnection.new(@socket)
|
|
269
|
+
@engine.connection_ready(conn, endpoint: @endpoint)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
# Stops the listener.
|
|
274
|
+
#
|
|
275
|
+
def stop
|
|
276
|
+
@socket.close rescue nil
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
data/lib/omq/version.rb
CHANGED
data/lib/omq.rb
CHANGED
|
@@ -1,74 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# OMQ — pure Ruby ZeroMQ (ZMTP 3.1).
|
|
4
|
-
#
|
|
5
|
-
# Socket types live directly under OMQ:: for a clean API:
|
|
6
|
-
# OMQ::PUSH, OMQ::PULL, OMQ::PUB, OMQ::SUB, etc.
|
|
7
|
-
#
|
|
8
|
-
|
|
9
3
|
require "protocol/zmtp"
|
|
10
4
|
require "io/stream"
|
|
11
5
|
|
|
12
|
-
require_relative "omq/version"
|
|
13
|
-
require_relative "omq/monitor_event"
|
|
14
|
-
|
|
15
|
-
module OMQ
|
|
16
|
-
# When OMQ_DEBUG is set, silent rescue clauses print the exception
|
|
17
|
-
# to stderr so transport/engine bugs surface immediately.
|
|
18
|
-
DEBUG = !!ENV["OMQ_DEBUG"]
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
# Raised when an internal pump task crashes unexpectedly.
|
|
22
|
-
# The socket is no longer usable; the original error is available via #cause.
|
|
23
|
-
#
|
|
24
|
-
class SocketDeadError < RuntimeError
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# Errors raised when a peer disconnects or resets the connection.
|
|
29
|
-
# Not frozen at load time — transport plugins append to this before
|
|
30
|
-
# the first bind/connect, which freezes both arrays.
|
|
31
|
-
CONNECTION_LOST = [
|
|
32
|
-
EOFError,
|
|
33
|
-
IOError,
|
|
34
|
-
Errno::EPIPE,
|
|
35
|
-
Errno::ECONNRESET,
|
|
36
|
-
Errno::ECONNABORTED,
|
|
37
|
-
Errno::ENOTCONN,
|
|
38
|
-
IO::Stream::ConnectionResetError,
|
|
39
|
-
]
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# Errors raised when a peer cannot be reached.
|
|
43
|
-
CONNECTION_FAILED = [
|
|
44
|
-
Errno::ECONNREFUSED,
|
|
45
|
-
Errno::ENOENT,
|
|
46
|
-
Errno::ETIMEDOUT,
|
|
47
|
-
Errno::EHOSTUNREACH,
|
|
48
|
-
Errno::ENETUNREACH,
|
|
49
|
-
Errno::EPROTOTYPE, # IPC: existing socket file is SOCK_DGRAM, not SOCK_STREAM
|
|
50
|
-
Socket::ResolutionError,
|
|
51
|
-
]
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
# Freezes module-level state so OMQ sockets can be used inside Ractors.
|
|
55
|
-
# Call this once before spawning any Ractors that create OMQ sockets.
|
|
56
|
-
#
|
|
57
|
-
def self.freeze_for_ractors!
|
|
58
|
-
CONNECTION_LOST.freeze
|
|
59
|
-
CONNECTION_FAILED.freeze
|
|
60
|
-
Engine.transports.freeze
|
|
61
|
-
Routing.registry.freeze
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
# Transport
|
|
67
|
-
require_relative "omq/transport/inproc"
|
|
68
|
-
require_relative "omq/transport/tcp"
|
|
69
|
-
require_relative "omq/transport/ipc"
|
|
70
6
|
|
|
71
7
|
# Core
|
|
8
|
+
require_relative "omq/version"
|
|
9
|
+
require_relative "omq/constants"
|
|
72
10
|
require_relative "omq/reactor"
|
|
73
11
|
require_relative "omq/options"
|
|
74
12
|
require_relative "omq/routing"
|
|
@@ -86,6 +24,13 @@ require_relative "omq/routing/xsub"
|
|
|
86
24
|
require_relative "omq/routing/push"
|
|
87
25
|
require_relative "omq/routing/pull"
|
|
88
26
|
require_relative "omq/engine"
|
|
27
|
+
|
|
28
|
+
# Transport
|
|
29
|
+
require_relative "omq/transport/inproc"
|
|
30
|
+
require_relative "omq/transport/tcp"
|
|
31
|
+
require_relative "omq/transport/ipc"
|
|
32
|
+
|
|
33
|
+
# Mixins
|
|
89
34
|
require_relative "omq/queue_interface"
|
|
90
35
|
require_relative "omq/readable"
|
|
91
36
|
require_relative "omq/writable"
|
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.
|
|
4
|
+
version: 0.23.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrik Wenger
|
|
@@ -65,6 +65,9 @@ files:
|
|
|
65
65
|
- LICENSE
|
|
66
66
|
- README.md
|
|
67
67
|
- lib/omq.rb
|
|
68
|
+
- lib/omq/channel.rb
|
|
69
|
+
- lib/omq/client_server.rb
|
|
70
|
+
- lib/omq/constants.rb
|
|
68
71
|
- lib/omq/drop_queue.rb
|
|
69
72
|
- lib/omq/engine.rb
|
|
70
73
|
- lib/omq/engine/connection_lifecycle.rb
|
|
@@ -73,37 +76,48 @@ files:
|
|
|
73
76
|
- lib/omq/engine/reconnect.rb
|
|
74
77
|
- lib/omq/engine/recv_pump.rb
|
|
75
78
|
- lib/omq/engine/socket_lifecycle.rb
|
|
76
|
-
- lib/omq/monitor_event.rb
|
|
77
79
|
- lib/omq/options.rb
|
|
78
80
|
- lib/omq/pair.rb
|
|
81
|
+
- lib/omq/peer.rb
|
|
79
82
|
- lib/omq/pub_sub.rb
|
|
80
83
|
- lib/omq/push_pull.rb
|
|
81
84
|
- lib/omq/queue_interface.rb
|
|
85
|
+
- lib/omq/radio_dish.rb
|
|
82
86
|
- lib/omq/reactor.rb
|
|
83
87
|
- lib/omq/readable.rb
|
|
84
88
|
- lib/omq/req_rep.rb
|
|
85
89
|
- lib/omq/router_dealer.rb
|
|
86
90
|
- lib/omq/routing.rb
|
|
91
|
+
- lib/omq/routing/channel.rb
|
|
92
|
+
- lib/omq/routing/client.rb
|
|
87
93
|
- lib/omq/routing/conn_send_pump.rb
|
|
88
94
|
- lib/omq/routing/dealer.rb
|
|
95
|
+
- lib/omq/routing/dish.rb
|
|
89
96
|
- lib/omq/routing/fan_out.rb
|
|
97
|
+
- lib/omq/routing/gather.rb
|
|
90
98
|
- lib/omq/routing/pair.rb
|
|
99
|
+
- lib/omq/routing/peer.rb
|
|
91
100
|
- lib/omq/routing/pub.rb
|
|
92
101
|
- lib/omq/routing/pull.rb
|
|
93
102
|
- lib/omq/routing/push.rb
|
|
103
|
+
- lib/omq/routing/radio.rb
|
|
94
104
|
- lib/omq/routing/rep.rb
|
|
95
105
|
- lib/omq/routing/req.rb
|
|
96
106
|
- lib/omq/routing/round_robin.rb
|
|
97
107
|
- lib/omq/routing/router.rb
|
|
108
|
+
- lib/omq/routing/scatter.rb
|
|
109
|
+
- lib/omq/routing/server.rb
|
|
98
110
|
- lib/omq/routing/sub.rb
|
|
99
111
|
- lib/omq/routing/xpub.rb
|
|
100
112
|
- lib/omq/routing/xsub.rb
|
|
113
|
+
- lib/omq/scatter_gather.rb
|
|
101
114
|
- lib/omq/single_frame.rb
|
|
102
115
|
- lib/omq/socket.rb
|
|
103
116
|
- lib/omq/transport/inproc.rb
|
|
104
117
|
- lib/omq/transport/inproc/direct_pipe.rb
|
|
105
118
|
- lib/omq/transport/ipc.rb
|
|
106
119
|
- lib/omq/transport/tcp.rb
|
|
120
|
+
- lib/omq/transport/udp.rb
|
|
107
121
|
- lib/omq/version.rb
|
|
108
122
|
- lib/omq/writable.rb
|
|
109
123
|
homepage: https://github.com/zeromq/omq
|
data/lib/omq/monitor_event.rb
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
# Lifecycle event emitted by {Socket#monitor}.
|
|
5
|
-
#
|
|
6
|
-
# @!attribute [r] type
|
|
7
|
-
# @return [Symbol] event type (:listening, :connected, :disconnected, etc.)
|
|
8
|
-
# @!attribute [r] endpoint
|
|
9
|
-
# @return [String, nil] the endpoint involved
|
|
10
|
-
# @!attribute [r] detail
|
|
11
|
-
# @return [Hash, nil] extra context (e.g. { error: }, { interval: }, etc.)
|
|
12
|
-
#
|
|
13
|
-
MonitorEvent = Data.define(:type, :endpoint, :detail) do
|
|
14
|
-
def initialize(type:, endpoint: nil, detail: nil) = super
|
|
15
|
-
end
|
|
16
|
-
end
|