omq 0.8.0 → 0.10.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 +87 -0
- data/README.md +9 -49
- data/lib/omq/channel.rb +3 -3
- data/lib/omq/client_server.rb +6 -6
- data/lib/omq/engine.rb +641 -0
- data/lib/omq/options.rb +46 -0
- data/lib/omq/pair.rb +2 -2
- data/lib/omq/peer.rb +3 -3
- data/lib/omq/pub_sub.rb +6 -6
- data/lib/omq/push_pull.rb +2 -2
- data/lib/omq/radio_dish.rb +2 -2
- data/lib/omq/reactor.rb +128 -0
- data/lib/omq/readable.rb +42 -0
- data/lib/omq/req_rep.rb +4 -4
- data/lib/omq/router_dealer.rb +4 -4
- data/lib/omq/routing/channel.rb +83 -0
- data/lib/omq/routing/client.rb +56 -0
- data/lib/omq/routing/dealer.rb +57 -0
- data/lib/omq/routing/dish.rb +78 -0
- data/lib/omq/routing/fan_out.rb +131 -0
- data/lib/omq/routing/gather.rb +46 -0
- data/lib/omq/routing/pair.rb +86 -0
- data/lib/omq/routing/peer.rb +101 -0
- data/lib/omq/routing/pub.rb +60 -0
- data/lib/omq/routing/pull.rb +46 -0
- data/lib/omq/routing/push.rb +81 -0
- data/lib/omq/routing/radio.rb +140 -0
- data/lib/omq/routing/rep.rb +101 -0
- data/lib/omq/routing/req.rb +65 -0
- data/lib/omq/routing/round_robin.rb +168 -0
- data/lib/omq/routing/router.rb +110 -0
- data/lib/omq/routing/scatter.rb +82 -0
- data/lib/omq/routing/server.rb +101 -0
- data/lib/omq/routing/sub.rb +78 -0
- data/lib/omq/routing/xpub.rb +72 -0
- data/lib/omq/routing/xsub.rb +83 -0
- data/lib/omq/routing.rb +66 -0
- data/lib/omq/scatter_gather.rb +4 -4
- data/lib/omq/single_frame.rb +18 -0
- data/lib/omq/socket.rb +24 -9
- data/lib/omq/transport/inproc.rb +355 -0
- data/lib/omq/transport/ipc.rb +117 -0
- data/lib/omq/transport/tcp.rb +111 -0
- data/lib/omq/version.rb +1 -1
- data/lib/omq/writable.rb +65 -0
- data/lib/omq.rb +60 -4
- metadata +38 -58
- data/exe/omq +0 -6
- data/lib/omq/cli/base_runner.rb +0 -459
- data/lib/omq/cli/channel.rb +0 -8
- data/lib/omq/cli/client_server.rb +0 -111
- data/lib/omq/cli/config.rb +0 -54
- data/lib/omq/cli/formatter.rb +0 -75
- data/lib/omq/cli/pair.rb +0 -31
- data/lib/omq/cli/peer.rb +0 -8
- data/lib/omq/cli/pipe.rb +0 -265
- data/lib/omq/cli/pub_sub.rb +0 -14
- data/lib/omq/cli/push_pull.rb +0 -14
- data/lib/omq/cli/radio_dish.rb +0 -27
- data/lib/omq/cli/req_rep.rb +0 -83
- data/lib/omq/cli/router_dealer.rb +0 -76
- data/lib/omq/cli/scatter_gather.rb +0 -14
- data/lib/omq/cli.rb +0 -540
- data/lib/omq/zmtp/engine.rb +0 -551
- data/lib/omq/zmtp/options.rb +0 -48
- data/lib/omq/zmtp/reactor.rb +0 -131
- data/lib/omq/zmtp/readable.rb +0 -29
- data/lib/omq/zmtp/routing/channel.rb +0 -81
- data/lib/omq/zmtp/routing/client.rb +0 -56
- data/lib/omq/zmtp/routing/dealer.rb +0 -57
- data/lib/omq/zmtp/routing/dish.rb +0 -80
- data/lib/omq/zmtp/routing/fan_out.rb +0 -131
- data/lib/omq/zmtp/routing/gather.rb +0 -48
- data/lib/omq/zmtp/routing/pair.rb +0 -84
- data/lib/omq/zmtp/routing/peer.rb +0 -100
- data/lib/omq/zmtp/routing/pub.rb +0 -62
- data/lib/omq/zmtp/routing/pull.rb +0 -48
- data/lib/omq/zmtp/routing/push.rb +0 -80
- data/lib/omq/zmtp/routing/radio.rb +0 -139
- data/lib/omq/zmtp/routing/rep.rb +0 -101
- data/lib/omq/zmtp/routing/req.rb +0 -65
- data/lib/omq/zmtp/routing/round_robin.rb +0 -143
- data/lib/omq/zmtp/routing/router.rb +0 -109
- data/lib/omq/zmtp/routing/scatter.rb +0 -81
- data/lib/omq/zmtp/routing/server.rb +0 -100
- data/lib/omq/zmtp/routing/sub.rb +0 -80
- data/lib/omq/zmtp/routing/xpub.rb +0 -74
- data/lib/omq/zmtp/routing/xsub.rb +0 -86
- data/lib/omq/zmtp/routing.rb +0 -65
- data/lib/omq/zmtp/single_frame.rb +0 -20
- data/lib/omq/zmtp/transport/inproc.rb +0 -359
- data/lib/omq/zmtp/transport/ipc.rb +0 -118
- data/lib/omq/zmtp/transport/tcp.rb +0 -117
- data/lib/omq/zmtp/writable.rb +0 -61
- data/lib/omq/zmtp.rb +0 -81
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "securerandom"
|
|
4
|
-
|
|
5
|
-
module OMQ
|
|
6
|
-
module ZMTP
|
|
7
|
-
module Routing
|
|
8
|
-
# PEER socket routing: bidirectional multi-peer with auto-generated
|
|
9
|
-
# 4-byte routing IDs.
|
|
10
|
-
#
|
|
11
|
-
# Prepends routing ID on receive. Strips routing ID on send and
|
|
12
|
-
# routes to the identified connection.
|
|
13
|
-
#
|
|
14
|
-
class Peer
|
|
15
|
-
# @param engine [Engine]
|
|
16
|
-
#
|
|
17
|
-
def initialize(engine)
|
|
18
|
-
@engine = engine
|
|
19
|
-
@recv_queue = Async::LimitedQueue.new(engine.options.recv_hwm)
|
|
20
|
-
@send_queue = Async::LimitedQueue.new(engine.options.send_hwm)
|
|
21
|
-
@connections_by_routing_id = {}
|
|
22
|
-
@tasks = []
|
|
23
|
-
@send_pump_started = false
|
|
24
|
-
@send_pump_idle = true
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# @return [Async::LimitedQueue]
|
|
28
|
-
#
|
|
29
|
-
attr_reader :recv_queue, :send_queue
|
|
30
|
-
|
|
31
|
-
# @param connection [Connection]
|
|
32
|
-
#
|
|
33
|
-
def connection_added(connection)
|
|
34
|
-
routing_id = SecureRandom.bytes(4)
|
|
35
|
-
@connections_by_routing_id[routing_id] = connection
|
|
36
|
-
|
|
37
|
-
task = @engine.start_recv_pump(connection, @recv_queue) do |msg|
|
|
38
|
-
[routing_id, *msg]
|
|
39
|
-
end
|
|
40
|
-
@tasks << task if task
|
|
41
|
-
|
|
42
|
-
start_send_pump unless @send_pump_started
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# @param connection [Connection]
|
|
46
|
-
#
|
|
47
|
-
def connection_removed(connection)
|
|
48
|
-
@connections_by_routing_id.reject! { |_, c| c == connection }
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# @param parts [Array<String>]
|
|
52
|
-
#
|
|
53
|
-
def enqueue(parts)
|
|
54
|
-
@send_queue.enqueue(parts)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def stop
|
|
58
|
-
@tasks.each(&:stop)
|
|
59
|
-
@tasks.clear
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
private
|
|
63
|
-
|
|
64
|
-
def send_pump_idle? = @send_pump_idle
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def start_send_pump
|
|
68
|
-
@send_pump_started = true
|
|
69
|
-
@tasks << @engine.spawn_pump_task(annotation: "send pump") do
|
|
70
|
-
loop do
|
|
71
|
-
@send_pump_idle = true
|
|
72
|
-
batch = [@send_queue.dequeue]
|
|
73
|
-
@send_pump_idle = false
|
|
74
|
-
Routing.drain_send_queue(@send_queue, batch)
|
|
75
|
-
|
|
76
|
-
written = Set.new
|
|
77
|
-
batch.each do |parts|
|
|
78
|
-
routing_id = parts.first
|
|
79
|
-
conn = @connections_by_routing_id[routing_id]
|
|
80
|
-
next unless conn # silently drop if peer gone
|
|
81
|
-
begin
|
|
82
|
-
conn.write_message(parts[1..])
|
|
83
|
-
written << conn
|
|
84
|
-
rescue *ZMTP::CONNECTION_LOST
|
|
85
|
-
# will be cleaned up
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
written.each do |conn|
|
|
90
|
-
conn.flush
|
|
91
|
-
rescue *ZMTP::CONNECTION_LOST
|
|
92
|
-
# will be cleaned up
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
data/lib/omq/zmtp/routing/pub.rb
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
module ZMTP
|
|
5
|
-
module Routing
|
|
6
|
-
# PUB socket routing: fan-out to all subscribers.
|
|
7
|
-
#
|
|
8
|
-
# Listens for SUBSCRIBE/CANCEL commands from peers.
|
|
9
|
-
# Drops messages if a subscriber's connection write fails.
|
|
10
|
-
#
|
|
11
|
-
class Pub
|
|
12
|
-
include FanOut
|
|
13
|
-
|
|
14
|
-
# @param engine [Engine]
|
|
15
|
-
#
|
|
16
|
-
def initialize(engine)
|
|
17
|
-
@engine = engine
|
|
18
|
-
@tasks = []
|
|
19
|
-
init_fan_out(engine)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# @return [Async::LimitedQueue]
|
|
23
|
-
#
|
|
24
|
-
attr_reader :send_queue
|
|
25
|
-
|
|
26
|
-
# PUB is write-only.
|
|
27
|
-
#
|
|
28
|
-
def recv_queue
|
|
29
|
-
raise "PUB sockets cannot receive"
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# @param connection [Connection]
|
|
33
|
-
#
|
|
34
|
-
def connection_added(connection)
|
|
35
|
-
@connections << connection
|
|
36
|
-
@subscriptions[connection] = Set.new
|
|
37
|
-
start_subscription_listener(connection)
|
|
38
|
-
start_send_pump unless @send_pump_started
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# @param connection [Connection]
|
|
42
|
-
#
|
|
43
|
-
def connection_removed(connection)
|
|
44
|
-
@connections.delete(connection)
|
|
45
|
-
@subscriptions.delete(connection)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# @param parts [Array<String>]
|
|
49
|
-
#
|
|
50
|
-
def enqueue(parts)
|
|
51
|
-
@send_queue.enqueue(parts)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
#
|
|
55
|
-
def stop
|
|
56
|
-
@tasks.each(&:stop)
|
|
57
|
-
@tasks.clear
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
module ZMTP
|
|
5
|
-
module Routing
|
|
6
|
-
# PULL socket routing: fair-queue receive from PUSH peers.
|
|
7
|
-
#
|
|
8
|
-
class Pull
|
|
9
|
-
# @param engine [Engine]
|
|
10
|
-
#
|
|
11
|
-
def initialize(engine)
|
|
12
|
-
@engine = engine
|
|
13
|
-
@recv_queue = Async::LimitedQueue.new(engine.options.recv_hwm)
|
|
14
|
-
@tasks = []
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# @return [Async::LimitedQueue]
|
|
18
|
-
#
|
|
19
|
-
attr_reader :recv_queue
|
|
20
|
-
|
|
21
|
-
# @param connection [Connection]
|
|
22
|
-
#
|
|
23
|
-
def connection_added(connection)
|
|
24
|
-
task = @engine.start_recv_pump(connection, @recv_queue)
|
|
25
|
-
@tasks << task if task
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# @param connection [Connection]
|
|
29
|
-
#
|
|
30
|
-
def connection_removed(connection)
|
|
31
|
-
# recv pump stops on EOFError
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# PULL is read-only.
|
|
35
|
-
#
|
|
36
|
-
def enqueue(_parts)
|
|
37
|
-
raise "PULL sockets cannot send"
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
#
|
|
41
|
-
def stop
|
|
42
|
-
@tasks.each(&:stop)
|
|
43
|
-
@tasks.clear
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
module ZMTP
|
|
5
|
-
module Routing
|
|
6
|
-
# PUSH socket routing: round-robin send to PULL peers.
|
|
7
|
-
#
|
|
8
|
-
class Push
|
|
9
|
-
include RoundRobin
|
|
10
|
-
|
|
11
|
-
# @param engine [Engine]
|
|
12
|
-
#
|
|
13
|
-
def initialize(engine)
|
|
14
|
-
@engine = engine
|
|
15
|
-
@tasks = []
|
|
16
|
-
init_round_robin(engine)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# @return [Async::LimitedQueue]
|
|
21
|
-
#
|
|
22
|
-
attr_reader :send_queue
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
# PUSH is write-only.
|
|
26
|
-
#
|
|
27
|
-
def recv_queue
|
|
28
|
-
raise "PUSH sockets cannot receive"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# @param connection [Connection]
|
|
33
|
-
#
|
|
34
|
-
def connection_added(connection)
|
|
35
|
-
@connections << connection
|
|
36
|
-
signal_connection_available
|
|
37
|
-
start_send_pump unless @send_pump_started
|
|
38
|
-
start_reaper(connection)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# @param connection [Connection]
|
|
43
|
-
#
|
|
44
|
-
def connection_removed(connection)
|
|
45
|
-
@connections.delete(connection)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
# @param parts [Array<String>]
|
|
50
|
-
#
|
|
51
|
-
def enqueue(parts)
|
|
52
|
-
@send_queue.enqueue(parts)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# Stops all background tasks (send pump, reapers).
|
|
57
|
-
#
|
|
58
|
-
def stop
|
|
59
|
-
@tasks.each(&:stop)
|
|
60
|
-
@tasks.clear
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
# Detects peer disconnection on write-only sockets. Without
|
|
67
|
-
# this, a dead peer is only noticed on the next send — which
|
|
68
|
-
# may succeed if the kernel send buffer absorbs the data.
|
|
69
|
-
#
|
|
70
|
-
def start_reaper(conn)
|
|
71
|
-
@tasks << Reactor.spawn_pump(annotation: "reaper") do
|
|
72
|
-
conn.receive_message # blocks until peer disconnects
|
|
73
|
-
rescue *ZMTP::CONNECTION_LOST
|
|
74
|
-
@engine.connection_lost(conn)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
module ZMTP
|
|
5
|
-
module Routing
|
|
6
|
-
# RADIO socket routing: group-based fan-out to DISH peers.
|
|
7
|
-
#
|
|
8
|
-
# Like PUB/FanOut but with exact group matching and JOIN/LEAVE
|
|
9
|
-
# commands instead of SUBSCRIBE/CANCEL.
|
|
10
|
-
#
|
|
11
|
-
# Messages are sent as two frames on the wire:
|
|
12
|
-
# group (MORE=1) + body (MORE=0)
|
|
13
|
-
#
|
|
14
|
-
class Radio
|
|
15
|
-
|
|
16
|
-
# @param engine [Engine]
|
|
17
|
-
#
|
|
18
|
-
def initialize(engine)
|
|
19
|
-
@engine = engine
|
|
20
|
-
@connections = []
|
|
21
|
-
@groups = {} # connection => Set of joined groups
|
|
22
|
-
@send_queue = Async::LimitedQueue.new(engine.options.send_hwm)
|
|
23
|
-
@send_pump_started = false
|
|
24
|
-
@conflate = engine.options.conflate
|
|
25
|
-
@tasks = []
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# @return [Async::LimitedQueue]
|
|
29
|
-
#
|
|
30
|
-
attr_reader :send_queue
|
|
31
|
-
|
|
32
|
-
# RADIO is write-only.
|
|
33
|
-
#
|
|
34
|
-
def recv_queue
|
|
35
|
-
raise "RADIO sockets cannot receive"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# @param connection [Connection]
|
|
39
|
-
#
|
|
40
|
-
def connection_added(connection)
|
|
41
|
-
@connections << connection
|
|
42
|
-
@groups[connection] = Set.new
|
|
43
|
-
start_group_listener(connection)
|
|
44
|
-
start_send_pump unless @send_pump_started
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# @param connection [Connection]
|
|
48
|
-
#
|
|
49
|
-
def connection_removed(connection)
|
|
50
|
-
@connections.delete(connection)
|
|
51
|
-
@groups.delete(connection)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Enqueues a message for sending.
|
|
55
|
-
#
|
|
56
|
-
# @param parts [Array<String>] [group, body]
|
|
57
|
-
#
|
|
58
|
-
def enqueue(parts)
|
|
59
|
-
@send_queue.enqueue(parts)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def stop
|
|
63
|
-
@tasks.each(&:stop)
|
|
64
|
-
@tasks.clear
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
private
|
|
68
|
-
|
|
69
|
-
def start_send_pump
|
|
70
|
-
@send_pump_started = true
|
|
71
|
-
@tasks << @engine.spawn_pump_task(annotation: "send pump") do
|
|
72
|
-
loop do
|
|
73
|
-
@send_pump_idle = true
|
|
74
|
-
batch = [@send_queue.dequeue]
|
|
75
|
-
@send_pump_idle = false
|
|
76
|
-
Routing.drain_send_queue(@send_queue, batch)
|
|
77
|
-
|
|
78
|
-
written = Set.new
|
|
79
|
-
|
|
80
|
-
if @conflate
|
|
81
|
-
# Keep only the last matching message per connection.
|
|
82
|
-
latest = {} # conn => [group, body]
|
|
83
|
-
batch.each do |parts|
|
|
84
|
-
group = parts[0]
|
|
85
|
-
body = parts[1] || "".b
|
|
86
|
-
@connections.each do |conn|
|
|
87
|
-
next unless @groups[conn]&.include?(group)
|
|
88
|
-
latest[conn] = [group, body]
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
latest.each do |conn, msg|
|
|
92
|
-
begin
|
|
93
|
-
conn.write_message(msg)
|
|
94
|
-
written << conn
|
|
95
|
-
rescue *ZMTP::CONNECTION_LOST
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
else
|
|
99
|
-
batch.each do |parts|
|
|
100
|
-
group = parts[0]
|
|
101
|
-
body = parts[1] || "".b
|
|
102
|
-
@connections.each do |conn|
|
|
103
|
-
next unless @groups[conn]&.include?(group)
|
|
104
|
-
begin
|
|
105
|
-
conn.write_message([group, body])
|
|
106
|
-
written << conn
|
|
107
|
-
rescue *ZMTP::CONNECTION_LOST
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
written.each do |conn|
|
|
114
|
-
conn.flush
|
|
115
|
-
rescue *ZMTP::CONNECTION_LOST
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def start_group_listener(conn)
|
|
122
|
-
@tasks << Reactor.spawn_pump(annotation: "recv pump") do
|
|
123
|
-
loop do
|
|
124
|
-
frame = conn.read_frame
|
|
125
|
-
next unless frame.command?
|
|
126
|
-
cmd = Codec::Command.from_body(frame.body)
|
|
127
|
-
case cmd.name
|
|
128
|
-
when "JOIN" then @groups[conn]&.add(cmd.data)
|
|
129
|
-
when "LEAVE" then @groups[conn]&.delete(cmd.data)
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
rescue *ZMTP::CONNECTION_LOST
|
|
133
|
-
@engine.connection_lost(conn)
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
end
|
data/lib/omq/zmtp/routing/rep.rb
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
module ZMTP
|
|
5
|
-
module Routing
|
|
6
|
-
# REP socket routing: fair-queue receive, reply routed back to sender.
|
|
7
|
-
#
|
|
8
|
-
# REP strips the routing envelope (everything up to and including the
|
|
9
|
-
# empty delimiter) on receive, saves it internally, and restores it
|
|
10
|
-
# on send.
|
|
11
|
-
#
|
|
12
|
-
class Rep
|
|
13
|
-
# @param engine [Engine]
|
|
14
|
-
#
|
|
15
|
-
def initialize(engine)
|
|
16
|
-
@engine = engine
|
|
17
|
-
@recv_queue = Async::LimitedQueue.new(engine.options.recv_hwm)
|
|
18
|
-
@send_queue = Async::LimitedQueue.new(engine.options.send_hwm)
|
|
19
|
-
@pending_replies = []
|
|
20
|
-
@tasks = []
|
|
21
|
-
@send_pump_started = false
|
|
22
|
-
@send_pump_idle = true
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# @return [Async::LimitedQueue]
|
|
26
|
-
#
|
|
27
|
-
attr_reader :recv_queue, :send_queue
|
|
28
|
-
|
|
29
|
-
# @param connection [Connection]
|
|
30
|
-
#
|
|
31
|
-
def connection_added(connection)
|
|
32
|
-
task = @engine.start_recv_pump(connection, @recv_queue) do |msg|
|
|
33
|
-
delimiter = msg.index(&:empty?) || msg.size
|
|
34
|
-
envelope = msg[0, delimiter]
|
|
35
|
-
body = msg[(delimiter + 1)..] || []
|
|
36
|
-
@pending_replies << { conn: connection, envelope: envelope }
|
|
37
|
-
body
|
|
38
|
-
end
|
|
39
|
-
@tasks << task if task
|
|
40
|
-
start_send_pump unless @send_pump_started
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# @param connection [Connection]
|
|
44
|
-
#
|
|
45
|
-
def connection_removed(connection)
|
|
46
|
-
# Remove any pending replies for this connection
|
|
47
|
-
@pending_replies.reject! { |r| r[:conn] == connection }
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Enqueues a reply for sending.
|
|
51
|
-
#
|
|
52
|
-
# @param parts [Array<String>]
|
|
53
|
-
#
|
|
54
|
-
def enqueue(parts)
|
|
55
|
-
@send_queue.enqueue(parts)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def stop
|
|
59
|
-
@tasks.each(&:stop)
|
|
60
|
-
@tasks.clear
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
def send_pump_idle? = @send_pump_idle
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def start_send_pump
|
|
69
|
-
@send_pump_started = true
|
|
70
|
-
@tasks << @engine.spawn_pump_task(annotation: "send pump") do
|
|
71
|
-
loop do
|
|
72
|
-
@send_pump_idle = true
|
|
73
|
-
batch = [@send_queue.dequeue]
|
|
74
|
-
@send_pump_idle = false
|
|
75
|
-
Routing.drain_send_queue(@send_queue, batch)
|
|
76
|
-
|
|
77
|
-
written = Set.new
|
|
78
|
-
batch.each do |parts|
|
|
79
|
-
reply_info = @pending_replies.shift
|
|
80
|
-
next unless reply_info
|
|
81
|
-
conn = reply_info[:conn]
|
|
82
|
-
begin
|
|
83
|
-
conn.write_message([*reply_info[:envelope], "".b, *parts])
|
|
84
|
-
written << conn
|
|
85
|
-
rescue *ZMTP::CONNECTION_LOST
|
|
86
|
-
# connection lost mid-write
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
written.each do |conn|
|
|
91
|
-
conn.flush
|
|
92
|
-
rescue *ZMTP::CONNECTION_LOST
|
|
93
|
-
# connection lost mid-flush
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
data/lib/omq/zmtp/routing/req.rb
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
module ZMTP
|
|
5
|
-
module Routing
|
|
6
|
-
# REQ socket routing: round-robin send with strict send/recv alternation.
|
|
7
|
-
#
|
|
8
|
-
# REQ prepends an empty delimiter frame on send and strips it on receive.
|
|
9
|
-
#
|
|
10
|
-
class Req
|
|
11
|
-
include RoundRobin
|
|
12
|
-
|
|
13
|
-
# @param engine [Engine]
|
|
14
|
-
#
|
|
15
|
-
def initialize(engine)
|
|
16
|
-
@engine = engine
|
|
17
|
-
@recv_queue = Async::LimitedQueue.new(engine.options.recv_hwm)
|
|
18
|
-
@tasks = []
|
|
19
|
-
init_round_robin(engine)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# @return [Async::LimitedQueue]
|
|
23
|
-
#
|
|
24
|
-
attr_reader :recv_queue, :send_queue
|
|
25
|
-
|
|
26
|
-
# @param connection [Connection]
|
|
27
|
-
#
|
|
28
|
-
def connection_added(connection)
|
|
29
|
-
@connections << connection
|
|
30
|
-
signal_connection_available
|
|
31
|
-
task = @engine.start_recv_pump(connection, @recv_queue) do |msg|
|
|
32
|
-
msg.first&.empty? ? msg[1..] : msg
|
|
33
|
-
end
|
|
34
|
-
@tasks << task if task
|
|
35
|
-
start_send_pump unless @send_pump_started
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# @param connection [Connection]
|
|
39
|
-
#
|
|
40
|
-
def connection_removed(connection)
|
|
41
|
-
@connections.delete(connection)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# @param parts [Array<String>]
|
|
45
|
-
#
|
|
46
|
-
def enqueue(parts)
|
|
47
|
-
@send_queue.enqueue(parts)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
#
|
|
51
|
-
def stop
|
|
52
|
-
@tasks.each(&:stop)
|
|
53
|
-
@tasks.clear
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
private
|
|
57
|
-
|
|
58
|
-
# REQ prepends empty delimiter frame on the wire.
|
|
59
|
-
#
|
|
60
|
-
def transform_send(parts) = ["".b, *parts]
|
|
61
|
-
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|