asterism-zenoh 0.2.0 → 0.4.0

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: e69691b1bce645a0c919495f5b666dd315f94cc6f2c34707cee76eeeccc1d9f7
4
- data.tar.gz: efff8d1807c7752b2d2cadd9d71a082ac96da2acf95af0e9f33873686b5be2d1
3
+ metadata.gz: d0a06884bbb4ef08eebe9eab69518c1d4c300b345ad7853742cda7ae48175e8d
4
+ data.tar.gz: acb609412809b6324c07d2a874819dfffa6499aec3b85d75e9c764bee551e2c4
5
5
  SHA512:
6
- metadata.gz: 18f12c15339bae03cbbe9116933d3eccbbf3c740376c5f348830cc7f8e2cf163bd5b0a86876b471955b08dcefa888e51bbcd8de5c4cf141816770e55b42f860f
7
- data.tar.gz: e25ab4b30899f357f9440a9c14d3cb12a7e8b80e36ff1962aa280726237c44b5a8af4091a14585273031e392658155f41d7946da2a2ebe092ef7184c9c8e1117
6
+ metadata.gz: 861adc9617255ca81225f4782e36c6fc664a37e56c34f778efebd6890359380ca047d9b9f29bc59aa12ddba39bee10f188cf3317244490bdc0299590a93e0e72
7
+ data.tar.gz: 75075726af74d8d6bfa6b785ac53b462e805f3445e9a434c94f5d38d07b1839d46493751c584e4c957f771b66ca36e76e11e2ee80bdec718340480c66b36279b
data/CHANGELOG.md ADDED
@@ -0,0 +1,89 @@
1
+ # Changelog
2
+
3
+ All notable changes to asterism-zenoh. The mruby / PicoRuby binding
4
+ (picoruby-asterism-zenoh) carries the same version number from 0.4.0 on.
5
+ Nothing has been published to rubygems.org yet; the versions below are
6
+ the ones in this repository.
7
+
8
+ ## 0.4.0
9
+
10
+ The first step of the API review toward 1.0 (the asterism gem's
11
+ docs/api_review.md). Additions and deprecations only: every 0.3.0 call
12
+ works as before.
13
+
14
+ Added
15
+
16
+ - Time limits in seconds: `timeout:` on `get`, `liveliness_get` and
17
+ `querier`, `query_timeout:` on `advanced_subscriber`, and
18
+ `connect_timeout:` on `Session.open` (it sets `connect/timeout_ms`).
19
+ `timeout_ms:` stays next to `timeout:`. Giving a time limit twice raises
20
+ `ArgumentError`, as does `scout(timeout:, timeout_ms:)`.
21
+ - Keywords next to the positional optionals: `get(key, params:, payload:)`,
22
+ `depth:` on `subscribe`, `queryable`, `liveliness_watch`,
23
+ `advanced_subscriber`, the listeners and the event streams, and
24
+ `Querier#get(params:, payload:)`.
25
+ - `depth:` on `get`, `liveliness_get` and `Querier#get`: the replies kept
26
+ until taken. Before, a get's queue held 16 and could not be changed, so
27
+ the replies to a wildcard past the 16th were dropped (a router answers
28
+ in one burst; `liveliness_get("@ros2_lv/**")` returned 16 of 31).
29
+ - `DEFAULT_DEPTH` (16), `DEFAULT_GET_DEPTH`, `DEFAULT_WATCH_DEPTH` and
30
+ `MAX_DEPTH`.
31
+ - `Asterism.warn_once(obj, message)`: warns once per object (the asterism
32
+ gem uses it for gets and watches that dropped something).
33
+ - `Session#connection_count` (the routers of a client session, or the peers
34
+ of a peer session).
35
+ - One error tree: `Asterism::Error` (defined here, reopened by the asterism
36
+ gem) > `Asterism::Zenoh::Error` > `Asterism::Zenoh::ClosedError` (the
37
+ session is closed or its connection was lost). `Error#code` is zenoh-c's
38
+ result code when the failure had one.
39
+ - `Session.open { |s| }` closes the session after the block.
40
+ - `Query#reply_error` / `reply_delete` (the spelled-out `reply_err` /
41
+ `reply_del`).
42
+ - `BACKEND` (`:zenoh_c`), `BACKEND_VERSION`, `PEER_SUPPORTED`,
43
+ `DEFAULT_TIMEOUT` (2.0 s).
44
+ - `express?`, `multicast?` and `streamed?` on the values that have those
45
+ members.
46
+ - A session used in a forked child raises `ClosedError` ("open a new
47
+ session after fork") instead of hanging on zenoh-c's threads, which do
48
+ not survive `fork`.
49
+ - `Asterism.deprecated` and `Asterism.deprecations = :warn / :raise /
50
+ :silent` (also `ASTERISM_DEPRECATIONS`): the one helper every Asterism
51
+ gem uses to warn once per name.
52
+
53
+ Changed
54
+
55
+ - The default queue depth of `get`, `liveliness_get`, `Querier#get` and
56
+ `liveliness_watch` is 1024 (was 16), so a burst of replies or of live
57
+ tokens is kept whole. The largest `depth:` is 65536 (was 1024). The
58
+ queues grow as entries come, so a deep one costs nothing while empty.
59
+
60
+ Deprecated (each warns once; removed or changed in 1.0)
61
+
62
+ - The time limit as a positional argument: `get(key, timeout_ms, params,
63
+ payload)` and `liveliness_get(key, timeout_ms)`. A Float there warns
64
+ with its own message: it is milliseconds and truncated (`get(key, 2.0)`
65
+ waits 2 ms).
66
+ - `Session#peers`: use `connection_count`.
67
+ - `Query#reply(payload)` when the query's key differs from the queryable's
68
+ own key and that key has no wildcard: from 1.0 such a reply answers on
69
+ the queryable's key.
70
+
71
+ ## 0.3.0
72
+
73
+ - Configuration (`config:` Hash or JSON5 String, `config_file:`; TLS and
74
+ the rest of zenoh's keys), scouting, `delete`, declared publishers and
75
+ queriers with matching status, the full sample and reply values (`Data`),
76
+ error and delete replies, encodings, timestamps, key expressions, the
77
+ advanced publisher / subscriber, transport and link events, zenoh-c's
78
+ log. All CRuby only.
79
+ - CI on Linux and macOS, Ruby 3.2 to 4.0, and an installed-gem check.
80
+
81
+ ## 0.2.0
82
+
83
+ - A session and its objects may be used from several Ruby threads.
84
+
85
+ ## 0.1.0
86
+
87
+ - The CRuby binding over the prebuilt zenoh-c, split out of the asterism
88
+ repository: the API of the mruby / PicoRuby binding (sessions, put /
89
+ subscribe, get / queryable, liveliness, attachments).
data/README.md CHANGED
@@ -18,6 +18,28 @@ loop do
18
18
  end
19
19
  ```
20
20
 
21
+ ## Feature coverage
22
+
23
+ Supported: sessions (client, peer, listening, multicast scouting), any
24
+ zenoh configuration (a Hash of keys, a JSON5 String or file: TLS, QUIC,
25
+ WebSocket, authentication, timeouts), put / delete with encoding, priority,
26
+ congestion control, express, reliability and timestamps, declared
27
+ publishers and queriers with matching status, subscribers with the full
28
+ sample (kind, encoding, timestamp, ...), get / queryable with error and
29
+ delete replies, liveliness, the advanced publisher / subscriber (history
30
+ for late subscribers, recovery, publisher detection; ROS 2 transient
31
+ local), transport and link events, key expression operations and declared
32
+ key expressions, HLC timestamps, zenoh-c's log.
33
+
34
+ Not exposed: shared memory, background declarations, zenoh's own
35
+ serializer (MessagePack and CDR are used instead), the publication cache /
36
+ querying subscriber (the older form of the advanced ones), cancelling a
37
+ get.
38
+
39
+ The table, with the reasons and what the boards' zenoh-pico could offer:
40
+ [docs/feature_coverage.md](docs/feature_coverage.md). The calls added in
41
+ 0.3.0 are CRuby only.
42
+
21
43
  ## API
22
44
 
23
45
  The same calls, arguments and results as the mruby / PicoRuby gem
@@ -25,25 +47,114 @@ The same calls, arguments and results as the mruby / PicoRuby gem
25
47
 
26
48
  | Call | Notes |
27
49
  |---|---|
28
- | `Session.open(locator = nil, mode: :client, listen: nil)` | client of a router, or `mode: :peer` connecting to `locator` and/or listening on `listen:`. `Error` when nobody answers within `CONNECT_TIMEOUT_MS`. Releases the GVL while connecting |
50
+ | `Session.open(locator = nil, mode: :client, listen: nil) { \|s\| }` | client of a router, or `mode: :peer` connecting to `locator` and/or listening on `listen:`. `Error` when nobody answers within `CONNECT_TIMEOUT_MS`. With a block: closes the session after it and returns the block's value. Releases the GVL while connecting |
29
51
  | `session.put(key, payload, attachment: nil)` | `payload` / `attachment` are Strings (bytes). Releases the GVL |
30
- | `session.subscribe(key, depth = 16)` -> `Subscriber` | `each_pending { \|key, payload, attachment\| }` (or an Array), `pending` / `received` / `dropped`, `close` / `closed?` |
31
- | `session.get(key, timeout_ms = 2000, params = nil, payload = nil, attachment: nil, target: :all, consolidation: :none)` -> `Get` | returns at once; `each_reply { \|key, payload, attachment\| }`, `done?`, `pending` / `received` / `dropped` / `errors` |
32
- | `session.queryable(key, depth = 16, complete: false)` -> `Queryable` | `each_pending { \|q\| }` (each query finished after the block) or an Array of `Query` |
33
- | `q.key` / `params` / `payload` / `attachment`, `q.reply([key,] payload, attachment: nil)`, `q.finish` / `finished?` | |
52
+ | `session.subscribe(key, depth: 16)` -> `Subscriber` | `each_pending { \|key, payload, attachment\| }` (or an Array), `pending` / `received` / `dropped`, `close` / `closed?`. `depth` may also be positional |
53
+ | `session.get(key, timeout: 2.0, params: nil, payload: nil, attachment: nil, target: :all, consolidation: :none, depth: DEFAULT_GET_DEPTH)` -> `Get` | `timeout:` in seconds, or `timeout_ms:`. `depth:` the replies kept until taken (see Queue depths). Returns at once; `each_reply { \|key, payload, attachment\| }`, `done?`, `pending` / `received` / `dropped` / `errors`. `consolidation: :none` (every reply) differs from zenoh's `:auto` on purpose: services and the object layer want every reply |
54
+ | `session.queryable(key, depth: 16, complete: false)` -> `Queryable` | `each_pending { \|q\| }` (each query finished after the block) or an Array of `Query` |
55
+ | `q.key` / `params` / `payload` / `attachment`, `q.reply(key, payload, attachment: nil)`, `q.finish` / `finished?` | `q.reply(payload)` answers on the query's key (see Deprecations) |
34
56
  | `session.liveliness(key)` -> `LivelinessToken` | `close` / `closed?` |
35
- | `session.liveliness_watch(key, depth = 16)` -> `LivelinessWatch` | `each_pending { \|key, alive\| }`; the tokens alive now come first |
36
- | `session.liveliness_get(key, timeout_ms = 2000)` -> `Get` | |
37
- | `session.poll(steps = 8)` / `closed?` / `close` / `zid` / `peers` | |
38
- | `Asterism::Zenoh::Error` | |
39
- | `CONNECT_TIMEOUT_MS`, `SEND_TIMEOUT_MS` (3000), `PEER` (true), `MAX_PEERS`, `C_VERSION` | `MAX_PEERS` is zenoh-c's `transport/unicast/max_sessions` (1000); `C_VERSION` stands for the mruby gem's `PICO_VERSION` |
57
+ | `session.liveliness_watch(key, depth: DEFAULT_WATCH_DEPTH)` -> `LivelinessWatch` | `each_pending { \|key, alive\| }`, `pending` / `received` / `dropped`; the tokens alive now come first, in one burst |
58
+ | `session.liveliness_get(key, timeout: 2.0, depth: DEFAULT_GET_DEPTH)` -> `Get` | or `timeout_ms:` |
59
+ | `session.poll(steps = 8)` / `closed?` / `close` / `zid` / `connection_count` | `connection_count`: the routers (client) or peers (peer mode) connected now |
60
+ | `Asterism::Error` > `Asterism::Zenoh::Error` > `Asterism::Zenoh::ClosedError` | `ClosedError`: the session is closed or its connection was lost. `Error#code`: zenoh-c's result code when there was one |
61
+ | `CONNECT_TIMEOUT_MS`, `SEND_TIMEOUT_MS` (3000), `PEER` / `PEER_SUPPORTED` (true), `MAX_PEERS`, `BACKEND` (`:zenoh_c`), `BACKEND_VERSION` (= `C_VERSION`), `DEFAULT_TIMEOUT` (2.0 s), `DEFAULT_DEPTH` (16), `DEFAULT_GET_DEPTH` / `DEFAULT_WATCH_DEPTH` (1024), `MAX_DEPTH` (65536), `VERSION` | `MAX_PEERS` is zenoh-c's `transport/unicast/max_sessions` (1000); on the boards `BACKEND` is `:zenoh_pico` |
62
+ | `Asterism.deprecations = :warn / :raise / :silent` | how deprecated calls are reported (below) |
63
+
64
+ Units: a keyword without a unit suffix is seconds (`timeout:`,
65
+ `connect_timeout:`, `query_timeout:`); anything else carries its unit
66
+ (`timeout_ms:`, `CONNECT_TIMEOUT_MS`). Giving a time limit twice
67
+ (`timeout:` and `timeout_ms:`) raises `ArgumentError`.
40
68
 
41
69
  Keys come back as UTF-8 Strings, payloads and attachments as binary
42
70
  (ASCII-8BIT) Strings.
43
71
 
72
+ ### Added in 0.3.0 (CRuby only)
73
+
74
+ Every 0.2.0 call works as before; these are new keywords and methods.
75
+
76
+ | Call | Notes |
77
+ |---|---|
78
+ | `Session.open(locator = nil, mode:, listen:, scouting:, timestamping:, config:, config_file:, connect_timeout:)` | `config:` a Hash (`{"transport/link/tls/root_ca_certificate" => "ca.pem"}`, Ruby values sent as JSON) or a JSON5 String; `config_file:` a JSON5 file. Lowest first: zenoh's defaults, the gem's own settings (no scouting, the time limits), the file / String, the arguments, the Hash. `scouting: true` needs no locator. `connect_timeout:` (seconds, 0.4.0) sets `connect/timeout_ms` |
79
+ | `Asterism::Zenoh.scout(what: [:router, :peer], timeout: 1.0, config: nil)` (or `timeout_ms:`) | Array of `Hello` (`zid`, `whatami`, `locators`) |
80
+ | `session.put(key, payload, attachment:, encoding:, priority:, congestion_control:, express:, reliability:, timestamp:, allowed_destination:)` | `priority:` `:real_time` .. `:background` (or 1..7), `congestion_control:` `:drop` / `:block` / `:block_first`, `reliability:` `:reliable` / `:best_effort`, `timestamp:` `true` or a `Timestamp`, `allowed_destination:` `:any` / `:remote` / `:session_local` |
81
+ | `session.delete(key, ...)` | the same options without payload, attachment and encoding |
82
+ | `session.publisher(key, encoding:, priority:, ...)` -> `Publisher` | `put(payload, attachment:, encoding:, timestamp:)`, `delete(timestamp:)`, `matching?`, `matching_listener(depth: 16)`, `close` / `closed?` |
83
+ | `session.querier(key, target:, consolidation:, timeout: 2.0, ...)` -> `Querier` | `timeout:` seconds or `timeout_ms:`; `get(params: nil, payload: nil, attachment:, encoding:, depth:)` -> `Get`, `matching?`, `matching_listener`, `close` |
84
+ | `sub.each_sample { \|sample\| }` | `Sample` (`key`, `payload`, `attachment`, `kind`, `encoding`, `timestamp`, `priority`, `congestion_control`, `express`, `reliability`, `source_zid`); same queue as `each_pending` |
85
+ | `get.each_result { \|reply\| }` | `Reply` (`ok?` / `error?`, `key`, `payload`, `encoding`, `kind`, `timestamp`, `replier_zid`); error replies included. `each_reply` still leaves them out |
86
+ | `session.get(..., encoding:, priority:, congestion_control:, express:, accept_replies:)` | |
87
+ | `q.reply(..., encoding:, timestamp:, priority:, congestion_control:, express:)`, `q.reply_error(payload, encoding:)`, `q.reply_delete(key = nil)`, `q.encoding` | `reply_err` / `reply_del` are the same (kept) |
88
+ | `session.advanced_publisher(key, cache:, sample_miss_detection:, publisher_detection:, ...)` -> `AdvancedPublisher` | as `Publisher`. `cache: N` keeps the last N samples for late subscribers |
89
+ | `session.advanced_subscriber(key, depth: 16, history:, recovery:, subscriber_detection:, query_timeout:)` -> `AdvancedSubscriber` | as `Subscriber`, plus `detect_publishers` (a `LivelinessWatch`) and `miss_listener` (`Miss`: `source_zid`, `source_eid`, `count`) |
90
+ | `session.transport_events(depth: 16, history: false)`, `session.link_events(...)` -> `EventListener` | `each_pending` gives `TransportEvent` / `LinkEvent` (`kind` `:added` / `:removed`, `zid`, ...) |
91
+ | `session.peer_zids`, `router_zids`, `transports`, `links` | the IDs, `Transport` and `Link` values connected now |
92
+ | `session.new_timestamp` -> `Timestamp` | `ntp64`, `id`, `to_time`, Comparable. From the session's HLC with `timestamping: true` (strictly increasing); otherwise from the system clock, so two in a row may be equal |
93
+ | `Asterism::Zenoh::KeyExpr.new(str, autocanonize: false)` | `intersects?`, `includes?`, `relation_to` (`:disjoint` / `:intersects` / `:includes` / `:equals`), `join`, `concat`, `==`; `KeyExpr.canonize(str)`, `KeyExpr.valid?(str)`. Accepted wherever a key String is |
94
+ | `session.declare_keyexpr(key)` -> `KeyExpr` | declared on the session (sent as a number afterwards); `undeclare` |
95
+ | `Asterism::Zenoh.init_log(level = nil)` | zenoh-c's log on standard output (`"info"`, `"debug"`, or a filter); `RUST_LOG` wins |
96
+
97
+ Listeners (`MatchingListener`, `EventListener`) are polled like the
98
+ subscribers: `each_pending` (yields or returns an Array), `pending`,
99
+ `received`, `dropped`, `close` / `closed?`. The values are `Data` objects
100
+ (`lib/asterism/zenoh/values.rb`), so they work with pattern matching; the
101
+ boolean members also have predicates (`express?`, `multicast?`,
102
+ `streamed?`).
103
+
104
+ ```ruby
105
+ Z = Asterism::Zenoh
106
+ s = Z::Session.open("tls/192.0.2.2:7447",
107
+ config: { "transport/link/tls/root_ca_certificate" => "ca.pem" })
108
+ pub = s.publisher("demo/temp", encoding: "text/plain", priority: :data_high)
109
+ watch = pub.matching_listener
110
+ sub = s.subscribe("demo/**")
111
+ loop do
112
+ watch.each_pending { |listening| puts "listened to: #{listening}" }
113
+ pub.put("21.5", timestamp: true)
114
+ sub.each_sample do |sm|
115
+ case sm
116
+ in {kind: :delete, key:} then puts "#{key} deleted"
117
+ in {encoding: "application/json", payload:} then p payload
118
+ else puts "#{sm.key} at #{sm.timestamp&.to_time}"
119
+ end
120
+ end
121
+ sleep 0.1
122
+ end
123
+
124
+ # A late subscriber gets the last values (ROS 2's transient local works this way)
125
+ latched = s.advanced_publisher("demo/mode", cache: 1, sample_miss_detection: true)
126
+ latched.put("eco")
127
+ late = s.advanced_subscriber("demo/mode", history: true)
128
+
129
+ Z.scout(what: :peer, timeout: 1.0).each { |h| puts "#{h.zid} #{h.locators}" }
130
+ Z::KeyExpr.new("demo/*").includes?("demo/temp") # => true
131
+ ```
132
+
44
133
  `require "asterism/zenoh/global"` defines `Zenoh = Asterism::Zenoh` for
45
134
  those who want the short name; nothing defines it by default.
46
135
 
136
+ ## Deprecations (0.4.0) and what 1.0 changes
137
+
138
+ 0.4.0 only adds; every 0.3.0 call still works. The old forms below warn
139
+ once per name (`warn`; on the boards `puts` when there is no `warn`).
140
+ `Asterism.deprecations = :raise` (or `ASTERISM_DEPRECATIONS=raise` in the
141
+ environment) raises `Asterism::DeprecationError` instead, which is what
142
+ the tests and CI use; `:silent` turns the warnings off.
143
+
144
+ | Deprecated | Use | 1.0 |
145
+ |---|---|---|
146
+ | `get(key, timeout_ms, params, payload)` (the time as a positional argument) | `get(key, timeout: 2.0, params:, payload:)` or `timeout_ms:` | removed (positional depth stays) |
147
+ | a Float there (`get(key, 2.0)` waits 2 ms) | `timeout: 2.0` | removed; warns with its own message now |
148
+ | `liveliness_get(key, timeout_ms)` | `liveliness_get(key, timeout: 1.0)` | removed |
149
+ | `session.peers` | `session.connection_count` | removed |
150
+ | `q.reply(payload)` on a query whose key differs from the queryable's own plain key | `q.reply(key, payload)` | answers on the queryable's own key when it has no wildcard (as the CRuby block API of the `asterism` gem does) |
151
+
152
+ Thread-safety: a `Session` and everything declared on it may be used from
153
+ several threads (below); each queued entry goes to exactly one taker. A
154
+ session opened before `fork` is unusable in the child: its calls raise
155
+ `ClosedError` ("open a new session after fork"); the parent's session is
156
+ not touched. Ractors are not supported.
157
+
47
158
  ## How receiving works
48
159
 
49
160
  zenoh-c runs the protocol on its own threads. Every subscriber, liveliness
@@ -67,18 +178,39 @@ thread and Enumerators on top of this API are in the CRuby layer of the
67
178
 
68
179
  ## Behaviour kept from the mruby gem
69
180
 
70
- - **No scouting**: the locator is given. A peer that only connects does not
71
- listen.
181
+ - **No scouting** unless asked for (`scouting: true`): the locator is
182
+ given. A peer that only connects does not listen.
72
183
  - **Remote only**: a session's own puts do not reach its own subscribers,
73
184
  and its gets do not reach its own queryables (zenoh-pico's behaviour;
74
185
  Asterism calls its own objects in place).
75
186
  - **Losing the connection**: a client session is closed when it has no
76
187
  router left, a peer session that only connects when it has no peer left;
77
- a listening session stays open. From then on `poll` is false, `closed?`
188
+ a listening (or scouting) session stays open. From then on `poll` is false, `closed?`
78
189
  true, and `put` raises `Asterism::Zenoh::Error`. No reconnection.
79
190
  - **Full queues drop the oldest** entry and count it in `dropped` (a dropped
80
191
  query is finished, so its requester gets no answer from it).
81
192
 
193
+ ### Queue depths
194
+
195
+ Every receiving object has a bounded queue; what does not fit is dropped,
196
+ oldest first, and counted in `dropped`. A router answers a wildcard get or
197
+ liveliness get, and a new liveliness watch, with everything at once, so
198
+ those queues are deep by default:
199
+
200
+ | | CRuby (zenoh-c) | Boards (zenoh-pico) |
201
+ |---|---|---|
202
+ | `subscribe`, `queryable`, listeners (`DEFAULT_DEPTH`) | 16 | 16 |
203
+ | `get`, `liveliness_get`, `querier.get` (`DEFAULT_GET_DEPTH`) | 1024 | 16 |
204
+ | `liveliness_watch` (`DEFAULT_WATCH_DEPTH`) | 1024 | 16 |
205
+ | largest `depth:` (`MAX_DEPTH`) | 65536 | 1024 |
206
+
207
+ On a PC a deep queue costs nothing until it fills (zenoh-c's FIFO and the
208
+ gem's lists grow as entries come). On a board a get's queue is allocated
209
+ when the get is sent; pass `depth:` when a wildcard can match more than 16
210
+ answers. Check `dropped` after a get whose answers matter; the asterism
211
+ gem's CRuby API warns once when one of its gets or watches dropped
212
+ something (`Asterism.warn_once`).
213
+
82
214
  Differences: `C_VERSION` instead of `PICO_VERSION`; `MAX_PEERS` is zenoh-c's
83
215
  limit, not 3; the time limits of gets are kept by zenoh-c (exact, not
84
216
  checked once a second); liveliness watches may also report the session's
@@ -0,0 +1,55 @@
1
+ # zenoh-c feature coverage of asterism-zenoh
2
+
3
+ Which zenoh-c 1.10.1 features the Ruby binding exposes (asterism-zenoh 0.4.0; 0.4.0 added
4
+ keywords and seconds, not features).
5
+ "Yes" = usable from Ruby, "Partial" = usable with fixed settings or a subset,
6
+ "No" = not exposed, with the reason. The Ruby-like layer of the `asterism`
7
+ gem builds on the same methods. The mruby gem (picoruby-asterism-zenoh) has
8
+ the 0.2.0 part of the API; its column says whether zenoh-pico could offer
9
+ the feature. Everything added in 0.3.0 is CRuby only for now.
10
+
11
+ | Area | zenoh-c | asterism-zenoh (CRuby) | Ruby | Possible on the boards (zenoh-pico) |
12
+ |---|---|---|---|---|
13
+ | Session: client / peer / listen | `z_open` | Yes | `Session.open(loc, mode:, listen:)` | Yes (done) |
14
+ | Session configuration | `zc_config_insert_json5`, `zc_config_from_str`, `zc_config_from_file` | Yes (0.3.0) | `config: {"key/path" => value}` (Ruby values sent as JSON), `config: "<JSON5>"`, `config_file:`. TLS, QUIC, WebSocket, authentication and timeouts are reachable this way; TLS is tested between two sessions | Partial (zenoh-pico has its own, smaller set of keys; no TLS on ESP32) |
15
+ | Scouting (finding peers / routers) | `z_scout`, multicast scouting, gossip | Yes (0.3.0) | `Asterism::Zenoh.scout(what:, timeout:)` -> `Hello` (zid, whatami, locators); `Session.open(scouting: true)` | Yes (off on purpose: the locator is given) |
16
+ | Session information | `z_info_zid`, `z_info_peers_zid`, `z_info_routers_zid`, `z_info_transports`, `z_info_links` | Yes (0.3.0) | `zid`, `connection_count` (count; `peers` is its deprecated name), `peer_zids`, `router_zids`, `transports`, `links` | Yes (zid lists); transports / links: No |
17
+ | put | `z_put` | Yes (0.3.0) | `put(key, payload, attachment:, encoding:, priority:, congestion_control:, express:, reliability:, timestamp:, allowed_destination:)` | Partial (encoding, priority, congestion control, express: yes) |
18
+ | delete | `z_delete` | Yes (0.3.0) | `session.delete(key, ...)` | Yes |
19
+ | Declared publisher | `z_declare_publisher`, `z_publisher_put`, `z_publisher_delete` | Yes (0.3.0) | `session.publisher(key, ...)` -> `put`, `delete`, `close` | Yes |
20
+ | Matching status (is anyone listening?) | `z_*_get_matching_status`, `z_*_declare_matching_listener` | Yes (0.3.0) | `matching?`, `matching_listener` -> `MatchingListener#each_pending` (polled) | Partial (zenoh-pico has it behind a build option) |
21
+ | Subscriber | `z_declare_subscriber` + FIFO channel | Yes | `each_pending { \|k, v, a\| }` as before; `each_sample` -> `Sample` (kind, encoding, timestamp, priority, congestion_control, express, reliability, source_zid) | Yes (done; the fields: Partial) |
22
+ | get | `z_get` | Yes | timeout, parameters, payload, attachment, target, consolidation; 0.3.0: encoding, priority, congestion control, express, accept_replies; `each_result` -> `Reply` with error replies; 0.4.0: `depth:` (the reply queue, 1024 by default) | Yes (done) |
23
+ | Declared querier | `z_declare_querier`, `z_querier_get` | Yes (0.3.0) | `session.querier(key, target:, consolidation:, timeout_ms:, ...)` -> `get(params, payload, attachment:, encoding:)`, `matching?`, `matching_listener` | Yes |
24
+ | Queryable | `z_declare_queryable`, `z_query_reply`, `z_query_reply_err`, `z_query_reply_del` | Yes (0.3.0) | `reply(..., encoding:, timestamp:, priority:, congestion_control:, express:)`, `reply_err(payload, encoding:)`, `reply_del(key)`, `query.encoding` | Yes |
25
+ | Liveliness | tokens, subscriber, get | Yes | `liveliness`, `liveliness_watch`, `liveliness_get`; `depth:` on the watch and the get (1024 by default on CRuby: a router sends every live token at once) | Yes (done) |
26
+ | Encoding (content types) | `z_encoding_from_str`, `z_encoding_to_string` | Yes (0.3.0) | Strings ("application/json", "text/plain;charset=utf-8"); default "zenoh/bytes" | Yes |
27
+ | Timestamps (HLC) | `z_timestamp_new`, `z_sample_timestamp`, timestamping | Yes (0.3.0) | `session.new_timestamp`, `Timestamp` (`ntp64`, `id`, `to_time`, Comparable), `put(timestamp: true)`, `Session.open(timestamping: true)` | Partial |
28
+ | Key expression operations | `z_keyexpr_intersects`, `includes`, `relation_to`, `join`, `concat`, `canonize`, `z_declare_keyexpr` | Yes (0.3.0) | `KeyExpr.new(str, autocanonize:)`, `intersects?`, `includes?`, `relation_to`, `join`, `concat`, `KeyExpr.canonize`, `KeyExpr.valid?`; `session.declare_keyexpr(key)`. A KeyExpr goes wherever a key String does | Yes |
29
+ | Advanced publisher / subscriber | `ze_declare_advanced_publisher`, `ze_declare_advanced_subscriber`, publisher detection, sample miss listener | Yes (0.3.0) | `advanced_publisher(key, cache:, sample_miss_detection:, publisher_detection:)`, `advanced_subscriber(key, history:, recovery:, subscriber_detection:)`, `detect_publishers`, `miss_listener`. A late rmw_zenoh subscriber with transient-local durability got the cached values | Partial (RAM to be measured) |
30
+ | Transport / link events | `z_declare_transport_events_listener`, `z_declare_link_events_listener` | Yes (0.3.0) | `session.transport_events(history:)`, `link_events` -> `EventListener#each_pending` (polled) of `TransportEvent` / `LinkEvent` | No |
31
+ | Logging | `zc_init_log_from_env_or`, `zc_try_init_log_from_env` | Yes (0.3.0) | `Asterism::Zenoh.init_log(level)`; written to standard output by zenoh-c; `RUST_LOG` wins | No |
32
+ | Error text | `zc_get_last_error` | Yes (0.3.0) | appended to the `Asterism::Zenoh::Error` messages of failed opens and declarations | No |
33
+ | Serialization helpers | `ze_serialize_*`, `ze_deserialize_*` | No | Not needed: MessagePack (objects) and CDR (ROS 2) are used; payloads stay Strings | Partial |
34
+ | Publication cache / querying subscriber | `ze_declare_publication_cache`, `ze_declare_querying_subscriber` | No | The older form of the advanced publisher / subscriber, which covers it | Partial |
35
+ | Shared memory | `z_shm_*` | No | Same-host only, and a Ruby String is copied anyway, so it would gain nothing | No |
36
+ | Background declarations | `z_declare_background_*` | No | Not needed: every object is closed by `close`, by its session or when it is freed | Partial |
37
+ | Cancellation of gets, source info on puts | `cancellation_token`, `source_info` | No | Rarely needed; a get ends by its time limit | No |
38
+
39
+ How receiving works, for all of the above: zenoh-c's callbacks copy what
40
+ arrives into a queue of plain C memory (no Ruby, no GVL), dropping the
41
+ oldest entry when it is full; Ruby takes the entries out by polling
42
+ (`each_pending`, `each_sample`, `each_result`). This holds for the matching
43
+ listeners, the transport / link events and the missed samples too.
44
+
45
+ Notes:
46
+
47
+ - The prebuilt zenoh-c that `gem install` downloads contains all of the above
48
+ (the "unstable" API included).
49
+ - An advanced publisher with a cache and without `sample_miss_detection`
50
+ needs a session with timestamping (`Session.open(..., timestamping: true)`).
51
+ - For ROS 2 transient-local, publish on the rmw_zenoh topic key with an
52
+ advanced publisher (`cache:`, `publisher_detection: true`,
53
+ `sample_miss_detection: true`) and declare the liveliness token with
54
+ durability transient local in its QoS (`":1:,10:,:,:,,"`).
55
+ `Asterism::ROS` does not do this by itself yet.