asterism-zenoh 0.1.0 → 0.3.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 +4 -4
- data/README.md +93 -5
- data/docs/feature_coverage.md +54 -0
- data/ext/asterism_zenoh/zenoh.c +3480 -771
- data/lib/asterism/zenoh/values.rb +105 -0
- data/lib/asterism/zenoh/version.rb +1 -1
- data/lib/asterism/zenoh.rb +5 -1
- metadata +8 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 67d782b46dad2501a9bb2ae1eed359b376c337ba0395f00dcf80d4d410df16a7
|
|
4
|
+
data.tar.gz: 394689733273761f4cd8e52be3c7e4339f55ae72501a4cdb247ce2c2cd48e4c0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 33b506497a568ba6851979bf141d53954ec221417f866c7e8438cb3e8e12bcf6d5530206b3854a18522d3bc46626037860aeb7f35065eb2338b8a24156c4afcc
|
|
7
|
+
data.tar.gz: 6db7c0db2a026ab7e6517d24fa996c0b31b5d90cd49f2e47fe335e3424703b62222788eeae631cef621d11a69d6f97bb3231baa52ccb06d654fe0a1ac107cf09
|
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
|
|
@@ -41,6 +63,65 @@ The same calls, arguments and results as the mruby / PicoRuby gem
|
|
|
41
63
|
Keys come back as UTF-8 Strings, payloads and attachments as binary
|
|
42
64
|
(ASCII-8BIT) Strings.
|
|
43
65
|
|
|
66
|
+
### Added in 0.3.0 (CRuby only)
|
|
67
|
+
|
|
68
|
+
Every 0.2.0 call works as before; these are new keywords and methods.
|
|
69
|
+
|
|
70
|
+
| Call | Notes |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `Session.open(locator = nil, mode:, listen:, scouting:, timestamping:, config:, config_file:)` | `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 |
|
|
73
|
+
| `Asterism::Zenoh.scout(what: [:router, :peer], timeout: 1.0, config: nil)` | Array of `Hello` (`zid`, `whatami`, `locators`) |
|
|
74
|
+
| `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` |
|
|
75
|
+
| `session.delete(key, ...)` | the same options without payload, attachment and encoding |
|
|
76
|
+
| `session.publisher(key, encoding:, priority:, ...)` -> `Publisher` | `put(payload, attachment:, encoding:, timestamp:)`, `delete(timestamp:)`, `matching?`, `matching_listener(depth = 16)`, `close` / `closed?` |
|
|
77
|
+
| `session.querier(key, target:, consolidation:, timeout_ms:, ...)` -> `Querier` | `get(params = nil, payload = nil, attachment:, encoding:)` -> `Get`, `matching?`, `matching_listener`, `close` |
|
|
78
|
+
| `sub.each_sample { \|sample\| }` | `Sample` (`key`, `payload`, `attachment`, `kind`, `encoding`, `timestamp`, `priority`, `congestion_control`, `express`, `reliability`, `source_zid`); same queue as `each_pending` |
|
|
79
|
+
| `get.each_result { \|reply\| }` | `Reply` (`ok?` / `error?`, `key`, `payload`, `encoding`, `kind`, `timestamp`, `replier_zid`); error replies included. `each_reply` still leaves them out |
|
|
80
|
+
| `session.get(..., encoding:, priority:, congestion_control:, express:, accept_replies:)` | |
|
|
81
|
+
| `q.reply(..., encoding:, timestamp:, priority:, congestion_control:, express:)`, `q.reply_err(payload, encoding:)`, `q.reply_del(key = nil)`, `q.encoding` | |
|
|
82
|
+
| `session.advanced_publisher(key, cache:, sample_miss_detection:, publisher_detection:, ...)` -> `AdvancedPublisher` | as `Publisher`. `cache: N` keeps the last N samples for late subscribers |
|
|
83
|
+
| `session.advanced_subscriber(key, depth = 16, history:, recovery:, subscriber_detection:, query_timeout_ms:)` -> `AdvancedSubscriber` | as `Subscriber`, plus `detect_publishers` (a `LivelinessWatch`) and `miss_listener` (`Miss`: `source_zid`, `source_eid`, `count`) |
|
|
84
|
+
| `session.transport_events(depth = 16, history: false)`, `session.link_events(...)` -> `EventListener` | `each_pending` gives `TransportEvent` / `LinkEvent` (`kind` `:added` / `:removed`, `zid`, ...) |
|
|
85
|
+
| `session.peer_zids`, `router_zids`, `transports`, `links` | the IDs, `Transport` and `Link` values connected now |
|
|
86
|
+
| `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 |
|
|
87
|
+
| `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 |
|
|
88
|
+
| `session.declare_keyexpr(key)` -> `KeyExpr` | declared on the session (sent as a number afterwards); `undeclare` |
|
|
89
|
+
| `Asterism::Zenoh.init_log(level = nil)` | zenoh-c's log on standard output (`"info"`, `"debug"`, or a filter); `RUST_LOG` wins |
|
|
90
|
+
|
|
91
|
+
Listeners (`MatchingListener`, `EventListener`) are polled like the
|
|
92
|
+
subscribers: `each_pending` (yields or returns an Array), `pending`,
|
|
93
|
+
`received`, `dropped`, `close` / `closed?`. The values are `Data` objects
|
|
94
|
+
(`lib/asterism/zenoh/values.rb`), so they work with pattern matching.
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
Z = Asterism::Zenoh
|
|
98
|
+
s = Z::Session.open("tls/192.0.2.2:7447",
|
|
99
|
+
config: { "transport/link/tls/root_ca_certificate" => "ca.pem" })
|
|
100
|
+
pub = s.publisher("demo/temp", encoding: "text/plain", priority: :data_high)
|
|
101
|
+
watch = pub.matching_listener
|
|
102
|
+
sub = s.subscribe("demo/**")
|
|
103
|
+
loop do
|
|
104
|
+
watch.each_pending { |listening| puts "listened to: #{listening}" }
|
|
105
|
+
pub.put("21.5", timestamp: true)
|
|
106
|
+
sub.each_sample do |sm|
|
|
107
|
+
case sm
|
|
108
|
+
in {kind: :delete, key:} then puts "#{key} deleted"
|
|
109
|
+
in {encoding: "application/json", payload:} then p payload
|
|
110
|
+
else puts "#{sm.key} at #{sm.timestamp&.to_time}"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
sleep 0.1
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# A late subscriber gets the last values (ROS 2's transient local works this way)
|
|
117
|
+
latched = s.advanced_publisher("demo/mode", cache: 1, sample_miss_detection: true)
|
|
118
|
+
latched.put("eco")
|
|
119
|
+
late = s.advanced_subscriber("demo/mode", history: true)
|
|
120
|
+
|
|
121
|
+
Z.scout(what: :peer, timeout: 1.0).each { |h| puts "#{h.zid} #{h.locators}" }
|
|
122
|
+
Z::KeyExpr.new("demo/*").includes?("demo/temp") # => true
|
|
123
|
+
```
|
|
124
|
+
|
|
44
125
|
`require "asterism/zenoh/global"` defines `Zenoh = Asterism::Zenoh` for
|
|
45
126
|
those who want the short name; nothing defines it by default.
|
|
46
127
|
|
|
@@ -55,19 +136,26 @@ its own thread. Nothing calls into Ruby behind its back, and `poll` does not
|
|
|
55
136
|
need to run for data to arrive: it only checks the connection.
|
|
56
137
|
|
|
57
138
|
Waiting calls (`Session.open`, `put`, `get`, `liveliness_get`, `close`)
|
|
58
|
-
release the GVL.
|
|
59
|
-
|
|
139
|
+
release the GVL. A `Session` and its objects may be used from several Ruby
|
|
140
|
+
threads: the calls that keep the GVL are serialized by it, the ones that
|
|
141
|
+
release it by a lock of the session, and a session that closes (by `close`
|
|
142
|
+
or because the connection was lost) is closed for every thread before
|
|
143
|
+
zenoh-c lets it go; calls made after that raise `Asterism::Zenoh::Error`.
|
|
144
|
+
Each entry of a queue is taken by exactly one `each_pending` /
|
|
145
|
+
`each_reply`. The gem itself starts no Ruby thread: blocks, a receiving
|
|
146
|
+
thread and Enumerators on top of this API are in the CRuby layer of the
|
|
147
|
+
`asterism` gem.
|
|
60
148
|
|
|
61
149
|
## Behaviour kept from the mruby gem
|
|
62
150
|
|
|
63
|
-
- **No scouting
|
|
64
|
-
listen.
|
|
151
|
+
- **No scouting** unless asked for (`scouting: true`): the locator is
|
|
152
|
+
given. A peer that only connects does not listen.
|
|
65
153
|
- **Remote only**: a session's own puts do not reach its own subscribers,
|
|
66
154
|
and its gets do not reach its own queryables (zenoh-pico's behaviour;
|
|
67
155
|
Asterism calls its own objects in place).
|
|
68
156
|
- **Losing the connection**: a client session is closed when it has no
|
|
69
157
|
router left, a peer session that only connects when it has no peer left;
|
|
70
|
-
a listening session stays open. From then on `poll` is false, `closed?`
|
|
158
|
+
a listening (or scouting) session stays open. From then on `poll` is false, `closed?`
|
|
71
159
|
true, and `put` raises `Asterism::Zenoh::Error`. No reconnection.
|
|
72
160
|
- **Full queues drop the oldest** entry and count it in `dropped` (a dropped
|
|
73
161
|
query is finished, so its requester gets no answer from it).
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# zenoh-c feature coverage of asterism-zenoh
|
|
2
|
+
|
|
3
|
+
Which zenoh-c 1.10.1 features the Ruby binding exposes (asterism-zenoh 0.3.0).
|
|
4
|
+
"Yes" = usable from Ruby, "Partial" = usable with fixed settings or a subset,
|
|
5
|
+
"No" = not exposed, with the reason. The Ruby-like layer of the `asterism`
|
|
6
|
+
gem builds on the same methods. The mruby gem (picoruby-asterism-zenoh) has
|
|
7
|
+
the 0.2.0 part of the API; its column says whether zenoh-pico could offer
|
|
8
|
+
the feature. Everything added in 0.3.0 is CRuby only for now.
|
|
9
|
+
|
|
10
|
+
| Area | zenoh-c | asterism-zenoh (CRuby) | Ruby | Possible on the boards (zenoh-pico) |
|
|
11
|
+
|---|---|---|---|---|
|
|
12
|
+
| Session: client / peer / listen | `z_open` | Yes | `Session.open(loc, mode:, listen:)` | Yes (done) |
|
|
13
|
+
| 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) |
|
|
14
|
+
| 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) |
|
|
15
|
+
| Session information | `z_info_zid`, `z_info_peers_zid`, `z_info_routers_zid`, `z_info_transports`, `z_info_links` | Yes (0.3.0) | `zid`, `peers` (count, as before), `peer_zids`, `router_zids`, `transports`, `links` | Yes (zid lists); transports / links: No |
|
|
16
|
+
| 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) |
|
|
17
|
+
| delete | `z_delete` | Yes (0.3.0) | `session.delete(key, ...)` | Yes |
|
|
18
|
+
| Declared publisher | `z_declare_publisher`, `z_publisher_put`, `z_publisher_delete` | Yes (0.3.0) | `session.publisher(key, ...)` -> `put`, `delete`, `close` | Yes |
|
|
19
|
+
| 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) |
|
|
20
|
+
| 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) |
|
|
21
|
+
| 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 | Yes (done) |
|
|
22
|
+
| 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 |
|
|
23
|
+
| 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 |
|
|
24
|
+
| Liveliness | tokens, subscriber, get | Yes | `liveliness`, `liveliness_watch`, `liveliness_get` | Yes (done) |
|
|
25
|
+
| 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 |
|
|
26
|
+
| 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 |
|
|
27
|
+
| 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 |
|
|
28
|
+
| 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) |
|
|
29
|
+
| 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 |
|
|
30
|
+
| 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 |
|
|
31
|
+
| Error text | `zc_get_last_error` | Yes (0.3.0) | appended to the `Asterism::Zenoh::Error` messages of failed opens and declarations | No |
|
|
32
|
+
| Serialization helpers | `ze_serialize_*`, `ze_deserialize_*` | No | Not needed: MessagePack (objects) and CDR (ROS 2) are used; payloads stay Strings | Partial |
|
|
33
|
+
| 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 |
|
|
34
|
+
| Shared memory | `z_shm_*` | No | Same-host only, and a Ruby String is copied anyway, so it would gain nothing | No |
|
|
35
|
+
| Background declarations | `z_declare_background_*` | No | Not needed: every object is closed by `close`, by its session or when it is freed | Partial |
|
|
36
|
+
| Cancellation of gets, source info on puts | `cancellation_token`, `source_info` | No | Rarely needed; a get ends by its time limit | No |
|
|
37
|
+
|
|
38
|
+
How receiving works, for all of the above: zenoh-c's callbacks copy what
|
|
39
|
+
arrives into a queue of plain C memory (no Ruby, no GVL), dropping the
|
|
40
|
+
oldest entry when it is full; Ruby takes the entries out by polling
|
|
41
|
+
(`each_pending`, `each_sample`, `each_result`). This holds for the matching
|
|
42
|
+
listeners, the transport / link events and the missed samples too.
|
|
43
|
+
|
|
44
|
+
Notes:
|
|
45
|
+
|
|
46
|
+
- The prebuilt zenoh-c that `gem install` downloads contains all of the above
|
|
47
|
+
(the "unstable" API included).
|
|
48
|
+
- An advanced publisher with a cache and without `sample_miss_detection`
|
|
49
|
+
needs a session with timestamping (`Session.open(..., timestamping: true)`).
|
|
50
|
+
- For ROS 2 transient-local, publish on the rmw_zenoh topic key with an
|
|
51
|
+
advanced publisher (`cache:`, `publisher_detection: true`,
|
|
52
|
+
`sample_miss_detection: true`) and declare the liveliness token with
|
|
53
|
+
durability transient local in its QoS (`":1:,10:,:,:,,"`).
|
|
54
|
+
`Asterism::ROS` does not do this by itself yet.
|