omq 0.9.0 → 0.11.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +129 -0
  3. data/README.md +28 -3
  4. data/lib/omq/channel.rb +5 -5
  5. data/lib/omq/client_server.rb +10 -10
  6. data/lib/omq/engine.rb +702 -0
  7. data/lib/omq/options.rb +48 -0
  8. data/lib/omq/pair.rb +4 -4
  9. data/lib/omq/peer.rb +5 -5
  10. data/lib/omq/pub_sub.rb +18 -18
  11. data/lib/omq/push_pull.rb +6 -6
  12. data/lib/omq/queue_interface.rb +73 -0
  13. data/lib/omq/radio_dish.rb +6 -6
  14. data/lib/omq/reactor.rb +128 -0
  15. data/lib/omq/readable.rb +44 -0
  16. data/lib/omq/req_rep.rb +8 -8
  17. data/lib/omq/router_dealer.rb +8 -8
  18. data/lib/omq/routing/channel.rb +83 -0
  19. data/lib/omq/routing/client.rb +56 -0
  20. data/lib/omq/routing/dealer.rb +57 -0
  21. data/lib/omq/routing/dish.rb +78 -0
  22. data/lib/omq/routing/fan_out.rb +140 -0
  23. data/lib/omq/routing/gather.rb +46 -0
  24. data/lib/omq/routing/pair.rb +86 -0
  25. data/lib/omq/routing/peer.rb +101 -0
  26. data/lib/omq/routing/pub.rb +60 -0
  27. data/lib/omq/routing/pull.rb +46 -0
  28. data/lib/omq/routing/push.rb +81 -0
  29. data/lib/omq/routing/radio.rb +150 -0
  30. data/lib/omq/routing/rep.rb +101 -0
  31. data/lib/omq/routing/req.rb +65 -0
  32. data/lib/omq/routing/round_robin.rb +168 -0
  33. data/lib/omq/routing/router.rb +110 -0
  34. data/lib/omq/routing/scatter.rb +82 -0
  35. data/lib/omq/routing/server.rb +101 -0
  36. data/lib/omq/routing/sub.rb +78 -0
  37. data/lib/omq/routing/xpub.rb +72 -0
  38. data/lib/omq/routing/xsub.rb +83 -0
  39. data/lib/omq/routing.rb +66 -0
  40. data/lib/omq/scatter_gather.rb +8 -8
  41. data/lib/omq/single_frame.rb +18 -0
  42. data/lib/omq/socket.rb +32 -11
  43. data/lib/omq/transport/inproc.rb +355 -0
  44. data/lib/omq/transport/ipc.rb +117 -0
  45. data/lib/omq/transport/tcp.rb +111 -0
  46. data/lib/omq/transport/tls.rb +146 -0
  47. data/lib/omq/version.rb +1 -1
  48. data/lib/omq/writable.rb +66 -0
  49. data/lib/omq.rb +64 -4
  50. metadata +34 -33
  51. data/lib/omq/zmtp/engine.rb +0 -551
  52. data/lib/omq/zmtp/options.rb +0 -48
  53. data/lib/omq/zmtp/reactor.rb +0 -131
  54. data/lib/omq/zmtp/readable.rb +0 -29
  55. data/lib/omq/zmtp/routing/channel.rb +0 -81
  56. data/lib/omq/zmtp/routing/client.rb +0 -56
  57. data/lib/omq/zmtp/routing/dealer.rb +0 -57
  58. data/lib/omq/zmtp/routing/dish.rb +0 -80
  59. data/lib/omq/zmtp/routing/fan_out.rb +0 -131
  60. data/lib/omq/zmtp/routing/gather.rb +0 -48
  61. data/lib/omq/zmtp/routing/pair.rb +0 -84
  62. data/lib/omq/zmtp/routing/peer.rb +0 -100
  63. data/lib/omq/zmtp/routing/pub.rb +0 -62
  64. data/lib/omq/zmtp/routing/pull.rb +0 -48
  65. data/lib/omq/zmtp/routing/push.rb +0 -80
  66. data/lib/omq/zmtp/routing/radio.rb +0 -139
  67. data/lib/omq/zmtp/routing/rep.rb +0 -101
  68. data/lib/omq/zmtp/routing/req.rb +0 -65
  69. data/lib/omq/zmtp/routing/round_robin.rb +0 -143
  70. data/lib/omq/zmtp/routing/router.rb +0 -109
  71. data/lib/omq/zmtp/routing/scatter.rb +0 -81
  72. data/lib/omq/zmtp/routing/server.rb +0 -100
  73. data/lib/omq/zmtp/routing/sub.rb +0 -80
  74. data/lib/omq/zmtp/routing/xpub.rb +0 -74
  75. data/lib/omq/zmtp/routing/xsub.rb +0 -86
  76. data/lib/omq/zmtp/routing.rb +0 -65
  77. data/lib/omq/zmtp/single_frame.rb +0 -20
  78. data/lib/omq/zmtp/transport/inproc.rb +0 -359
  79. data/lib/omq/zmtp/transport/ipc.rb +0 -118
  80. data/lib/omq/zmtp/transport/tcp.rb +0 -117
  81. data/lib/omq/zmtp/writable.rb +0 -61
  82. data/lib/omq/zmtp.rb +0 -81
