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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/coverage.yml +20 -0
  3. data/.github/workflows/draft_api.yml +27 -0
  4. data/.github/workflows/{main.yml → stable_api.yml} +6 -6
  5. data/.rubocop.yml +175 -0
  6. data/CHANGES.md +8 -1
  7. data/Gemfile +5 -0
  8. data/README.md +3 -1
  9. data/ci/install-libczmq +22 -0
  10. data/ci/install-libzmq +22 -0
  11. data/cztop.gemspec +3 -2
  12. data/lib/cztop/actor.rb +55 -26
  13. data/lib/cztop/authenticator.rb +18 -9
  14. data/lib/cztop/beacon.rb +22 -10
  15. data/lib/cztop/cert_store.rb +8 -2
  16. data/lib/cztop/certificate.rb +47 -18
  17. data/lib/cztop/config/comments.rb +14 -3
  18. data/lib/cztop/config/serialization.rb +25 -5
  19. data/lib/cztop/config/traversing.rb +44 -13
  20. data/lib/cztop/config.rb +23 -9
  21. data/lib/cztop/frame.rb +23 -10
  22. data/lib/cztop/has_ffi_delegate.rb +11 -1
  23. data/lib/cztop/message/frames.rb +16 -2
  24. data/lib/cztop/message.rb +36 -22
  25. data/lib/cztop/metadata.rb +35 -24
  26. data/lib/cztop/monitor.rb +14 -5
  27. data/lib/cztop/poller/aggregated.rb +31 -15
  28. data/lib/cztop/poller/zmq.rb +25 -22
  29. data/lib/cztop/poller/zpoller.rb +18 -6
  30. data/lib/cztop/poller.rb +43 -18
  31. data/lib/cztop/polymorphic_zsock_methods.rb +6 -1
  32. data/lib/cztop/proxy.rb +34 -19
  33. data/lib/cztop/send_receive_methods.rb +5 -1
  34. data/lib/cztop/socket/types.rb +128 -22
  35. data/lib/cztop/socket.rb +23 -18
  36. data/lib/cztop/version.rb +5 -1
  37. data/lib/cztop/z85/padded.rb +12 -3
  38. data/lib/cztop/z85/pipe.rb +40 -17
  39. data/lib/cztop/z85.rb +17 -6
  40. data/lib/cztop/zap.rb +57 -32
  41. data/lib/cztop/zsock_options.rb +155 -122
  42. data/lib/cztop.rb +2 -1
  43. metadata +28 -10
  44. data/.ruby-version +0 -1
@@ -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, "no block given" unless block_given?
16
- exception = nil
17
- block_value = nil
18
- ret = nil
19
- callback = CZMQ::FFI::Zconfig.fct do |zconfig, _arg, level|
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 = from_ffi_delegate(zconfig)
27
+ config = from_ffi_delegate(zconfig)
25
28
  block_value = yield config, level
26
- ret = 0 # report success to keep zconfig_execute() going
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
- return block_value
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 = current.ffi_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
- return true
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
- module CZTop
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 = parent.ffi_delegate if parent.is_a?(Config)
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 "" if ptr.null? # NOTE: for root elements
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("%s", :string, new_value.to_s)
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
- alias_method :put, :[]=
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
- alias_method :get, :[]
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
- value == other.value
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 && self.children == other.children
131
+ self == other && children == other.children
119
132
  end
133
+
120
134
  end
121
135
  end
data/lib/cztop/frame.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CZTop
2
4
  # Represents a CZMQ::FFI::Zframe, a part of a message.
3
5
  #
@@ -8,6 +10,7 @@ module CZTop
8
10
  #
9
11
  # @see http://api.zeromq.org/czmq3-0:zframe
10
12
  class Frame
13
+
11
14
  include HasFFIDelegate
12
15
  extend CZTop::HasFFIDelegate::ClassMethods
13
16
 
@@ -18,8 +21,8 @@ module CZTop
18
21
  self.content = content if content
19
22
  end
20
23
 
21
- FLAG_MORE = 1
22
- FLAG_REUSE = 2
24
+ FLAG_MORE = 1
25
+ FLAG_REUSE = 2
23
26
  FLAG_DONTWAIT = 4
24
27
 
25
28
  # Send {Message} to a {Socket}/{Actor}.
@@ -39,14 +42,14 @@ module CZTop
39
42
  # @raise [SystemCallError] if there was some error. In that case, the
40
43
  # native counterpart still exists and this {Frame} can be reused.
41
44
  def send_to(destination, more: false, reuse: false, dontwait: false)
42
- flags = 0
45
+ flags = 0
43
46
  flags |= FLAG_MORE if more
