omq 0.1.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 (43) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +30 -0
  3. data/LICENSE +15 -0
  4. data/README.md +145 -0
  5. data/lib/omq/pair.rb +13 -0
  6. data/lib/omq/pub_sub.rb +77 -0
  7. data/lib/omq/push_pull.rb +21 -0
  8. data/lib/omq/req_rep.rb +23 -0
  9. data/lib/omq/router_dealer.rb +36 -0
  10. data/lib/omq/socket.rb +178 -0
  11. data/lib/omq/version.rb +5 -0
  12. data/lib/omq/zmtp/codec/command.rb +207 -0
  13. data/lib/omq/zmtp/codec/frame.rb +104 -0
  14. data/lib/omq/zmtp/codec/greeting.rb +96 -0
  15. data/lib/omq/zmtp/codec.rb +18 -0
  16. data/lib/omq/zmtp/connection.rb +233 -0
  17. data/lib/omq/zmtp/engine.rb +339 -0
  18. data/lib/omq/zmtp/mechanism/null.rb +70 -0
  19. data/lib/omq/zmtp/options.rb +57 -0
  20. data/lib/omq/zmtp/reactor.rb +142 -0
  21. data/lib/omq/zmtp/readable.rb +29 -0
  22. data/lib/omq/zmtp/routing/dealer.rb +57 -0
  23. data/lib/omq/zmtp/routing/fan_out.rb +89 -0
  24. data/lib/omq/zmtp/routing/pair.rb +68 -0
  25. data/lib/omq/zmtp/routing/pub.rb +62 -0
  26. data/lib/omq/zmtp/routing/pull.rb +48 -0
  27. data/lib/omq/zmtp/routing/push.rb +57 -0
  28. data/lib/omq/zmtp/routing/rep.rb +83 -0
  29. data/lib/omq/zmtp/routing/req.rb +70 -0
  30. data/lib/omq/zmtp/routing/round_robin.rb +69 -0
  31. data/lib/omq/zmtp/routing/router.rb +88 -0
  32. data/lib/omq/zmtp/routing/sub.rb +80 -0
  33. data/lib/omq/zmtp/routing/xpub.rb +74 -0
  34. data/lib/omq/zmtp/routing/xsub.rb +80 -0
  35. data/lib/omq/zmtp/routing.rb +38 -0
  36. data/lib/omq/zmtp/transport/inproc.rb +299 -0
  37. data/lib/omq/zmtp/transport/ipc.rb +114 -0
  38. data/lib/omq/zmtp/transport/tcp.rb +98 -0
  39. data/lib/omq/zmtp/valid_peers.rb +21 -0
  40. data/lib/omq/zmtp/writable.rb +44 -0
  41. data/lib/omq/zmtp.rb +47 -0
  42. data/lib/omq.rb +19 -0
  43. metadata +110 -0
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
4
+ require "uri"
5
+ require "io/stream"
6
+
7
+ module OMQ
8
+ module ZMTP
9
+ module Transport
10
+ # TCP transport using Ruby sockets with Async.
11
+ #
12
+ module TCP
13
+ class << self
14
+ # Binds a TCP server.
15
+ #
16
+ # @param endpoint [String] e.g. "tcp://127.0.0.1:5555" or "tcp://*:0"
17
+ # @param engine [Engine]
18
+ # @return [Listener]
19
+ #
20
+ def bind(endpoint, engine)
21
+ host, port = parse_endpoint(endpoint)
22
+ host = "0.0.0.0" if host == "*"
23
+ server = TCPServer.new(host, port)
24
+ actual_port = server.local_address.ip_port
25
+ host_part = host.include?(":") ? "[#{host}]" : host
26
+ resolved = "tcp://#{host_part}:#{actual_port}"
27
+
28
+ accept_task = Reactor.spawn_pump do
29
+ loop do
30
+ client = server.accept
31
+ Reactor.run do
32
+ engine.handle_accepted(IO::Stream::Buffered.wrap(client, minimum_write_size: 0), endpoint: resolved)
33
+ rescue => e
34
+ client.close rescue nil
35
+ raise if !e.is_a?(ProtocolError) && !e.is_a?(EOFError)
36
+ end
37
+ end
38
+ rescue IOError
39
+ # server closed
40
+ end
41
+
42
+ Listener.new(resolved, server, accept_task, actual_port)
43
+ end
44
+
45
+ # Connects to a TCP endpoint.
46
+ #
47
+ # @param endpoint [String] e.g. "tcp://127.0.0.1:5555"
48
+ # @param engine [Engine]
49
+ # @return [void]
50
+ #
51
+ def connect(endpoint, engine)
52
+ host, port = parse_endpoint(endpoint)
53
+ timeout = engine.options.connect_timeout
54
+ sock = if timeout
55
+ ::Socket.tcp(host, port, connect_timeout: timeout)
56
+ else
57
+ TCPSocket.new(host, port)
58
+ end
59
+ engine.handle_connected(IO::Stream::Buffered.wrap(sock, minimum_write_size: 0), endpoint: endpoint)
60
+ end
61
+
62
+ private
63
+
64
+ def parse_endpoint(endpoint)
65
+ uri = URI.parse(endpoint)
66
+ [uri.hostname, uri.port]
67
+ end
68
+ end
69
+
70
+ # A bound TCP listener.
71
+ #
72
+ class Listener
73
+ # @return [String] resolved endpoint with actual port
74
+ #
75
+ attr_reader :endpoint
76
+
77
+ # @return [Integer] bound port
78
+ #
79
+ attr_reader :port
80
+
81
+ def initialize(endpoint, server, accept_task, port)
82
+ @endpoint = endpoint
83
+ @server = server
84
+ @accept_task = accept_task
85
+ @port = port
86
+ end
87
+
88
+ # Stops the listener.
89
+ #
90
+ def stop
91
+ @accept_task.stop
92
+ @server.close rescue nil
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OMQ
4
+ module ZMTP
5
+ # Valid socket type peer combinations per ZMTP spec.
6
+ #
7
+ VALID_PEERS = {
8
+ PAIR: %i[PAIR].freeze,
9
+ REQ: %i[REP ROUTER].freeze,
10
+ REP: %i[REQ DEALER].freeze,
11
+ DEALER: %i[REP DEALER ROUTER].freeze,
12
+ ROUTER: %i[REQ DEALER ROUTER].freeze,
13
+ PUB: %i[SUB XSUB].freeze,
14
+ SUB: %i[PUB XPUB].freeze,
15
+ XPUB: %i[SUB XSUB].freeze,
16
+ XSUB: %i[PUB XPUB].freeze,
17
+ PUSH: %i[PULL].freeze,
18
+ PULL: %i[PUSH].freeze,
19
+ }.freeze
20
+ end
21
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timeout"
4
+
5
+ module OMQ
6
+ module ZMTP
7
+ # Pure Ruby Writable mixin. Enqueues messages to the engine's send path.
8
+ #
9
+ module Writable
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 = message.is_a?(Array) ? message : [message]
18
+ raise ArgumentError, "message has no parts" if parts.empty?
19
+ parts = parts.map { |p| p.b.freeze }
20
+
21
+ with_timeout(@options.write_timeout) { @engine.enqueue_send(parts) }
22
+ self
23
+ end
24
+
25
+ # Sends a message (chainable).
26
+ #
27
+ # @param message [String, Array<String>]
28
+ # @return [self]
29
+ #
30
+ def <<(message)
31
+ send(message)
32
+ end
33
+
34
+ # Waits until the socket is writable.
35
+ #
36
+ # @param timeout [Numeric, nil] timeout in seconds
37
+ # @return [true]
38
+ #
39
+ def wait_writable(timeout = @options.write_timeout)
40
+ true
41
+ end
42
+ end
43
+ end
44
+ end
data/lib/omq/zmtp.rb ADDED
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OMQ
4
+ # ZMTP 3.1 protocol internals.
5
+ #
6
+ # These classes implement the wire protocol, transports, and routing
7
+ # strategies. They are not part of the public API.
8
+ #
9
+ module ZMTP
10
+ end
11
+ end
12
+
13
+ # Constants
14
+ require_relative "zmtp/valid_peers"
15
+
16
+ # Codec
17
+ require_relative "zmtp/codec"
18
+
19
+ # Transport
20
+ require_relative "zmtp/transport/inproc"
21
+ require_relative "zmtp/transport/tcp"
22
+ require_relative "zmtp/transport/ipc"
23
+
24
+ # Mechanisms
25
+ require_relative "zmtp/mechanism/null"
26
+
27
+ # Core
28
+ require_relative "zmtp/reactor"
29
+ require_relative "zmtp/options"
30
+ require_relative "zmtp/connection"
31
+ require_relative "zmtp/routing"
32
+ require_relative "zmtp/routing/round_robin"
33
+ require_relative "zmtp/routing/fan_out"
34
+ require_relative "zmtp/routing/pair"
35
+ require_relative "zmtp/routing/req"
36
+ require_relative "zmtp/routing/rep"
37
+ require_relative "zmtp/routing/dealer"
38
+ require_relative "zmtp/routing/router"
39
+ require_relative "zmtp/routing/pub"
40
+ require_relative "zmtp/routing/sub"
41
+ require_relative "zmtp/routing/xpub"
42
+ require_relative "zmtp/routing/xsub"
43
+ require_relative "zmtp/routing/push"
44
+ require_relative "zmtp/routing/pull"
45
+ require_relative "zmtp/engine"
46
+ require_relative "zmtp/readable"
47
+ require_relative "zmtp/writable"
data/lib/omq.rb ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
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
+ # Protocol internals live under OMQ::ZMTP:: and are not part
9
+ # of the public API.
10
+ #
11
+
12
+ require_relative "omq/version"
13
+ require_relative "omq/zmtp"
14
+ require_relative "omq/socket"
15
+ require_relative "omq/req_rep"
16
+ require_relative "omq/router_dealer"
17
+ require_relative "omq/pub_sub"
18
+ require_relative "omq/push_pull"
19
+ require_relative "omq/pair"
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omq
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Patrik Wenger
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: async
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: io-stream
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.11'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.11'
40
+ description: Pure Ruby implementation of the ZMTP 3.1 wire protocol (ZeroMQ) using
41
+ the Async gem. No native libraries required.
42
+ email:
43
+ - paddor@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - CHANGELOG.md
49
+ - LICENSE
50
+ - README.md
51
+ - lib/omq.rb
52
+ - lib/omq/pair.rb
53
+ - lib/omq/pub_sub.rb
54
+ - lib/omq/push_pull.rb
55
+ - lib/omq/req_rep.rb
56
+ - lib/omq/router_dealer.rb
57
+ - lib/omq/socket.rb
58
+ - lib/omq/version.rb
59
+ - lib/omq/zmtp.rb
60
+ - lib/omq/zmtp/codec.rb
61
+ - lib/omq/zmtp/codec/command.rb
62
+ - lib/omq/zmtp/codec/frame.rb
63
+ - lib/omq/zmtp/codec/greeting.rb
64
+ - lib/omq/zmtp/connection.rb
65
+ - lib/omq/zmtp/engine.rb
66
+ - lib/omq/zmtp/mechanism/null.rb
67
+ - lib/omq/zmtp/options.rb
68
+ - lib/omq/zmtp/reactor.rb
69
+ - lib/omq/zmtp/readable.rb
70
+ - lib/omq/zmtp/routing.rb
71
+ - lib/omq/zmtp/routing/dealer.rb
72
+ - lib/omq/zmtp/routing/fan_out.rb
73
+ - lib/omq/zmtp/routing/pair.rb
74
+ - lib/omq/zmtp/routing/pub.rb
75
+ - lib/omq/zmtp/routing/pull.rb
76
+ - lib/omq/zmtp/routing/push.rb
77
+ - lib/omq/zmtp/routing/rep.rb
78
+ - lib/omq/zmtp/routing/req.rb
79
+ - lib/omq/zmtp/routing/round_robin.rb
80
+ - lib/omq/zmtp/routing/router.rb
81
+ - lib/omq/zmtp/routing/sub.rb
82
+ - lib/omq/zmtp/routing/xpub.rb
83
+ - lib/omq/zmtp/routing/xsub.rb
84
+ - lib/omq/zmtp/transport/inproc.rb
85
+ - lib/omq/zmtp/transport/ipc.rb
86
+ - lib/omq/zmtp/transport/tcp.rb
87
+ - lib/omq/zmtp/valid_peers.rb
88
+ - lib/omq/zmtp/writable.rb
89
+ homepage: https://github.com/paddor/omq
90
+ licenses:
91
+ - ISC
92
+ metadata: {}
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '3.3'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubygems_version: 4.0.6
108
+ specification_version: 4
109
+ summary: OMQ — pure Ruby ZeroMQ (ZMTP 3.1)
110
+ test_files: []