asterism-zenoh 0.3.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.
@@ -43,11 +43,13 @@
43
43
  * undeclared or the get is finished); whichever lets go last frees it.
44
44
  */
45
45
  #include <pthread.h>
46
+ #include <stdarg.h>
46
47
  #include <stdatomic.h>
47
48
  #include <stdbool.h>
48
49
  #include <stdint.h>
49
50
  #include <stdlib.h>
50
51
  #include <string.h>
52
+ #include <unistd.h>
51
53
 
52
54
  #include <ruby.h>
53
55
  #include <ruby/encoding.h>
@@ -56,7 +58,13 @@
56
58
  #include <zenoh.h>
57
59
 
58
60
  #define ZRB_DEFAULT_DEPTH 16
59
- #define ZRB_MAX_DEPTH 1024
61
+ /* A get, a liveliness get and a liveliness watch hold every reply or token
62
+ * a router sends in one burst (a wildcard over a busy network). On a PC the
63
+ * queue costs nothing until it fills: zenoh-c's FIFO and the gem's lists
64
+ * grow as entries come. */
65
+ #define ZRB_DEFAULT_GET_DEPTH 1024
66
+ #define ZRB_DEFAULT_WATCH_DEPTH 1024
67
+ #define ZRB_MAX_DEPTH 65536
60
68
  #define ZRB_DEFAULT_POLL_STEPS 8
61
69
  #define ZRB_DEFAULT_GET_TIMEOUT_MS 2000
62
70
  #define ZRB_MAX_GET_TIMEOUT_MS 600000
@@ -64,13 +72,13 @@
64
72
  #define ZRB_CONNECT_TIMEOUT_MS 3000
65
73
  #define ZRB_SEND_TIMEOUT_MS 3000
66
74
 
67
- static VALUE mAsterism, mZenoh, eZenohError;
75
+ static VALUE mAsterism, mZenoh, eAsterismError, eZenohError, eClosedError;
68
76
  static VALUE cSession, cSubscriber, cWatch, cQueryable, cQuery, cGet, cToken;
69
77
  static VALUE cAdvSubscriber, cPublisher, cAdvPublisher, cQuerier, cKeyExpr, cTimestamp;
70
78
  static VALUE cMatchingListener, cEventListener;
71
79
  static ID id_attachment, id_target, id_consolidation, id_complete, id_mode, id_listen;
72
80
  static ID id_config, id_config_file, id_scouting, id_history, id_new;
73
- static ID id_iv_session, id_iv_key, id_iv_parent;
81
+ static ID id_iv_session, id_iv_key, id_iv_parent, id_iv_code, id_iv_qkey;
74
82
  static ID id_client, id_peer, id_router, id_all, id_all_complete, id_best_matching;
75
83
  static ID id_none, id_latest, id_monotonic, id_auto;
76
84
 
@@ -347,14 +355,16 @@ static void zrb_owned_key(z_owned_keyexpr_t *ke, const char *key) {
347
355
  }
348
356
  }
349
357
 