44
47
  flags |= FLAG_REUSE if reuse
45
48
  flags |= FLAG_DONTWAIT if dontwait
46
49
 
47
50
  # remember pointer, in case the zframe_t won't be destroyed
48
51
  zframe_ptr = ffi_delegate.to_ptr
49
- ret = CZMQ::FFI::Zframe.send(ffi_delegate, destination, flags)
52
+ ret = CZMQ::FFI::Zframe.send(ffi_delegate, destination, flags)
50
53
 
51
54
  if reuse || ret == -1
52
55
  # zframe_t hasn't been destroyed yet: avoid memory leak.
@@ -55,14 +58,13 @@ module CZTop
55
58
  end
56
59
 
57
60
  if ret == -1
58
- if dontwait && FFI.errno == Errno::EAGAIN::Errno
59
- raise IO::EAGAINWaitWritable
60
- end
61
+ raise IO::EAGAINWaitWritable if dontwait && FFI.errno == Errno::EAGAIN::Errno
61
62
 
62
63
  raise_zmq_err
63
64
  end
64
65
  end
65
66
 
67
+
66
68
  # Receive {Frame} from a {Socket}/{Actor}.
67
69
  # @note This is low-level. Consider just receiving a {Message}.
68
70
  # @return [Frame]
@@ -70,18 +72,20 @@ module CZTop
70
72
  from_ffi_delegate(CZMQ::FFI::Zframe.recv(source))
71
73
  end
72
74
 
75
+
73
76
  # @note This string is always binary. Use String#force_encoding if needed.
74
77
  # @return [String] content as string (encoding = Encoding::BINARY)
75
78
  def content
76
79
  ffi_delegate.data.read_string(size)
77
80
  end
78
- alias_method :to_s, :content
81
+ alias to_s content
79
82
 
80
83
  # @return [Boolean] if this {Frame} has zero-sized content
81
84
  def empty?
82
85
  size.zero?
83
86
  end
84
87
 
88
+
85
89
  # Sets new content of this {Frame}.
86
90
  # @param new_content [String]
87
91
  # @return [new_content]
@@ -92,12 +96,14 @@ module CZTop
92
96
  # NOTE: FFI::MemoryPointer will autorelease
93
97
  end
94
98
 
99
+
95
100
  # Duplicates a frame.
96
101
  # @return [Frame] new frame with same content
97
102
  def dup
98
103
  from_ffi_delegate(ffi_delegate.dup)
99
104
  end
100
105
 
106
+
101
107
  # @return [Boolean] if the MORE indicator is set
102
108
  # @note This happens when reading a frame from a {Socket} or using
103
109
  # {#more=}.
@@ -105,6 +111,7 @@ module CZTop
105
111
  ffi_delegate.more == 1
106
112
  end
107
113
 
114
+
108
115
  # Sets the MORE indicator.
109
116
  # @param indicator [Boolean]
110
117
  # @note This is NOT used when sending frame to socket.
@@ -114,6 +121,7 @@ module CZTop
114
121
  ffi_delegate.set_more(indicator ? 1 : 0)
115
122
  end
116
123
 
124
+
117
125
  # Compare to another frame.
118
126
  # @param other [Frame]
119
127
  # @return [Boolean] if this and the other frame have identical size and
@@ -151,10 +159,12 @@ module CZTop
151
159
  def routing_id=(new_routing_id)
152
160
  # need to raise manually, as FFI lacks this feature.
153
161
  # @see https://github.com/ffi/ffi/issues/473
154
- raise RangeError if new_routing_id < 0
162
+ raise RangeError if new_routing_id.negative?
163
+
155
164
  ffi_delegate.set_routing_id(new_routing_id)
156
165
  end
157
166
 
167
+
158
168
  # Gets the group (radio/dish pattern).
159
169
  # @note This is only set when the frame has been read from
160
170
  # a {CZTop::Socket::DISH} socket.
@@ -163,9 +173,11 @@ module CZTop
163
173
  def group
164
174
  group = ffi_delegate.group
165
175
  return nil if group.nil? || group.empty?
176
+
166
177
  group
167
178
  end
168
179
 
180
+
169
181
  # Sets a new group (radio/dish pattern).
170
182
  # @note This is used when the frame is sent via a {CZTop::Socket::RADIO}
171
183
  # socket.
@@ -174,7 +186,8 @@ module CZTop
174
186
  # @return [new_group]
175
187
  def group=(new_group)
176
188
  rc = ffi_delegate.set_group(new_group)
177
- raise_zmq_err("unable to set group to %p" % new_group) if rc == -1
189
+ raise_zmq_err(format('unable to set group to %p', new_group)) if rc == -1
178
190
  end
