omq 0.6.5 → 0.8.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 +78 -1
- data/README.md +76 -81
- data/lib/omq/cli/base_runner.rb +54 -21
- data/lib/omq/cli/client_server.rb +14 -9
- data/lib/omq/cli/config.rb +7 -4
- data/lib/omq/cli/pair.rb +1 -1
- data/lib/omq/cli/pipe.rb +37 -21
- data/lib/omq/cli/req_rep.rb +8 -4
- data/lib/omq/cli/router_dealer.rb +12 -6
- data/lib/omq/cli.rb +100 -34
- data/lib/omq/version.rb +1 -1
- data/lib/omq/zmtp/engine.rb +69 -22
- data/lib/omq/zmtp/routing/peer.rb +3 -2
- data/lib/omq/zmtp/routing/rep.rb +2 -3
- data/lib/omq/zmtp/routing/req.rb +3 -7
- data/lib/omq/zmtp/routing/router.rb +3 -2
- data/lib/omq/zmtp/routing/server.rb +3 -2
- data/lib/omq/zmtp.rb +16 -13
- data/lib/omq.rb +1 -0
- metadata +15 -8
- data/lib/omq/zmtp/codec/command.rb +0 -210
- data/lib/omq/zmtp/codec/frame.rb +0 -89
- data/lib/omq/zmtp/codec/greeting.rb +0 -78
- data/lib/omq/zmtp/codec.rb +0 -18
- data/lib/omq/zmtp/connection.rb +0 -282
- data/lib/omq/zmtp/mechanism/null.rb +0 -72
- data/lib/omq/zmtp/valid_peers.rb +0 -29
|
@@ -35,8 +35,9 @@ module OMQ
|
|
|
35
35
|
identity = SecureRandom.bytes(5) if identity.nil? || identity.empty?
|
|
36
36
|
@connections_by_identity[identity] = connection
|
|
37
37
|
|
|
38
|
-
task = @engine.start_recv_pump(connection, @recv_queue
|
|
39
|
-
|
|
38
|
+
task = @engine.start_recv_pump(connection, @recv_queue) do |msg|
|
|
39
|
+
[identity, *msg]
|
|
40
|
+
end
|
|
40
41
|
@tasks << task if task
|
|
41
42
|
|
|
42
43
|
start_send_pump unless @send_pump_started
|
|
@@ -34,8 +34,9 @@ module OMQ
|
|
|
34
34
|
routing_id = SecureRandom.bytes(4)
|
|
35
35
|
@connections_by_routing_id[routing_id] = connection
|
|
36
36
|
|
|
37
|
-
task = @engine.start_recv_pump(connection, @recv_queue
|
|
38
|
-
|
|
37
|
+
task = @engine.start_recv_pump(connection, @recv_queue) do |msg|
|
|
38
|
+
[routing_id, *msg]
|
|
39
|
+
end
|
|
39
40
|
@tasks << task if task
|
|
40
41
|
|
|
41
42
|
start_send_pump unless @send_pump_started
|
data/lib/omq/zmtp.rb
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "protocol/zmtp"
|
|
4
|
+
require "io/stream"
|
|
5
|
+
|
|
3
6
|
module OMQ
|
|
4
7
|
# ZMTP 3.1 protocol internals.
|
|
5
8
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
9
|
+
# The wire protocol (codec, connection, mechanisms) lives in the
|
|
10
|
+
# protocol-zmtp gem. This module re-exports those classes under the
|
|
11
|
+
# OMQ::ZMTP namespace and adds the transport/routing/engine layers.
|
|
8
12
|
#
|
|
9
13
|
module ZMTP
|
|
10
|
-
|
|
14
|
+
# Re-export protocol-zmtp classes
|
|
15
|
+
Codec = Protocol::ZMTP::Codec
|
|
16
|
+
Connection = Protocol::ZMTP::Connection
|
|
17
|
+
ProtocolError = Protocol::ZMTP::Error
|
|
18
|
+
VALID_PEERS = Protocol::ZMTP::VALID_PEERS
|
|
19
|
+
|
|
20
|
+
module Mechanism
|
|
21
|
+
Null = Protocol::ZMTP::Mechanism::Null
|
|
22
|
+
Curve = Protocol::ZMTP::Mechanism::Curve if defined?(Protocol::ZMTP::Mechanism::Curve)
|
|
23
|
+
end
|
|
11
24
|
|
|
12
25
|
# Errors raised when a peer disconnects or resets the connection.
|
|
13
26
|
CONNECTION_LOST = [
|
|
@@ -32,24 +45,14 @@ module OMQ
|
|
|
32
45
|
end
|
|
33
46
|
end
|
|
34
47
|
|
|
35
|
-
# Constants
|
|
36
|
-
require_relative "zmtp/valid_peers"
|
|
37
|
-
|
|
38
|
-
# Codec
|
|
39
|
-
require_relative "zmtp/codec"
|
|
40
|
-
|
|
41
48
|
# Transport
|
|
42
49
|
require_relative "zmtp/transport/inproc"
|
|
43
50
|
require_relative "zmtp/transport/tcp"
|
|
44
51
|
require_relative "zmtp/transport/ipc"
|
|
45
52
|
|
|
46
|
-
# Mechanisms
|
|
47
|
-
require_relative "zmtp/mechanism/null"
|
|
48
|
-
|
|
49
53
|
# Core
|
|
50
54
|
require_relative "zmtp/reactor"
|
|
51
55
|
require_relative "zmtp/options"
|
|
52
|
-
require_relative "zmtp/connection"
|
|
53
56
|
require_relative "zmtp/routing"
|
|
54
57
|
require_relative "zmtp/routing/round_robin"
|
|
55
58
|
require_relative "zmtp/routing/fan_out"
|
data/lib/omq.rb
CHANGED
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.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrik Wenger
|
|
@@ -9,6 +9,20 @@ bindir: exe
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: protocol-zmtp
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
12
26
|
- !ruby/object:Gem::Dependency
|
|
13
27
|
name: async
|
|
14
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -83,13 +97,7 @@ files:
|
|
|
83
97
|
- lib/omq/socket.rb
|
|
84
98
|
- lib/omq/version.rb
|
|
85
99
|
- lib/omq/zmtp.rb
|
|
86
|
-
- lib/omq/zmtp/codec.rb
|
|
87
|
-
- lib/omq/zmtp/codec/command.rb
|
|
88
|
-
- lib/omq/zmtp/codec/frame.rb
|
|
89
|
-
- lib/omq/zmtp/codec/greeting.rb
|
|
90
|
-
- lib/omq/zmtp/connection.rb
|
|
91
100
|
- lib/omq/zmtp/engine.rb
|
|
92
|
-
- lib/omq/zmtp/mechanism/null.rb
|
|
93
101
|
- lib/omq/zmtp/options.rb
|
|
94
102
|
- lib/omq/zmtp/reactor.rb
|
|
95
103
|
- lib/omq/zmtp/readable.rb
|
|
@@ -119,7 +127,6 @@ files:
|
|
|
119
127
|
- lib/omq/zmtp/transport/inproc.rb
|
|
120
128
|
- lib/omq/zmtp/transport/ipc.rb
|
|
121
129
|
- lib/omq/zmtp/transport/tcp.rb
|
|
122
|
-
- lib/omq/zmtp/valid_peers.rb
|
|
123
130
|
- lib/omq/zmtp/writable.rb
|
|
124
131
|
homepage: https://github.com/zeromq/omq
|
|
125
132
|
licenses:
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
module ZMTP
|
|
5
|
-
module Codec
|
|
6
|
-
# ZMTP command encode/decode.
|
|
7
|
-
#
|
|
8
|
-
# Command frame body format:
|
|
9
|
-
# 1 byte: command name length
|
|
10
|
-
# N bytes: command name
|
|
11
|
-
# remaining: command data
|
|
12
|
-
#
|
|
13
|
-
# READY command data = property list:
|
|
14
|
-
# 1 byte: property name length
|
|
15
|
-
# N bytes: property name
|
|
16
|
-
# 4 bytes: property value length (big-endian)
|
|
17
|
-
# N bytes: property value
|
|
18
|
-
#
|
|
19
|
-
class Command
|
|
20
|
-
# @return [String] command name (e.g. "READY", "SUBSCRIBE")
|
|
21
|
-
#
|
|
22
|
-
attr_reader :name
|
|
23
|
-
|
|
24
|
-
# @return [String] command data (binary)
|
|
25
|
-
#
|
|
26
|
-
attr_reader :data
|
|
27
|
-
|
|
28
|
-
# @param name [String] command name
|
|
29
|
-
# @param data [String] command data
|
|
30
|
-
#
|
|
31
|
-
def initialize(name, data = "".b)
|
|
32
|
-
@name = name
|
|
33
|
-
@data = data.b
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Encodes as a command frame body.
|
|
37
|
-
#
|
|
38
|
-
# @return [String] binary body (name-length + name + data)
|
|
39
|
-
#
|
|
40
|
-
def to_body
|
|
41
|
-
name_bytes = @name.b
|
|
42
|
-
name_bytes.bytesize.chr.b + name_bytes + @data
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Encodes as a complete command Frame.
|
|
46
|
-
#
|
|
47
|
-
# @return [Frame]
|
|
48
|
-
#
|
|
49
|
-
def to_frame
|
|
50
|
-
Frame.new(to_body, command: true)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Decodes a command from a frame body.
|
|
54
|
-
#
|
|
55
|
-
# @param body [String] binary frame body
|
|
56
|
-
# @return [Command]
|
|
57
|
-
# @raise [ProtocolError] on malformed command
|
|
58
|
-
#
|
|
59
|
-
def self.from_body(body)
|
|
60
|
-
body = body.b
|
|
61
|
-
raise ProtocolError, "command body too short" if body.bytesize < 1
|
|
62
|
-
|
|
63
|
-
name_len = body.getbyte(0)
|
|
64
|
-
|
|
65
|
-
raise ProtocolError, "command name truncated" if body.bytesize < 1 + name_len
|
|
66
|
-
|
|
67
|
-
name = body.byteslice(1, name_len)
|
|
68
|
-
data = body.byteslice(1 + name_len..)
|
|
69
|
-
new(name, data)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Builds a READY command with Socket-Type and Identity properties.
|
|
73
|
-
#
|
|
74
|
-
# @param socket_type [String] e.g. "REQ", "REP", "PAIR"
|
|
75
|
-
# @param identity [String] peer identity (can be empty)
|
|
76
|
-
# @return [Command]
|
|
77
|
-
#
|
|
78
|
-
def self.ready(socket_type:, identity: "")
|
|
79
|
-
props = encode_properties(
|
|
80
|
-
"Socket-Type" => socket_type,
|
|
81
|
-
"Identity" => identity,
|
|
82
|
-
)
|
|
83
|
-
new("READY", props)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# Builds a SUBSCRIBE command.
|
|
87
|
-
#
|
|
88
|
-
# @param prefix [String] subscription prefix
|
|
89
|
-
# @return [Command]
|
|
90
|
-
#
|
|
91
|
-
def self.subscribe(prefix)
|
|
92
|
-
new("SUBSCRIBE", prefix.b)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# Builds a CANCEL command (unsubscribe).
|
|
96
|
-
#
|
|
97
|
-
# @param prefix [String] subscription prefix to cancel
|
|
98
|
-
# @return [Command]
|
|
99
|
-
#
|
|
100
|
-
def self.cancel(prefix)
|
|
101
|
-
new("CANCEL", prefix.b)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# Builds a JOIN command (RADIO/DISH group subscription).
|
|
105
|
-
#
|
|
106
|
-
# @param group [String] group name
|
|
107
|
-
# @return [Command]
|
|
108
|
-
#
|
|
109
|
-
def self.join(group)
|
|
110
|
-
new("JOIN", group.b)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# Builds a LEAVE command (RADIO/DISH group unsubscription).
|
|
114
|
-
#
|
|
115
|
-
# @param group [String] group name
|
|
116
|
-
# @return [Command]
|
|
117
|
-
#
|
|
118
|
-
def self.leave(group)
|
|
119
|
-
new("LEAVE", group.b)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# Builds a PING command.
|
|
123
|
-
#
|
|
124
|
-
# @param ttl [Numeric] time-to-live in seconds (sent as deciseconds)
|
|
125
|
-
# @param context [String] optional context bytes (up to 16 bytes)
|
|
126
|
-
# @return [Command]
|
|
127
|
-
#
|
|
128
|
-
def self.ping(ttl: 0, context: "".b)
|
|
129
|
-
ttl_ds = (ttl * 10).to_i
|
|
130
|
-
new("PING", [ttl_ds].pack("n") + context.b)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# Builds a PONG command.
|
|
134
|
-
#
|
|
135
|
-
# @param context [String] context bytes from the PING
|
|
136
|
-
# @return [Command]
|
|
137
|
-
#
|
|
138
|
-
def self.pong(context: "".b)
|
|
139
|
-
new("PONG", context.b)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# Extracts TTL (in seconds) and context from a PING command's data.
|
|
143
|
-
#
|
|
144
|
-
# @return [Array(Numeric, String)] [ttl_seconds, context_bytes]
|
|
145
|
-
#
|
|
146
|
-
def ping_ttl_and_context
|
|
147
|
-
ttl_ds = @data.unpack1("n")
|
|
148
|
-
context = @data.bytesize > 2 ? @data.byteslice(2..) : "".b
|
|
149
|
-
[ttl_ds / 10.0, context]
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
# Parses READY command data as a property list.
|
|
153
|
-
#
|
|
154
|
-
# @return [Hash<String, String>] property name => value
|
|
155
|
-
# @raise [ProtocolError] on malformed properties
|
|
156
|
-
#
|
|
157
|
-
def properties
|
|
158
|
-
self.class.decode_properties(@data)
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
# Encodes a hash of properties into ZMTP property list format.
|
|
162
|
-
#
|
|
163
|
-
# @param props [Hash<String, String>]
|
|
164
|
-
# @return [String] binary property list
|
|
165
|
-
#
|
|
166
|
-
def self.encode_properties(props)
|
|
167
|
-
parts = props.map do |name, value|
|
|
168
|
-
name_bytes = name.b
|
|
169
|
-
value_bytes = value.b
|
|
170
|
-
name_bytes.bytesize.chr.b + name_bytes + [value_bytes.bytesize].pack("N") + value_bytes
|
|
171
|
-
end
|
|
172
|
-
parts.join
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
# Decodes a ZMTP property list from binary data.
|
|
176
|
-
#
|
|
177
|
-
# @param data [String] binary property list
|
|
178
|
-
# @return [Hash<String, String>] property name => value
|
|
179
|
-
# @raise [ProtocolError] on malformed properties
|
|
180
|
-
#
|
|
181
|
-
def self.decode_properties(data)
|
|
182
|
-
result = {}
|
|
183
|
-
offset = 0
|
|
184
|
-
|
|
185
|
-
while offset < data.bytesize
|
|
186
|
-
raise ProtocolError, "property name truncated" if offset + 1 > data.bytesize
|
|
187
|
-
name_len = data.getbyte(offset)
|
|
188
|
-
offset += 1
|
|
189
|
-
|
|
190
|
-
raise ProtocolError, "property name truncated" if offset + name_len > data.bytesize
|
|
191
|
-
name = data.byteslice(offset, name_len)
|
|
192
|
-
offset += name_len
|
|
193
|
-
|
|
194
|
-
raise ProtocolError, "property value length truncated" if offset + 4 > data.bytesize
|
|
195
|
-
value_len = data.byteslice(offset, 4).unpack1("N")
|
|
196
|
-
offset += 4
|
|
197
|
-
|
|
198
|
-
raise ProtocolError, "property value truncated" if offset + value_len > data.bytesize
|
|
199
|
-
value = data.byteslice(offset, value_len)
|
|
200
|
-
offset += value_len
|
|
201
|
-
|
|
202
|
-
result[name] = value
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
result
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
end
|
data/lib/omq/zmtp/codec/frame.rb
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
module ZMTP
|
|
5
|
-
module Codec
|
|
6
|
-
# ZMTP frame encode/decode.
|
|
7
|
-
#
|
|
8
|
-
# Wire format:
|
|
9
|
-
# Byte 0: flags (bit 0=MORE, bit 1=LONG, bit 2=COMMAND)
|
|
10
|
-
# Next 1-8: size (1-byte if short, 8-byte big-endian if LONG)
|
|
11
|
-
# Next N: body
|
|
12
|
-
#
|
|
13
|
-
class Frame
|
|
14
|
-
FLAGS_MORE = 0x01
|
|
15
|
-
FLAGS_LONG = 0x02
|
|
16
|
-
FLAGS_COMMAND = 0x04
|
|
17
|
-
|
|
18
|
-
# Short frame: 1-byte size, max body 255 bytes.
|
|
19
|
-
#
|
|
20
|
-
SHORT_MAX = 255
|
|
21
|
-
|
|
22
|
-
# @return [String] frame body (binary)
|
|
23
|
-
#
|
|
24
|
-
attr_reader :body
|
|
25
|
-
|
|
26
|
-
# @param body [String] frame body
|
|
27
|
-
# @param more [Boolean] more frames follow
|
|
28
|
-
# @param command [Boolean] this is a command frame
|
|
29
|
-
#
|
|
30
|
-
def initialize(body, more: false, command: false)
|
|
31
|
-
@body = body.b
|
|
32
|
-
@more = more
|
|
33
|
-
@command = command
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# @return [Boolean] true if more frames follow in this message
|
|
37
|
-
#
|
|
38
|
-
def more? = @more
|
|
39
|
-
|
|
40
|
-
# @return [Boolean] true if this is a command frame
|
|
41
|
-
#
|
|
42
|
-
def command? = @command
|
|
43
|
-
|
|
44
|
-
# Encodes to wire bytes.
|
|
45
|
-
#
|
|
46
|
-
# @return [String] binary wire representation (flags + size + body)
|
|
47
|
-
#
|
|
48
|
-
def to_wire
|
|
49
|
-
size = @body.bytesize
|
|
50
|
-
flags = 0
|
|
51
|
-
flags |= FLAGS_MORE if @more
|
|
52
|
-
flags |= FLAGS_COMMAND if @command
|
|
53
|
-
|
|
54
|
-
if size > SHORT_MAX
|
|
55
|
-
(flags | FLAGS_LONG).chr.b + [size].pack("Q>") + @body
|
|
56
|
-
else
|
|
57
|
-
flags.chr.b + size.chr.b + @body
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Reads one frame from an IO-like object.
|
|
62
|
-
#
|
|
63
|
-
# @param io [#read_exactly] must support read_exactly(n)
|
|
64
|
-
# @return [Frame]
|
|
65
|
-
# @raise [ProtocolError] on invalid frame
|
|
66
|
-
# @raise [EOFError] if the connection is closed
|
|
67
|
-
#
|
|
68
|
-
def self.read_from(io)
|
|
69
|
-
flags = io.read_exactly(1).getbyte(0)
|
|
70
|
-
|
|
71
|
-
more = (flags & FLAGS_MORE) != 0
|
|
72
|
-
long = (flags & FLAGS_LONG) != 0
|
|
73
|
-
command = (flags & FLAGS_COMMAND) != 0
|
|
74
|
-
|
|
75
|
-
size = if long
|
|
76
|
-
io.read_exactly(8).unpack1("Q>")
|
|
77
|
-
else
|
|
78
|
-
io.read_exactly(1).getbyte(0)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
body = size > 0 ? io.read_exactly(size) : "".b
|
|
82
|
-
|
|
83
|
-
new(body, more: more, command: command)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
module ZMTP
|
|
5
|
-
module Codec
|
|
6
|
-
# ZMTP 3.1 greeting encode/decode.
|
|
7
|
-
#
|
|
8
|
-
# The greeting is always exactly 64 bytes:
|
|
9
|
-
# Offset Bytes Field
|
|
10
|
-
# 0 1 0xFF (signature start)
|
|
11
|
-
# 1-8 8 0x00 padding
|
|
12
|
-
# 9 1 0x7F (signature end)
|
|
13
|
-
# 10 1 major version
|
|
14
|
-
# 11 1 minor version
|
|
15
|
-
# 12-31 20 mechanism (null-padded ASCII)
|
|
16
|
-
# 32 1 as-server flag (0x00 or 0x01)
|
|
17
|
-
# 33-63 31 filler (0x00)
|
|
18
|
-
#
|
|
19
|
-
module Greeting
|
|
20
|
-
SIZE = 64
|
|
21
|
-
SIGNATURE_START = 0xFF
|
|
22
|
-
SIGNATURE_END = 0x7F
|
|
23
|
-
VERSION_MAJOR = 3
|
|
24
|
-
VERSION_MINOR = 1
|
|
25
|
-
MECHANISM_OFFSET = 12
|
|
26
|
-
MECHANISM_LENGTH = 20
|
|
27
|
-
AS_SERVER_OFFSET = 32
|
|
28
|
-
|
|
29
|
-
# Encodes a ZMTP 3.1 greeting.
|
|
30
|
-
#
|
|
31
|
-
# @param mechanism [String] security mechanism name (e.g. "NULL")
|
|
32
|
-
# @param as_server [Boolean] whether this peer is the server
|
|
33
|
-
# @return [String] 64-byte binary greeting
|
|
34
|
-
#
|
|
35
|
-
def self.encode(mechanism: "NULL", as_server: false)
|
|
36
|
-
buf = "\xFF".b + ("\x00" * 8) + "\x7F".b
|
|
37
|
-
buf << [VERSION_MAJOR, VERSION_MINOR].pack("CC")
|
|
38
|
-
buf << mechanism.b.ljust(MECHANISM_LENGTH, "\x00")
|
|
39
|
-
buf << (as_server ? "\x01" : "\x00")
|
|
40
|
-
buf << ("\x00" * 31)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Decodes a ZMTP greeting.
|
|
44
|
-
#
|
|
45
|
-
# @param data [String] 64-byte binary greeting
|
|
46
|
-
# @return [Hash] { major:, minor:, mechanism:, as_server: }
|
|
47
|
-
# @raise [ProtocolError] on invalid greeting
|
|
48
|
-
#
|
|
49
|
-
def self.decode(data)
|
|
50
|
-
raise ProtocolError, "greeting too short (#{data.bytesize} bytes)" if data.bytesize < SIZE
|
|
51
|
-
|
|
52
|
-
data = data.b
|
|
53
|
-
|
|
54
|
-
unless data.getbyte(0) == SIGNATURE_START && data.getbyte(9) == SIGNATURE_END
|
|
55
|
-
raise ProtocolError, "invalid greeting signature"
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
major = data.getbyte(10)
|
|
59
|
-
minor = data.getbyte(11)
|
|
60
|
-
|
|
61
|
-
unless major >= 3
|
|
62
|
-
raise ProtocolError, "unsupported ZMTP version #{major}.#{minor} (need >= 3.0)"
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
mechanism = data.byteslice(MECHANISM_OFFSET, MECHANISM_LENGTH).delete("\x00")
|
|
66
|
-
as_server = data.getbyte(AS_SERVER_OFFSET) == 1
|
|
67
|
-
|
|
68
|
-
{
|
|
69
|
-
major: major,
|
|
70
|
-
minor: minor,
|
|
71
|
-
mechanism: mechanism,
|
|
72
|
-
as_server: as_server,
|
|
73
|
-
}
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
data/lib/omq/zmtp/codec.rb
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module OMQ
|
|
4
|
-
module ZMTP
|
|
5
|
-
# ZMTP 3.1 wire protocol codec.
|
|
6
|
-
#
|
|
7
|
-
module Codec
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
# Raised on ZMTP protocol violations.
|
|
11
|
-
#
|
|
12
|
-
class ProtocolError < RuntimeError; end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
require_relative "codec/greeting"
|
|
17
|
-
require_relative "codec/frame"
|
|
18
|
-
require_relative "codec/command"
|