cztop 2.0.1 → 2.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3e896a163e0a640e37c5010ca8456e42918e441015cc6ac34c1d87cf5b8a515
4
- data.tar.gz: fbfc76eafa56cf7684043d4b7d802be08b4ddee737a965fca640151858c941da
3
+ metadata.gz: f3e5938035e1b344dafa25665293cddc9017c5b9c47280bacc9fc4b9ff97fc2e
4
+ data.tar.gz: 16b1a7896a2f118cfd2fcfa2829acbeb5e3d021472c34aa6dfd190ed8bb1a5bf
5
5
  SHA512:
6
- metadata.gz: 30ce4f0baf5bd011f4745e64a526e4c20a236c94f6f9b3cda1195e8ecf21ffbdbda0bcbe71817d3832a315bed34e67efe36691bd7adc11e6b90993045cf84e7f
7
- data.tar.gz: b8f5ae6e4864b73b48ac5013cb29d627d51bee82151e27a2e0f462dd000cc793a92d122c4a19a2c34ca2bc59d4a517bf0385fc6b3d69482c1889d084c6f37299
6
+ metadata.gz: 5e6058194cbb28727e78f92a431c203ee45f5363a89e4fbaa3026553d3b3b8610240947b7336f5625218458acd77388038734b00a966c8f6fa3ac7c45d9616a0
7
+ data.tar.gz: b549f127a5031b643807702ee279a0dc4565f252c3489b10da5f6191617162f618946518175e3bb4de4c3c7b1628fb355ad5c063f31c2b05c34bf93c07d15f2c
data/CHANGES.md CHANGED
@@ -1,3 +1,34 @@
1
+ ## [Unreleased]
2
+
3
+ 2.0.3
4
+ -----
5
+
6
+ * Port specs to named `Minitest::Spec` subclasses with ordinary Ruby helpers
7
+ * Add regression coverage for native library loading and fallback
8
+ * Raise native send/receive errors immediately instead of waiting for readiness
9
+ * Raise `IO::EAGAINWaitReadable`/`IO::EAGAINWaitWritable` when nonblocking I/O
10
+ would block
11
+ * Convert all multipart message parts before sending the first frame
12
+ * Avoid an extra array allocation for scalar sends without modifying caller arrays
13
+ * Free native identity strings and messages retained after failed sends
14
+ * Reject endpoint and subscription operations on closed sockets, and receive
15
+ operations on closed monitors
16
+ * Close the CURVE authentication socket in its responder thread during shutdown
17
+ * Fix linger documentation to use seconds
18
+ * Clean up benchmark socket lifetimes and refresh measurements and README
19
+
20
+ 2.0.2
21
+ -----
22
+
23
+ * Fix `ffi_lib` fallback: use arrays so versioned sonames (`libzmq.so.5`,
24
+ `libczmq.so.4`) are tried first with unversioned names as actual fallbacks
25
+
26
+ 2.0.1
27
+ -----
28
+
29
+ * Prefer versioned sonames (`libzmq.so.5`, `libczmq.so.4`) over unversioned
30
+ names that require `-dev` packages
31
+
1
32
  2.0.0
2
33
  -----
3
34
 
data/README.md CHANGED
@@ -5,17 +5,17 @@
5
5
  [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](LICENSE)