@@ -0,0 +1,146 @@
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
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.9.0"
4
+ VERSION = "0.11.0"
5
5
  end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timeout"
4
+
5
+ module OMQ
6
+ # Pure Ruby Writable mixin. Enqueues messages to the engine's send path.
7
+ #
8
+ module Writable
9
+ include QueueWritable
10
+ # Sends a message.
11
+ #
12
+ # @param message [String, Array<String>] message parts
13
+ # @return [self]
14
+ # @raise [IO::TimeoutError] if write_timeout exceeded
15
+ #
16
+ def send(message)
17
+ parts = freeze_message(message)
18
+ Reactor.run { with_timeout(@options.write_timeout) { @engine.enqueue_send(parts) } }
19
+ self
20
+ end
21
+
22
+ # Sends a message (chainable).
23
+ #
24
+ # @param message [String, Array<String>]
25
+ # @return [self]
26
+ #
27
+ def <<(message)
28
+ send(message)
29
+ end
30
+
31
+ private
32
+
33
+ # Converts a message into a frozen array of frozen binary strings.
34
+ #
35
+ # @param message [String, Array<String>]
36
+ # @return [Array<String>] frozen array of frozen binary strings
37
+ #
38
+ def freeze_message(message)
39
+ parts = message.is_a?(Array) ? message : [message]
40
+ raise ArgumentError, "message has no parts" if parts.empty?
41
+ if parts.frozen?
42
+ parts = parts.map { |p| frozen_binary(p) }
43
+ else
44
+ parts.map! { |p| frozen_binary(p) }
45
+ end
46
+ parts.freeze
47
+ end
48
+
49
+ def frozen_binary(str)
50
+ s = str.to_str
51
+ return s if s.frozen? && s.encoding == Encoding::BINARY
52
+ s.b.freeze
53
+ end
54
+
55
+ public
56
+
57
+ # Waits until the socket is writable.
58
+ #
59
+ # @param timeout [Numeric, nil] timeout in seconds
60
+ # @return [true]
61
+ #
62
+ def wait_writable(timeout = @options.write_timeout)
63
+ true
64
+ end
65
+ end
66
+ end
data/lib/omq.rb CHANGED
@@ -5,9 +5,10 @@
5
5
  # Socket types live directly under OMQ:: for a clean API:
6
6
  # OMQ::PUSH, OMQ::PULL, OMQ::PUB, OMQ::SUB, etc.
7
7
  #
8
- # Protocol internals live under OMQ::ZMTP:: and are not part
9
- # of the public API.
10
- #
8
+
9
+ require "protocol/zmtp"
10
+ require "io/stream"
11
+ require "openssl"
11
12
 
12
13
  require_relative "omq/version"
13
14
 
@@ -16,9 +17,68 @@ module OMQ
16
17
  # The socket is no longer usable; the original error is available via #cause.
17
18
  #
18
19
  class SocketDeadError < RuntimeError; end
20
+
21
+ # Errors raised when a peer disconnects or resets the connection.
22
+ CONNECTION_LOST = [
23
+ EOFError,
24
+ IOError,
25
+ Errno::EPIPE,
26
+ Errno::ECONNRESET,
27
+ Errno::ECONNABORTED,
28
+ Errno::ENOTCONN,
29
+ IO::Stream::ConnectionResetError,
30
+ OpenSSL::SSL::SSLError,
31
+ ].freeze
32
+
33
+ # Errors raised when a peer cannot be reached.
34
+ CONNECTION_FAILED = [
35
+ Errno::ECONNREFUSED,
36
+ Errno::ENOENT,
37
+ Errno::ETIMEDOUT,
38
+ Errno::EHOSTUNREACH,
39
+ Errno::ENETUNREACH,
40
+ Socket::ResolutionError,
41
+ ].freeze
19
42
  end
20
43
 
21
- require_relative "omq/zmtp"
44
+ # Transport
45
+ require_relative "omq/transport/inproc"
46
+ require_relative "omq/transport/tcp"
47
+ require_relative "omq/transport/tls"
48
+ require_relative "omq/transport/ipc"
49
+
50
+ # Core
51
+ require_relative "omq/reactor"
52
+ require_relative "omq/options"
53
+ require_relative "omq/routing"
54
+ require_relative "omq/routing/round_robin"
55
+ require_relative "omq/routing/fan_out"
56
+ require_relative "omq/routing/pair"
57
+ require_relative "omq/routing/req"
58
+ require_relative "omq/routing/rep"
59
+ require_relative "omq/routing/dealer"
60
+ require_relative "omq/routing/router"
61
+ require_relative "omq/routing/pub"
62
+ require_relative "omq/routing/sub"
63
+ require_relative "omq/routing/xpub"
64
+ require_relative "omq/routing/xsub"
65
+ require_relative "omq/routing/push"
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
+ require_relative "omq/engine"
77
+ require_relative "omq/queue_interface"
78
+ require_relative "omq/readable"
79
+ require_relative "omq/writable"
80
+
81
+ # Socket types
22
82
  require_relative "omq/socket"