350
- static long zrb_check_depth(VALUE v) {
351
- long depth = NIL_P(v) ? ZRB_DEFAULT_DEPTH : NUM2LONG(v);
358
+ static long zrb_check_depth_or(VALUE v, long def) {
359
+ long depth = NIL_P(v) ? def : NUM2LONG(v);
352
360
  if (depth < 1 || depth > ZRB_MAX_DEPTH) {
353
361
  rb_raise(rb_eArgError, "depth must be 1..%d", ZRB_MAX_DEPTH);
354
362
  }
355
363
  return depth;
356
364
  }
357
365
 
366
+ static long zrb_check_depth(VALUE v) { return zrb_check_depth_or(v, ZRB_DEFAULT_DEPTH); }
367
+
358
368
  static long zrb_check_timeout(VALUE v) {
359
369
  long t = NIL_P(v) ? ZRB_DEFAULT_GET_TIMEOUT_MS : NUM2LONG(v);
360
370
  if (t < 1 || t > ZRB_MAX_GET_TIMEOUT_MS) {
@@ -407,6 +417,22 @@ static void zrb_hold_session(VALUE obj, VALUE session, VALUE key) {
407
417
  }
408
418
  }
409
419
 
420
+ /* Raises klass with the zenoh-c result code as the exception's code
421
+ * (Asterism::Zenoh::Error#code) as well as in the message. */
422
+ #ifdef RBIMPL_ATTR_FORMAT
423
+ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
424
+ #endif
425
+ NORETURN(static void zrb_raise_code(VALUE klass, int code, const char *fmt, ...));
426
+ static void zrb_raise_code(VALUE klass, int code, const char *fmt, ...) {
427
+ va_list ap;
428
+ va_start(ap, fmt);
429
+ VALUE msg = rb_vsprintf(fmt, ap);
430
+ va_end(ap);
431
+ VALUE exc = rb_exc_new_str(klass, msg);
432
+ rb_ivar_set(exc, id_iv_code, INT2NUM(code));
433
+ rb_exc_raise(exc);
434
+ }
435
+
410
436
  /* ------------------------------------------------------- object structs */
411
437
 
412
438
  typedef struct zrb_session zrb_session;
@@ -441,6 +467,7 @@ struct zrb_session {
441
467
  zrb_qable *qables;
442
468
  zrb_token *tokens;
443
469
  zrb_ent *ents; /* the rest (0.3.0) */
470
+ pid_t pid; /* the process that opened it (zenoh-c's threads do not survive fork) */
444
471
  };
445
472
 
446
473
  typedef enum { ZSUB_PLAIN, ZSUB_LIVELINESS, ZSUB_ADVANCED } zsub_type;
@@ -913,6 +940,7 @@ typedef struct {
913
940
  int accept_replies;
914
941
  VALUE target, consolidation, timeout;
915
942
  bool has_target, has_consolidation, has_timeout;
943
+ VALUE depth; /* gets: nil (the default) or the queue depth */
916
944
  } zrb_opts;
917
945
 
918
946
  static int zrb_priority_arg(VALUE v) {
@@ -1018,6 +1046,7 @@ static void zrb_opts_parse(VALUE hash, const char *const *names, int n, zrb_opts
1018
1046
  o->priority = o->congestion_control = o->express = o->reliability = o->destination = o->accept_replies = -1;
1019
1047
  o->target = o->consolidation = o->timeout = Qnil;
1020
1048
  o->has_target = o->has_consolidation = o->has_timeout = false;
1049
+ o->depth = Qnil;
1021
1050
  if (NIL_P(hash)) {
1022
1051
  return;
1023
1052
  }
@@ -1079,6 +1108,8 @@ static void zrb_opts_parse(VALUE hash, const char *const *names, int n, zrb_opts
1079
1108
  } else if (strcmp(k, "timeout_ms") == 0) {
1080
1109
  o->timeout = v;
1081
1110
  o->has_timeout = true;
1111
+ } else if (strcmp(k, "depth") == 0) {
1112
+ o->depth = v;
1082
1113
  }
1083
1114
  }
1084
1115
  }
@@ -1670,6 +1701,9 @@ static VALUE zrb_query_yield_ensure(VALUE obj) {
1670
1701
  static VALUE zrb_qable_each_pending(VALUE self) {
1671
1702
  zrb_qable *q = zrb_qable_get(self);
1672
1703
  bool collect = !rb_block_given_p();
1704
+ /* The queryable's own key goes with each query (Query#reply with one
1705
+ * argument looks at it). */
1706
+ VALUE qkey = rb_attr_get(self, id_iv_key);
1673
1707
  VALUE out = collect ? rb_ary_new() : Qnil;
1674
1708
  long taken = 0;
1675
1709
  unsigned todo = atomic_load(&q->ch->queued);
@@ -1680,6 +1714,9 @@ static VALUE zrb_qable_each_pending(VALUE self) {
1680
1714
  break;
1681
1715
  }
1682
1716
  VALUE obj = zrb_query_wrap(&oq);
1717
+ if (!NIL_P(qkey)) {
1718
+ rb_ivar_set(obj, id_iv_qkey, qkey);
1719
+ }
1683
1720
  taken++;
1684
1721
  if (collect) {
1685
1722
  rb_ary_push(out, obj);
@@ -1806,7 +1843,7 @@ static VALUE zrb_query_reply(int argc, VALUE *argv, VALUE self) {
1806
1843
  zrb_bytes_from_str(&bytes, payload, "payload");
1807
1844
  z_result_t ret = z_query_reply(z_loan(zq->query), kp, z_move(bytes), &ro);
1808
1845
  if (ret != Z_OK) {
1809
- rb_raise(eZenohError, "reply failed (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
1846
+ zrb_raise_code(eZenohError, (int)ret, "reply failed (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
1810
1847
  }
1811
1848
  return Qnil;
1812
1849
  }
@@ -1833,7 +1870,7 @@ static VALUE zrb_query_reply_err(int argc, VALUE *argv, VALUE self) {
1833
1870
  zrb_bytes_from_str(&bytes, payload, "payload");
1834
1871
  z_result_t ret = z_query_reply_err(z_loan(zq->query), z_move(bytes), &eo);
1835
1872
  if (ret != Z_OK) {
1836
- rb_raise(eZenohError, "reply_err failed (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
1873
+ zrb_raise_code(eZenohError, (int)ret, "reply_err failed (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
1837
1874
  }
1838
1875
  return Qnil;
1839
1876
  }
@@ -1876,7 +1913,7 @@ static VALUE zrb_query_reply_del(int argc, VALUE *argv, VALUE self) {
1876
1913
  }
1877
1914
  z_result_t ret = z_query_reply_del(z_loan(zq->query), kp, &d);
1878
1915
  if (ret != Z_OK) {
1879
- rb_raise(eZenohError, "reply_del failed (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
1916
+ zrb_raise_code(eZenohError, (int)ret, "reply_del failed (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
1880
1917
  }
1881
1918
  return Qnil;
1882
1919
  }
@@ -1915,10 +1952,12 @@ static zrb_get *zrb_get_get(VALUE self) {
1915
1952
  return g;
1916
1953
  }
1917
1954
 
1918
- static VALUE zrb_get_new(zrb_get **out) {
1955
+ /* depth: how many replies wait to be taken; past it the oldest go (and
1956
+ * are counted in dropped). */
1957
+ static VALUE zrb_get_new(long depth, zrb_get **out) {
1919
1958
  zrb_get *g;
1920
1959
  VALUE obj = TypedData_Make_Struct(cGet, zrb_get, &zrb_get_type, g);
1921
- g->ch = zch_new(ZCH_REPLY, ZRB_DEFAULT_DEPTH);
1960
+ g->ch = zch_new(ZCH_REPLY, (uint32_t)depth);
1922
1961
  *out = g;
1923
1962
  return obj;
1924
1963
  }
@@ -2084,6 +2123,12 @@ static void *zrb_session_close_nogvl(void *p) {
2084
2123
  }
2085
2124
 
2086
2125
  static void zrb_session_shutdown(zrb_session *z, bool with_gvl_release) {
2126
+ if (z->open && z->pid != getpid()) {
2127
+ /* Opened before a fork: zenoh-c's threads are in the parent. Leave
2128
+ * the session to it; only this process's view is closed. */
2129
+ z->open = false;
2130
+ return;
2131
+ }
2087
2132
  zrb_session_detach_all(z);
2088
2133
  if (!z->open) {
2089
2134
  return;
@@ -2142,6 +2187,9 @@ static bool zrb_session_check_link(zrb_session *z) {
2142
2187
  if (!z->open) {
2143
2188
  return true;
2144
2189
  }
2190
+ if (z->pid != getpid()) {
2191
+ return true;
2192
+ }
2145
2193
  if (z_session_is_closed(z_loan(z->session))) {
2146
2194
  zrb_session_shutdown(z, true);
2147
2195
  return true;
@@ -2158,8 +2206,12 @@ static bool zrb_session_check_link(zrb_session *z) {
2158
2206
 
2159
2207
  static zrb_session *zrb_session_get_open(VALUE self) {
2160
2208
  zrb_session *z = zrb_session_get(self);
2209
+ if (z->open && z->pid != getpid()) {
2210
+ rb_raise(eClosedError, "the session was opened in process %ld; open a new session after fork",
2211
+ (long)z->pid);
2212
+ }
2161
2213
  if (zrb_session_check_link(z)) {
2162
- rb_raise(eZenohError, "session is closed");
2214
+ rb_raise(eClosedError, "session is closed");
2163
2215
  }
2164
2216
  return z;
2165
2217
  }
@@ -2441,13 +2493,14 @@ static VALUE zrb_session_s_open(int argc, VALUE *argv, VALUE klass) {
2441
2493
 
2442
2494
  rb_thread_call_without_gvl(zrb_open_nogvl, &a, RUBY_UBF_IO, NULL);
2443
2495
  if (a.ret != Z_OK) {
2444
- rb_raise(eZenohError, "cannot open a session to %s (%d)%" PRIsVALUE,
2496
+ zrb_raise_code(eZenohError, (int)a.ret, "cannot open a session to %s (%d)%" PRIsVALUE,
2445
2497
  locator != NULL ? locator : (listen != NULL ? listen : "the configured endpoints"), (int)a.ret,
2446
2498
  zrb_last_error());
2447
2499
  }
2448
2500
  z->open = true;
2449
2501
  z->live = true;
2450
2502
  z->peer = peer;
2503
+ z->pid = getpid();
2451
2504
  /* A peer that listens (or finds the others by scouting) stays open
2452
2505
  * without peers; one that only connects closes when it has none. */
2453
2506
  z->listening = peer && (is_router || listens || scouts);
@@ -2483,7 +2536,7 @@ static VALUE zrb_sub_new(VALUE self, zrb_session *z, VALUE key_v, long depth, bo
2483
2536
  ret = z_declare_subscriber(z_loan(z->session), &s->u.sub, z_loan(ke), z_move(cb), &so);
2484
2537
  }
2485
2538
  if (ret != Z_OK) {
2486
- rb_raise(eZenohError, "cannot subscribe to %s (%d)%" PRIsVALUE, key, (int)ret, zrb_last_error());
2539
+ zrb_raise_code(eZenohError, (int)ret, "cannot subscribe to %s (%d)%" PRIsVALUE, key, (int)ret, zrb_last_error());
2487
2540
  }
2488
2541
  s->declared = true;
2489
2542
  s->owner = z;
@@ -2503,11 +2556,12 @@ static VALUE zrb_session_subscribe(int argc, VALUE *argv, VALUE self) {
2503
2556
  return zrb_sub_new(self, z, key_v, depth, false);
2504
2557
  }
2505
2558
 
2506
- /* session.liveliness_watch(key, depth = 16) -> LivelinessWatch */
2559
+ /* session.liveliness_watch(key, depth = 1024) -> LivelinessWatch. The
2560
+ * tokens alive when it is declared come in one burst. */
2507
2561
  static VALUE zrb_session_liveliness_watch(int argc, VALUE *argv, VALUE self) {
2508
2562
  VALUE key_v, depth_v = Qnil;
2509
2563
  rb_scan_args(argc, argv, "11", &key_v, &depth_v);
2510
- long depth = zrb_check_depth(depth_v);
2564
+ long depth = zrb_check_depth_or(depth_v, ZRB_DEFAULT_WATCH_DEPTH);
2511
2565
  StringValueCStr(key_v);
2512
2566
  zrb_session *z = zrb_session_get_open(self);
2513
2567
  return zrb_sub_new(self, z, key_v, depth, true);
@@ -2541,7 +2595,7 @@ static VALUE zrb_session_queryable(int argc, VALUE *argv, VALUE self) {
2541
2595
  qo.allowed_origin = Z_LOCALITY_REMOTE;
2542
2596
  z_result_t ret = z_declare_queryable(z_loan(z->session), &q->qable, z_loan(ke), z_move(cb), &qo);
2543
2597
  if (ret != Z_OK) {
2544
- rb_raise(eZenohError, "cannot declare a queryable on %s (%d)%" PRIsVALUE, key, (int)ret, zrb_last_error());
2598
+ zrb_raise_code(eZenohError, (int)ret, "cannot declare a queryable on %s (%d)%" PRIsVALUE, key, (int)ret, zrb_last_error());
2545
2599
  }
2546
2600
  q->declared = true;
2547
2601
  q->owner = z;
@@ -2626,29 +2680,31 @@ static VALUE zrb_run_get(VALUE self, zrb_session *z, zrb_get_args *a, VALUE obj,
2626
2680
  z_drop(z_move(a->key));
2627
2681
  free(a->params);
2628
2682
  if (zrb_session_check_link(z)) {
2629
- rb_raise(eZenohError, "%s failed: the connection is lost (%d)", what, (int)a->ret);
2683
+ zrb_raise_code(eClosedError, (int)a->ret, "%s failed: the connection is lost (%d)", what, (int)a->ret);
2630
2684
  }
2631
2685
  if (a->ret != Z_OK) {
2632
- rb_raise(eZenohError, "%s failed (%d)", what, (int)a->ret);
2686
+ zrb_raise_code(eZenohError, (int)a->ret, "%s failed (%d)", what, (int)a->ret);
2633
2687
  }
2634
2688
  zrb_hold_session(obj, self, key_v);
2635
2689
  return obj;
2636
2690
  }
2637
2691
 
2638
- static const char *const zrb_get_kw[] = {"attachment", "target", "consolidation", "encoding",
2639
- "priority", "congestion_control", "express", "accept_replies"};
2692
+ static const char *const zrb_get_kw[] = {"attachment", "target", "consolidation", "encoding", "priority",
2693
+ "congestion_control", "express", "accept_replies", "depth"};
2640
2694
 
2641
2695
  /* session.get(key, timeout_ms = 2000, params = nil, payload = nil,
2642
2696
  * attachment: nil, target: :all, consolidation: :none,
2643
2697
  * encoding: nil, priority: nil, congestion_control: nil,
2644
- * express: nil, accept_replies: nil) -> Get.
2698
+ * express: nil, accept_replies: nil, depth: 1024) -> Get.
2645
2699
  * Returns at once; the replies come in on zenoh's threads. key: a String
2646
- * or a KeyExpr. accept_replies: :matching_query (zenoh's default) or :any. */
2700
+ * or a KeyExpr. accept_replies: :matching_query (zenoh's default) or :any.
2701
+ * depth: the replies kept until taken (the oldest go past it; dropped). */
2647
2702
  static VALUE zrb_session_get_m(int argc, VALUE *argv, VALUE self) {
2648
2703
  VALUE key_v, timeout_v = Qnil, params_v = Qnil, payload = Qnil, opts = Qnil;
2649
2704
  rb_scan_args(argc, argv, "13:", &key_v, &timeout_v, &params_v, &payload, &opts);
2650
2705
  zrb_opts o;
2651
- zrb_opts_parse(opts, zrb_get_kw, 8, &o);
2706
+ zrb_opts_parse(opts, zrb_get_kw, 9, &o);
2707
+ long depth = zrb_check_depth_or(o.depth, ZRB_DEFAULT_GET_DEPTH);
2652
2708
  VALUE key_str = zrb_key_string(key_v);
2653
2709
  long timeout_ms = zrb_check_timeout(timeout_v);
2654
2710
  const char *params = NIL_P(params_v) ? NULL : StringValueCStr(params_v);
@@ -2664,7 +2720,7 @@ static VALUE zrb_session_get_m(int argc, VALUE *argv, VALUE self) {
2664
2720
  a.z = z;
2665
2721
  zrb_key_owned(key_v, &a.key);
2666
2722
  zrb_get *g;
2667
- VALUE obj = zrb_get_new(&g);
2723
+ VALUE obj = zrb_get_new(depth, &g);
2668
2724
  z_get_options_default(&a.opts);
2669
2725
  a.opts.timeout_ms = (uint64_t)timeout_ms;
2670
2726
  a.opts.target = target;
@@ -2714,7 +2770,7 @@ static VALUE zrb_session_liveliness(VALUE self, VALUE key_v) {
2714
2770
  VALUE obj = TypedData_Make_Struct(cToken, zrb_token, &zrb_token_type, t);
2715
2771
  z_result_t ret = z_liveliness_declare_token(z_loan(z->session), &t->token, z_loan(ke), NULL);
2716
2772
  if (ret != Z_OK) {
2717
- rb_raise(eZenohError, "cannot declare a liveliness token on %s (%d)%" PRIsVALUE, key, (int)ret, zrb_last_error());
2773
+ zrb_raise_code(eZenohError, (int)ret, "cannot declare a liveliness token on %s (%d)%" PRIsVALUE, key, (int)ret, zrb_last_error());
2718
2774
  }
2719
2775
  t->declared = true;
2720
2776
  t->owner = z;
@@ -2724,10 +2780,15 @@ static VALUE zrb_session_liveliness(VALUE self, VALUE key_v) {
2724
2780
  return obj;
2725
2781
  }
2726
2782
 
2727
- /* session.liveliness_get(key, timeout_ms = 2000) -> Get */
2783
+ static const char *const zrb_lget_kw[] = {"depth"};
2784
+
2785
+ /* session.liveliness_get(key, timeout_ms = 2000, depth: 1024) -> Get */
2728
2786
  static VALUE zrb_session_liveliness_get(int argc, VALUE *argv, VALUE self) {
2729
- VALUE key_v, timeout_v = Qnil;
2730
- rb_scan_args(argc, argv, "11", &key_v, &timeout_v);
2787
+ VALUE key_v, timeout_v = Qnil, opts = Qnil;
2788
+ rb_scan_args(argc, argv, "11:", &key_v, &timeout_v, &opts);
2789
+ zrb_opts o;
2790
+ zrb_opts_parse(opts, zrb_lget_kw, 1, &o);
2791
+ long depth = zrb_check_depth_or(o.depth, ZRB_DEFAULT_GET_DEPTH);
2731
2792
  const char *key = StringValueCStr(key_v);
2732
2793
  long timeout_ms = zrb_check_timeout(timeout_v);
2733
2794
  zrb_session *z = zrb_session_get_open(self);
@@ -2738,7 +2799,7 @@ static VALUE zrb_session_liveliness_get(int argc, VALUE *argv, VALUE self) {
2738
2799
  a.liveliness = true;
2739
2800
  zrb_owned_key(&a.key, key);
2740
2801
  zrb_get *g;
2741
- VALUE obj = zrb_get_new(&g);
2802
+ VALUE obj = zrb_get_new(depth, &g);
2742
2803
  z_liveliness_get_options_default(&a.lopts);
2743
2804
  a.lopts.timeout_ms = (uint64_t)timeout_ms;
2744
2805
  zch_closure_reply(g->ch, &a.cb);
@@ -2778,8 +2839,9 @@ static VALUE zrb_session_zid(VALUE self) {
2778
2839
  return out;
2779
2840
  }
2780
2841
 
2781
- /* session.peers -> Integer: connected peers (peer mode), or routers (1
2782
- * normally) for a client session; 0 once closed. */
2842
+ /* session.connection_count -> Integer: connected peers (peer mode), or
2843
+ * routers (1 normally) for a client session; 0 once closed. (peers, its
2844
+ * old name, is defined in Ruby with a deprecation warning.) */
2783
2845
  static VALUE zrb_session_peers(VALUE self) {
2784
2846
  zrb_session *z = zrb_session_get(self);
2785
2847
  if (zrb_session_check_link(z)) {
@@ -2901,13 +2963,13 @@ static void zrb_send_run(zrb_send *s, const char *what) {
2901
2963
  z_drop(z_move(s->att));
2902
2964
  z_drop(z_move(s->enc));
2903
2965
  if (zrb_session_check_link(s->z)) {
2904
- rb_raise(eZenohError, "%s failed: the connection is lost (%d)", what, (int)s->ret);
2966
+ zrb_raise_code(eClosedError, (int)s->ret, "%s failed: the connection is lost (%d)", what, (int)s->ret);
2905
2967
  }
2906
2968
  if (s->undeclared) {
2907
2969
  rb_raise(eZenohError, "%s failed: the publisher is closed", what);
2908
2970
  }
2909
2971
  if (s->ret != Z_OK) {
2910
- rb_raise(eZenohError, "%s failed (%d)", what, (int)s->ret);
2972
+ zrb_raise_code(eZenohError, (int)s->ret, "%s failed (%d)", what, (int)s->ret);
2911
2973
  }
2912
2974
  }
2913
2975
 
@@ -3059,7 +3121,7 @@ static zrb_pub *zrb_pub_get_open(VALUE self) {
3059
3121
  rb_raise(eZenohError, "the publisher is closed");
3060
3122
  }
3061
3123
  if (zrb_session_check_link(p->ent.owner)) {
3062
- rb_raise(eZenohError, "session is closed");
3124
+ rb_raise(eClosedError, "session is closed");
3063
3125
  }
3064
3126
  return p;
3065
3127
  }
@@ -3153,7 +3215,7 @@ static VALUE zrb_session_publisher(int argc, VALUE *argv, VALUE self) {
3153
3215
  }
3154
3216
  z_result_t ret = z_declare_publisher(z_loan(z->session), &p->u.p, ke, &po);
3155
3217
  if (ret != Z_OK) {
3156
- rb_raise(eZenohError, "cannot declare a publisher on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
3218
+ zrb_raise_code(eZenohError, (int)ret, "cannot declare a publisher on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
3157
3219
  }
3158
3220
  return zrb_pub_wrap(self, z, p, obj, key_str);
3159
3221
  }
@@ -3259,7 +3321,7 @@ static VALUE zrb_session_advanced_publisher(int argc, VALUE *argv, VALUE self) {
3259
3321
  }
3260
3322
  z_result_t ret = ze_declare_advanced_publisher(z_loan(z->session), &p->u.a, ke, &ao);
3261
3323
  if (ret != Z_OK) {
3262
- rb_raise(eZenohError, "cannot declare an advanced publisher on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
3324
+ zrb_raise_code(eZenohError, (int)ret, "cannot declare an advanced publisher on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
3263
3325
  }
3264
3326
  return zrb_pub_wrap(self, z, p, obj, key_str);
3265
3327
  }
@@ -3326,7 +3388,7 @@ static VALUE zrb_pub_matching_p(VALUE self) {
3326
3388
  z_result_t r = p->advanced ? ze_advanced_publisher_get_matching_status(z_loan(p->u.a), &st)
3327
3389
  : z_publisher_get_matching_status(z_loan(p->u.p), &st);
3328
3390
  if (r != Z_OK) {
3329
- rb_raise(eZenohError, "cannot get the matching status (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3391
+ zrb_raise_code(eZenohError, (int)r, "cannot get the matching status (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3330
3392
  }
3331
3393
  return st.matching ? Qtrue : Qfalse;
3332
3394
  }
@@ -3370,7 +3432,7 @@ static zrb_querier *zrb_querier_get_open(VALUE self) {
3370
3432
  rb_raise(eZenohError, "the querier is closed");
3371
3433
  }
3372
3434
  if (zrb_session_check_link(q->ent.owner)) {
3373
- rb_raise(eZenohError, "session is closed");
3435
+ rb_raise(eClosedError, "session is closed");
3374
3436
  }
3375
3437
  return q;
3376
3438
  }
@@ -3415,7 +3477,7 @@ static VALUE zrb_session_querier(int argc, VALUE *argv, VALUE self) {
3415
3477
  VALUE obj = TypedData_Make_Struct(cQuerier, zrb_querier, &zrb_querier_type, q);
3416
3478
  z_result_t ret = z_declare_querier(z_loan(z->session), &q->q, ke, &qo);
3417
3479
  if (ret != Z_OK) {
3418
- rb_raise(eZenohError, "cannot declare a querier on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
3480
+ zrb_raise_code(eZenohError, (int)ret, "cannot declare a querier on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
3419
3481
  }
3420
3482
  zrb_ent_link(&q->ent, z, ZENT_ENTITY, true, zrb_querier_undeclare);
3421
3483
  zrb_hold_session(obj, self, key_str);
@@ -3449,14 +3511,16 @@ static void *zrb_qget_nogvl(void *p) {
3449
3511
  return NULL;
3450
3512
  }
3451
3513
 
3452
- static const char *const zrb_qget_kw[] = {"attachment", "encoding"};
3514
+ static const char *const zrb_qget_kw[] = {"attachment", "encoding", "depth"};
3453
3515
 
3454
- /* querier.get(params = nil, payload = nil, attachment: nil, encoding: nil) -> Get */
3516
+ /* querier.get(params = nil, payload = nil, attachment: nil, encoding: nil,
3517
+ * depth: 1024) -> Get */
3455
3518
  static VALUE zrb_querier_get_m(int argc, VALUE *argv, VALUE self) {
3456
3519
  VALUE params_v = Qnil, payload = Qnil, opts = Qnil;
3457
3520
  rb_scan_args(argc, argv, "02:", &params_v, &payload, &opts);
3458
3521
  zrb_opts o;
3459
- zrb_opts_parse(opts, zrb_qget_kw, 2, &o);
3522
+ zrb_opts_parse(opts, zrb_qget_kw, 3, &o);
3523
+ long depth = zrb_check_depth_or(o.depth, ZRB_DEFAULT_GET_DEPTH);
3460
3524
  const char *params = NIL_P(params_v) ? NULL : StringValueCStr(params_v);
3461
3525
  if (!NIL_P(payload) && !RB_TYPE_P(payload, T_STRING)) {
3462
3526
  rb_raise(rb_eTypeError, "payload must be a String");
@@ -3470,7 +3534,7 @@ static VALUE zrb_querier_get_m(int argc, VALUE *argv, VALUE self) {
3470
3534
  z_internal_bytes_null(&a.att);
3471
3535
  z_internal_encoding_null(&a.enc);
3472
3536
  zrb_get *g;
3473
- VALUE obj = zrb_get_new(&g);
3537
+ VALUE obj = zrb_get_new(depth, &g);
3474
3538
  z_querier_get_options_default(&a.opts);
3475
3539
  if (!NIL_P(payload)) {
3476
3540
  zrb_bytes_from_str(&a.payload, payload, "payload");
@@ -3493,13 +3557,13 @@ static VALUE zrb_querier_get_m(int argc, VALUE *argv, VALUE self) {
3493
3557
  z_drop(z_move(a.att));
3494
3558
  z_drop(z_move(a.enc));
3495
3559
  if (zrb_session_check_link(a.z)) {
3496
- rb_raise(eZenohError, "get failed: the connection is lost (%d)", (int)a.ret);
3560
+ zrb_raise_code(eClosedError, (int)a.ret, "get failed: the connection is lost (%d)", (int)a.ret);
3497
3561
  }
3498
3562
  if (a.undeclared) {
3499
3563
  rb_raise(eZenohError, "get failed: the querier is closed");
3500
3564
  }
3501
3565
  if (a.ret != Z_OK) {
3502
- rb_raise(eZenohError, "get failed (%d)", (int)a.ret);
3566
+ zrb_raise_code(eZenohError, (int)a.ret, "get failed (%d)", (int)a.ret);
3503
3567
  }
3504
3568
  rb_ivar_set(obj, id_iv_session, rb_ivar_get(self, id_iv_session));
3505
3569
  return obj;
@@ -3510,7 +3574,7 @@ static VALUE zrb_querier_matching_p(VALUE self) {
3510
3574
  z_matching_status_t st = {false};
3511
3575
  z_result_t r = z_querier_get_matching_status(z_loan(q->q), &st);
3512
3576
  if (r != Z_OK) {
3513
- rb_raise(eZenohError, "cannot get the matching status (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3577
+ zrb_raise_code(eZenohError, (int)r, "cannot get the matching status (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3514
3578
  }
3515
3579
  return st.matching ? Qtrue : Qfalse;
3516
3580
  }
@@ -3618,7 +3682,7 @@ static VALUE zrb_pub_matching_listener(int argc, VALUE *argv, VALUE self) {
3618
3682
  ? ze_advanced_publisher_declare_matching_listener(z_loan(p->u.a), &l->u.m, z_move(cb))
3619
3683
  : z_publisher_declare_matching_listener(z_loan(p->u.p), &l->u.m, z_move(cb));
3620
3684
  if (r != Z_OK) {
3621
- rb_raise(eZenohError, "cannot declare a matching listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3685
+ zrb_raise_code(eZenohError, (int)r, "cannot declare a matching listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3622
3686
  }
3623
3687
  zrb_lst_linked(obj, l, p->ent.owner, self);
3624
3688
  return obj;
@@ -3634,7 +3698,7 @@ static VALUE zrb_querier_matching_listener(int argc, VALUE *argv, VALUE self) {
3634
3698
  z_closure_matching_status(&cb, zev_on_matching, zevq_on_drop, zevq_ref(l->q));
3635
3699
  z_result_t r = z_querier_declare_matching_listener(z_loan(q->q), &l->u.m, z_move(cb));
3636
3700
  if (r != Z_OK) {
3637
- rb_raise(eZenohError, "cannot declare a matching listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3701
+ zrb_raise_code(eZenohError, (int)r, "cannot declare a matching listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3638
3702
  }
3639
3703
  zrb_lst_linked(obj, l, q->ent.owner, self);
3640
3704
  return obj;
@@ -3666,7 +3730,7 @@ static VALUE zrb_session_transport_events(int argc, VALUE *argv, VALUE self) {
3666
3730
  to.history = history;
3667
3731
  z_result_t r = z_declare_transport_events_listener(z_loan(z->session), &l->u.t, z_move(cb), &to);
3668
3732
  if (r != Z_OK) {
3669
- rb_raise(eZenohError, "cannot declare a transport events listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3733
+ zrb_raise_code(eZenohError, (int)r, "cannot declare a transport events listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3670
3734
  }
3671
3735
  zrb_lst_linked(obj, l, z, self);
3672
3736
  return obj;
@@ -3689,7 +3753,7 @@ static VALUE zrb_session_link_events(int argc, VALUE *argv, VALUE self) {
3689
3753
  lo.history = history;
3690
3754
  z_result_t r = z_declare_link_events_listener(z_loan(z->session), &l->u.l, z_move(cb), &lo);
3691
3755
  if (r != Z_OK) {
3692
- rb_raise(eZenohError, "cannot declare a link events listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3756
+ zrb_raise_code(eZenohError, (int)r, "cannot declare a link events listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3693
3757
  }
3694
3758
  zrb_lst_linked(obj, l, z, self);
3695
3759
  return obj;
@@ -3777,7 +3841,7 @@ static VALUE zrb_session_advanced_subscriber(int argc, VALUE *argv, VALUE self)
3777
3841
  zch_closure_sample(s->ch, &cb);
3778
3842
  z_result_t ret = ze_declare_advanced_subscriber(z_loan(z->session), &s->u.adv, ke, z_move(cb), &ao);
3779
3843
  if (ret != Z_OK) {
3780
- rb_raise(eZenohError, "cannot declare an advanced subscriber on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
3844
+ zrb_raise_code(eZenohError, (int)ret, "cannot declare an advanced subscriber on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
3781
3845
  }
3782
3846
  s->declared = true;
3783
3847
  s->owner = z;
@@ -3793,7 +3857,7 @@ static zrb_sub *zrb_advsub_get_open(VALUE self) {
3793
3857
  rb_raise(eZenohError, "the subscriber is closed");
3794
3858
  }
3795
3859
  if (zrb_session_check_link(s->owner)) {
3796
- rb_raise(eZenohError, "session is closed");
3860
+ rb_raise(eClosedError, "session is closed");
3797
3861
  }
3798
3862
  return s;
3799
3863
  }
@@ -3811,7 +3875,7 @@ static VALUE zrb_advsub_miss_listener(int argc, VALUE *argv, VALUE self) {
3811
3875
  ze_closure_miss(&cb, zev_on_miss, zevq_on_drop, zevq_ref(l->q));
3812
3876
  z_result_t r = ze_advanced_subscriber_declare_sample_miss_listener(z_loan(s->u.adv), &l->u.s, z_move(cb));
3813
3877
  if (r != Z_OK) {
3814
- rb_raise(eZenohError, "cannot declare a sample miss listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3878
+ zrb_raise_code(eZenohError, (int)r, "cannot declare a sample miss listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3815
3879
  }
3816
3880
  zrb_lst_linked(obj, l, s->owner, self);
3817
3881
  return obj;
@@ -3842,7 +3906,7 @@ static VALUE zrb_advsub_detect_publishers(int argc, VALUE *argv, VALUE self) {
3842
3906
  lo.history = history;
3843
3907
  z_result_t ret = ze_advanced_subscriber_detect_publishers(z_loan(as->u.adv), &s->u.sub, z_move(cb), &lo);
3844
3908
  if (ret != Z_OK) {
3845
- rb_raise(eZenohError, "cannot detect publishers (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
3909
+ zrb_raise_code(eZenohError, (int)ret, "cannot detect publishers (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
3846
3910
  }
3847
3911
  s->declared = true;
3848
3912
  s->owner = as->owner;
@@ -3970,7 +4034,7 @@ static VALUE zrb_session_declare_keyexpr(VALUE self, VALUE key_v) {
3970
4034
  z_internal_keyexpr_null(&k->decl);
3971
4035
  z_result_t r = z_declare_keyexpr(z_loan(z->session), &k->decl, ke);
3972
4036
  if (r != Z_OK) {
3973
- rb_raise(eZenohError, "cannot declare the key expression (%d)%" PRIsVALUE, (int)r, zrb_last_error());
4037
+ zrb_raise_code(eZenohError, (int)r, "cannot declare the key expression (%d)%" PRIsVALUE, (int)r, zrb_last_error());
3974
4038
  }
3975
4039
  zrb_ent_link(&k->ent, z, ZENT_KEYEXPR, true, zrb_ke_undeclare);
3976
4040
  rb_ivar_set(obj, id_iv_session, self);
@@ -4032,7 +4096,7 @@ static VALUE zrb_s_scout(VALUE mod, VALUE what_v, VALUE timeout_v, VALUE config_
4032
4096
  VALUE out = zevq_each_pending_noblock(q, false);
4033
4097
  zevq_unref(q);
4034
4098
  if (a.ret != Z_OK) {
4035
- rb_raise(eZenohError, "scouting failed (%d)", (int)a.ret);
4099
+ zrb_raise_code(eZenohError, (int)a.ret, "scouting failed (%d)", (int)a.ret);
4036
4100
  }
4037
4101
  return out;
4038
4102
  }
@@ -4063,11 +4127,23 @@ void Init_asterism_zenoh(void) {
4063
4127
  /* Asterism::Zenoh. No top-level Zenoh (require "asterism/zenoh/global"). */
4064
4128
  mAsterism = rb_define_module("Asterism");
4065
4129
  mZenoh = rb_define_module_under(mAsterism, "Zenoh");
4066
- eZenohError = rb_define_class_under(mZenoh, "Error", rb_eStandardError);
4130
+ /* The root of every Asterism error. Defined here because this binding
4131
+ * loads first; the asterism gem reopens it (same superclass). */
4132
+ eAsterismError = rb_define_class_under(mAsterism, "Error", rb_eStandardError);
4133
+ eZenohError = rb_define_class_under(mZenoh, "Error", eAsterismError);
4134
+ /* The session is closed, or its connection was lost. */
4135
+ eClosedError = rb_define_class_under(mZenoh, "ClosedError", eZenohError);
4067
4136
  rb_define_const(mZenoh, "C_VERSION", rb_str_freeze(rb_str_new_cstr(ZENOH_C)));
4068
4137
  rb_define_const(mZenoh, "CONNECT_TIMEOUT_MS", INT2FIX(ZRB_CONNECT_TIMEOUT_MS));
4069
4138
  rb_define_const(mZenoh, "SEND_TIMEOUT_MS", INT2FIX(ZRB_SEND_TIMEOUT_MS));
4070
4139
  rb_define_const(mZenoh, "PEER", Qtrue);
4140
+ /* Queue depths: the default of subscribe, queryable and the listeners;
4141
+ * of get, liveliness_get and querier.get; of liveliness_watch; and the
4142
+ * largest accepted. */
4143
+ rb_define_const(mZenoh, "DEFAULT_DEPTH", INT2FIX(ZRB_DEFAULT_DEPTH));
4144
+ rb_define_const(mZenoh, "DEFAULT_GET_DEPTH", INT2FIX(ZRB_DEFAULT_GET_DEPTH));
4145
+ rb_define_const(mZenoh, "DEFAULT_WATCH_DEPTH", INT2FIX(ZRB_DEFAULT_WATCH_DEPTH));
4146
+ rb_define_const(mZenoh, "MAX_DEPTH", INT2FIX(ZRB_MAX_DEPTH));
4071
4147
  rb_define_const(mZenoh, "MAX_PEERS", LONG2NUM(zrb_default_max_sessions()));
4072
4148
 
4073
4149
  id_attachment = rb_intern("attachment");
@@ -4078,6 +4154,8 @@ void Init_asterism_zenoh(void) {
4078
4154
  id_listen = rb_intern("listen");
4079
4155
  id_iv_session = rb_intern("@session");
4080
4156
  id_iv_key = rb_intern("@key");
4157
+ id_iv_code = rb_intern("@code");
4158
+ id_iv_qkey = rb_intern("@asterism_queryable_key");
4081
4159
  id_iv_parent = rb_intern("@parent");
4082
4160
  id_config = rb_intern("config");
4083
4161
  id_config_file = rb_intern("config_file");
@@ -4119,7 +4197,7 @@ void Init_asterism_zenoh(void) {
4119
4197
  rb_define_method(cSession, "liveliness_watch", zrb_session_liveliness_watch, -1);
4120
4198
  rb_define_method(cSession, "liveliness_get", zrb_session_liveliness_get, -1);
4121
4199
  rb_define_method(cSession, "poll", zrb_session_poll, -1);
4122
- rb_define_method(cSession, "peers", zrb_session_peers, 0);
4200
+ rb_define_method(cSession, "connection_count", zrb_session_peers, 0);
4123
4201
  rb_define_method(cSession, "zid", zrb_session_zid, 0);
4124
4202
  rb_define_method(cSession, "closed?", zrb_session_closed_p, 0);
4125
4203
  rb_define_method(cSession, "close", zrb_session_close, 0);