cztop 1.3.1 → 2.0.0.rc2

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +110 -0
  3. data/CLAUDE.md +39 -0
  4. data/Gemfile +0 -4
  5. data/README.md +92 -177
  6. data/ZGUIDE_SUMMARY.md +1109 -0
  7. data/cztop.gemspec +6 -9
  8. data/lib/cztop/curve/auth.rb +100 -0
  9. data/lib/cztop/curve.rb +126 -0
  10. data/lib/cztop/ffi.rb +489 -0
  11. data/lib/cztop/has_ffi_delegate.rb +20 -9
  12. data/lib/cztop/monitor.rb +88 -87
  13. data/lib/cztop/socket/dealer.rb +30 -0
  14. data/lib/cztop/socket/fd_wait.rb +88 -0
  15. data/lib/cztop/socket/pair.rb +30 -0
  16. data/lib/cztop/socket/pub.rb +29 -0
  17. data/lib/cztop/socket/pull.rb +29 -0
  18. data/lib/cztop/socket/push.rb +29 -0
  19. data/lib/cztop/socket/readable.rb +76 -0
  20. data/lib/cztop/socket/rep.rb +30 -0
  21. data/lib/cztop/socket/req.rb +30 -0
  22. data/lib/cztop/socket/router.rb +40 -0
  23. data/lib/cztop/socket/stream.rb +31 -0
  24. data/lib/cztop/socket/sub.rb +52 -0
  25. data/lib/cztop/socket/types.rb +2 -341
  26. data/lib/cztop/socket/writable.rb +86 -0
  27. data/lib/cztop/socket/xpub.rb +30 -0
  28. data/lib/cztop/socket/xsub.rb +30 -0
  29. data/lib/cztop/socket.rb +68 -27
  30. data/lib/cztop/version.rb +1 -1
  31. data/lib/cztop/zsock_options.rb +333 -364
  32. data/lib/cztop.rb +28 -48
  33. metadata +34 -63
  34. data/bin/console +0 -7
  35. data/bin/setup +0 -7
  36. data/exe/z85decode +0 -31
  37. data/exe/z85encode +0 -31
  38. data/lib/cztop/actor.rb +0 -340
  39. data/lib/cztop/authenticator.rb +0 -113
  40. data/lib/cztop/beacon.rb +0 -117
  41. data/lib/cztop/cert_store.rb +0 -65
  42. data/lib/cztop/certificate.rb +0 -234
  43. data/lib/cztop/config/comments.rb +0 -77
  44. data/lib/cztop/config/serialization.rb +0 -102
  45. data/lib/cztop/config/traversing.rb +0 -188
  46. data/lib/cztop/config.rb +0 -135
  47. data/lib/cztop/frame.rb +0 -193
  48. data/lib/cztop/message/frames.rb +0 -88
  49. data/lib/cztop/message.rb +0 -220
  50. data/lib/cztop/metadata.rb +0 -111
  51. data/lib/cztop/poller/aggregated.rb +0 -142
  52. data/lib/cztop/poller/zmq.rb +0 -92
  53. data/lib/cztop/poller/zpoller.rb +0 -125
  54. data/lib/cztop/poller.rb +0 -245
  55. data/lib/cztop/polymorphic_zsock_methods.rb +0 -32
  56. data/lib/cztop/proxy.rb +0 -164
  57. data/lib/cztop/send_receive_methods.rb +0 -171
  58. data/lib/cztop/z85/padded.rb +0 -107
  59. data/lib/cztop/z85/pipe.rb +0 -200
  60. data/lib/cztop/z85.rb +0 -90
  61. data/lib/cztop/zap.rb +0 -259
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1347b002694da386afc7249ac227de7ee7f1224bb140564334b20d646336e73a
4
- data.tar.gz: faa02a6ba73af47cbff6af9664562e41d359ba4f13eb5813d6e1e5fc992b6aa8
3
+ metadata.gz: 3381b5cf1edd7c878bb5c26ccc16bf096a354cfab0724a8da61e7f4ce3146272
4
+ data.tar.gz: c6081e0b22ee66190b3d34eb9d4d6a2d5ecfda537e8cdbfc223cfd23d2b56e9f
5
5
  SHA512:
