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
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OMQ
4
- class SCATTER < Socket
5
- include Writable
6
- include SingleFrame
7
-
8
- def initialize(endpoints = nil, linger: 0, send_hwm: nil, send_timeout: nil, backend: nil)
9
- _init_engine(:SCATTER, linger: linger, send_hwm: send_hwm, send_timeout: send_timeout, backend: backend)
10
- _attach(endpoints, default: :connect)
11
- end
12
- end
13
-
14
- class GATHER < Socket
15
- include Readable
16
- include SingleFrame
17
-
18
- def initialize(endpoints = nil, linger: 0, recv_hwm: nil, recv_timeout: nil, backend: nil)
19
- _init_engine(:GATHER, linger: linger, recv_hwm: recv_hwm, recv_timeout: recv_timeout, backend: backend)
20
- _attach(endpoints, default: :bind)
21
- end
22
- end
23
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OMQ
4
- # Mixin that rejects multipart messages.
5
- #
6
- # All draft socket types (CLIENT, SERVER, RADIO, DISH, SCATTER,
7
- # GATHER, PEER, CHANNEL) require single-frame messages for
8
- # thread-safe atomic operations.
9
- #
10
- module SingleFrame
11
- def send(message)
12
- if message.is_a?(Array) && message.size > 1
13
- raise ArgumentError, "#{self.class} does not support multipart messages"
14
- end
15
- super
16
- end
17
- end
18
- end
@@ -1,146 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "socket"
4
- require "uri"
5
- require "openssl"
6
- require "io/stream"
7
-
8
- module OMQ
9
- module Transport
10
- # TLS transport — TLS v1.3 on top of TCP.
11
- #
12
- # Requires the socket's +tls_context+ to be set to an
13
- # +OpenSSL::SSL::SSLContext+ before bind or connect.
14
- #
15
- module TLS
16
- TLS_PREFIX = "tls+tcp://"
17
-
18
- class << self
19
- # Binds a TLS server.
20
- #
21
- # @param endpoint [String] e.g. "tls+tcp://127.0.0.1:5555" or "tls+tcp://*:0"
22
- # @param engine [Engine]
23
- # @return [Listener]
24
- #
25
- def bind(endpoint, engine)
26
- ctx = require_context!(engine)
27
- host, port = parse_endpoint(endpoint)
28
- host = "0.0.0.0" if host == "*"
29
-
30
- addrs = Addrinfo.getaddrinfo(host, port, nil, :STREAM, nil, ::Socket::AI_PASSIVE)
31
- raise ::Socket::ResolutionError, "no addresses for #{host}" if addrs.empty?
32
-
33
- servers = []
34
- actual_port = nil
35
-
36
- addrs.each do |addr|
37
- server = TCPServer.new(addr.ip_address, actual_port || port)
38
- actual_port ||= server.local_address.ip_port
39
- servers << server
40
- end
41
-
42
- host_part = host.include?(":") ? "[#{host}]" : host
43
- resolved = "#{TLS_PREFIX}#{host_part}:#{actual_port}"
44
- Listener.new(resolved, servers, actual_port, ctx)
45
- end
46
-
47
- # Connects to a TLS endpoint.
48
- #
49
- # @param endpoint [String] e.g. "tls+tcp://127.0.0.1:5555"
50
- # @param engine [Engine]
51
- # @return [void]
52
- #
53
- def connect(endpoint, engine)
54
- ctx = require_context!(engine)
55
- host, port = parse_endpoint(endpoint)
56
- tcp_sock = TCPSocket.new(host, port)
57
-
58
- ssl = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx)
59
- ssl.sync_close = true
60
- ssl.hostname = host
61
- ssl.connect
62
-
63
- engine.handle_connected(IO::Stream::Buffered.wrap(ssl), endpoint: endpoint)
64
- rescue
65
- tcp_sock&.close unless ssl&.sync_close
66
- raise
67
- end
68
-
69
- private
70
-
71
- # Validates and freezes the TLS context from engine options.
72
- #
73
- # The context SHOULD have min_version set to TLS1_3_VERSION.
74
- # We cannot validate this because SSLContext#min_version is
75
- # write-only in Ruby's OpenSSL binding.
76
- #
77
- # @return [OpenSSL::SSL::SSLContext]
78
- # @raise [ArgumentError] if no context is set
79
- #
80
- def require_context!(engine)
81
- ctx = engine.options.tls_context
82
- raise ArgumentError, "tls_context must be set for tls+tcp:// endpoints" unless ctx
83
- ctx.freeze unless ctx.frozen?
84
- ctx
85
- end
86
-
87
- # Parses a tls+tcp:// endpoint URI into host and port.
88
- #
89
- # @param endpoint [String]
90
- # @return [Array(String, Integer)]
91
- #
92
- def parse_endpoint(endpoint)
93
- uri = URI.parse("http://#{endpoint.delete_prefix(TLS_PREFIX)}")
94
- [uri.hostname, uri.port]
95
- end
96
- end
97
-
98
- # A bound TLS listener.
99
- #
100
- class Listener
101
- # @return [String] resolved endpoint with actual port
102
- attr_reader :endpoint
103
-
104
- # @return [Integer] bound port
105
- attr_reader :port
106
-
107
- # @return [Array<TCPServer>] bound server sockets
108
- attr_reader :servers
109
-
110
- # @return [OpenSSL::SSL::SSLContext]
111
- attr_reader :ssl_context
112
-
113
-
114
- # @param endpoint [String] resolved endpoint URI
115
- # @param servers [Array<TCPServer>]
116
- # @param port [Integer] bound port number
117
- # @param ssl_context [OpenSSL::SSL::SSLContext]
118
- #
119
- def initialize(endpoint, servers, port, ssl_context)
120
- @endpoint = endpoint
121
- @servers = servers
122
- @port = port
123
- @ssl_context = ssl_context
124
- @tasks = []
125
- end
126
-
127
-
128
- # Registers accept loop tasks owned by the engine.
129
- #
130
- # @param tasks [Array<Async::Task>]
131
- #
132
- def accept_tasks=(tasks)
133
- @tasks = tasks
134
- end
135
-
136
-
137
- # Stops the listener.
138
- #
139
- def stop
140
- @tasks.each(&:stop)
141
- @servers.each { |s| s.close rescue nil }
142
- end
143
- end
144
- end
145
- end
146
- end