cztop 1.0.0 → 1.1.0.pre1
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/.github/workflows/coverage.yml +20 -0
- data/.github/workflows/draft_api.yml +27 -0
- data/.github/workflows/{main.yml → stable_api.yml} +6 -6
- data/.rubocop.yml +175 -0
- data/CHANGES.md +8 -1
- data/Gemfile +5 -0
- data/README.md +3 -1
- data/ci/install-libczmq +22 -0
- data/ci/install-libzmq +22 -0
- data/cztop.gemspec +3 -2
- data/lib/cztop/actor.rb +55 -26
- data/lib/cztop/authenticator.rb +18 -9
- data/lib/cztop/beacon.rb +22 -10
- data/lib/cztop/cert_store.rb +8 -2
- data/lib/cztop/certificate.rb +47 -18
- data/lib/cztop/config/comments.rb +14 -3
- data/lib/cztop/config/serialization.rb +25 -5
- data/lib/cztop/config/traversing.rb +44 -13
- data/lib/cztop/config.rb +23 -9
- data/lib/cztop/frame.rb +23 -10
- data/lib/cztop/has_ffi_delegate.rb +11 -1
- data/lib/cztop/message/frames.rb +16 -2
- data/lib/cztop/message.rb +36 -22
- data/lib/cztop/metadata.rb +35 -24
- data/lib/cztop/monitor.rb +14 -5
- data/lib/cztop/poller/aggregated.rb +31 -15
- data/lib/cztop/poller/zmq.rb +25 -22
- data/lib/cztop/poller/zpoller.rb +18 -6
- data/lib/cztop/poller.rb +43 -18
- data/lib/cztop/polymorphic_zsock_methods.rb +6 -1
- data/lib/cztop/proxy.rb +34 -19
- data/lib/cztop/send_receive_methods.rb +5 -1
- data/lib/cztop/socket/types.rb +128 -22
- data/lib/cztop/socket.rb +23 -18
- data/lib/cztop/version.rb +5 -1
- data/lib/cztop/z85/padded.rb +12 -3
- data/lib/cztop/z85/pipe.rb +40 -17
- data/lib/cztop/z85.rb +17 -6
- data/lib/cztop/zap.rb +57 -32
- data/lib/cztop/zsock_options.rb +155 -122
- data/lib/cztop.rb +2 -1
- metadata +28 -10
- data/.ruby-version +0 -1
data/lib/cztop/socket/types.rb
CHANGED
@@ -1,29 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CZTop
|
2
4
|
class Socket
|
5
|
+
|
3
6
|
# Socket types. Each constant in this namespace holds the type code used
|
4
7
|
# for the zsock_new() function.
|
5
8
|
module Types
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
|
10
|
+
PAIR = 0
|
11
|
+
PUB = 1
|
12
|
+
SUB = 2
|
13
|
+
REQ = 3
|
14
|
+
REP = 4
|
11
15
|
DEALER = 5
|
12
16
|
ROUTER = 6
|
13
|
-
PULL
|
14
|
-
PUSH
|
15
|
-
XPUB
|
16
|
-
XSUB
|
17
|
+
PULL = 7
|
18
|
+
PUSH = 8
|
19
|
+
XPUB = 9
|
20
|
+
XSUB = 10
|
17
21
|
STREAM = 11
|
18
22
|
SERVER = 12
|
19
23
|
CLIENT = 13
|
24
|
+
|
20
25
|
end
|
21
26
|
|
27
|
+
|
22
28
|
# All the available type codes, mapped to their Symbol equivalent.
|
23
29
|
# @return [Hash<Integer, Symbol>]
|
24
|
-
TypeNames =
|
25
|
-
|
26
|
-
|
30
|
+
TypeNames = Types.constants.to_h do |name|
|
31
|
+
i = Types.const_get(name)
|
32
|
+
[i, name]
|
33
|
+
end.freeze
|
34
|
+
|
27
35
|
|
28
36
|
# @param type [Symbol, Integer] type from {Types} or like +:PUB+
|
29
37
|
# @return [REQ, REP, PUSH, PULL, ... ] the new socket
|
@@ -33,75 +41,108 @@ module CZTop
|
|
33
41
|
def self.new_by_type(type)
|
34
42
|
case type
|
35
43
|
when Integer
|
36
|
-
type_code
|
37
|
-
type_name
|
38
|
-
raise ArgumentError,
|
44
|
+
type_code = type
|
45
|
+
type_name = TypeNames[type_code] or
|
46
|
+
raise ArgumentError, format('invalid type %p', type)
|
39
47
|
type_class = Socket.const_get(type_name)
|
40
48
|
when Symbol
|
41
|
-
type_code
|
49
|
+
type_code = Types.const_get(type)
|
42
50
|
type_class = Socket.const_get(type)
|
43
51
|
else
|
44
|
-
raise ArgumentError,
|
52
|
+
raise ArgumentError, format('invalid socket type: %p', type)
|
45
53
|
end
|
46
54
|
ffi_delegate = Zsock.new(type_code)
|
47
|
-
sock
|
55
|
+
sock = type_class.allocate
|
48
56
|
sock.attach_ffi_delegate(ffi_delegate)
|
49
57
|
sock
|
50
58
|
end
|
51
59
|
|
60
|
+
|
61
|
+
def initialize(endpoints = nil); end
|
62
|
+
|
63
|
+
|
52
64
|
# Client socket for the ZeroMQ Client-Server Pattern.
|
53
65
|
# @see http://rfc.zeromq.org/spec:41
|
54
66
|
class CLIENT < Socket
|
67
|
+
|
55
68
|
# @param endpoints [String] endpoints to connect to
|
56
69
|
def initialize(endpoints = nil)
|
70
|
+
super
|
71
|
+
|
57
72
|
attach_ffi_delegate(Zsock.new_client(endpoints))
|
58
73
|
end
|
74
|
+
|
59
75
|
end
|
60
76
|
|
77
|
+
|
61
78
|
# Server socket for the ZeroMQ Client-Server Pattern.
|
62
79
|
# @see http://rfc.zeromq.org/spec:41
|
63
80
|
class SERVER < Socket
|
81
|
+
|
64
82
|
# @param endpoints [String] endpoints to bind to
|
65
83
|
def initialize(endpoints = nil)
|
84
|
+
super
|
85
|
+
|
66
86
|
attach_ffi_delegate(Zsock.new_server(endpoints))
|
67
87
|
end
|
88
|
+
|
68
89
|
end
|
69
90
|
|
91
|
+
|
70
92
|
# Request socket for the ZeroMQ Request-Reply Pattern.
|
71
93
|
# @see http://rfc.zeromq.org/spec:28
|
72
94
|
class REQ < Socket
|
95
|
+
|
73
96
|
# @param endpoints [String] endpoints to connect to
|
74
97
|
def initialize(endpoints = nil)
|
98
|
+
super
|
99
|
+
|
75
100
|
attach_ffi_delegate(Zsock.new_req(endpoints))
|
76
101
|
end
|
102
|
+
|
77
103
|
end
|
78
104
|
|
105
|
+
|
79
106
|
# Reply socket for the ZeroMQ Request-Reply Pattern.
|
80
107
|
# @see http://rfc.zeromq.org/spec:28
|
81
108
|
class REP < Socket
|
109
|
+
|
82
110
|
# @param endpoints [String] endpoints to bind to
|
83
111
|
def initialize(endpoints = nil)
|
112
|
+
super
|
113
|
+
|
84
114
|
attach_ffi_delegate(Zsock.new_rep(endpoints))
|
85
115
|
end
|
116
|
+
|
86
117
|
end
|
87
118
|
|
119
|
+
|
88
120
|
# Dealer socket for the ZeroMQ Request-Reply Pattern.
|
89
121
|
# @see http://rfc.zeromq.org/spec:28
|
90
122
|
class DEALER < Socket
|
123
|
+
|
91
124
|
# @param endpoints [String] endpoints to connect to
|
92
125
|
def initialize(endpoints = nil)
|
126
|
+
super
|
127
|
+
|
93
128
|
attach_ffi_delegate(Zsock.new_dealer(endpoints))
|
94
129
|
end
|
130
|
+
|
95
131
|
end
|
96
132
|
|
133
|
+
|
97
134
|
# Router socket for the ZeroMQ Request-Reply Pattern.
|
98
135
|
# @see http://rfc.zeromq.org/spec:28
|
99
136
|
class ROUTER < Socket
|
137
|
+
|
100
138
|
# @param endpoints [String] endpoints to bind to
|
101
139
|
def initialize(endpoints = nil)
|
140
|
+
super
|
141
|
+
|
102
142
|
attach_ffi_delegate(Zsock.new_router(endpoints))
|
103
143
|
end
|
104
144
|
|
145
|
+
|
105
146
|
# Send a message to a specific receiver. This is a shorthand for when
|
106
147
|
# you send a message to a specific receiver with no hops in between.
|
107
148
|
# @param receiver [String] receiving peer's socket identity
|
@@ -110,32 +151,42 @@ module CZTop
|
|
110
151
|
# destroyed.
|
111
152
|
def send_to(receiver, message)
|
112
153
|
message = Message.coerce(message)
|
113
|
-
message.prepend
|
154
|
+
message.prepend '' # separator frame
|
114
155
|
message.prepend receiver # receiver envelope
|
115
156
|
self << message
|
116
157
|
end
|
158
|
+
|
117
159
|
end
|
118
160
|
|
161
|
+
|
119
162
|
# Publish socket for the ZeroMQ Publish-Subscribe Pattern.
|
120
163
|
# @see http://rfc.zeromq.org/spec:29
|
121
164
|
class PUB < Socket
|
165
|
+
|
122
166
|
# @param endpoints [String] endpoints to bind to
|
123
167
|
def initialize(endpoints = nil)
|
168
|
+
super
|
169
|
+
|
124
170
|
attach_ffi_delegate(Zsock.new_pub(endpoints))
|
125
171
|
end
|
172
|
+
|
126
173
|
end
|
127
174
|
|
175
|
+
|
128
176
|
# Subscribe socket for the ZeroMQ Publish-Subscribe Pattern.
|
129
177
|
# @see http://rfc.zeromq.org/spec:29
|
130
178
|
class SUB < Socket
|
179
|
+
|
131
180
|
# @param endpoints [String] endpoints to connect to
|
132
181
|
# @param subscription [String] what to subscribe to
|
133
182
|
def initialize(endpoints = nil, subscription = nil)
|
183
|
+
super(endpoints)
|
184
|
+
|
134
185
|
attach_ffi_delegate(Zsock.new_sub(endpoints, subscription))
|
135
186
|
end
|
136
187
|
|
137
188
|
# @return [String] subscription prefix to subscribe to everything
|
138
|
-
EVERYTHING =
|
189
|
+
EVERYTHING = ''
|
139
190
|
|
140
191
|
# Subscribes to the given prefix string.
|
141
192
|
# @param prefix [String] prefix string to subscribe to
|
@@ -144,86 +195,128 @@ module CZTop
|
|
144
195
|
ffi_delegate.set_subscribe(prefix)
|
145
196
|
end
|
146
197
|
|
198
|
+
|
147
199
|
# Unsubscribes from the given prefix.
|
148
200
|
# @param prefix [String] prefix string to unsubscribe from
|
149
201
|
# @return [void]
|
150
202
|
def unsubscribe(prefix)
|
151
203
|
ffi_delegate.set_unsubscribe(prefix)
|
152
204
|
end
|
205
|
+
|
153
206
|
end
|
154
207
|
|
208
|
+
|
155
209
|
# Extended publish socket for the ZeroMQ Publish-Subscribe Pattern.
|
156
210
|
# @see http://rfc.zeromq.org/spec:29
|
157
211
|
class XPUB < Socket
|
212
|
+
|
158
213
|
# @param endpoints [String] endpoints to bind to
|
159
214
|
def initialize(endpoints = nil)
|
215
|
+
super
|
216
|
+
|
160
217
|
attach_ffi_delegate(Zsock.new_xpub(endpoints))
|
161
218
|
end
|
219
|
+
|
162
220
|
end
|
163
221
|
|
222
|
+
|
164
223
|
# Extended subscribe socket for the ZeroMQ Publish-Subscribe Pattern.
|
165
224
|
# @see http://rfc.zeromq.org/spec:29
|
166
225
|
class XSUB < Socket
|
226
|
+
|
167
227
|
# @param endpoints [String] endpoints to connect to
|
168
228
|
def initialize(endpoints = nil)
|
229
|
+
super
|
230
|
+
|
169
231
|
attach_ffi_delegate(Zsock.new_xsub(endpoints))
|
170
232
|
end
|
233
|
+
|
171
234
|
end
|
172
235
|
|
236
|
+
|
173
237
|
# Push socket for the ZeroMQ Pipeline Pattern.
|
174
238
|
# @see http://rfc.zeromq.org/spec:30
|
175
239
|
class PUSH < Socket
|
240
|
+
|
176
241
|
# @param endpoints [String] endpoints to connect to
|
177
242
|
def initialize(endpoints = nil)
|
243
|
+
super
|
244
|
+
|
178
245
|
attach_ffi_delegate(Zsock.new_push(endpoints))
|
179
246
|
end
|
247
|
+
|
180
248
|
end
|
181
249
|
|
250
|
+
|
182
251
|
# Pull socket for the ZeroMQ Pipeline Pattern.
|
183
252
|
# @see http://rfc.zeromq.org/spec:30
|
184
253
|
class PULL < Socket
|
254
|
+
|
185
255
|
# @param endpoints [String] endpoints to bind to
|
186
256
|
def initialize(endpoints = nil)
|
257
|
+
super
|
258
|
+
|
187
259
|
attach_ffi_delegate(Zsock.new_pull(endpoints))
|
188
260
|
end
|
261
|
+
|
189
262
|
end
|
190
263
|
|
264
|
+
|
191
265
|
# Pair socket for inter-thread communication.
|
192
266
|
# @see http://rfc.zeromq.org/spec:31
|
193
267
|
class PAIR < Socket
|
268
|
+
|
194
269
|
# @param endpoints [String] endpoints to connect to
|
195
270
|
def initialize(endpoints = nil)
|
271
|
+
super
|
272
|
+
|
196
273
|
attach_ffi_delegate(Zsock.new_pair(endpoints))
|
197
274
|
end
|
275
|
+
|
198
276
|
end
|
199
277
|
|
278
|
+
|
200
279
|
# Stream socket for the native pattern. This is useful when
|
201
280
|
# communicating with a non-ZMQ peer over TCP.
|
202
281
|
# @see http://api.zeromq.org/4-2:zmq-socket#toc16
|
203
282
|
class STREAM < Socket
|
283
|
+
|
204
284
|
# @param endpoints [String] endpoints to connect to
|
205
285
|
def initialize(endpoints = nil)
|
286
|
+
super
|
287
|
+
|
206
288
|
attach_ffi_delegate(Zsock.new_stream(endpoints))
|
207
289
|
end
|
290
|
+
|
208
291
|
end
|
209
292
|
|
293
|
+
|
210
294
|
# Group-based pub/sub (vs topic-based). This is the publisher socket.
|
211
295
|
# @see https://github.com/zeromq/libzmq/pull/1727
|
212
296
|
class RADIO < Socket
|
297
|
+
|
213
298
|
# @param endpoints [String] endpoints to connect to
|
214
299
|
def initialize(endpoints = nil)
|
300
|
+
super
|
301
|
+
|
215
302
|
attach_ffi_delegate(Zsock.new_radio(endpoints))
|
216
303
|
end
|
304
|
+
|
217
305
|
end
|
218
306
|
|
307
|
+
|
219
308
|
# Group-based pub/sub (vs topic-based). This is the subscriber socket.
|
220
309
|
# @see https://github.com/zeromq/libzmq/pull/1727
|
221
310
|
class DISH < Socket
|
311
|
+
|
222
312
|
# @param endpoints [String] endpoints to connect to
|
223
313
|
def initialize(endpoints = nil)
|
314
|
+
super
|
315
|
+
|
224
316
|
attach_ffi_delegate(Zsock.new_dish(endpoints))
|
225
317
|
end
|
226
318
|
|
319
|
+
|
227
320
|
# Joins the given group.
|
228
321
|
# @param group [String] group to join, up to 15 characters
|
229
322
|
# @return [void]
|
@@ -232,9 +325,10 @@ module CZTop
|
|
232
325
|
# @raise [SystemCallError] in case of failure
|
233
326
|
def join(group)
|
234
327
|
rc = ffi_delegate.join(group)
|
235
|
-
raise_zmq_err(
|
328
|
+
raise_zmq_err(format('unable to join group %p', group)) if rc == -1
|
236
329
|
end
|
237
330
|
|
331
|
+
|
238
332
|
# Leaves the given group.
|
239
333
|
# @param group [String] group to leave
|
240
334
|
# @return [void]
|
@@ -242,26 +336,38 @@ module CZTop
|
|
242
336
|
# @raise [SystemCallError] in case of another failure
|
243
337
|
def leave(group)
|
244
338
|
rc = ffi_delegate.leave(group)
|
245
|
-
raise_zmq_err(
|
339
|
+
raise_zmq_err(format('unable to leave group %p', group)) if rc == -1
|
246
340
|
end
|
341
|
+
|
247
342
|
end
|
248
343
|
|
344
|
+
|
249
345
|
# Scatter/gather pattern.
|
250
346
|
# @see https://github.com/zeromq/libzmq/pull/1909
|
251
347
|
class SCATTER < Socket
|
348
|
+
|
252
349
|
# @param endpoints [String] endpoints to connect to
|
253
350
|
def initialize(endpoints = nil)
|
351
|
+
super
|
352
|
+
|
254
353
|
attach_ffi_delegate(Zsock.new_scatter(endpoints))
|
255
354
|
end
|
355
|
+
|
256
356
|
end
|
257
357
|
|
358
|
+
|
258
359
|
# Scatter/gather pattern.
|
259
360
|
# @see https://github.com/zeromq/libzmq/pull/1909
|
260
361
|
class GATHER < Socket
|
362
|
+
|
261
363
|
# @param endpoints [String] endpoints to connect to
|
262
364
|
def initialize(endpoints = nil)
|
365
|
+
super
|
366
|
+
|
263
367
|
attach_ffi_delegate(Zsock.new_gather(endpoints))
|
264
368
|
end
|
369
|
+
|
265
370
|
end
|
371
|
+
|
266
372
|
end
|
267
373
|
end
|
data/lib/cztop/socket.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CZTop
|
2
4
|
# Represents a CZMQ::FFI::Zsock.
|
3
5
|
class Socket
|
6
|
+
|
4
7
|
include HasFFIDelegate
|
5
8
|
extend CZTop::HasFFIDelegate::ClassMethods
|
6
9
|
include ZsockOptions
|
@@ -21,6 +24,7 @@ module CZTop
|
|
21
24
|
cert.apply(self) # NOTE: desired: raises if no secret key in cert
|
22
25
|
end
|
23
26
|
|
27
|
+
|
24
28
|
# Enables CURVE security and makes this socket a CURVE client.
|
25
29
|
# @param client_cert [Certificate] client's certificate, to secure
|
26
30
|
# communication (and be authenticated by the server)
|
@@ -31,9 +35,7 @@ module CZTop
|
|
31
35
|
# which means it's not secret anymore
|
32
36
|
# @raise [SystemCallError] if there's no secret key in client_cert
|
33
37
|
def CURVE_client!(client_cert, server_cert)
|
34
|
-
if server_cert.secret_key
|
35
|
-
raise SecurityError, "server's secret key not secret"
|
36
|
-
end
|
38
|
+
raise SecurityError, "server's secret key not secret" if server_cert.secret_key
|
37
39
|
|
38
40
|
client_cert.apply(self) # NOTE: desired: raises if no secret key in cert
|
39
41
|
options.CURVE_serverkey = server_cert.public_key
|
@@ -41,30 +43,34 @@ module CZTop
|
|
41
43
|
|
42
44
|
# @!endgroup
|
43
45
|
|
46
|
+
|
44
47
|
# @return [String] last bound endpoint, if any
|
45
48
|
# @return [nil] if not bound
|
46
49
|
def last_endpoint
|
47
50
|
ffi_delegate.endpoint
|
48
51
|
end
|
49
52
|
|
53
|
+
|
50
54
|
# Connects to an endpoint.
|
51
55
|
# @param endpoint [String]
|
52
56
|
# @return [void]
|
53
57
|
# @raise [ArgumentError] if the endpoint is incorrect
|
54
58
|
def connect(endpoint)
|
55
|
-
rc = ffi_delegate.connect(
|
56
|
-
raise ArgumentError,
|
59
|
+
rc = ffi_delegate.connect('%s', :string, endpoint)
|
60
|
+
raise ArgumentError, format('incorrect endpoint: %p', endpoint) if rc == -1
|
57
61
|
end
|
58
62
|
|
63
|
+
|
59
64
|
# Disconnects from an endpoint.
|
60
65
|
# @param endpoint [String]
|
61
66
|
# @return [void]
|
62
67
|
# @raise [ArgumentError] if the endpoint is incorrect
|
63
68
|
def disconnect(endpoint)
|
64
|
-
rc = ffi_delegate.disconnect(
|
65
|
-
raise ArgumentError,
|
69
|
+
rc = ffi_delegate.disconnect('%s', :string, endpoint)
|
70
|
+
raise ArgumentError, format('incorrect endpoint: %p', endpoint) if rc == -1
|
66
71
|
end
|
67
72
|
|
73
|
+
|
68
74
|
# Closes and destroys the native socket.
|
69
75
|
# @return [void]
|
70
76
|
# @note Don't try to use it anymore afterwards.
|
@@ -83,30 +89,29 @@ module CZTop
|
|
83
89
|
# @return [void]
|
84
90
|
# @raise [SystemCallError] in case of failure
|
85
91
|
def bind(endpoint)
|
86
|
-
rc = ffi_delegate.bind(
|
87
|
-
raise_zmq_err(
|
88
|
-
@last_tcp_port = rc if rc
|
92
|
+
rc = ffi_delegate.bind('%s', :string, endpoint)
|
93
|
+
raise_zmq_err(format('unable to bind to %p', endpoint)) if rc == -1
|
94
|
+
@last_tcp_port = rc if rc.positive?
|
89
95
|
end
|
90
96
|
|
97
|
+
|
91
98
|
# Unbinds from an endpoint.
|
92
99
|
# @param endpoint [String]
|
93
100
|
# @return [void]
|
94
101
|
# @raise [ArgumentError] if the endpoint is incorrect
|
95
102
|
def unbind(endpoint)
|
96
|
-
rc = ffi_delegate.unbind(
|
97
|
-
raise ArgumentError,
|
103
|
+
rc = ffi_delegate.unbind('%s', :string, endpoint)
|
104
|
+
raise ArgumentError, format('incorrect endpoint: %p', endpoint) if rc == -1
|
98
105
|
end
|
99
106
|
|
107
|
+
|
100
108
|
# Inspects this {Socket}.
|
101
109
|
# @return [String] shows class, native address, and {#last_endpoint}
|
102
110
|
def inspect
|
103
|
-
|
104
|
-
self.class,
|
105
|
-
to_ptr.address,
|
106
|
-
last_endpoint
|
107
|
-
]
|
111
|
+
format('#<%s:0x%x last_endpoint=%p>', self.class, to_ptr.address, last_endpoint)
|
108
112
|
rescue Zsock::DestroyedError
|
109
|
-
|
113
|
+
format('#<%s: invalid>', self.class)
|
110
114
|
end
|
115
|
+
|
111
116
|
end
|
112
117
|
end
|
data/lib/cztop/version.rb
CHANGED
data/lib/cztop/z85/padded.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Z85 with simple padding. This allows you to {#encode} input of any
|
2
4
|
# length.
|
3
5
|
#
|
@@ -29,7 +31,9 @@
|
|
29
31
|
#
|
30
32
|
# @see https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7
|
31
33
|
class CZTop::Z85::Padded < CZTop::Z85
|
34
|
+
|
32
35
|
class << self
|
36
|
+
|
33
37
|
# Same as {Z85::Padded#encode}, but without the need to create an
|
34
38
|
# instance first.
|
35
39
|
#
|
@@ -41,6 +45,7 @@ class CZTop::Z85::Padded < CZTop::Z85
|
|
41
45
|
default.encode(input)
|
42
46
|
end
|
43
47
|
|
48
|
+
|
44
49
|
# Same as {Z85::Padded#decode}, but without the need to create an
|
45
50
|
# instance first.
|
46
51
|
#
|
@@ -59,6 +64,7 @@ class CZTop::Z85::Padded < CZTop::Z85
|
|
59
64
|
def default
|
60
65
|
@default ||= CZTop::Z85::Padded.new
|
61
66
|
end
|
67
|
+
|
62
68
|
end
|
63
69
|
|
64
70
|
# Encododes to Z85, with padding if needed.
|
@@ -72,14 +78,15 @@ class CZTop::Z85::Padded < CZTop::Z85
|
|
72
78
|
padding_bytes = 4 - (input.bytesize % 4)
|
73
79
|
|
74
80
|
# if 0, make it 4. we MUST append padding.
|
75
|
-
padding_bytes = 4 if padding_bytes
|
81
|
+
padding_bytes = 4 if padding_bytes.zero?
|
76
82
|
|
77
83
|
# generate and append padding
|
78
|
-
padding = [padding_bytes].pack(
|
84
|
+
padding = [padding_bytes].pack('C') * padding_bytes
|
79
85
|
|
80
86
|
super("#{input}#{padding}")
|
81
87
|
end
|
82
88
|
|
89
|
+
|
83
90
|
# Decodes from Z85 with padding.
|
84
91
|
#
|
85
92
|
# @param input [String] Z85 encoded data (including padding, or empty
|
@@ -88,11 +95,13 @@ class CZTop::Z85::Padded < CZTop::Z85
|
|
88
95
|
# @raise [SystemCallError] if this fails
|
89
96
|
def decode(input)
|
90
97
|
return super if input.empty?
|
98
|
+
|
91
99
|
decoded = super
|
92
100
|
|
93
101
|
# last byte contains number of padding bytes
|
94
102
|
padding_bytes = decoded.byteslice(-1).ord
|
95
103
|
|
96
|
-
decoded.byteslice(
|
104
|
+
decoded.byteslice(0...-padding_bytes)
|
97
105
|
end
|
106
|
+
|
98
107
|
end
|