6
- metadata.gz: fd22665b89635d5f5a6bbd8326a1de9c13f77a39a253a07316089d9124ec18dadebc67f86b5ec471cc3e09cb0eb6c32d027ad523573fc2b8e502c37b05119cc2
7
- data.tar.gz: 1de1565a9d4656e9887958befb29ea0cad66ad90f30d84244f3f60bbcc7069a0cfc20bb1be1c8ff06db34e02546ca9ff8349c01689faa1725e6f8cb069e846db
6
+ metadata.gz: 8142a5ff3b45d88a3ebfc35b3a002dfb8b9be5937f0c37e1779530229d959b0457a1dfd49c062550b2c46d9389e5c3937272e979e5b703d09f68ed4732925201
7
+ data.tar.gz: 8591012e556649e6397c16a871f8f892a8b111ec06339e3271d03fd5eca187268363258429a949eb1d03c8245907cfbf30ae00662d9168f47e28aea14592094f
data/CHANGES.md CHANGED
@@ -1,3 +1,113 @@
1
+ 2.0.0.rc2
2
+ -----
3
+
4
+ ### Breaking changes
5
+
6
+ * **Removed `Socket.new_by_type` factory method** — use type-specific constructors
7
+ instead (e.g. `Socket::REQ.new`, `Socket::PUB.new`)
8
+ * **`linger` now defaults to 0** on all socket constructors — ZMQ's default of
9
+ infinite (-1) caused `#close` to block when unsent messages remained. Pass
10
+ `linger:` to override (e.g. `Socket::REQ.new(endpoint, linger: 1)`)
11
+
12
+ 2.0.0.rc1
13
+ -----
14
+
15
+ ### Breaking changes
16
+
17
+ * **Removed classes:** Actor, Authenticator, Beacon, Certificate, CertStore, Config,
18
+ Frame, Message, Metadata, Monitor, Poller, Proxy, Z85, ZAP
19
+ * **Removed modules:** SendReceiveMethods, PolymorphicZsockMethods
20
+ * **Removed socket types (draft API dropped):** SERVER, CLIENT, RADIO, DISH,
21
+ GATHER, SCATTER
22
+ * **Removed CURVE/PLAIN/GSSAPI security API:**
23
+ - `Socket#CURVE_server!`, `Socket#CURVE_client!`
24
+ - CURVE option methods (`#CURVE_server?`, `#CURVE_serverkey`,
25
+ `#CURVE_secretkey`, `#CURVE_publickey`, etc.)
26
+ - PLAIN option methods (`#PLAIN_server?`, `#PLAIN_username`,
27
+ `#PLAIN_password`, etc.)
28
+ - `#mechanism`, `#zap_domain`
29
+ * **Send/receive API changed:**
30
+ - `#receive` now returns `Array<String>` (was `CZTop::Message`)
31
+ - `#<<` accepts `String` or `Array<String>` directly (was `Message.coerce`)
32
+ - `#send` is the primary method; `#<<` is an alias (note: `#send` shadows
33
+ `Object#send`; use `__send__` for Ruby dispatch)
34
+ - `SendReceiveMethods` split into `Socket::Readable`, `Socket::Writable`, and
35
+ `Socket::FdWait` mixins; socket types include only what they need
36
+ (e.g. PUB includes only Writable, SUB only Readable)
37
+ * **Time-based options now use seconds** (was milliseconds) — applies to
38
+ `#recv_timeout`, `#send_timeout`, `#linger`, `#heartbeat_ivl`, `#heartbeat_ttl`,
39
+ `#heartbeat_timeout`, `#reconnect_ivl`
40
+ * **Sentinel values changed from -1 to nil:**
41
+ - `#recv_timeout` / `#send_timeout` — returns/accepts `nil` instead
42
+ of `-1` for "no timeout"
43
+ - `#linger` — `nil` instead of `-1` for "wait indefinitely"
44
+ - `#heartbeat_timeout` — `nil` instead of `-1` for "use IVL"
45
+ - `#reconnect_ivl` — `nil` instead of `-1` for "disabled"
46
+ * **`Socket::SUB#initialize` subscription is now a `prefix:` kwarg** — was a
47
+ positional parameter; defaults to `EVERYTHING` (`''`), pass `prefix: nil` to
48
+ skip subscribing
49
+ * **`#set_unbounded` moved from PolymorphicZsockMethods to Socket**
50
+ * **`OptionsAccessor` removed** — all option methods now live directly on
51
+ `Socket` (e.g. `socket.sndhwm` instead of `socket.options.sndhwm`)
52
+ * **`#rcvtimeo` / `#sndtimeo` removed** — use `#recv_timeout` / `#send_timeout`
53
+ (aliased as `#read_timeout` / `#write_timeout`). `nil` = no timeout
54
+ (block forever), `0` = nonblocking, positive = timeout in seconds.
55
+ * **Fuzzy `#[]` / `#[]=` accessors removed**
56
+ * **`czmq-ffi-gen` gem dependency removed** — replaced with handcrafted FFI
57
+ bindings in `lib/cztop/ffi.rb`
58
+ * **Minimum Ruby version raised to 3.3**
59
+
60
+ ### New features
61
+
62
+ * **`CZTop::Monitor`** — socket event monitoring via CZMQ's zmonitor actor;
63
+ detects CONNECTED, LISTENING, ACCEPTED, DISCONNECTED, and other ZMQ events.
64
+ Returns `Monitor::Event` value objects (`Data.define(:name, :endpoint, :peer_address)`)
65
+ * **`Cztop` module alias** — `Cztop = CZTop` for conventional Ruby naming;
66
+ both `Cztop::Socket::REQ` and `CZTop::Socket::REQ` work
67
+ * **`.bind` and `.connect` class methods** on all socket types —
68
+ `REP.bind(endpoint)` and `REQ.connect(endpoint)` as shorthand for
69
+ `new(nil).tap { |s| s.bind(endpoint) }`; passes through `curve:`,
70
+ `prefix:` (SUB), and other kwargs
71
+ * **CURVE encryption** with ergonomic `curve:` kwarg on all socket constructors:
72
+ - `CZTop::CURVE.keypair` — generate keypairs (32-byte binary)
73
+ - `CZTop::CURVE.public_key(secret_key)` — derive public from secret
74
+ - `CZTop::CURVE.z85_encode` / `.z85_decode` — Z85 utility for interop
75
+ - `CZTop::CURVE::Auth` — in-memory ZAP handler (no filesystem, no zauth actor)
76
+ - Server: `CZTop::Socket::REP.new(endpoint, curve: { secret_key: sk })`
77
+ - Client: `CZTop::Socket::REQ.new(endpoint, curve: { secret_key: sk, server_key: pk })`
78
+ * **`@`/`>` endpoint prefix convention** supported on all socket constructors
79
+ (e.g. `PAIR.new("@inproc://ep")` to bind, `PAIR.new(">inproc://ep")` to connect)
80
+ * **New socket options:**
81
+ - `#reconnect_ivl_max` — max reconnect backoff interval (exponential backoff)
82
+ - `#max_msg_size` — max inbound message size (DoS protection)
83
+ - `#immediate?` / `#immediate=` — queue only for completed connections
84
+ - `#conflate?` / `#conflate=` — keep only last message (last-value-cache)
85
+ - `#tcp_keepalive` / `#tcp_keepalive_idle` / `#tcp_keepalive_cnt` /
86
+ `#tcp_keepalive_intvl` — TCP keepalive tuning
87
+
88
+ ### Other changes
89
+
90
+ * **FFI bindings for zactor, zstr, zsock_wait** — foundational bindings for
91
+ CZMQ actor-based APIs (used by Monitor, extensible for future actors)
92
+ * replace old examples with numbered `examples/zguide/` pattern files
93
+ (01–12: req/rep, pub/sub, pipeline, lazy pirate, heartbeat, LVC, clone,
94
+ majordomo, titanic, binary star, freelance)
95
+ * expand ZGUIDE_SUMMARY.md to ~30 min read with working code excerpts,
96
+ threading/concurrency guidance, and common mistakes section
97
+ * replace RSpec with Minitest
98
+ * replace `perf/` with `bench/` using benchmark-ips
99
+ * add per-socket-type integration test files for all 13 types
100
+ * add socket combination tests (ROUTER+REQ, ROUTER+ROUTER, pipeline, XPUB+multi SUB)
101
+ * add HWM mute state tests (PUSH/PULL blocking, PUB/SUB dropping, ROUTER mandatory)
102
+ * add REQ/REP reconnection tests (TCP restart, stuck-state demonstration)
103
+ * add STREAM ↔ raw TCP integration tests
104
+ * add CURVE throughput benchmark (`bench/threads/curve_throughput.rb`)
105
+ * add Shannon entropy system tests for CURVE (`test/system/`)
106
+ * split socket creation from connect/bind to support pre-connect option setting
107
+ * tune FD_TIMEOUT (500ms → 250ms) and JIFFY (15ms → 1ms) for better responsiveness
108
+ * fix zmq_errno race condition in `#raise_zmq_err`
109
+ * move CZMQ signal handler disabling into `lib/cztop/ffi.rb`
110
+
1
111
  1.3.2 (1/3/2025)
