cztop 0.14.1 → 1.1.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/coverage.yml +20 -0
- data/.github/workflows/draft_api.yml +27 -0
- data/.github/workflows/stable_api.yml +26 -0
- data/.rubocop.yml +175 -0
- data/CHANGES.md +9 -4
- data/Gemfile +3 -7
- data/README.md +19 -58
- data/ci/install-libczmq +22 -0
- data/ci/install-libzmq +22 -0
- data/cztop.gemspec +12 -13
- 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 +25 -90
- data/.gitlab-ci.yml +0 -32
- data/Guardfile +0 -61
- data/Procfile +0 -3
- data/ci-scripts/install-deps +0 -8
data/lib/cztop/certificate.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CZTop
|
2
4
|
# Represents a CZMQ::FFI::Zcert.
|
3
5
|
class Certificate
|
6
|
+
|
4
7
|
include HasFFIDelegate
|
5
8
|
extend CZTop::HasFFIDelegate::ClassMethods
|
6
9
|
include ::CZMQ::FFI
|
@@ -9,9 +12,11 @@ module CZTop
|
|
9
12
|
# @return [void]
|
10
13
|
def self.check_curve_availability
|
11
14
|
return if Zsys.has_curve
|
15
|
+
|
12
16
|
warn "CZTop: CURVE isn't available. Consider installing libsodium."
|
13
17
|
end
|
14
18
|
|
19
|
+
|
15
20
|
# Loads a certificate from a file.
|
16
21
|
# @param filename [String, Pathname, #to_s] path to certificate file
|
17
22
|
# @return [Certificate] the loaded certificate
|
@@ -20,6 +25,7 @@ module CZTop
|
|
20
25
|
from_ffi_delegate(ptr)
|
21
26
|
end
|
22
27
|
|
28
|
+
|
23
29
|
# Creates a new certificate from the given keys (either binary or in Z85
|
24
30
|
# format).
|
25
31
|
# @param public_key [String] binary public key (32 or 40 bytes)
|
@@ -29,25 +35,28 @@ module CZTop
|
|
29
35
|
# @raise [ArgumentError] if keys passed are invalid
|
30
36
|
# @raise [SystemCallError] if this fails
|
31
37
|
def self.new_from(public_key, secret_key = nil)
|
32
|
-
raise ArgumentError,
|
38
|
+
raise ArgumentError, 'no public key given' unless public_key
|
39
|
+
|
33
40
|
secret_key ||= "\x00" * 32 # no secret key given, provide 32 null bytes
|
34
41
|
|
35
42
|
# convert Z85 => binary
|
36
43
|
public_key = Z85.decode(public_key) if public_key.bytesize == 40
|
37
44
|
secret_key = Z85.decode(secret_key) if secret_key.bytesize == 40
|
38
45
|
|
39
|
-
raise ArgumentError,
|
40
|
-
raise ArgumentError,
|
46
|
+
raise ArgumentError, 'invalid public key size' if public_key.bytesize != 32
|
47
|
+
raise ArgumentError, 'invalid secret key size' if secret_key.bytesize != 32
|
41
48
|
|
42
49
|
ptr = Zcert.new_from(public_key, secret_key)
|
43
50
|
from_ffi_delegate(ptr)
|
44
51
|
end
|
45
52
|
|
53
|
+
|
46
54
|
# Initialize a new in-memory certificate with random keys.
|
47
55
|
def initialize
|
48
56
|
attach_ffi_delegate(Zcert.new)
|
49
57
|
end
|
50
58
|
|
59
|
+
|
51
60
|
# Returns the public key either as Z85-encoded ASCII string (default) or
|
52
61
|
# binary string.
|
53
62
|
# @param format [Symbol] +:z85+ for Z85, +:binary+ for binary
|
@@ -59,10 +68,11 @@ module CZTop
|
|
59
68
|
when :binary
|
60
69
|
ffi_delegate.public_key.read_string(32)
|
61
70
|
else
|
62
|
-
raise ArgumentError,
|
71
|
+
raise ArgumentError, format('invalid format: %p', format)
|
63
72
|
end
|
64
73
|
end
|
65
74
|
|
75
|
+
|
66
76
|
# Returns the secret key either as Z85-encoded ASCII string (default) or
|
67
77
|
# binary string.
|
68
78
|
# @param format [Symbol] +:z85+ for Z85, +:binary+ for binary
|
@@ -73,16 +83,17 @@ module CZTop
|
|
73
83
|
case format
|
74
84
|
when :z85
|
75
85
|
key = ffi_delegate.secret_txt.force_encoding(Encoding::ASCII)
|
76
|
-
return nil if key.count(
|
86
|
+
return nil if key.count('0') == 40
|
77
87
|
when :binary
|
78
88
|
key = ffi_delegate.secret_key.read_string(32)
|
79
89
|
return nil if key.count("\0") == 32
|
80
90
|
else
|
81
|
-
raise ArgumentError,
|
91
|
+
raise ArgumentError, format('invalid format: %p', format)
|
82
92
|
end
|
83
93
|
key
|
84
94
|
end
|
85
95
|
|
96
|
+
|
86
97
|
# Get metadata.
|
87
98
|
# @param key [String] metadata key
|
88
99
|
# @return [String] value for meta key
|
@@ -90,32 +101,38 @@ module CZTop
|
|
90
101
|
def [](key)
|
91
102
|
ffi_delegate.meta(key)
|
92
103
|
end
|
104
|
+
|
105
|
+
|
93
106
|
# Set metadata.
|
94
107
|
# @param key [String] metadata key
|
95
108
|
# @param value [String] metadata value
|
96
109
|
# @return [value]
|
97
110
|
def []=(key, value)
|
98
111
|
if value
|
99
|
-
ffi_delegate.set_meta(key,
|
112
|
+
ffi_delegate.set_meta(key, '%s', :string, value)
|
100
113
|
else
|
101
114
|
ffi_delegate.unset_meta(key)
|
102
115
|
end
|
103
116
|
end
|
104
117
|
|
118
|
+
|
105
119
|
# Returns meta keys set.
|
106
120
|
# @return [Array<String>]
|
107
121
|
def meta_keys
|
108
|
-
zlist
|
122
|
+
zlist = ffi_delegate.meta_keys
|
109
123
|
first_key = zlist.first
|
110
124
|
return [] if first_key.null?
|
125
|
+
|
111
126
|
keys = [first_key.read_string]
|
112
|
-
while key = zlist.next
|
127
|
+
while (key = zlist.next)
|
113
128
|
break if key.null?
|
129
|
+
|
114
130
|
keys << key.read_string
|
115
131
|
end
|
116
132
|
keys
|
117
133
|
end
|
118
134
|
|
135
|
+
|
119
136
|
# Save full certificate (public + secret) to files.
|
120
137
|
# @param filename [String, #to_s] path/filename to public file
|
121
138
|
# @return [void]
|
@@ -126,55 +143,67 @@ module CZTop
|
|
126
143
|
def save(filename)
|
127
144
|
# see https://github.com/zeromq/czmq/issues/1244
|
128
145
|
raise ArgumentError, "filename can't be empty" if filename.to_s.empty?
|
146
|
+
|
129
147
|
rc = ffi_delegate.save(filename.to_s)
|
130
|
-
return if rc
|
131
|
-
|
148
|
+
return if rc.zero?
|
149
|
+
|
150
|
+
raise_zmq_err(format('error while saving to file %p', filename))
|
132
151
|
end
|
133
152
|
|
153
|
+
|
134
154
|
# Saves the public key to file in ZPL ({Config}) format.
|
135
155
|
# @param filename [String, #to_s] path/filename to public file
|
136
156
|
# @return [void]
|
137
157
|
# @raise [SystemCallError] if this fails
|
138
158
|
def save_public(filename)
|
139
159
|
rc = ffi_delegate.save_public(filename.to_s)
|
140
|
-
return if rc
|
141
|
-
|
160
|
+
return if rc.zero?
|
161
|
+
|
162
|
+
raise_zmq_err(format('error while saving to the file %p', filename))
|
142
163
|
end
|
143
164
|
|
165
|
+
|
144
166
|
# Saves the secret key to file in ZPL ({Config}) format.
|
145
167
|
# @param filename [String, #to_s] path/filename to secret file
|
146
168
|
# @return [void]
|
147
169
|
# @raise [SystemCallError] if this fails
|
148
170
|
def save_secret(filename)
|
149
171
|
rc = ffi_delegate.save_secret(filename.to_s)
|
150
|
-
return if rc
|
151
|
-
|
172
|
+
return if rc.zero?
|
173
|
+
|
174
|
+
raise_zmq_err(format('error while saving to the file %p', filename))
|
152
175
|
end
|
153
176
|
|
177
|
+
|
154
178
|
# Applies this certificate on a {Socket} or {Actor}.
|
155
179
|
# @param zocket [Socket, Actor] path/filename to secret file
|
156
180
|
# @return [void]
|
157
181
|
# @raise [SystemCallError] if secret key is undefined
|
158
182
|
def apply(zocket)
|
159
|
-
raise ArgumentError,
|
183
|
+
raise ArgumentError, format('invalid zocket argument %p', zocket) unless zocket
|
160
184
|
return ffi_delegate.apply(zocket) unless secret_key.nil?
|
161
|
-
|
185
|
+
|
186
|
+
raise_zmq_err('secret key is undefined')
|
162
187
|
end
|
163
188
|
|
189
|
+
|
164
190
|
# Duplicates the certificate.
|
165
191
|
# @return [Certificate]
|
166
192
|
# @raise [SystemCallError] if this fails
|
167
193
|
def dup
|
168
194
|
ptr = ffi_delegate.dup
|
169
195
|
return from_ffi_delegate(ptr) unless ptr.null?
|
170
|
-
|
196
|
+
|
197
|
+
raise_zmq_err('unable to duplicate certificate')
|
171
198
|
end
|
172
199
|
|
200
|
+
|
173
201
|
# Compares this certificate to another.
|
174
202
|
# @param other [Cert] other certificate
|
175
203
|
# @return [Boolean] whether they have the same keys
|
176
204
|
def ==(other)
|
177
205
|
ffi_delegate.eq(other.ffi_delegate)
|
178
206
|
end
|
207
|
+
|
179
208
|
end
|
180
209
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CZTop
|
2
4
|
class Config
|
3
5
|
|
@@ -7,11 +9,13 @@ module CZTop
|
|
7
9
|
# are accessible.
|
8
10
|
# @return [CommentsAccessor]
|
9
11
|
def comments
|
10
|
-
|
12
|
+
CommentsAccessor.new(self)
|
11
13
|
end
|
12
14
|
|
15
|
+
|
13
16
|
# Used to access a {Config}'s comments.
|
14
17
|
class CommentsAccessor
|
18
|
+
|
15
19
|
include Enumerable
|
16
20
|
|
17
21
|
# @param config [Config]
|
@@ -19,26 +23,30 @@ module CZTop
|
|
19
23
|
@config = config
|
20
24
|
end
|
21
25
|
|
26
|
+
|
22
27
|
# Adds a new comment.
|
23
28
|
# @param new_comment [String]
|
24
29
|
# @return [self]
|
25
30
|
def <<(new_comment)
|
26
|
-
@config.ffi_delegate.set_comment(
|
27
|
-
|
31
|
+
@config.ffi_delegate.set_comment('%s', :string, new_comment)
|
32
|
+
self
|
28
33
|
end
|
29
34
|
|
35
|
+
|
30
36
|
# Deletes all comments for this {Config} item.
|
31
37
|
# @return [void]
|
32
38
|
def delete_all
|
33
39
|
@config.ffi_delegate.set_comment(nil)
|
34
40
|
end
|
35
41
|
|
42
|
+
|
36
43
|
# Yields all comments for this {Config} item.
|
37
44
|
# @yieldparam comment [String]
|
38
45
|
# @return [void]
|
39
46
|
def each
|
40
47
|
while comment = _zlist.next
|
41
48
|
break if comment.null?
|
49
|
+
|
42
50
|
yield comment.read_string
|
43
51
|
end
|
44
52
|
rescue CZMQ::FFI::Zlist::DestroyedError
|
@@ -46,6 +54,7 @@ module CZTop
|
|
46
54
|
nil
|
47
55
|
end
|
48
56
|
|
57
|
+
|
49
58
|
# Returns the number of comments for this {Config} item.
|
50
59
|
# @return [Integer] number of comments
|
51
60
|
def size
|
@@ -61,6 +70,8 @@ module CZTop
|
|
61
70
|
def _zlist
|
62
71
|
@config.ffi_delegate.comments
|
63
72
|
end
|
73
|
+
|
64
74
|
end
|
75
|
+
|
65
76
|
end
|
66
77
|
end
|
@@ -1,19 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Methods used around serialization of {CZTop::Config} items.
|
2
4
|
module CZTop::Config::Serialization
|
5
|
+
|
3
6
|
# Serialize to a string in the ZPL format.
|
4
7
|
# @return [String]
|
5
8
|
def to_s
|
6
9
|
ffi_delegate.str_save.read_string
|
7
10
|
end
|
8
11
|
|
12
|
+
|
9
13
|
# Returns the path/filename of the file this {Config} tree was loaded from.
|
10
14
|
# @return [String]
|
11
15
|
def filename
|
12
16
|
ffi_delegate.filename
|
13
17
|
end
|
14
18
|
|
19
|
+
|
15
20
|
# Some class methods for {Config} related to serialization.
|
16
21
|
module ClassMethods
|
22
|
+
|
17
23
|
# Loads a {Config} tree from a string.
|
18
24
|
# @param string [String] the tree
|
19
25
|
# @return [Config]
|
@@ -21,6 +27,7 @@ module CZTop::Config::Serialization
|
|
21
27
|
from_ffi_delegate CZMQ::FFI::Zconfig.str_load(string)
|
22
28
|
end
|
23
29
|
|
30
|
+
|
24
31
|
# Loads a {Config} tree from a file.
|
25
32
|
# @param path [String, Pathname, #to_s] the path to the ZPL config file
|
26
33
|
# @raise [SystemCallError] if this fails
|
@@ -28,10 +35,13 @@ module CZTop::Config::Serialization
|
|
28
35
|
def load(path)
|
29
36
|
ptr = CZMQ::FFI::Zconfig.load(path.to_s)
|
30
37
|
return from_ffi_delegate(ptr) unless ptr.null?
|
38
|
+
|
31
39
|
CZTop::HasFFIDelegate.raise_zmq_err(
|
32
|
-
|
40
|
+
format('error while reading the file %p', path.to_s)
|
41
|
+
)
|
33
42
|
end
|
34
43
|
|
44
|
+
|
35
45
|
# Loads a {Config} tree from a marshalled string.
|
36
46
|
# @note This method is automatically used by Marshal.load.
|
37
47
|
# @param string [String] marshalled {Config}
|
@@ -39,18 +49,22 @@ module CZTop::Config::Serialization
|
|
39
49
|
def _load(string)
|
40
50
|
from_string(string)
|
41
51
|
end
|
52
|
+
|
42
53
|
end
|
43
54
|
|
55
|
+
|
44
56
|
# Saves the Config tree to a file.
|
45
57
|
# @param path [String, Pathname, #to_s] the path to the ZPL config file
|
46
58
|
# @return [void]
|
47
59
|
# @raise [SystemCallError] if this fails
|
48
60
|
def save(path)
|
49
61
|
rc = ffi_delegate.save(path.to_s)
|
50
|
-
return if rc
|
51
|
-
|
62
|
+
return if rc.zero?
|
63
|
+
|
64
|
+
raise_zmq_err(format('error while saving to the file %s', path))
|
52
65
|
end
|
53
66
|
|
67
|
+
|
54
68
|
# Reload config tree from same file that it was previously loaded from.
|
55
69
|
# @raise [TypeError] if this is an in-memory config
|
56
70
|
# @raise [SystemCallError] if this fails (no existing data will be
|
@@ -62,11 +76,13 @@ module CZTop::Config::Serialization
|
|
62
76
|
# swap out the FFI delegate.
|
63
77
|
filename = filename() or
|
64
78
|
raise TypeError, "can't reload in-memory config"
|
65
|
-
ptr
|
79
|
+
ptr = CZMQ::FFI::Zconfig.load(filename)
|
66
80
|
return attach_ffi_delegate(ptr) unless ptr.null?
|
67
|
-
|
81
|
+
|
82
|
+
raise_zmq_err(format('error while reloading from the file %p', filename))
|
68
83
|
end
|
69
84
|
|
85
|
+
|
70
86
|
# Serialize (marshal) this Config and all its children.
|
71
87
|
#
|
72
88
|
# @note This method is automatically used by Marshal.dump.
|
@@ -74,9 +90,13 @@ module CZTop::Config::Serialization
|
|
74
90
|
def _dump(_level)
|
75
91
|
to_s
|
76
92
|
end
|
93
|
+
|
77
94
|
end
|
78
95
|
|
96
|
+
|
79
97
|
class CZTop::Config
|
98
|
+
|
80
99
|
include Serialization
|
81
100
|
extend Serialization::ClassMethods
|
101
|
+
|
82
102
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Methods used to traverse a {CZTop::Config} tree.
|
2
4
|
module CZTop::Config::Traversing
|
3
5
|
|
@@ -12,24 +14,25 @@ module CZTop::Config::Traversing
|
|
12
14
|
# @raise [Exception] the block's exception, in case it raises (it won't
|
13
15
|
# call the block any more after that)
|
14
16
|
def execute
|
15
|
-
raise ArgumentError,
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
raise ArgumentError, 'no block given' unless block_given?
|
18
|
+
|
19
|
+
exception = nil
|
20
|
+
block_value = nil
|
21
|
+
ret = nil
|
22
|
+
callback = CZMQ::FFI::Zconfig.fct do |zconfig, _arg, level|
|
20
23
|
begin
|
21
24
|
# NOTE: work around JRuby and Rubinius bug, where it'd keep calling
|
22
25
|
# this FFI::Function, even when the block `break`ed
|
23
26
|
if ret != -1
|
24
|
-
config
|
27
|
+
config = from_ffi_delegate(zconfig)
|
25
28
|
block_value = yield config, level
|
26
|
-
ret
|
29
|
+
ret = 0 # report success to keep zconfig_execute() going
|
27
30
|
end
|
28
|
-
rescue
|
31
|
+
rescue StandardError
|
29
32
|
# remember exception, so we can raise it later to the ruby code
|
30
33
|
# (it can't be raised now, as we have to report failure to
|
31
34
|
# zconfig_execute())
|
32
|
-
exception =
|
35
|
+
exception = $ERROR_INFO
|
33
36
|
|
34
37
|
ret = -1 # report failure to stop zconfig_execute() immediately
|
35
38
|
ensure
|
@@ -39,15 +42,18 @@ module CZTop::Config::Traversing
|
|
39
42
|
end
|
40
43
|
ffi_delegate.execute(callback, _arg = nil)
|
41
44
|
raise exception if exception
|
42
|
-
|
45
|
+
|
46
|
+
block_value
|
43
47
|
end
|
44
48
|
|
49
|
+
|
45
50
|
# Access to this config item's direct children.
|
46
51
|
# @return [ChildrenAccessor]
|
47
52
|
def children
|
48
53
|
ChildrenAccessor.new(self)
|
49
54
|
end
|
50
55
|
|
56
|
+
|
51
57
|
# Access to this config item's siblings.
|
52
58
|
# @note Only the "younger" (later in the ZPL file) config items are
|
53
59
|
# considered.
|
@@ -56,9 +62,11 @@ module CZTop::Config::Traversing
|
|
56
62
|
SiblingsAccessor.new(self)
|
57
63
|
end
|
58
64
|
|
65
|
+
|
59
66
|
# Used to give access to a {Config} item's children or siblings.
|
60
67
|
# @abstract
|
61
68
|
class FamilyAccessor
|
69
|
+
|
62
70
|
include Enumerable
|
63
71
|
|
64
72
|
# @param config [Config] the relative starting point (either parent or
|
@@ -67,25 +75,30 @@ module CZTop::Config::Traversing
|
|
67
75
|
@config = config
|
68
76
|
end
|
69
77
|
|
78
|
+
|
70
79
|
# This is supposed to return the first relevant config item.
|
71
80
|
# @abstract
|
72
81
|
# @return [Config, nil]
|
73
82
|
def first; end
|
74
83
|
|
84
|
+
|
75
85
|
# Yields all direct children/younger siblings. Starts with {#first}, if
|
76
86
|
# set.
|
77
87
|
# @yieldparam config [Config]
|
78
88
|
def each
|
79
|
-
current = first
|
89
|
+
current = first
|
80
90
|
return if current.nil?
|
91
|
+
|
81
92
|
yield current
|
82
|
-
current_delegate
|
93
|
+
current_delegate = current.ffi_delegate
|
83
94
|
while current_delegate = current_delegate.next
|
84
95
|
break if current_delegate.null?
|
96
|
+
|
85
97
|
yield CZTop::Config.from_ffi_delegate(current_delegate)
|
86
98
|
end
|
87
99
|
end
|
88
100
|
|
101
|
+
|
89
102
|
# Recursively compares these config items with the ones of the other.
|
90
103
|
# @param other [FamilyAccessor]
|
91
104
|
def ==(other)
|
@@ -94,30 +107,39 @@ module CZTop::Config::Traversing
|
|
94
107
|
these.size == those.size && these.zip(those) do |this, that|
|
95
108
|
this.tree_equal?(that) or return false
|
96
109
|
end
|
97
|
-
|
110
|
+
true
|
98
111
|
end
|
112
|
+
|
99
113
|
end
|
100
114
|
|
115
|
+
|
101
116
|
# Accesses the younger siblings of a given {Config} item.
|
102
117
|
class SiblingsAccessor < FamilyAccessor
|
118
|
+
|
103
119
|
# Returns the first sibling.
|
104
120
|
# @return [Config]
|
105
121
|
# @return [nil] if no younger siblings
|
106
122
|
def first
|
107
123
|
ptr = @config.ffi_delegate.next
|
108
124
|
return nil if ptr.null?
|
125
|
+
|
109
126
|
CZTop::Config.from_ffi_delegate(ptr)
|
110
127
|
end
|
128
|
+
|
111
129
|
end
|
112
130
|
|
131
|
+
|
113
132
|
# Accesses the direct children of a given {Config} item.
|
114
133
|
class ChildrenAccessor < FamilyAccessor
|
134
|
+
|
115
135
|
def first
|
116
136
|
ptr = @config.ffi_delegate.child
|
117
137
|
return nil if ptr.null?
|
138
|
+
|
118
139
|
CZTop::Config.from_ffi_delegate(ptr)
|
119
140
|
end
|
120
141
|
|
142
|
+
|
121
143
|
# Adds a new Config item and yields it, so it can be configured in
|
122
144
|
# a block.
|
123
145
|
# @param name [String] name for new config item
|
@@ -129,8 +151,10 @@ module CZTop::Config::Traversing
|
|
129
151
|
yield config if block_given?
|
130
152
|
config
|
131
153
|
end
|
154
|
+
|
132
155
|
end
|
133
156
|
|
157
|
+
|
134
158
|
# Finds a config item along a path, relative to the current item.
|
135
159
|
# @param path [String] path (leading slash is optional and will be
|
136
160
|
# ignored)
|
@@ -139,19 +163,26 @@ module CZTop::Config::Traversing
|
|
139
163
|
def locate(path)
|
140
164
|
ptr = ffi_delegate.locate(path)
|
141
165
|
return nil if ptr.null?
|
166
|
+
|
142
167
|
from_ffi_delegate(ptr)
|
143
168
|
end
|
144
169
|
|
170
|
+
|
145
171
|
# Finds last item at given level (0 = root).
|
146
172
|
# @return [Config] the last config item at given level
|
147
173
|
# @return [nil] if there's no config item at given level
|
148
174
|
def last_at_depth(level)
|
149
175
|
ptr = ffi_delegate.at_depth(level)
|
150
176
|
return nil if ptr.null?
|
177
|
+
|
151
178
|
from_ffi_delegate(ptr)
|
152
179
|
end
|
180
|
+
|
153
181
|
end
|
154
182
|
|
183
|
+
|
155
184
|
class CZTop::Config
|
185
|
+
|
156
186
|
include Traversing
|
187
|
+
|
157
188
|
end
|
data/lib/cztop/config.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CZTop
|
3
4
|
# Represents a CZMQ::FFI::Zconfig item.
|
4
5
|
# @see http://rfc.zeromq.org/spec:4/ZPL
|
5
6
|
class Config
|
7
|
+
|
6
8
|
include HasFFIDelegate
|
7
9
|
extend CZTop::HasFFIDelegate::ClassMethods
|
8
10
|
|
11
|
+
|
9
12
|
# Initializes a new {Config} item. Takes an optional block to initialize
|
10
13
|
# the item further.
|
11
14
|
# @param name [String] config item name
|
@@ -17,7 +20,7 @@ module CZTop
|
|
17
20
|
# {Config} object is garbage collected).
|
18
21
|
def initialize(name = nil, value = nil, parent: nil)
|
19
22
|
if parent
|
20
|
-
parent
|
23
|
+
parent = parent.ffi_delegate if parent.is_a?(Config)
|
21
24
|
delegate = ::CZMQ::FFI::Zconfig.new(name, parent)
|
22
25
|
attach_ffi_delegate(delegate)
|
23
26
|
|
@@ -42,9 +45,11 @@ module CZTop
|
|
42
45
|
def name
|
43
46
|
ptr = ffi_delegate.name
|
44
47
|
return nil if ptr.null? # NOTE: for unnamed elements
|
48
|
+
|
45
49
|
ptr.read_string
|
46
50
|
end
|
47
51
|
|
52
|
+
|
48
53
|
# Sets a new name.
|
49
54
|
# @param new_name [String, #to_s]
|
50
55
|
# @return [new_name]
|
@@ -52,28 +57,33 @@ module CZTop
|
|
52
57
|
ffi_delegate.set_name(new_name.to_s)
|
53
58
|
end
|
54
59
|
|
60
|
+
|
55
61
|
# Get the value of the config item.
|
56
62
|
# @return [String]
|
57
63
|
# @note This returns an empty string if the value is unset.
|
58
64
|
def value
|
59
65
|
ptr = ffi_delegate.value
|
60
|
-
return
|
66
|
+
return '' if ptr.null? # NOTE: for root elements
|
67
|
+
|
61
68
|
ptr.read_string
|
62
69
|
end
|
63
70
|
|
71
|
+
|
64
72
|
# Set or update the value of the config item.
|
65
73
|
# @param new_value [String, #to_s]
|
66
74
|
# @return [new_value]
|
67
75
|
def value=(new_value)
|
68
|
-
ffi_delegate.set_value(
|
76
|
+
ffi_delegate.set_value('%s', :string, new_value.to_s)
|
69
77
|
end
|
70
78
|
|
79
|
+
|
71
80
|
# Inspects this {Config} item.
|
72
81
|
# @return [String] shows class, name, and value
|
73
82
|
def inspect
|
74
83
|
"#<#{self.class.name}: name=#{name.inspect} value=#{value.inspect}>"
|
75
84
|
end
|
76
85
|
|
86
|
+
|
77
87
|
# Update the value of a config item by path.
|
78
88
|
# @param path [String, #to_s] path to config item
|
79
89
|
# @param value [String, #to_s] path to config item
|
@@ -81,7 +91,7 @@ module CZTop
|
|
81
91
|
def []=(path, value)
|
82
92
|
ffi_delegate.put(path.to_s, value.to_s)
|
83
93
|
end
|
84
|
-
|
94
|
+
alias put []=
|
85
95
|
|
86
96
|
# Get the value of the current config item.
|
87
97
|
# @param path [String, #to_s] path to config item
|
@@ -92,30 +102,34 @@ module CZTop
|
|
92
102
|
# @note The default value is not returned when the config item exists but
|
93
103
|
# just doesn't have a value. In that case, it'll return the empty
|
94
104
|
# string.
|
95
|
-
def [](path, default =
|
105
|
+
def [](path, default = '')
|
96
106
|
ptr = ffi_delegate.get(path, default)
|
97
107
|
return nil if ptr.null?
|
108
|
+
|
98
109
|
ptr.read_string
|
99
110
|
end
|
100
|
-
|
111
|
+
alias get []
|
101
112
|
|
102
113
|
# @!endgroup
|
103
114
|
|
115
|
+
|
104
116
|
# Compares this config item to another. Only the name and value are
|
105
117
|
# considered. If you need to compare a config tree, use {#tree_equal?}.
|
106
118
|
# @param other [Config] the other config item
|
107
119
|
# @return [Boolean] whether they're equal
|
108
120
|
def ==(other)
|
109
121
|
name == other.name &&
|
110
|
-
|
122
|
+
value == other.value
|
111
123
|
end
|
112
124
|
|
125
|
+
|
113
126
|
# Compares this config tree to another tree or subtree. Names, values, and
|
114
127
|
# children are considered.
|
115
128
|
# @param other [Config] the other config tree
|
116
129
|
# @return [Boolean] whether they're equal
|
117
130
|
def tree_equal?(other)
|
118
|
-
self == other &&
|
131
|
+
self == other && children == other.children
|
119
132
|
end
|
133
|
+
|
120
134
|
end
|
121
135
|
end
|