6
6
  [![Ruby](https://img.shields.io/badge/Ruby-%3E%3D%203.3-CC342D?logo=ruby&logoColor=white)](https://www.ruby-lang.org)
7
7
 
8
- Ruby FFI binding for [CZMQ](http://czmq.zeromq.org/) / [ZeroMQ](https://zeromq.org/) — high-performance asynchronous messaging for distributed systems.
8
+ Ruby FFI binding for [CZMQ](https://github.com/zeromq/czmq) and [ZeroMQ](https://zeromq.org/), with support for threads, Fiber Scheduler, and CURVE encryption.
9
9
 
10
- > **353k msg/s** inproc throughput | **49 µs** fiber roundtrip latency | nonblock fast path
10
+ > **310k msg/s** inproc throughput (64 B) | **61 µs** Async roundtrip latency
11
11
 
12
12
  ---
13
13
 
14
14
  ## Highlights
15
15
 
16
- - **All socket types** — req/rep, pub/sub, push/pull, dealer/router, xpub/xsub, pair, stream
17
- - **Async-first** — first-class [async](https://github.com/socketry/async) fiber support, also works with plain threads
18
- - **Ruby-idiomatic API** — messages as `Array<String>`, errors as exceptions, timeouts as `IO::TimeoutError`
16
+ - **Socket types:** REQ/REP, PUB/SUB, PUSH/PULL, DEALER/ROUTER, XPUB/XSUB, PAIR, STREAM
17
+ - **Fibers and threads:** works with [async](https://github.com/socketry/async) and plain threads
18
+ - **Ruby API:** messages as `Array<String>`, errors as exceptions, timeouts as `IO::TimeoutError`
19
19
 
20
20
  ## Install
21
21
 
@@ -33,17 +33,21 @@ Then add the gem:
33
33
 
34
34
  ```sh
35
35
  gem install cztop
36
- # or in Gemfile
36
+ ```
37
+
38
+ Or add it to your Gemfile:
39
+
40
+ ```ruby
37
41
  gem 'cztop'
38
42
  ```
39
43
 
40
44
  ## Learning ZeroMQ
41
45
 
42
- New to ZeroMQ? See [ZGUIDE_SUMMARY.md](ZGUIDE_SUMMARY.md) — a ~30 min read covering all major patterns with working CZTop code examples.
46
+ New to ZeroMQ? See [ZGUIDE_SUMMARY.md](ZGUIDE_SUMMARY.md) for messaging patterns and working CZTop examples.
43
47
 
44
48
  ## Quick Start
45
49
 
46
- ### Request / Reply
50
+ ### REQ / REP
47
51
 
48
52
  ```ruby
49
53
  require 'cztop'
@@ -63,7 +67,7 @@ Async do |task|
63
67
  end
64
68
  ```
65
69
 
66
- ### Pub / Sub
70
+ ### PUB / SUB
67
71
 
68
72
  ```ruby
69
73
  Async do |task|
@@ -78,7 +82,7 @@ Async do |task|
78
82
  end
79
83
  ```
80
84
 
81
- ### Push / Pull (Pipeline)
85
+ ### PUSH / PULL (Pipeline)
82
86
 
83
87
  ```ruby
84
88
  Async do
@@ -95,7 +99,8 @@ end
95
99
  | Pattern | Classes | Direction |
96
100
  |---------|---------|-----------|
97
101
  | Request/Reply | `REQ`, `REP` | bidirectional |
98
- | Publish/Subscribe | `PUB`, `SUB`, `XPUB`, `XSUB` | unidirectional |
102
+ | Publish/Subscribe | `PUB`, `SUB` | unidirectional |
103
+ | Subscription forwarding | `XPUB`, `XSUB` | bidirectional |
99
104
  | Pipeline | `PUSH`, `PULL` | unidirectional |
100
105
  | Routing | `DEALER`, `ROUTER` | bidirectional |
101
106
  | Exclusive pair | `PAIR` | bidirectional |
@@ -105,23 +110,23 @@ All classes live under `CZTop::Socket::`.
105
110
 
106
111
  ## Performance
107
112
 
108
- Benchmarked with benchmark-ips on Linux x86_64 (CZMQ 4.2.1, ZMQ 4.3.5, Ruby 4.0.1 +YJIT):
113
+ Benchmarked with benchmark-ips on Linux x86_64 (CZMQ 4.2.1, ZMQ 4.3.5, Ruby 4.0.6 +YJIT):
109
114
 
110
- #### Throughput (push/pull)
115
+ #### Throughput (PUSH/PULL, 64 B messages)
111
116
 
112
117
  | | inproc | ipc | tcp |
113
118
  |---|--------|-----|-----|
114
- | **Async** | 284k/s | 17k/s | 14k/s |
115
- | **Threads** | 353k/s | 25k/s | 21k/s |
119
+ | **Async** | 278k/s | 18.3k/s | 15.8k/s |
120
+ | **Threads** | 310k/s | 18.3k/s | 16.2k/s |
116
121
 
117
- #### Latency (req/rep roundtrip)
122
+ #### Latency (REQ/REP roundtrip)
118
123
 
119
124
  | | inproc | ipc | tcp |
120
125
  |---|--------|-----|-----|
121
- | **Async** | 49 µs | 100 µs | 107 µs |
122
- | **Threads** | 113 µs | 154 µs | 168 µs |
126
+ | **Async** | 60.7 µs | 112.6 µs | 127.8 µs |
127
+ | **Threads** | 74.9 µs | 109.2 µs | 119.6 µs |
123
128
 
124
- Async fibers deliver 2.3x lower inproc latency thanks to cheap context switching. See [`bench/`](bench/) for full results and scripts.
129
+ See [bench/README.md](bench/README.md) for full results, measurement details, and scripts.
125
130
 
126
131
  ## API Reference
127
132
 
@@ -29,7 +29,9 @@ module CZTop
29
29
  @allow_any = allow_any
30
30
  @zap = CZTop::Socket::REP.new
31
31
  @zap.linger = 0
32
+ @zap.recv_timeout = 0.1
32
33
  @zap.bind('inproc://zeromq.zap.01')
34
+ @stopping = false
33
35
  @thread = Thread.new { run }
34
36
  ObjectSpace.define_finalizer(self, self.class._poststop(@thread))
35
37
  end
@@ -60,8 +62,9 @@ module CZTop
60
62
  #
61
63
  def stop
62
64
  ObjectSpace.undefine_finalizer(self)
63
- @zap.close
64
- @thread.join(1)
65
+ @stopping = true
66
+ @thread.join
67
+ nil
65
68
  end
66
69
 
67
70
  # @api private
@@ -75,8 +78,12 @@ module CZTop
75
78
  private
76
79
 
77
80
  def run
78
- loop do
79
- msg = @zap.receive
81
+ until @stopping
82
+ begin
83
+ msg = @zap.receive
84
+ rescue IO::TimeoutError
85
+ next
86
+ end
80
87
  # ZAP request: [version, request_id, domain, address, identity, mechanism, credential]
81
88
  version = msg[0]
82
89
  request_id = msg[1]
@@ -90,8 +97,8 @@ module CZTop
90
97
 
91
98
  @zap.__send__(:send, [version, request_id, status, '', '', ''])
92
99
  end
93
- rescue
94
- # Socket closed or thread interrupted → exit gracefully
100
+ ensure
101
+ @zap.close
95
102
  end
96
103
 
97
104
  end
data/lib/cztop/curve.rb CHANGED
@@ -6,7 +6,7 @@ module CZTop
6
6
  #
7
7
  # Provides keypair generation, key derivation, and Z85 encoding/decoding.
8
8
  # CURVE options are applied to sockets via the +curve:+ keyword argument
9
- # in socket constructors — there are no public CURVE methods on Socket.
9
+ # in socket constructors; there are no public CURVE methods on Socket.
10
10
  #
11
11
  module CURVE
12
12
 
data/lib/cztop/ffi.rb CHANGED
@@ -6,8 +6,9 @@ module CZMQ
6
6
  module FFI
7
7
  extend ::FFI::Library
8
8
 
9
- ffi_lib 'libzmq.so.5', 'libzmq'
10
- ffi_lib 'libczmq.so.4', 'libczmq'
9
+ # Runtime packages may only include versioned sonames. Keep each library's
10
+ # alternatives in one array so FFI can fall back to platform-specific names.
11
+ ffi_lib ['libzmq.so.5', 'libzmq'], ['libczmq.so.4', 'libczmq']
11
12
 
12
13
  # -----------------------------------------------------------------
13
14
  # libzmq functions
@@ -123,6 +124,7 @@ module CZMQ
123
124
  # -----------------------------------------------------------------
124
125
  attach_function :zstr_send, [:pointer, :string], :int, **opts
125
126
  attach_function :zstr_sendm, [:pointer, :string], :int, **opts
127
+ attach_function :zstr_free, [:pointer], :void
126
128
 
127
129
  # -----------------------------------------------------------------
128
130
  # zsock_wait (used for zactor START synchronization)
@@ -297,23 +299,23 @@ module CZMQ
297
299
 
298
300
  # Instance methods
299
301
  def endpoint
300
- CZMQ::FFI.zsock_endpoint(@ptr)
302
+ CZMQ::FFI.zsock_endpoint(to_ptr)
301
303
  end
302
304
 
303
305
  def connect(format, *args)
304
- CZMQ::FFI.zsock_connect(@ptr, format, *args)
306
+ CZMQ::FFI.zsock_connect(to_ptr, format, *args)
305
307
  end
306
308
 
307
309
  def disconnect(format, *args)
308
- CZMQ::FFI.zsock_disconnect(@ptr, format, *args)
310
+ CZMQ::FFI.zsock_disconnect(to_ptr, format, *args)
309
311
  end
310
312
 
311
313
  def bind(format, *args)
312
- CZMQ::FFI.zsock_bind(@ptr, format, *args)
314
+ CZMQ::FFI.zsock_bind(to_ptr, format, *args)
313
315
  end
314
316
 
315
317
  def unbind(format, *args)
316
- CZMQ::FFI.zsock_unbind(@ptr, format, *args)
318
+ CZMQ::FFI.zsock_unbind(to_ptr, format, *args)
317
319
  end
318
320
 
319
321
  def destroy
@@ -326,11 +328,11 @@ module CZMQ
326
328
  end
327
329
 
328
330
  def set_subscribe(prefix)
329
- CZMQ::FFI.zsock_set_subscribe(@ptr, prefix)
331
+ CZMQ::FFI.zsock_set_subscribe(to_ptr, prefix)
330
332
  end
331
333
 
332
334
  def set_unsubscribe(prefix)
333
- CZMQ::FFI.zsock_set_unsubscribe(@ptr, prefix)
335
+ CZMQ::FFI.zsock_set_unsubscribe(to_ptr, prefix)
334
336
  end
335
337
 
336
338
  # Class methods that take a zsock pointer (or wrapper with to_ptr)
@@ -424,9 +426,15 @@ module CZMQ
424
426
  # Override Object#send: int zmsg_send(zmsg_t **self_p, void *dest)
425
427
  # Called as: Zmsg.send(zmsg_wrapper_or_ptr, destination)
426
428
  def self.send(msg, dest)
427
- msg_ptr = msg.respond_to?(:__ptr_give_ref) ? msg.__ptr_give_ref : msg
428
429
  dest_ptr = dest.respond_to?(:to_ptr) ? dest.to_ptr : dest
429
- CZMQ::FFI.zmsg_send(msg_ptr, dest_ptr)
430
+ msg_ptr = msg.respond_to?(:__ptr_give_ref) ? msg.__ptr_give_ref : msg
431
+ rc = CZMQ::FFI.zmsg_send(msg_ptr, dest_ptr)
432
+ unless rc.zero?
433
+ errno = CZMQ::FFI::Errors.errno
434
+ CZMQ::FFI.zmsg_destroy(msg_ptr) if msg.respond_to?(:__ptr_give_ref)
435
+ CZTop::HasFFIDelegate.raise_zmq_err(errno: errno)
436
+ end
437
+ rc
430
438
  end
431
439
 
432
440
  def self.recv(source)
@@ -438,17 +446,17 @@ module CZMQ
438
446
  # Appends a Ruby string directly without intermediate MemoryPointer copy.
439
447
  # Uses :buffer_in to pass the string's internal buffer pointer to C.
440
448
  def add_buffer(str)
441
- CZMQ::FFI.zmsg_addmem_s(@ptr, str, str.bytesize)
449
+ CZMQ::FFI.zmsg_addmem_s(to_ptr, str, str.bytesize)
442
450
  end
443
451
 
444
452
  def first
445
- ptr = CZMQ::FFI.zmsg_first(@ptr)
453
+ ptr = CZMQ::FFI.zmsg_first(to_ptr)
446
454
  return nil if ptr.null?
447
455
  _borrowed_frame(ptr)
448
456
  end
449
457
 
450
458
  def next
451
- ptr = CZMQ::FFI.zmsg_next(@ptr)
459
+ ptr = CZMQ::FFI.zmsg_next(to_ptr)
452
460
  return nil if ptr.null?
453
461
  _borrowed_frame(ptr)
454
462
  end
@@ -462,7 +470,7 @@ module CZMQ
462
470
  end
463
471
 
464
472
  # -----------------------------------------------------------------
465
- # Zframe (lightweight — only used for borrowed frames from Zmsg)
473
+ # Zframe (lightweight; only used for borrowed frames from Zmsg)
466
474
  # -----------------------------------------------------------------
467
475
  class Zframe
468
476
  # Wraps a borrowed zframe_t pointer (not owned, no finalizer).
data/lib/cztop/monitor.rb CHANGED
@@ -69,6 +69,7 @@ module CZTop
69
69
  # @return [Event, nil] the event, or nil on timeout
70
70
  #
71
71
  def receive(timeout: 0.1)
72
+ raise IOError, 'monitor is closed' if @closed
72
73
  CZMQ::FFI.zsock_set_rcvtimeo(@actor_ptr, (timeout * 1000).to_i)
73
74
 
74
75
  zmsg_ptr = CZMQ::FFI.zmsg_recv(@actor_ptr)
@@ -13,7 +13,7 @@ module CZTop
13
13
 
14
14
  # @param endpoints [String] endpoints to connect to
15
15
  # @param curve [Hash, nil] CURVE encryption options
16
- # @param linger [Integer] linger period in milliseconds (default: 0)
16
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
17
17
  #
18
18
  def initialize(endpoints = nil, curve: nil, linger: 0)
19
19
  super
@@ -13,7 +13,7 @@ module CZTop
13
13
 
14
14
  # @param endpoints [String] endpoints to connect to
15
15
  # @param curve [Hash, nil] CURVE encryption options
16
- # @param linger [Integer] linger period in milliseconds (default: 0)
16
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
17
17
  #
18
18
  def initialize(endpoints = nil, curve: nil, linger: 0)
19
19
  super
@@ -12,7 +12,7 @@ module CZTop
12
12
 
13
13
  # @param endpoints [String] endpoints to bind to
14
14
  # @param curve [Hash, nil] CURVE encryption options
15
- # @param linger [Integer] linger period in milliseconds (default: 0)
15
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
16
16
  #
17
17
  def initialize(endpoints = nil, curve: nil, linger: 0)
18
18
  super
@@ -12,7 +12,7 @@ module CZTop
12
12
 
13
13
  # @param endpoints [String] endpoints to bind to
14
14
  # @param curve [Hash, nil] CURVE encryption options
15
- # @param linger [Integer] linger period in milliseconds (default: 0)
15
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
16
16
  #
17
17
  def initialize(endpoints = nil, curve: nil, linger: 0)
18
18
  super
@@ -12,7 +12,7 @@ module CZTop
12
12
 
13
13
  # @param endpoints [String] endpoints to connect to
14
14
  # @param curve [Hash, nil] CURVE encryption options
15
- # @param linger [Integer] linger period in milliseconds (default: 0)
15
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
16
16
  #
17
17
  def initialize(endpoints = nil, curve: nil, linger: 0)
18
18
  super
@@ -18,6 +18,7 @@ module CZTop
18
18
  # Fast path: nonblock recv (no GVL release)
19
19
  parts = recv_nonblock
20
20
  return parts if parts
21
+ raise IO::EAGAINWaitReadable if read_timeout == 0
21
22
 
22
23
  # Slow path: FD poll → blocking recv
23
24
  wait_readable
@@ -56,7 +57,11 @@ module CZTop
56
57
  def recv_nonblock
57
58
  sock_ptr = to_ptr
58
59
  frame = CZMQ::FFI.zframe_recv_nowait(sock_ptr)
59
- return nil if frame.null?
60
+ if frame.null?
61
+ errno = CZMQ::FFI::Errors.errno
62
+ HasFFIDelegate.raise_zmq_err(errno: errno) unless errno == Errno::EAGAIN::Errno
63
+ return nil
64
+ end
60
65
 
61
66
  pp = _zframe_pp
62
67
  parts = []
@@ -13,7 +13,7 @@ module CZTop
13
13
 
14
14
  # @param endpoints [String] endpoints to bind to
15
15
  # @param curve [Hash, nil] CURVE encryption options
16
- # @param linger [Integer] linger period in milliseconds (default: 0)
16
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
17
17
  #
18
18
  def initialize(endpoints = nil, curve: nil, linger: 0)
19
19
  super
@@ -13,7 +13,7 @@ module CZTop
13
13
 
14
14
  # @param endpoints [String] endpoints to connect to
15
15
  # @param curve [Hash, nil] CURVE encryption options
16
- # @param linger [Integer] linger period in milliseconds (default: 0)
16
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
17
17
  #
18
18
  def initialize(endpoints = nil, curve: nil, linger: 0)
19
19
  super
@@ -13,7 +13,7 @@ module CZTop
13
13
 
14
14
  # @param endpoints [String] endpoints to bind to
15
15
  # @param curve [Hash, nil] CURVE encryption options
16
- # @param linger [Integer] linger period in milliseconds (default: 0)
16
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
17
17
  #
18
18
  def initialize(endpoints = nil, curve: nil, linger: 0)
19
19
  super
@@ -14,7 +14,7 @@ module CZTop
14
14
 
15
15
  # @param endpoints [String] endpoints to connect to
16
16
  # @param curve [Hash, nil] CURVE encryption options
17
- # @param linger [Integer] linger period in milliseconds (default: 0)
17
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
18
18
  #
19
19
  def initialize(endpoints = nil, curve: nil, linger: 0)
20
20
  super
@@ -17,7 +17,7 @@ module CZTop
17
17
  # @param prefix [String, nil] subscription prefix; defaults to no
18
18
  # subscription. Pass {EVERYTHING} (+""+) to subscribe to everything.
19
19
  # @param curve [Hash, nil] CURVE encryption options
20
- # @param linger [Integer] linger period in milliseconds (default: 0)
20
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
21
21
  #
22
22
  def initialize(endpoints = nil, prefix: nil, curve: nil, linger: 0)
23
23
  super(endpoints, curve: curve, linger: linger)
@@ -16,18 +16,19 @@ module CZTop
16
16
  # @return [self]
17
17
  #
18
18
  def send(message)
19
- parts = message.is_a?(Array) ? message : [message]
19
+ parts = message.is_a?(Array) ? message.map(&:to_s) : [message.to_s]
20
20
  raise ArgumentError, 'message has no parts' if parts.empty?
21
21
 
22
22
  # Fast path: nonblock send (no GVL release)
23
23
  return self if send_nonblock(parts)
24
+ raise IO::EAGAINWaitWritable if write_timeout == 0
24
25
 
25
26
  # Slow path: FD poll → blocking send
26
27
  wait_writable
27
28
 
28
29
  zmsg = CZMQ::FFI::Zmsg.new
29
30
  parts.each do |part|
30
- rc = zmsg.add_buffer(part.to_s)
31
+ rc = zmsg.add_buffer(part)
31
32
  HasFFIDelegate.raise_zmq_err unless rc.zero?
32
33
  end
33
34
 
@@ -65,9 +66,8 @@ module CZTop
65
66
  last_idx = parts.size - 1
66
67
 
67
68
  parts.each_with_index do |part, i|
68
- str = part.to_s
69
- frame = CZMQ::FFI.zframe_new_s(str, str.bytesize)
70
- return false if frame.null?
69
+ frame = CZMQ::FFI.zframe_new_s(part, part.bytesize)
70
+ raise NoMemoryError, 'could not allocate message frame' if frame.null?
71
71
 
72
72
  flags = CZMQ::FFI::ZFRAME_DONTWAIT
73
73
  flags |= CZMQ::FFI::ZFRAME_MORE if i < last_idx
@@ -75,7 +75,9 @@ module CZTop
75
75
  pp.write_pointer(frame)
76
76
  rc = CZMQ::FFI.zframe_send(pp, sock_ptr, flags)
77
77
  unless rc.zero?
78
+ errno = CZMQ::FFI::Errors.errno
78
79
  CZMQ::FFI.zframe_destroy(pp)
80
+ HasFFIDelegate.raise_zmq_err(errno: errno) unless errno == Errno::EAGAIN::Errno
79
81
  return false
80
82
  end
81
83
  end
@@ -13,7 +13,7 @@ module CZTop
13
13
 
14
14
  # @param endpoints [String] endpoints to bind to
15
15
  # @param curve [Hash, nil] CURVE encryption options
16
- # @param linger [Integer] linger period in milliseconds (default: 0)
16
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
17
17
  #
18
18
  def initialize(endpoints = nil, curve: nil, linger: 0)
19
19
  super
@@ -13,7 +13,7 @@ module CZTop
13
13
 
14
14
  # @param endpoints [String] endpoints to connect to
15
15
  # @param curve [Hash, nil] CURVE encryption options
16
- # @param linger [Integer] linger period in milliseconds (default: 0)
16
+ # @param linger [Numeric, nil] linger period in seconds (default: 0)
17
17
  #
18
18
  def initialize(endpoints = nil, curve: nil, linger: 0)
19
19
  super
data/lib/cztop/socket.rb CHANGED
@@ -142,7 +142,7 @@ module CZTop
142
142
  # Connects or binds based on CZMQ endpoint prefix convention.
143
143
  # @api private
144
144
  # @param endpoints [String] endpoint, optionally prefixed with +@+ (bind) or +>+ (connect)
145
- # @param default [Symbol] +:connect+ or +:bind+ — action when no prefix given
145
+ # @param default [Symbol] +:connect+ or +:bind+; action when no prefix given
146
146
  #
147
147
  def _attach(endpoints, default:)
148
148
  return unless endpoints
data/lib/cztop/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CZTop
4
4
 
5
- VERSION = '2.0.1'
5
+ VERSION = '2.0.3'
6
6
 
7
7
  end
@@ -145,7 +145,15 @@ module CZTop
145
145
  # @return [String] current socket identity
146
146
  #
147
147
  def identity
148
- Zsock.identity(self).read_string
148
+ ptr = Zsock.identity(self)
149
+ HasFFIDelegate.raise_zmq_err if ptr.null?
150
+ begin
151
+ ptr.read_string
152
+ ensure
153
+ ref = ::FFI::MemoryPointer.new(:pointer)
154
+ ref.write_pointer(ptr)
155
+ CZMQ::FFI.zstr_free(ref)
156
+ end
149
157
  end
150
158
 
151
159
 
data/lib/cztop.rb CHANGED
@@ -40,5 +40,5 @@ require_relative 'cztop/monitor'
40
40
  require_relative 'cztop/curve'
41
41
  require_relative 'cztop/curve/auth'
42
42
 
43
- # Convenience alias — allows `Cztop::Socket::REQ` alongside `CZTop::Socket::REQ`.
43
+ # Convenience alias; allows `Cztop::Socket::REQ` alongside `CZTop::Socket::REQ`.
44
44
  Cztop = CZTop
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cztop
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger
@@ -198,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
198
  - !ruby/object:Gem::Version
199
199
  version: '0'
200
200
  requirements: []
201
- rubygems_version: 4.0.6
201
+ rubygems_version: 4.0.20
202
202
  specification_version: 4
203
203
  summary: CZMQ FFI binding to bring ZMQ sockets to Ruby
204
204
  test_files: []