2
112
  -----
3
113
  * add 'benchmark' dependency for specs
data/CLAUDE.md ADDED
@@ -0,0 +1,39 @@
1
+ # CZTop
2
+
3
+ Ruby FFI binding for CZMQ/ZMQ. Version 2.0.0.pre1. Requires Ruby >= 3.3.
4
+
5
+ ## Architecture
6
+
7
+ - `lib/cztop/socket.rb` — Socket base class (connect, bind, etc.)
8
+ - `lib/cztop/socket/fd_wait.rb` — `FdWait` mixin: FD polling infrastructure (`FD_TIMEOUT`, `JIFFY`, `#wait_for_fd_signal`, `#wait_for_socket_state`)
9
+ - `lib/cztop/socket/readable.rb` — `Readable` mixin: `#receive` → `Array<String>`, `#wait_readable`, `#read_timeout`
10
+ - `lib/cztop/socket/writable.rb` — `Writable` mixin: `#send` accepts `String`/`Array<String>`, `#<<`, `#wait_writable`, `#write_timeout`
11
+ - `lib/cztop/socket/types.rb` — `Types` constants + `TypeNames`
12
+ - `lib/cztop/socket/{req,rep,dealer,router,pub,sub,xpub,xsub,push,pull,pair,stream}.rb` — individual socket types
13
+ - `lib/cztop/ffi.rb` — FFI bindings (zsock, zmsg, zframe, zstr) + CZMQ signal handler disabling
14
+ - `bench/` — benchmark-ips scripts (async/threads × throughput/latency)
15
+
16
+ ### ZMQ FD polling
17
+
18
+ ZMQ uses a single edge-triggered FD for both read/write signaling. `#wait_for_socket_state`
19
+ checks socket readiness first (fast path via `#readable?`/`#writable?`), then polls the FD.
20
+
21
+ - `FD_TIMEOUT` (250ms) — max time in `IO#wait_readable` per loop iteration; safety net for missed edges
22
+ - `JIFFY` (1ms) — sleep after false wakeup (FD signals but socket not ready)
23
+ - Edge misses are rare (~0.2% of calls in ipc/tcp req/rep), never in inproc throughput
24
+ - `IO#wait_readable` is interruptible by signals — Ctrl-C works immediately
25
+ - `__send__` used instead of `send` to avoid clash with ZMQ `#send` method
26
+ - Socket types include only the mixins they need (e.g. PUB includes only Writable, SUB only Readable)
27
+
28
+ ### Tuning rationale
29
+
30
+ - JIFFY 15ms→1ms: each edge miss stalls for full JIFFY duration; 1ms reduces impact 15x
31
+ - FD_TIMEOUT 500ms→250ms: halves worst-case stall; no measurable perf impact since FD signals correctly 99.8% of the time
32
+ - Measured with `bench/jiffy_sweep.rb`, `bench/fd_timeout_sweep.rb`, `bench/edge_miss_count.rb`
33
+
34
+ ## Benchmarking
35
+
36
+ - Uses benchmark-ips with `warmup: 1, time: 3`
37
+ - Run benchmarks sequentially to reduce variance
38
+ - For parameter sweeps: test multiple values in a single script with 3 runs each, report median
39
+ - Sister project **rbnng** (`/home/roadster/dev/oss/rbnng`) has identical bench structure for comparison
data/Gemfile CHANGED
@@ -1,10 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
- # useful when working on czmq-ffi-gen in parallel
5
- # gem "czmq-ffi-gen", path: "../czmq-ffi-gen"
6
-
7
4
  group :development do