191
+
179
192
  end
180
193
  end
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
2
4
  require 'socket' # for SocketError
3
5
 
4
6
  # This module is used to attach the low-level objects of classes within the
5
7
  # CZMQ::FFI namespace (coming from the _czmq-ffi-gen_ gem) as delegates.
6
8
  module CZTop::HasFFIDelegate
9
+
7
10
  # @return [CZMQ::FFI::*] the attached delegate
8
11
  attr_reader :ffi_delegate
9
12
 
@@ -12,6 +15,7 @@ module CZTop::HasFFIDelegate
12
15
  @ffi_delegate.to_ptr
13
16
  end
14
17
 
18
+
15
19
  # Attaches an FFI delegate to the current (probably new) {CZTop} object.
16
20
  # @param ffi_delegate an instance of the corresponding class in the
17
21
  # CZMQ::FFI namespace
@@ -27,6 +31,7 @@ module CZTop::HasFFIDelegate
27
31
  @ffi_delegate = ffi_delegate
28
32
  end
29
33
 
34
+
30
35
  # Same as the counterpart in {ClassMethods}, but usable from within an
31
36
  # instance.
32
37
  # @see CZTop::FFIDelegate::ClassMethods#from_ffi_delegate
@@ -60,8 +65,10 @@ module CZTop::HasFFIDelegate
60
65
  end
61
66
  end
62
67
 
68
+
63
69
  # Some class methods related to FFI delegates.
64
70
  module ClassMethods
71
+
65
72
  include Forwardable
66
73
 
67
74
  # Delegate specified instance method to the registered FFI delegate.
@@ -73,6 +80,7 @@ module CZTop::HasFFIDelegate
73
80
  def_delegator(:@ffi_delegate, method)
74
81
  end
75
82
 
83
+
76
84
  # Allocates a new instance and attaches the FFI delegate to it. This is
77
85
  # useful if you already have an FFI delegate and need to attach it to a
78
86
  # fresh high-level object.
@@ -84,7 +92,9 @@ module CZTop::HasFFIDelegate
84
92
  def from_ffi_delegate(ffi_delegate)
85
93
  obj = allocate
86
94
  obj.attach_ffi_delegate(ffi_delegate)
87
- return obj
95
+ obj
88
96
  end
97
+
89
98
  end
99
+
90
100
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CZTop
2
4
  class Message
3
5
 
@@ -7,14 +9,17 @@ module CZTop
7
9
  frames.count
8
10
  end
9
11
 
12
+
10
13
  # Access to this {Message}'s {Frame}s.
11
14
  # @return [FramesAccessor]
12
15
  def frames
13
16
  FramesAccessor.new(self)
14
17
  end
15
18
 
19
+
16
20
  # Used to access a {Message}'s {Frame}s.
17
21
  class FramesAccessor
22
+
18
23
  include Enumerable
19
24
 
20
25
  # @param message [Message]
@@ -22,24 +27,29 @@ module CZTop
22
27
  @message = message
23
28
  end
24
29
 
30
+
25
31
  # Returns the last frame of this message.
26
32
  # @return [Frame] first frame of Message
27
33
  # @return [nil] if there are no frames
28
34
  def first
29
35
  first = @message.ffi_delegate.first
30
36
  return nil if first.null?
37
+
31
38
  Frame.from_ffi_delegate(first)
32
39
  end
33
40
 
41
+
34
42
  # Returns the last frame of this message.
35
43
  # @return [Frame] last {Frame} of {Message}
36
44
  # @return [nil] if there are no frames
37
45
  def last
38
46
  last = @message.ffi_delegate.last
39
47
  return nil if last.null?
48
+
40
49
  Frame.from_ffi_delegate(last)
41
50
  end
42
51
 
52
+
43
53
  # Index access to a frame/frames of this message, just like with an
44
54
  # array.
45
55
  # @overload [](index)
@@ -56,6 +66,7 @@ module CZTop
56
66
  end
57
67
  end
58
68
 
69
+
59
70
  # Yields all frames for this message to the given block.
60
71
  # @note Not thread safe.
61
72
  # @yieldparam frame [Frame]
@@ -63,12 +74,15 @@ module CZTop
63
74
  def each
64
75
  first = first()
65
76
  return unless first
77
+
66
78
  yield first
67
- while frame = @message.ffi_delegate.next and not frame.null?
79
+ while (frame = @message.ffi_delegate.next) && !frame.null?
68
80
  yield Frame.from_ffi_delegate(frame)
69
81
  end
70
- return self
82
+ self
71
83
  end
84
+
72
85
  end
86
+
73
87
  end
74
88
  end