23
83
  require_relative "omq/req_rep"
24
84
  require_relative "omq/router_dealer"
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.9.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger
@@ -67,48 +67,49 @@ files:
67
67
  - lib/omq.rb
68
68
  - lib/omq/channel.rb
69
69
  - lib/omq/client_server.rb
70
+ - lib/omq/engine.rb
71
+ - lib/omq/options.rb
70
72
  - lib/omq/pair.rb
71
73
  - lib/omq/peer.rb
72
74
  - lib/omq/pub_sub.rb
73
75
  - lib/omq/push_pull.rb
76
+ - lib/omq/queue_interface.rb
74
77
  - lib/omq/radio_dish.rb
78
+ - lib/omq/reactor.rb
79
+ - lib/omq/readable.rb
75
80
  - lib/omq/req_rep.rb
76
81
  - lib/omq/router_dealer.rb
82
+ - lib/omq/routing.rb
83
+ - lib/omq/routing/channel.rb
84
+ - lib/omq/routing/client.rb
85
+ - lib/omq/routing/dealer.rb
86
+ - lib/omq/routing/dish.rb
87
+ - lib/omq/routing/fan_out.rb
88
+ - lib/omq/routing/gather.rb
89
+ - lib/omq/routing/pair.rb
90
+ - lib/omq/routing/peer.rb
91
+ - lib/omq/routing/pub.rb
92
+ - lib/omq/routing/pull.rb
93
+ - lib/omq/routing/push.rb
94
+ - lib/omq/routing/radio.rb
95
+ - lib/omq/routing/rep.rb
96
+ - lib/omq/routing/req.rb
97
+ - lib/omq/routing/round_robin.rb
98
+ - lib/omq/routing/router.rb
99
+ - lib/omq/routing/scatter.rb
100
+ - lib/omq/routing/server.rb
101
+ - lib/omq/routing/sub.rb
102
+ - lib/omq/routing/xpub.rb
103
+ - lib/omq/routing/xsub.rb
77
104
  - lib/omq/scatter_gather.rb
105
+ - lib/omq/single_frame.rb
78
106
  - lib/omq/socket.rb
107
+ - lib/omq/transport/inproc.rb
108
+ - lib/omq/transport/ipc.rb
109
+ - lib/omq/transport/tcp.rb
110
+ - lib/omq/transport/tls.rb
79
111
  - lib/omq/version.rb
80
- - lib/omq/zmtp.rb
81
- - lib/omq/zmtp/engine.rb
82
- - lib/omq/zmtp/options.rb
83
- - lib/omq/zmtp/reactor.rb
84
- - lib/omq/zmtp/readable.rb
85
- - lib/omq/zmtp/routing.rb
86
- - lib/omq/zmtp/routing/channel.rb
87
- - lib/omq/zmtp/routing/client.rb
88
- - lib/omq/zmtp/routing/dealer.rb
89
- - lib/omq/zmtp/routing/dish.rb
90
- - lib/omq/zmtp/routing/fan_out.rb
91
- - lib/omq/zmtp/routing/gather.rb
92
- - lib/omq/zmtp/routing/pair.rb
93
- - lib/omq/zmtp/routing/peer.rb
94
- - lib/omq/zmtp/routing/pub.rb
95
- - lib/omq/zmtp/routing/pull.rb
96
- - lib/omq/zmtp/routing/push.rb
97
- - lib/omq/zmtp/routing/radio.rb
98
- - lib/omq/zmtp/routing/rep.rb
99
- - lib/omq/zmtp/routing/req.rb
100
- - lib/omq/zmtp/routing/round_robin.rb
101
- - lib/omq/zmtp/routing/router.rb
102
- - lib/omq/zmtp/routing/scatter.rb
103
- - lib/omq/zmtp/routing/server.rb
104
- - lib/omq/zmtp/routing/sub.rb
105
- - lib/omq/zmtp/routing/xpub.rb
106
- - lib/omq/zmtp/routing/xsub.rb
107
- - lib/omq/zmtp/single_frame.rb
108
- - lib/omq/zmtp/transport/inproc.rb
109
- - lib/omq/zmtp/transport/ipc.rb
110
- - lib/omq/zmtp/transport/tcp.rb
111
- - lib/omq/zmtp/writable.rb
112
+ - lib/omq/writable.rb
112
113
  homepage: https://github.com/zeromq/omq
113
114
  licenses:
114
115
  - ISC