8
- gem 'codecov', require: false
9
5
  gem 'simplecov', require: false
10
6
  end
data/README.md CHANGED
@@ -1,224 +1,139 @@
1
- ![Specs status](https://github.com/paddor/cztop/workflows/STABLE%20API/badge.svg)
2
- ![Specs status](https://github.com/paddor/cztop/workflows/DRAFT%20API%20on%20Ruby%203.3/badge.svg)
3
- ![Specs status](https://github.com/paddor/cztop/workflows/DRAFT%20API%20on%20Ruby%203.4/badge.svg)
4
- [![codecov](https://codecov.io/gh/paddor/cztop/branch/master/graph/badge.svg?token=TnjOba97R7)](https://codecov.io/gh/paddor/cztop)
5
-
6
1
  # CZTop
7
2
 
8
- CZTop is a CZMQ binding for Ruby. It is based on
9
- [czmq-ffi-gen](https://github.com/paddor/czmq-ffi-gen), the generated low-level
10
- FFI binding of [CZMQ](https://github.com/zeromq/czmq) and has a focus on being
11
- easy to use for Rubyists (POLS) and providing first class support for security
12
- mechanisms (like CURVE).
13
-
3
+ [![CI](https://github.com/paddor/cztop/actions/workflows/ci.yml/badge.svg)](https://github.com/paddor/cztop/actions/workflows/ci.yml)
4
+ [![Gem Version](https://img.shields.io/gem/v/cztop?color=e9573f)](https://rubygems.org/gems/cztop)
5
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](LICENSE)
6
+ [![Ruby](https://img.shields.io/badge/Ruby-%3E%3D%203.3-CC342D?logo=ruby&logoColor=white)](https://www.ruby-lang.org)
14
7
 
15
- ## Example with Async
8
+ Ruby FFI binding for [CZMQ](http://czmq.zeromq.org/) / [ZeroMQ](https://zeromq.org/) — high-performance asynchronous messaging for distributed systems.
16
9
 
17
- See [this example](https://github.com/paddor/cztop/blob/master/examples/async.rb):
18
-
19
- ```ruby
20
- #! /usr/bin/env ruby
10
+ > **353k msg/s** inproc throughput | **49 µs** fiber roundtrip latency | nonblock fast path
21
11
 
22
- require 'bundler/inline'
12
+ ---
23
13
 
24
- gemfile do
25
- source 'https://rubygems.org'
26
- gem 'cztop', path: '../../'
27
- gem 'async'
28
- end
14
+ ## Highlights
29
15
 
30
- ENDPOINT = 'inproc://req_rep_example'
31
- # ENDPOINT = 'ipc:///tmp/req_rep_example0'
32
- # ENDPOINT = 'tcp://localhost:5556'
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`
33
19
 
34
- Async do |task|
35
- rep_task = task.async do |t|
36
- socket = CZTop::Socket::REP.new ENDPOINT
37
-
38
- loop do
39
- msg = socket.receive
40
- puts "<<< #{msg.to_a.inspect}"
41
- socket << msg.to_a.map(&:upcase)
42
- end
43
- ensure
44
- puts "REP done."
45
- end
20
+ ## Install
46
21
 
47
- task.async do
48
- socket = CZTop::Socket::REQ.new ENDPOINT
22
+ Install CZMQ on your system:
49
23
 
50
- 10.times do |i|
51
- socket << "foobar ##{i}"
52
- msg = socket.receive
53
- puts ">>> #{msg.to_a.inspect}"
54
- end
24
+ ```sh
25
+ # Debian/Ubuntu
26
+ sudo apt install libczmq-dev
55
27
 
56
- puts "REQ done."
57
- rep_task.stop
58
- end
59
- end
28
+ # macOS
29
+ brew install czmq
60
30
  ```
61
31
 
32
+ Then add the gem:
62
33
 
63
- Output:
34
+ ```sh
35
+ gem install cztop
36
+ # or in Gemfile
37
+ gem 'cztop'
64
38
  ```
65
- $ cd examples
66
- $ time ./async.rb
67
- <<< ["foobar #0"]
68
- >>> ["FOOBAR #0"]
69
- <<< ["foobar #1"]
70
- >>> ["FOOBAR #1"]
71
- <<< ["foobar #2"]
72
- >>> ["FOOBAR #2"]
73
- <<< ["foobar #3"]
74
- >>> ["FOOBAR #3"]
75
- <<< ["foobar #4"]
76
- >>> ["FOOBAR #4"]
77
- <<< ["foobar #5"]
78
- >>> ["FOOBAR #5"]
79
- <<< ["foobar #6"]
80
- >>> ["FOOBAR #6"]
81
- <<< ["foobar #7"]
82
- >>> ["FOOBAR #7"]
83
- <<< ["foobar #8"]
84
- >>> ["FOOBAR #8"]
85
- <<< ["foobar #9"]
86
- >>> ["FOOBAR #9"]
87
- REQ done.
88
- REP done.
89
-
90
- ________________________________________________________
91
- Executed in 401.51 millis fish external
92
- usr time 308.44 millis 605.00 micros 307.83 millis
93
- sys time 40.08 millis 278.00 micros 39.81 millis
94
39
 
95
- ```
40
+ ## Learning ZeroMQ
96
41
 
97
- A slightly more complex version (more sockets) is [here](https://github.com/paddor/cztop/blob/master/examples/massive_async.rb).
42
+ New to ZeroMQ? See [ZGUIDE_SUMMARY.md](ZGUIDE_SUMMARY.md) a ~30 min read covering all major patterns with working CZTop code examples.
98
43
 
99
- ## Overview
44
+ ## Quick Start
100
45
 
101
- ### Features
46
+ ### Request / Reply
102
47
 
103
- * Ruby idiomatic API
104
- * compatible with Fiber Scheduler (only on Ruby >= 3.2)
105
- * errors as exceptions
106
- * CURVE security
107
- * supports CZMQ DRAFT API
108
- * extensive spec coverage
48
+ ```ruby
49
+ require 'cztop'
50
+ require 'async'
109
51
 
110
- ## Requirements
52
+ Async do |task|
53
+ rep = CZTop::Socket::REP.new('inproc://example')
54
+ req = CZTop::Socket::REQ.new('inproc://example')
111
55
 
56
+ task.async do
57
+ msg = rep.receive
58
+ rep << msg.map(&:upcase)
59
+ end
112
60
 
113
- * CZMQ >= 4.2
114
- * ZMQ >= 4.3
61
+ req << 'hello'
62
+ puts req.receive.inspect # => ["HELLO"]
63
+ end
64
+ ```
115
65
 
66
+ ### Pub / Sub
116
67
 
117
- On Ubuntu 20.04+:
68
+ ```ruby
69
+ Async do |task|
70
+ pub = CZTop::Socket::PUB.new('inproc://pubsub')
71
+ sub = CZTop::Socket::SUB.new('inproc://pubsub')
72
+ sub.subscribe('') # subscribe to all
118
73
 
119
- $ sudo apt install libczmq-dev
74
+ sleep 0.01 # allow connection to establish
120
75
 
121
- On macOS using Homebrew, run:
76
+ task.async { pub << 'news flash' }
77
+ puts sub.receive.inspect # => ["news flash"]
78
+ end
79
+ ```
122
80
 
123
- $ brew install czmq
81
+ ### Push / Pull (Pipeline)
124
82
 
125
- ### Supported Rubies
83
+ ```ruby
84
+ Async do
85
+ push = CZTop::Socket::PUSH.new('inproc://pipeline')
86
+ pull = CZTop::Socket::PULL.new('inproc://pipeline')
126
87
 
127
- At least:
88
+ push << 'work item'
89
+ puts pull.receive.inspect # => ["work item"]
90
+ end
91
+ ```
128
92
 
129
- * Ruby 3.0, 3.1, 3.2, 3.3
93
+ ## Socket Types
130
94
 
131
- ## Installation
95
+ | Pattern | Classes | Direction |
96
+ |---------|---------|-----------|
97
+ | Request/Reply | `REQ`, `REP` | bidirectional |
98
+ | Publish/Subscribe | `PUB`, `SUB`, `XPUB`, `XSUB` | unidirectional |
99
+ | Pipeline | `PUSH`, `PULL` | unidirectional |
100
+ | Routing | `DEALER`, `ROUTER` | bidirectional |
101
+ | Exclusive pair | `PAIR` | bidirectional |
102
+ | Raw TCP | `STREAM` | bidirectional |
132
103
 
133
- To use this gem, add this line to your application's Gemfile:
104
+ All classes live under `CZTop::Socket::`.
134
105
 
135
- ```ruby
136
- gem 'cztop'
137
- ```
106
+ ## Performance
138
107
 
139
- And then execute:
140
-
141
- $ bundle
142
-
143
- Or install it yourself as:
144
-
145
- $ gem install cztop
146
-
147
- ### Class Hierarchy
148
-
149
- Here's an overview of the core classes:
150
-
151
- * [CZTop](http://www.rubydoc.info/gems/cztop/CZTop)
152
- * [Actor](http://www.rubydoc.info/gems/cztop/CZTop)
153
- * [Authenticator](http://www.rubydoc.info/gems/cztop/CZTop/Authenticator)
154
- * [Beacon](http://www.rubydoc.info/gems/cztop/CZTop/Beacon)
155
- * [Certificate](http://www.rubydoc.info/gems/cztop/CZTop/Certificate)
156
- * [CertStore](http://www.rubydoc.info/gems/cztop/CZTop/CertStore)
157
- * [Config](http://www.rubydoc.info/gems/cztop/CZTop/Config)
158
- * [Frame](http://www.rubydoc.info/gems/cztop/CZTop/Frame)
159
- * [Message](http://www.rubydoc.info/gems/cztop/CZTop/Message)
160
- * [Monitor](http://www.rubydoc.info/gems/cztop/CZTop/Monitor)
161
- * [Metadata](http://www.rubydoc.info/gems/cztop/CZTop/Metadata)
162
- * [Proxy](http://www.rubydoc.info/gems/cztop/CZTop/Proxy)
163
- * [Poller](http://www.rubydoc.info/gems/cztop/CZTop/Poller) (based on `zmq_poller_*()` functions)
164
- * [Aggregated](http://www.rubydoc.info/gems/cztop/CZTop/Poller/Aggregated)
165
- * [ZPoller](http://www.rubydoc.info/gems/cztop/CZTop/Poller/ZPoller)
166
- * [Socket](http://www.rubydoc.info/gems/cztop/CZTop/Socket)
167
- * [REQ](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REQ) < Socket
168
- * [REP](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REP) < Socket
169
- * [ROUTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/ROUTER) < Socket
170
- * [DEALER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DEALER) < Socket
171
- * [PUSH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUSH) < Socket
172
- * [PULL](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PULL) < Socket
173
- * [PUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUB) < Socket
174
- * [SUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SUB) < Socket
175
- * [XPUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XPUB) < Socket
176
- * [XSUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XSUB) < Socket
177
- * [PAIR](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PAIR) < Socket
178
- * [STREAM](http://www.rubydoc.info/gems/cztop/CZTop/Socket/STREAM) < Socket
179
- * [CLIENT](http://www.rubydoc.info/gems/cztop/CZTop/Socket/CLIENT) < Socket
180
- * [SERVER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SERVER) < Socket
181
- * [RADIO](http://www.rubydoc.info/gems/cztop/CZTop/Socket/RADIO) < Socket
182
- * [DISH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DISH) < Socket
183
- * [SCATTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SCATTER) < Socket
184
- * [GATHER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/GATHER) < Socket
185
- * [Z85](http://www.rubydoc.info/gems/cztop/CZTop/Z85)
186
- * [Padded](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Padded) < Z85
187
- * [Pipe](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Pipe)
188
- * [ZAP](http://www.rubydoc.info/gems/cztop/CZTop/ZAP)
189
-
190
- More information in the [API documentation](http://www.rubydoc.info/github/paddor/cztop).
191
-
192
- ## Documentation
193
-
194
- The API should be fairly straight-forward to anyone who is familiar with CZMQ
195
- and Ruby. The following API documentation is currently available:
196
-
197
- * [YARD API documentation](http://www.rubydoc.info/gems/cztop) (release)
198
-
199
- Feel free to start a [wiki](https://github.com/paddor/cztop/wiki) page.
108
+ Benchmarked with benchmark-ips on Linux x86_64 (CZMQ 4.2.1, ZMQ 4.3.5, Ruby 4.0.1 +YJIT):
200
109
 
201
- ## Performance
110
+ #### Throughput (push/pull)
202
111
 
203
- CZTop is just a convenience layer on top of the thin czmq-ffi-gen library.
112
+ | | inproc | ipc | tcp |
113
+ |---|--------|-----|-----|
114
+ | **Async** | 284k/s | 17k/s | 14k/s |
115
+ | **Threads** | 353k/s | 25k/s | 21k/s |
204
116
 
205
- Make sure to check out the
206
- [perf](https://github.com/paddor/cztop/blob/master/perf) directory for latency
207
- and throughput measurement scripts.
117
+ #### Latency (req/rep roundtrip)
208
118
 
209
- ## Usage
119
+ | | inproc | ipc | tcp |
120
+ |---|--------|-----|-----|
121
+ | **Async** | 49 µs | 100 µs | 107 µs |
122
+ | **Threads** | 113 µs | 154 µs | 168 µs |
210
123
 
211
- See the [examples](https://github.com/paddor/cztop/blob/master/examples) directory for some examples.
124
+ Async fibers deliver 2.3x lower inproc latency thanks to cheap context switching. See [`bench/`](bench/) for full results and scripts.
212
125
 
126
+ ## API Reference
213
127
 
214
- ## Contributing
128
+ Full [API documentation](http://www.rubydoc.info/gems/cztop).
215
129
 
216
- Bug reports and pull requests are welcome on GitHub at https://github.com/paddor/cztop.
130
+ ## Development
217
131
 
218
- To run the tests before/after you made any changes to the source and have
219
- created a test case for it, use `rake spec`.
132
+ ```sh
133
+ bundle install
134
+ bundle exec rake
135
+ ```
220
136
 
221
137
  ## License
222
138
 
223
- The gem is available as open source under the terms of the [ISC License](http://opensource.org/licenses/ISC).
224
- See the [LICENSE](https://github.com/paddor/cztop/blob/master/LICENSE) file.
139
+ [ISC](LICENSE)