cztop 1.0.0 → 1.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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