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/authenticator.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CZTop
|
3
4
|
# Authentication for ZeroMQ security mechanisms.
|
4
5
|
#
|
5
6
|
# This is implemented using an {Actor}.
|
6
7
|
#
|
7
8
|
# @see http://api.zeromq.org/czmq3-0:zauth
|
8
9
|
class Authenticator
|
10
|
+
|
9
11
|
include ::CZMQ::FFI
|
10
12
|
|
11
13
|
# function pointer to the +zauth()+ function
|
12
14
|
ZAUTH_FPTR = ::CZMQ::FFI.ffi_libraries.each do |dl|
|
13
|
-
fptr = dl.find_function(
|
15
|
+
fptr = dl.find_function('zauth')
|
14
16
|
break fptr if fptr
|
15
17
|
end
|
16
18
|
raise LoadError, "couldn't find zauth()" if ZAUTH_FPTR.nil?
|
@@ -23,6 +25,7 @@ module CZTop
|
|
23
25
|
def initialize(cert_store = nil)
|
24
26
|
if cert_store
|
25
27
|
raise ArgumentError unless cert_store.is_a?(CertStore)
|
28
|
+
|
26
29
|
cert_store = cert_store.ffi_delegate
|
27
30
|
cert_store.__undef_finalizer # native object is now owned by zauth() actor
|
28
31
|
end
|
@@ -38,13 +41,15 @@ module CZTop
|
|
38
41
|
@actor.terminate
|
39
42
|
end
|
40
43
|
|
44
|
+
|
41
45
|
# Enable verbose logging of commands and activity.
|
42
46
|
# @return [void]
|
43
47
|
def verbose!
|
44
|
-
@actor <<
|
48
|
+
@actor << 'VERBOSE'
|
45
49
|
@actor.wait
|
46
50
|
end
|
47
51
|
|
52
|
+
|
48
53
|
# Add a list of IP addresses to the whitelist. For _NULL_, all clients
|
49
54
|
# from these addresses will be accepted. For _PLAIN_ and _CURVE_, they
|
50
55
|
# will be allowed to continue with authentication.
|
@@ -52,10 +57,11 @@ module CZTop
|
|
52
57
|
# @param addrs [String] IP address(es) to allow
|
53
58
|
# @return [void]
|
54
59
|
def allow(*addrs)
|
55
|
-
@actor << [
|
60
|
+
@actor << ['ALLOW', *addrs]
|
56
61
|
@actor.wait
|
57
62
|
end
|
58
63
|
|
64
|
+
|
59
65
|
# Add a list of IP addresses to the blacklist. For all security
|
60
66
|
# mechanisms, this rejects the connection without any further
|
61
67
|
# authentication. Use either a whitelist, or a blacklist, not not both. If
|
@@ -65,22 +71,23 @@ module CZTop
|
|
65
71
|
# @param addrs [String] IP address(es) to deny
|
66
72
|
# @return [void]
|
67
73
|
def deny(*addrs)
|
68
|
-
@actor << [
|
74
|
+
@actor << ['DENY', *addrs]
|
69
75
|
@actor.wait
|
70
76
|
end
|
71
77
|
|
78
|
+
|
72
79
|
# Configure PLAIN security mechanism using a plain-text password file. The
|
73
80
|
# password file will be reloaded automatically if modified externally.
|
74
81
|
#
|
75
82
|
# @param filename [String] path to the password file
|
76
83
|
# @return [void]
|
77
84
|
def plain(filename)
|
78
|
-
@actor << [
|
85
|
+
@actor << ['PLAIN', *filename]
|
79
86
|
@actor.wait
|
80
87
|
end
|
81
88
|
|
82
89
|
# used to allow any CURVE client
|
83
|
-
ALLOW_ANY =
|
90
|
+
ALLOW_ANY = '*'
|
84
91
|
|
85
92
|
# Configure CURVE authentication, using a directory that holds all public
|
86
93
|
# client certificates, i.e. their public keys. The certificates must have been
|
@@ -90,15 +97,17 @@ module CZTop
|
|
90
97
|
# @param directory [String] the directory to take the keys from
|
91
98
|
# @return [void]
|
92
99
|
def curve(directory = ALLOW_ANY)
|
93
|
-
@actor << [
|
100
|
+
@actor << ['CURVE', directory]
|
94
101
|
@actor.wait
|
95
102
|
end
|
96
103
|
|
104
|
+
|
97
105
|
# Configure GSSAPI authentication.
|
98
106
|
# @return [void]
|
99
107
|
def gssapi
|
100
|
-
@actor <<
|
108
|
+
@actor << 'GSSAPI'
|
101
109
|
@actor.wait
|
102
110
|
end
|
111
|
+
|
103
112
|
end
|
104
113
|
end
|
data/lib/cztop/beacon.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CZTop
|
2
4
|
# Used for LAN discovery and presence.
|
3
5
|
#
|
@@ -5,11 +7,12 @@ module CZTop
|
|
5
7
|
#
|
6
8
|
# @see http://api.zeromq.org/czmq3-0:zbeacon
|
7
9
|
class Beacon
|
10
|
+
|
8
11
|
include ::CZMQ::FFI
|
9
12
|
|
10
13
|
# function pointer to the +zbeacon()+ function
|
11
14
|
ZBEACON_FPTR = ::CZMQ::FFI.ffi_libraries.each do |dl|
|
12
|
-
fptr = dl.find_function(
|
15
|
+
fptr = dl.find_function('zbeacon')
|
13
16
|
break fptr if fptr
|
14
17
|
end
|
15
18
|
raise LoadError, "couldn't find zbeacon()" if ZBEACON_FPTR.nil?
|
@@ -28,12 +31,14 @@ module CZTop
|
|
28
31
|
@actor.terminate
|
29
32
|
end
|
30
33
|
|
34
|
+
|
31
35
|
# Enable verbose logging of commands and activity.
|
32
36
|
# @return [void]
|
33
37
|
def verbose!
|
34
|
-
@actor <<
|
38
|
+
@actor << 'VERBOSE'
|
35
39
|
end
|
36
40
|
|
41
|
+
|
37
42
|
# Run the beacon on the specified UDP port.
|
38
43
|
#
|
39
44
|
# @param port [Integer] port number to
|
@@ -43,7 +48,7 @@ module CZTop
|
|
43
48
|
# interrupted
|
44
49
|
# @raise [NotImplementedError] if the system doesn't support UDP broadcasts
|
45
50
|
def configure(port)
|
46
|
-
@actor.send_picture(
|
51
|
+
@actor.send_picture('si', :string, 'CONFIGURE', :int, port)
|
47
52
|
ptr = Zstr.recv(@actor)
|
48
53
|
|
49
54
|
# NULL if context terminated or interrupted
|
@@ -64,42 +69,49 @@ module CZTop
|
|
64
69
|
# @raise [ArgumentError] if data is longer than {MAX_BEACON_DATA} bytes
|
65
70
|
# @return [void]
|
66
71
|
def publish(data, interval)
|
67
|
-
raise ArgumentError,
|
68
|
-
|
69
|
-
|
72
|
+
raise ArgumentError, 'data too long' if data.bytesize > MAX_BEACON_DATA
|
73
|
+
|
74
|
+
@actor.send_picture('sbi', :string, 'PUBLISH', :string, data,
|
75
|
+
:int, data.bytesize, :int, interval)
|
70
76
|
end
|
71
77
|
|
78
|
+
|
72
79
|
# Stop broadcasting the beacon.
|
73
80
|
# @return [void]
|
74
81
|
def silence
|
75
|
-
@actor <<
|
82
|
+
@actor << 'SILENCE'
|
76
83
|
end
|
77
84
|
|
85
|
+
|
78
86
|
# Start listening to beacons from peers.
|
79
87
|
# @param filter [String] do a prefix match on received beacons
|
80
88
|
# @return [void]
|
81
89
|
def subscribe(filter)
|
82
|
-
@actor.send_picture(
|
90
|
+
@actor.send_picture('sb', :string, 'SUBSCRIBE',
|
83
91
|
:string, filter, :int, filter.bytesize)
|
84
92
|
end
|
85
93
|
|
94
|
+
|
86
95
|
# Just like {#subscribe}, but subscribe to all peer beacons.
|
87
96
|
# @return [void]
|
88
97
|
def listen
|
89
|
-
@actor.send_picture(
|
98
|
+
@actor.send_picture('sb', :string, 'SUBSCRIBE',
|
90
99
|
:string, nil, :int, 0)
|
91
100
|
end
|
92
101
|
|
102
|
+
|
93
103
|
# Stop listening to other peers.
|
94
104
|
# @return [void]
|
95
105
|
def unsubscribe
|
96
|
-
@actor <<
|
106
|
+
@actor << 'UNSUBSCRIBE'
|
97
107
|
end
|
98
108
|
|
109
|
+
|
99
110
|
# Receive next beacon from a peer.
|
100
111
|
# @return [Message] 2-frame message with ([ipaddr, data])
|
101
112
|
def receive
|
102
113
|
@actor.receive
|
103
114
|
end
|
115
|
+
|
104
116
|
end
|
105
117
|
end
|
data/lib/cztop/cert_store.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'set'
|
2
4
|
|
3
5
|
module CZTop
|
4
|
-
|
5
6
|
# A store for CURVE security certificates, either backed by files on disk or
|
6
7
|
# in-memory.
|
7
8
|
#
|
8
9
|
# @see http://api.zeromq.org/czmq3-0:zcertstore
|
9
10
|
class CertStore
|
11
|
+
|
10
12
|
include ::CZMQ::FFI
|
11
13
|
include HasFFIDelegate
|
12
14
|
extend CZTop::HasFFIDelegate::ClassMethods
|
@@ -21,6 +23,7 @@ module CZTop
|
|
21
23
|
attach_ffi_delegate(Zcertstore.new(location))
|
22
24
|
end
|
23
25
|
|
26
|
+
|
24
27
|
# Looks up a certificate in the store by its public key.
|
25
28
|
#
|
26
29
|
# @param pubkey [String] the public key in question, in Z85 format
|
@@ -29,9 +32,11 @@ module CZTop
|
|
29
32
|
def lookup(pubkey)
|
30
33
|
ptr = ffi_delegate.lookup(pubkey)
|
31
34
|
return nil if ptr.null?
|
35
|
+
|
32
36
|
Certificate.from_ffi_delegate(ptr)
|
33
37
|
end
|
34
38
|
|
39
|
+
|
35
40
|
# Inserts a new certificate into the store.
|
36
41
|
#
|
37
42
|
# @note The same public key must not be inserted more than once.
|
@@ -43,11 +48,12 @@ module CZTop
|
|
43
48
|
raise ArgumentError unless cert.is_a?(Certificate)
|
44
49
|
|
45
50
|
@_inserted_pubkeys ||= Set.new
|
46
|
-
pubkey
|
51
|
+
pubkey = cert.public_key
|
47
52
|
raise ArgumentError if @_inserted_pubkeys.include? pubkey
|
48
53
|
|
49
54
|
ffi_delegate.insert(cert.ffi_delegate)
|
50
55
|
@_inserted_pubkeys << pubkey
|
51
56
|
end
|
57
|
+
|
52
58
|
end
|
53
59
|
end
|
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
|