cztop 0.14.1 → 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/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
|