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 +4 -4
- data/CHANGELOG.md +89 -0
- data/README.md +145 -13
- data/docs/feature_coverage.md +55 -0
- data/ext/asterism_zenoh/zenoh.c +3562 -785
- data/lib/asterism/zenoh/common.rb +221 -0
- data/lib/asterism/zenoh/cruby.rb +128 -0
- data/lib/asterism/zenoh/values.rb +112 -0
- data/lib/asterism/zenoh/version.rb +1 -1
- data/lib/asterism/zenoh.rb +7 -1
- metadata +12 -5
data/ext/asterism_zenoh/zenoh.c
CHANGED
|
@@ -5,7 +5,14 @@
|
|
|
5
5
|
* (ruby-asterism/picoruby-asterism-zenoh, over zenoh-pico): sessions
|
|
6
6
|
* (client, or peer with an optional listener), put / subscribe, get /
|
|
7
7
|
* queryable (query and reply), liveliness tokens and watches, attachments,
|
|
8
|
-
* Session#zid. Code written for one runs on the other.
|
|
8
|
+
* Session#zid. Code written for one runs on the other. 0.3.0 adds, for
|
|
9
|
+
* CRuby only, the configuration, scouting, delete, declared publishers and
|
|
10
|
+
* queriers, matching status, the fields of samples and replies, error and
|
|
11
|
+
* delete replies, encodings, timestamps, key expressions, the advanced
|
|
12
|
+
* publisher / subscriber, transport and link events and the log
|
|
13
|
+
* (docs/feature_coverage.md). They receive in the same way: what zenoh-c's
|
|
14
|
+
* callbacks get is copied into a queue (a channel, or a zevq for small
|
|
15
|
+
* events) and Ruby takes it out by polling.
|
|
9
16
|
*
|
|
10
17
|
* Threading model: zenoh-c runs the protocol on its own threads and calls
|
|
11
18
|
* the callbacks below from them. No callback touches Ruby (no GVL, no Ruby
|
|
@@ -36,11 +43,13 @@
|
|
|
36
43
|
* undeclared or the get is finished); whichever lets go last frees it.
|
|
37
44
|
*/
|
|
38
45
|
#include <pthread.h>
|
|
46
|
+
#include <stdarg.h>
|
|
39
47
|
#include <stdatomic.h>
|
|
40
48
|
#include <stdbool.h>
|
|
41
49
|
#include <stdint.h>
|
|
42
50
|
#include <stdlib.h>
|
|
43
51
|
#include <string.h>
|
|
52
|
+
#include <unistd.h>
|
|
44
53
|
|
|
45
54
|
#include <ruby.h>
|
|
46
55
|
#include <ruby/encoding.h>
|
|
@@ -49,7 +58,13 @@
|
|
|
49
58
|
#include <zenoh.h>
|
|
50
59
|
|
|
51
60
|
#define ZRB_DEFAULT_DEPTH 16
|
|
52
|
-
|
|
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
|
|
53
68
|
#define ZRB_DEFAULT_POLL_STEPS 8
|
|
54
69
|
#define ZRB_DEFAULT_GET_TIMEOUT_MS 2000
|
|
55
70
|
#define ZRB_MAX_GET_TIMEOUT_MS 600000
|
|
@@ -57,11 +72,14 @@
|
|
|
57
72
|
#define ZRB_CONNECT_TIMEOUT_MS 3000
|
|
58
73
|
#define ZRB_SEND_TIMEOUT_MS 3000
|
|
59
74
|
|
|
60
|
-
static VALUE mAsterism, mZenoh, eZenohError;
|
|
75
|
+
static VALUE mAsterism, mZenoh, eAsterismError, eZenohError, eClosedError;
|
|
61
76
|
static VALUE cSession, cSubscriber, cWatch, cQueryable, cQuery, cGet, cToken;
|
|
77
|
+
static VALUE cAdvSubscriber, cPublisher, cAdvPublisher, cQuerier, cKeyExpr, cTimestamp;
|
|
78
|
+
static VALUE cMatchingListener, cEventListener;
|
|
62
79
|
static ID id_attachment, id_target, id_consolidation, id_complete, id_mode, id_listen;
|
|
63
|
-
static ID
|
|
64
|
-
static ID
|
|
80
|
+
static ID id_config, id_config_file, id_scouting, id_history, id_new;
|
|
81
|
+
static ID id_iv_session, id_iv_key, id_iv_parent, id_iv_code, id_iv_qkey;
|
|
82
|
+
static ID id_client, id_peer, id_router, id_all, id_all_complete, id_best_matching;
|
|
65
83
|
static ID id_none, id_latest, id_monotonic, id_auto;
|
|
66
84
|
|
|
67
85
|
/* ------------------------------------------------------------- channels */
|
|
@@ -202,17 +220,16 @@ static void zch_on_sample(z_loaned_sample_t *sample, void *ctx) {
|
|
|
202
220
|
pthread_mutex_unlock(&c->lock);
|
|
203
221
|
}
|
|
204
222
|
|
|
223
|
+
/* Error replies are queued too (each_result returns them; each_reply skips
|
|
224
|
+
* them). They are counted in errors, the others in received. */
|
|
205
225
|
static void zch_on_reply(z_loaned_reply_t *reply, void *ctx) {
|
|
206
226
|
zch *c = (zch *)ctx;
|
|
207
|
-
|
|
208
|
-
atomic_fetch_add(&c->errors, 1);
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
227
|
+
bool ok = z_reply_is_ok(reply);
|
|
211
228
|
pthread_mutex_lock(&c->lock);
|
|
212
229
|
zch_make_room(c);
|
|
213
230
|
z_closure_reply_call(z_loan(c->tx.reply), reply);
|
|
214
231
|
atomic_fetch_add(&c->queued, 1);
|
|
215
|
-
atomic_fetch_add(&c->received, 1);
|
|
232
|
+
atomic_fetch_add(ok ? &c->received : &c->errors, 1);
|
|
216
233
|
pthread_mutex_unlock(&c->lock);
|
|
217
234
|
}
|
|
218
235
|
|
|
@@ -287,6 +304,18 @@ static VALUE zrb_str_from_view(const z_loaned_string_t *s) {
|
|
|
287
304
|
return rb_utf8_str_new(z_string_data(s), (long)z_string_len(s));
|
|
288
305
|
}
|
|
289
306
|
|
|
307
|
+
/* zenoh-c's text for the last error on this thread (": ..."), or "". Read
|
|
308
|
+
* right after the failing call: the next call that can fail replaces it. */
|
|
309
|
+
static VALUE zrb_last_error(void) {
|
|
310
|
+
z_view_string_t s;
|
|
311
|
+
zc_get_last_error(&s);
|
|
312
|
+
size_t n = z_string_len(z_loan(s));
|
|
313
|
+
if (n == 0) {
|
|
314
|
+
return rb_str_new_cstr("");
|
|
315
|
+
}
|
|
316
|
+
return rb_sprintf(": %.*s", (int)n, z_string_data(z_loan(s)));
|
|
317
|
+
}
|
|
318
|
+
|
|
290
319
|
static VALUE zrb_key_str(const z_loaned_keyexpr_t *ke) {
|
|
291
320
|
z_view_string_t ks;
|
|
292
321
|
z_keyexpr_as_view_string(ke, &ks);
|
|
@@ -326,14 +355,16 @@ static void zrb_owned_key(z_owned_keyexpr_t *ke, const char *key) {
|
|
|
326
355
|
}
|
|
327
356
|
}
|
|
328
357
|
|
|
329
|
-
static long
|
|
330
|
-
long depth = NIL_P(v) ?
|
|
358
|
+
static long zrb_check_depth_or(VALUE v, long def) {
|
|
359
|
+
long depth = NIL_P(v) ? def : NUM2LONG(v);
|
|
331
360
|
if (depth < 1 || depth > ZRB_MAX_DEPTH) {
|
|
332
361
|
rb_raise(rb_eArgError, "depth must be 1..%d", ZRB_MAX_DEPTH);
|
|
333
362
|
}
|
|
334
363
|
return depth;
|
|
335
364
|
}
|
|
336
365
|
|
|
366
|
+
static long zrb_check_depth(VALUE v) { return zrb_check_depth_or(v, ZRB_DEFAULT_DEPTH); }
|
|
367
|
+
|
|
337
368
|
static long zrb_check_timeout(VALUE v) {
|
|
338
369
|
long t = NIL_P(v) ? ZRB_DEFAULT_GET_TIMEOUT_MS : NUM2LONG(v);
|
|
339
370
|
if (t < 1 || t > ZRB_MAX_GET_TIMEOUT_MS) {
|
|
@@ -386,12 +417,44 @@ static void zrb_hold_session(VALUE obj, VALUE session, VALUE key) {
|
|
|
386
417
|
}
|
|
387
418
|
}
|
|
388
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
|
+
|
|
389
436
|
/* ------------------------------------------------------- object structs */
|
|
390
437
|
|
|
391
438
|
typedef struct zrb_session zrb_session;
|
|
392
439
|
typedef struct zrb_sub zrb_sub;
|
|
393
440
|
typedef struct zrb_qable zrb_qable;
|
|
394
441
|
typedef struct zrb_token zrb_token;
|
|
442
|
+
typedef struct zrb_ent zrb_ent;
|
|
443
|
+
|
|
444
|
+
/* The entities added in 0.3.0 (publishers, queriers, listeners, declared
|
|
445
|
+
* key expressions) share one list of the session. undeclare drops the
|
|
446
|
+
* zenoh-c object; order says when the session undeclares it on close
|
|
447
|
+
* (listeners first, declared key expressions last). */
|
|
448
|
+
enum { ZENT_LISTENER = 0, ZENT_ENTITY = 1, ZENT_KEYEXPR = 2 };
|
|
449
|
+
|
|
450
|
+
struct zrb_ent {
|
|
451
|
+
zrb_session *owner; /* NULL once detached */
|
|
452
|
+
zrb_ent *next;
|
|
453
|
+
int order;
|
|
454
|
+
bool declared;
|
|
455
|
+
bool gvl_free_use; /* used without the GVL: undeclared under op_lock */
|
|
456
|
+
void (*undeclare)(zrb_ent *e);
|
|
457
|
+
};
|
|
395
458
|
|
|
396
459
|
struct zrb_session {
|
|
397
460
|
z_owned_session_t session;
|
|
@@ -403,12 +466,20 @@ struct zrb_session {
|
|
|
403
466
|
zrb_sub *subs; /* live subscribers and liveliness watches */
|
|
404
467
|
zrb_qable *qables;
|
|
405
468
|
zrb_token *tokens;
|
|
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) */
|
|
406
471
|
};
|
|
407
472
|
|
|
473
|
+
typedef enum { ZSUB_PLAIN, ZSUB_LIVELINESS, ZSUB_ADVANCED } zsub_type;
|
|
474
|
+
|
|
408
475
|
struct zrb_sub {
|
|
409
|
-
|
|
476
|
+
union {
|
|
477
|
+
z_owned_subscriber_t sub; /* plain and liveliness */
|
|
478
|
+
ze_owned_advanced_subscriber_t adv;
|
|
479
|
+
} u;
|
|
410
480
|
bool declared;
|
|
411
481
|
bool liveliness;
|
|
482
|
+
zsub_type type;
|
|
412
483
|
zrb_session *owner; /* NULL once detached */
|
|
413
484
|
zrb_sub *next;
|
|
414
485
|
zch *ch;
|
|
@@ -438,1033 +509,3616 @@ typedef struct {
|
|
|
438
509
|
bool live;
|
|
439
510
|
} zrb_query;
|
|
440
511
|
|
|
441
|
-
/*
|
|
512
|
+
/* ----------------------------------------------- entities (0.3.0 list) */
|
|
442
513
|
|
|
443
|
-
static void
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
514
|
+
static void zrb_ent_link(zrb_ent *e, zrb_session *z, int order, bool gvl_free_use, void (*undeclare)(zrb_ent *)) {
|
|
515
|
+
e->owner = z;
|
|
516
|
+
e->order = order;
|
|
517
|
+
e->declared = true;
|
|
518
|
+
e->gvl_free_use = gvl_free_use;
|
|
519
|
+
e->undeclare = undeclare;
|
|
520
|
+
e->next = z->ents;
|
|
521
|
+
z->ents = e;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/* Undeclares the entity (once) and takes it off its session's list. With
|
|
525
|
+
* the GVL held. An entity that other threads use without the GVL
|
|
526
|
+
* (publishers, queriers) is undeclared under the session's op_lock, so a
|
|
527
|
+
* put in progress finishes first. */
|
|
528
|
+
static void zrb_ent_detach(zrb_ent *e) {
|
|
529
|
+
if (e->declared) {
|
|
530
|
+
zrb_session *z = e->owner;
|
|
531
|
+
bool lock = e->gvl_free_use && z != NULL;
|
|
532
|
+
if (lock) {
|
|
533
|
+
pthread_mutex_lock(&z->op_lock);
|
|
534
|
+
}
|
|
535
|
+
e->undeclare(e);
|
|
536
|
+
e->declared = false;
|
|
537
|
+
if (lock) {
|
|
538
|
+
pthread_mutex_unlock(&z->op_lock);
|
|
539
|
+
}
|
|
447
540
|
}
|
|
448
|
-
if (
|
|
449
|
-
|
|
541
|
+
if (e->owner != NULL) {
|
|
542
|
+
zrb_ent **pp = &e->owner->ents;
|
|
450
543
|
while (*pp != NULL) {
|
|
451
|
-
if (*pp ==
|
|
452
|
-
*pp =
|
|
544
|
+
if (*pp == e) {
|
|
545
|
+
*pp = e->next;
|
|
453
546
|
break;
|
|
454
547
|
}
|
|
455
548
|
pp = &(*pp)->next;
|
|
456
549
|
}
|
|
457
|
-
|
|
458
|
-
|
|
550
|
+
e->owner = NULL;
|
|
551
|
+
e->next = NULL;
|
|
459
552
|
}
|
|
460
553
|
}
|
|
461
554
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
555
|
+
/* -------------------------------------------------------- event queues */
|
|
556
|
+
|
|
557
|
+
/* Small events (matching status, transports and links, missed samples,
|
|
558
|
+
* scouting answers) copied out of zenoh-c's callbacks into plain C memory.
|
|
559
|
+
* Same rules as the channels: the callbacks never touch Ruby, a full queue
|
|
560
|
+
* drops its oldest entry, Ruby takes the entries out by polling. */
|
|
561
|
+
typedef enum { ZEV_MATCHING, ZEV_TRANSPORT, ZEV_LINK, ZEV_MISS, ZEV_HELLO } zev_kind;
|
|
562
|
+
|
|
563
|
+
typedef struct zev {
|
|
564
|
+
struct zev *next;
|
|
565
|
+
bool flag; /* matching status; added (not removed) for transports / links */
|
|
566
|
+
z_id_t zid;
|
|
567
|
+
uint32_t eid, nb;
|
|
568
|
+
int whatami;
|
|
569
|
+
bool qos, multicast, streamed, has_reliability;
|
|
570
|
+
int reliability;
|
|
571
|
+
uint16_t mtu;
|
|
572
|
+
char *src, *dst, *group, *auth;
|
|
573
|
+
char **strs; /* interfaces of a link, locators of a hello */
|
|
574
|
+
size_t nstrs;
|
|
575
|
+
} zev;
|
|
468
576
|
|
|
469
|
-
|
|
577
|
+
typedef struct {
|
|
578
|
+
zev_kind kind;
|
|
579
|
+
pthread_mutex_t lock;
|
|
580
|
+
zev *head, *tail;
|
|
581
|
+
uint32_t depth;
|
|
582
|
+
atomic_uint queued;
|
|
583
|
+
atomic_uint received;
|
|
584
|
+
atomic_uint dropped;
|
|
585
|
+
atomic_bool done;
|
|
586
|
+
atomic_int refs;
|
|
587
|
+
} zevq;
|
|
470
588
|
|
|
471
|
-
static
|
|
472
|
-
|
|
589
|
+
static void zev_free(zev *e) {
|
|
590
|
+
if (e == NULL) {
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
free(e->src);
|
|
594
|
+
free(e->dst);
|
|
595
|
+
free(e->group);
|
|
596
|
+
free(e->auth);
|
|
597
|
+
for (size_t i = 0; i < e->nstrs; i++) {
|
|
598
|
+
free(e->strs[i]);
|
|
599
|
+
}
|
|
600
|
+
free(e->strs);
|
|
601
|
+
free(e);
|
|
602
|
+
}
|
|
473
603
|
|
|
474
|
-
static
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
604
|
+
static zevq *zevq_new(zev_kind kind, uint32_t depth) {
|
|
605
|
+
zevq *q = (zevq *)calloc(1, sizeof(zevq));
|
|
606
|
+
if (q == NULL) {
|
|
607
|
+
rb_raise(rb_eNoMemError, "cannot allocate an event queue");
|
|
608
|
+
}
|
|
609
|
+
q->kind = kind;
|
|
610
|
+
q->depth = depth;
|
|
611
|
+
pthread_mutex_init(&q->lock, NULL);
|
|
612
|
+
atomic_init(&q->queued, 0);
|
|
613
|
+
atomic_init(&q->received, 0);
|
|
614
|
+
atomic_init(&q->dropped, 0);
|
|
615
|
+
atomic_init(&q->done, false);
|
|
616
|
+
atomic_init(&q->refs, 1);
|
|
617
|
+
return q;
|
|
478
618
|
}
|
|
479
619
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
zrb_sub *s = zrb_sub_get(self);
|
|
484
|
-
bool collect = !rb_block_given_p();
|
|
485
|
-
VALUE out = collect ? rb_ary_new() : Qnil;
|
|
486
|
-
long taken = 0;
|
|
487
|
-
unsigned todo = atomic_load(&s->ch->queued);
|
|
488
|
-
while (todo > 0) {
|
|
489
|
-
todo--;
|
|
490
|
-
z_owned_sample_t sm;
|
|
491
|
-
if (zch_take_sample(s->ch, &sm) != Z_OK) {
|
|
492
|
-
break;
|
|
493
|
-
}
|
|
494
|
-
const z_loaned_sample_t *l = z_loan(sm);
|
|
495
|
-
VALUE vals[3];
|
|
496
|
-
int n;
|
|
497
|
-
vals[0] = zrb_key_str(z_sample_keyexpr(l));
|
|
498
|
-
if (s->liveliness) {
|
|
499
|
-
/* A token appearing is a PUT, one going away a DELETE. */
|
|
500
|
-
vals[1] = (z_sample_kind(l) == Z_SAMPLE_KIND_PUT) ? Qtrue : Qfalse;
|
|
501
|
-
n = 2;
|
|
502
|
-
} else {
|
|
503
|
-
vals[1] = zrb_str_from_bytes(z_sample_payload(l));
|
|
504
|
-
vals[2] = zrb_attachment_value(z_sample_attachment(l));
|
|
505
|
-
n = 3;
|
|
506
|
-
}
|
|
507
|
-
z_drop(z_move(sm));
|
|
508
|
-
taken++;
|
|
509
|
-
if (collect) {
|
|
510
|
-
rb_ary_push(out, rb_ary_new_from_values(n, vals));
|
|
511
|
-
} else {
|
|
512
|
-
rb_yield_values2(n, vals);
|
|
513
|
-
}
|
|
620
|
+
static void zevq_unref(zevq *q) {
|
|
621
|
+
if (q == NULL || atomic_fetch_sub(&q->refs, 1) != 1) {
|
|
622
|
+
return;
|
|
514
623
|
}
|
|
515
|
-
|
|
624
|
+
zev *e = q->head;
|
|
625
|
+
while (e != NULL) {
|
|
626
|
+
zev *n = e->next;
|
|
627
|
+
zev_free(e);
|
|
628
|
+
e = n;
|
|
629
|
+
}
|
|
630
|
+
pthread_mutex_destroy(&q->lock);
|
|
631
|
+
free(q);
|
|
516
632
|
}
|
|
517
633
|
|
|
518
|
-
|
|
519
|
-
static
|
|
520
|
-
|
|
634
|
+
/* The context of a closure handed to zenoh-c holds a reference. */
|
|
635
|
+
static zevq *zevq_ref(zevq *q) {
|
|
636
|
+
atomic_fetch_add(&q->refs, 1);
|
|
637
|
+
return q;
|
|
638
|
+
}
|
|
521
639
|
|
|
522
|
-
static
|
|
523
|
-
|
|
524
|
-
|
|
640
|
+
static void zevq_on_drop(void *ctx) {
|
|
641
|
+
zevq *q = (zevq *)ctx;
|
|
642
|
+
atomic_store(&q->done, true);
|
|
643
|
+
zevq_unref(q);
|
|
525
644
|
}
|
|
526
645
|
|
|
527
|
-
|
|
646
|
+
/* From zenoh's threads (or, for the snapshots, the calling one). */
|
|
647
|
+
static void zevq_push(zevq *q, zev *e) {
|
|
648
|
+
if (e == NULL) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
pthread_mutex_lock(&q->lock);
|
|
652
|
+
if (atomic_load(&q->queued) >= q->depth && q->head != NULL) {
|
|
653
|
+
zev *old = q->head;
|
|
654
|
+
q->head = old->next;
|
|
655
|
+
if (q->head == NULL) {
|
|
656
|
+
q->tail = NULL;
|
|
657
|
+
}
|
|
658
|
+
zev_free(old);
|
|
659
|
+
atomic_fetch_sub(&q->queued, 1);
|
|
660
|
+
atomic_fetch_add(&q->dropped, 1);
|
|
661
|
+
}
|
|
662
|
+
e->next = NULL;
|
|
663
|
+
if (q->tail != NULL) {
|
|
664
|
+
q->tail->next = e;
|
|
665
|
+
} else {
|
|
666
|
+
q->head = e;
|
|
667
|
+
}
|
|
668
|
+
q->tail = e;
|
|
669
|
+
atomic_fetch_add(&q->queued, 1);
|
|
670
|
+
atomic_fetch_add(&q->received, 1);
|
|
671
|
+
pthread_mutex_unlock(&q->lock);
|
|
672
|
+
}
|
|
528
673
|
|
|
529
|
-
|
|
674
|
+
static zev *zevq_take(zevq *q) {
|
|
675
|
+
pthread_mutex_lock(&q->lock);
|
|
676
|
+
zev *e = q->head;
|
|
677
|
+
if (e != NULL) {
|
|
678
|
+
q->head = e->next;
|
|
679
|
+
if (q->head == NULL) {
|
|
680
|
+
q->tail = NULL;
|
|
681
|
+
}
|
|
682
|
+
atomic_fetch_sub(&q->queued, 1);
|
|
683
|
+
}
|
|
684
|
+
pthread_mutex_unlock(&q->lock);
|
|
685
|
+
return e;
|
|
686
|
+
}
|
|
530
687
|
|
|
531
|
-
static
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
z_drop(z_move(q->qable));
|
|
537
|
-
q->declared = false;
|
|
688
|
+
static char *zev_strdup_n(const char *s, size_t n) {
|
|
689
|
+
char *out = (char *)malloc(n + 1);
|
|
690
|
+
if (out != NULL) {
|
|
691
|
+
memcpy(out, s, n);
|
|
692
|
+
out[n] = '\0';
|
|
538
693
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
694
|
+
return out;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/* Copies an owned string out (and drops it). */
|
|
698
|
+
static char *zev_take_string(z_owned_string_t *s) {
|
|
699
|
+
char *out = zev_strdup_n(z_string_data(z_loan(*s)), z_string_len(z_loan(*s)));
|
|
700
|
+
z_drop(z_move(*s));
|
|
701
|
+
return out;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
static void zev_take_strings(zev *e, z_owned_string_array_t *arr) {
|
|
705
|
+
size_t n = z_string_array_len(z_loan(*arr));
|
|
706
|
+
e->strs = (char **)calloc(n > 0 ? n : 1, sizeof(char *));
|
|
707
|
+
if (e->strs != NULL) {
|
|
708
|
+
for (size_t i = 0; i < n; i++) {
|
|
709
|
+
const z_loaned_string_t *s = z_string_array_get(z_loan(*arr), i);
|
|
710
|
+
e->strs[i] = zev_strdup_n(z_string_data(s), z_string_len(s));
|
|
547
711
|
}
|
|
548
|
-
|
|
549
|
-
q->next = NULL;
|
|
712
|
+
e->nstrs = n;
|
|
550
713
|
}
|
|
714
|
+
z_drop(z_move(*arr));
|
|
551
715
|
}
|
|
552
716
|
|
|
553
|
-
static
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
717
|
+
static zev *zev_new(void) { return (zev *)calloc(1, sizeof(zev)); }
|
|
718
|
+
|
|
719
|
+
static void zev_fill_transport(zev *e, const z_loaned_transport_t *t) {
|
|
720
|
+
e->zid = z_transport_zid(t);
|
|
721
|
+
e->whatami = (int)z_transport_whatami(t);
|
|
722
|
+
e->qos = z_transport_is_qos(t);
|
|
723
|
+
e->multicast = z_transport_is_multicast(t);
|
|
558
724
|
}
|
|
559
725
|
|
|
560
|
-
static
|
|
726
|
+
static void zev_fill_link(zev *e, const z_loaned_link_t *l) {
|
|
727
|
+
z_owned_string_t s;
|
|
728
|
+
e->zid = z_link_zid(l);
|
|
729
|
+
z_link_src(l, &s);
|
|
730
|
+
e->src = zev_take_string(&s);
|
|
731
|
+
z_link_dst(l, &s);
|
|
732
|
+
e->dst = zev_take_string(&s);
|
|
733
|
+
z_link_group(l, &s);
|
|
734
|
+
e->group = zev_take_string(&s);
|
|
735
|
+
z_link_auth_identifier(l, &s);
|
|
736
|
+
e->auth = zev_take_string(&s);
|
|
737
|
+
e->mtu = z_link_mtu(l);
|
|
738
|
+
e->streamed = z_link_is_streamed(l);
|
|
739
|
+
z_reliability_t rel;
|
|
740
|
+
e->has_reliability = z_link_reliability(l, &rel);
|
|
741
|
+
e->reliability = (int)rel;
|
|
742
|
+
z_owned_string_array_t arr;
|
|
743
|
+
z_link_interfaces(l, &arr);
|
|
744
|
+
zev_take_strings(e, &arr);
|
|
745
|
+
}
|
|
561
746
|
|
|
562
|
-
|
|
563
|
-
|
|
747
|
+
/* The callbacks (zenoh's threads; no Ruby). */
|
|
748
|
+
static void zev_on_matching(const z_matching_status_t *st, void *ctx) {
|
|
749
|
+
zev *e = zev_new();
|
|
750
|
+
if (e != NULL) {
|
|
751
|
+
e->flag = st->matching;
|
|
752
|
+
}
|
|
753
|
+
zevq_push((zevq *)ctx, e);
|
|
754
|
+
}
|
|
564
755
|
|
|
565
|
-
static
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
756
|
+
static void zev_on_transport_event(z_loaned_transport_event_t *ev, void *ctx) {
|
|
757
|
+
zev *e = zev_new();
|
|
758
|
+
if (e != NULL) {
|
|
759
|
+
e->flag = (z_transport_event_kind(ev) == Z_SAMPLE_KIND_PUT);
|
|
760
|
+
zev_fill_transport(e, z_transport_event_transport(ev));
|
|
761
|
+
}
|
|
762
|
+
zevq_push((zevq *)ctx, e);
|
|
569
763
|
}
|
|
570
764
|
|
|
571
|
-
|
|
765
|
+
static void zev_on_transport(z_loaned_transport_t *t, void *ctx) {
|
|
766
|
+
zev *e = zev_new();
|
|
767
|
+
if (e != NULL) {
|
|
768
|
+
e->flag = true;
|
|
769
|
+
zev_fill_transport(e, t);
|
|
770
|
+
}
|
|
771
|
+
zevq_push((zevq *)ctx, e);
|
|
772
|
+
}
|
|
572
773
|
|
|
573
|
-
static void
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
774
|
+
static void zev_on_link_event(z_loaned_link_event_t *ev, void *ctx) {
|
|
775
|
+
zev *e = zev_new();
|
|
776
|
+
if (e != NULL) {
|
|
777
|
+
e->flag = (z_link_event_kind(ev) == Z_SAMPLE_KIND_PUT);
|
|
778
|
+
zev_fill_link(e, z_link_event_link(ev));
|
|
577
779
|
}
|
|
780
|
+
zevq_push((zevq *)ctx, e);
|
|
578
781
|
}
|
|
579
782
|
|
|
580
|
-
static void
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
783
|
+
static void zev_on_link(z_loaned_link_t *l, void *ctx) {
|
|
784
|
+
zev *e = zev_new();
|
|
785
|
+
if (e != NULL) {
|
|
786
|
+
e->flag = true;
|
|
787
|
+
zev_fill_link(e, l);
|
|
788
|
+
}
|
|
789
|
+
zevq_push((zevq *)ctx, e);
|
|
584
790
|
}
|
|
585
791
|
|
|
586
|
-
static
|
|
792
|
+
static void zev_on_miss(const ze_miss_t *m, void *ctx) {
|
|
793
|
+
zev *e = zev_new();
|
|
794
|
+
if (e != NULL) {
|
|
795
|
+
e->zid = z_entity_global_id_zid(&m->source);
|
|
796
|
+
e->eid = z_entity_global_id_eid(&m->source);
|
|
797
|
+
e->nb = m->nb;
|
|
798
|
+
}
|
|
799
|
+
zevq_push((zevq *)ctx, e);
|
|
800
|
+
}
|
|
587
801
|
|
|
588
|
-
static
|
|
589
|
-
|
|
802
|
+
static void zev_on_hello(z_loaned_hello_t *h, void *ctx) {
|
|
803
|
+
zev *e = zev_new();
|
|
804
|
+
if (e != NULL) {
|
|
805
|
+
e->zid = z_hello_zid(h);
|
|
806
|
+
e->whatami = (int)z_hello_whatami(h);
|
|
807
|
+
z_owned_string_array_t arr;
|
|
808
|
+
z_hello_locators(h, &arr);
|
|
809
|
+
zev_take_strings(e, &arr);
|
|
810
|
+
}
|
|
811
|
+
zevq_push((zevq *)ctx, e);
|
|
812
|
+
}
|
|
590
813
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
814
|
+
/* --------------------------------------------------- values for Ruby */
|
|
815
|
+
|
|
816
|
+
/* The value classes are Ruby (lib/asterism/zenoh/values.rb). */
|
|
817
|
+
static VALUE zrb_value_class(const char *name) { return rb_const_get(mZenoh, rb_intern(name)); }
|
|
818
|
+
|
|
819
|
+
static VALUE zrb_new_value(const char *klass, VALUE hash) {
|
|
820
|
+
return rb_class_new_instance_kw(1, &hash, zrb_value_class(klass), RB_PASS_KEYWORDS);
|
|
595
821
|
}
|
|
596
822
|
|
|
597
|
-
static
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
823
|
+
static void zrb_hset(VALUE h, const char *key, VALUE v) { rb_hash_aset(h, ID2SYM(rb_intern(key)), v); }
|
|
824
|
+
|
|
825
|
+
static VALUE zrb_zid_value(const z_id_t *id) {
|
|
826
|
+
z_owned_string_t str;
|
|
827
|
+
z_id_to_string(id, &str);
|
|
828
|
+
VALUE out = zrb_str_from_view(z_loan(str));
|
|
829
|
+
z_drop(z_move(str));
|
|
830
|
+
return out;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
static VALUE zrb_cstr_or_nil(const char *s) { return s == NULL ? Qnil : rb_utf8_str_new_cstr(s); }
|
|
834
|
+
|
|
835
|
+
static VALUE zrb_whatami_sym(int w) {
|
|
836
|
+
switch (w) {
|
|
837
|
+
case Z_WHATAMI_ROUTER:
|
|
838
|
+
return ID2SYM(rb_intern("router"));
|
|
839
|
+
case Z_WHATAMI_PEER:
|
|
840
|
+
return ID2SYM(rb_intern("peer"));
|
|
841
|
+
case Z_WHATAMI_CLIENT:
|
|
842
|
+
return ID2SYM(rb_intern("client"));
|
|
601
843
|
}
|
|
602
|
-
return
|
|
844
|
+
return Qnil;
|
|
603
845
|
}
|
|
604
846
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
zrb_query *zq;
|
|
608
|
-
VALUE obj = TypedData_Make_Struct(cQuery, zrb_query, &zrb_query_type, zq);
|
|
609
|
-
zq->query = *q;
|
|
610
|
-
zq->live = true;
|
|
611
|
-
z_internal_query_null(q);
|
|
612
|
-
return obj;
|
|
847
|
+
static VALUE zrb_reliability_sym(int r) {
|
|
848
|
+
return ID2SYM(rb_intern(r == Z_RELIABILITY_BEST_EFFORT ? "best_effort" : "reliable"));
|
|
613
849
|
}
|
|
614
850
|
|
|
615
|
-
static VALUE
|
|
851
|
+
static VALUE zrb_strs_value(const zev *e) {
|
|
852
|
+
VALUE a = rb_ary_new_capa((long)e->nstrs);
|
|
853
|
+
for (size_t i = 0; i < e->nstrs; i++) {
|
|
854
|
+
rb_ary_push(a, zrb_cstr_or_nil(e->strs[i]));
|
|
855
|
+
}
|
|
856
|
+
return a;
|
|
857
|
+
}
|
|
616
858
|
|
|
617
|
-
|
|
618
|
-
|
|
859
|
+
/* event: true for a listener (adds kind), false for a snapshot. */
|
|
860
|
+
static VALUE zev_to_ruby(zev_kind kind, const zev *e, bool event) {
|
|
861
|
+
VALUE h = rb_hash_new();
|
|
862
|
+
switch (kind) {
|
|
863
|
+
case ZEV_MATCHING:
|
|
864
|
+
return e->flag ? Qtrue : Qfalse;
|
|
865
|
+
case ZEV_TRANSPORT:
|
|
866
|
+
if (event) {
|
|
867
|
+
zrb_hset(h, "kind", ID2SYM(rb_intern(e->flag ? "added" : "removed")));
|
|
868
|
+
}
|
|
869
|
+
zrb_hset(h, "zid", zrb_zid_value(&e->zid));
|
|
870
|
+
zrb_hset(h, "whatami", zrb_whatami_sym(e->whatami));
|
|
871
|
+
zrb_hset(h, "qos", e->qos ? Qtrue : Qfalse);
|
|
872
|
+
zrb_hset(h, "multicast", e->multicast ? Qtrue : Qfalse);
|
|
873
|
+
return zrb_new_value(event ? "TransportEvent" : "Transport", h);
|
|
874
|
+
case ZEV_LINK:
|
|
875
|
+
if (event) {
|
|
876
|
+
zrb_hset(h, "kind", ID2SYM(rb_intern(e->flag ? "added" : "removed")));
|
|
877
|
+
}
|
|
878
|
+
zrb_hset(h, "zid", zrb_zid_value(&e->zid));
|
|
879
|
+
zrb_hset(h, "src", zrb_cstr_or_nil(e->src));
|
|
880
|
+
zrb_hset(h, "dst", zrb_cstr_or_nil(e->dst));
|
|
881
|
+
zrb_hset(h, "mtu", UINT2NUM(e->mtu));
|
|
882
|
+
zrb_hset(h, "streamed", e->streamed ? Qtrue : Qfalse);
|
|
883
|
+
zrb_hset(h, "reliability", e->has_reliability ? zrb_reliability_sym(e->reliability) : Qnil);
|
|
884
|
+
zrb_hset(h, "interfaces", zrb_strs_value(e));
|
|
885
|
+
zrb_hset(h, "group", (e->group && *e->group) ? zrb_cstr_or_nil(e->group) : Qnil);
|
|
886
|
+
zrb_hset(h, "auth_identifier", (e->auth && *e->auth) ? zrb_cstr_or_nil(e->auth) : Qnil);
|
|
887
|
+
return zrb_new_value(event ? "LinkEvent" : "Link", h);
|
|
888
|
+
case ZEV_MISS:
|
|
889
|
+
zrb_hset(h, "source_zid", zrb_zid_value(&e->zid));
|
|
890
|
+
zrb_hset(h, "source_eid", UINT2NUM(e->eid));
|
|
891
|
+
zrb_hset(h, "count", UINT2NUM(e->nb));
|
|
892
|
+
return zrb_new_value("Miss", h);
|
|
893
|
+
case ZEV_HELLO:
|
|
894
|
+
zrb_hset(h, "zid", zrb_zid_value(&e->zid));
|
|
895
|
+
zrb_hset(h, "whatami", zrb_whatami_sym(e->whatami));
|
|
896
|
+
zrb_hset(h, "locators", zrb_strs_value(e));
|
|
897
|
+
return zrb_new_value("Hello", h);
|
|
898
|
+
}
|
|
619
899
|
return Qnil;
|
|
620
900
|
}
|
|
621
901
|
|
|
622
|
-
/*
|
|
623
|
-
|
|
624
|
-
* qa.each_pending -> Array of Query; each stays open until Query#finish or
|
|
625
|
-
* garbage collection. */
|
|
626
|
-
static VALUE zrb_qable_each_pending(VALUE self) {
|
|
627
|
-
zrb_qable *q = zrb_qable_get(self);
|
|
902
|
+
/* Takes what is queued now, oldest first; yields each, or returns them. */
|
|
903
|
+
static VALUE zevq_each_pending(zevq *q, bool event) {
|
|
628
904
|
bool collect = !rb_block_given_p();
|
|
629
905
|
VALUE out = collect ? rb_ary_new() : Qnil;
|
|
630
906
|
long taken = 0;
|
|
631
|
-
unsigned todo = atomic_load(&q->
|
|
907
|
+
unsigned todo = atomic_load(&q->queued);
|
|
632
908
|
while (todo > 0) {
|
|
633
909
|
todo--;
|
|
634
|
-
|
|
635
|
-
if (
|
|
910
|
+
zev *e = zevq_take(q);
|
|
911
|
+
if (e == NULL) {
|
|
636
912
|
break;
|
|
637
913
|
}
|
|
638
|
-
VALUE
|
|
914
|
+
VALUE v = zev_to_ruby(q->kind, e, event);
|
|
915
|
+
zev_free(e);
|
|
639
916
|
taken++;
|
|
640
917
|
if (collect) {
|
|
641
|
-
rb_ary_push(out,
|
|
918
|
+
rb_ary_push(out, v);
|
|
642
919
|
} else {
|
|
643
|
-
|
|
920
|
+
rb_yield(v);
|
|
644
921
|
}
|
|
645
922
|
}
|
|
646
923
|
return collect ? out : LONG2NUM(taken);
|
|
647
924
|
}
|
|
648
925
|
|
|
649
|
-
|
|
650
|
-
static VALUE zrb_qable_received(VALUE self) { return UINT2NUM(atomic_load(&zrb_qable_get(self)->ch->received)); }
|
|
651
|
-
static VALUE zrb_qable_dropped(VALUE self) { return UINT2NUM(atomic_load(&zrb_qable_get(self)->ch->dropped)); }
|
|
926
|
+
/* ------------------------------------------------------------ options */
|
|
652
927
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
928
|
+
/* Keyword arguments of the calls that send (put, delete, publishers,
|
|
929
|
+
* replies, queriers). -1: not given (zenoh-c's default). */
|
|
930
|
+
typedef struct {
|
|
931
|
+
VALUE attachment; /* nil or String */
|
|
932
|
+
VALUE encoding; /* nil or String */
|
|
933
|
+
VALUE timestamp; /* nil, true or a Timestamp */
|
|
934
|
+
VALUE payload; /* nil or String */
|
|
935
|
+
int priority;
|
|
936
|
+
int congestion_control;
|
|
937
|
+
int express;
|
|
938
|
+
int reliability;
|
|
939
|
+
int destination;
|
|
940
|
+
int accept_replies;
|
|
941
|
+
VALUE target, consolidation, timeout;
|
|
942
|
+
bool has_target, has_consolidation, has_timeout;
|
|
943
|
+
VALUE depth; /* gets: nil (the default) or the queue depth */
|
|
944
|
+
} zrb_opts;
|
|
945
|
+
|
|
946
|
+
static int zrb_priority_arg(VALUE v) {
|
|
947
|
+
if (RB_INTEGER_TYPE_P(v)) {
|
|
948
|
+
int p = NUM2INT(v);
|
|
949
|
+
if (p < Z_PRIORITY_REAL_TIME || p > Z_PRIORITY_BACKGROUND) {
|
|
950
|
+
rb_raise(rb_eArgError, "priority must be 1..7");
|
|
951
|
+
}
|
|
952
|
+
return p;
|
|
953
|
+
}
|
|
954
|
+
static const char *const names[] = {"real_time", "interactive_high", "interactive_low", "data_high",
|
|
955
|
+
"data", "data_low", "background"};
|
|
956
|
+
ID id = zrb_sym_id(v);
|
|
957
|
+
for (int i = 0; i < 7; i++) {
|
|
958
|
+
if (id == rb_intern(names[i])) {
|
|
959
|
+
return i + 1;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
rb_raise(rb_eArgError,
|
|
963
|
+
"priority must be :real_time, :interactive_high, :interactive_low, :data_high, :data, :data_low, "
|
|
964
|
+
":background or 1..7");
|
|
965
|
+
return 0;
|
|
656
966
|
}
|
|
657
967
|
|
|
658
|
-
static VALUE
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
968
|
+
static VALUE zrb_priority_sym(int p) {
|
|
969
|
+
static const char *const names[] = {"real_time", "interactive_high", "interactive_low", "data_high",
|
|
970
|
+
"data", "data_low", "background"};
|
|
971
|
+
if (p < 1 || p > 7) {
|
|
972
|
+
return Qnil;
|
|
973
|
+
}
|
|
974
|
+
return ID2SYM(rb_intern(names[p - 1]));
|
|
663
975
|
}
|
|
664
976
|
|
|
665
|
-
static
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
977
|
+
static int zrb_cc_arg(VALUE v) {
|
|
978
|
+
ID id = zrb_sym_id(v);
|
|
979
|
+
if (id == rb_intern("drop")) {
|
|
980
|
+
return Z_CONGESTION_CONTROL_DROP;
|
|
981
|
+
}
|
|
982
|
+
if (id == rb_intern("block")) {
|
|
983
|
+
return Z_CONGESTION_CONTROL_BLOCK;
|
|
984
|
+
}
|
|
985
|
+
if (id == rb_intern("block_first")) {
|
|
986
|
+
return Z_CONGESTION_CONTROL_BLOCK_FIRST;
|
|
987
|
+
}
|
|
988
|
+
rb_raise(rb_eArgError, "congestion_control must be :drop, :block or :block_first");
|
|
989
|
+
return 0;
|
|
670
990
|
}
|
|
671
991
|
|
|
672
|
-
static VALUE
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
992
|
+
static VALUE zrb_cc_sym(int c) {
|
|
993
|
+
switch (c) {
|
|
994
|
+
case Z_CONGESTION_CONTROL_BLOCK:
|
|
995
|
+
return ID2SYM(rb_intern("block"));
|
|
996
|
+
case Z_CONGESTION_CONTROL_DROP:
|
|
997
|
+
return ID2SYM(rb_intern("drop"));
|
|
998
|
+
case Z_CONGESTION_CONTROL_BLOCK_FIRST:
|
|
999
|
+
return ID2SYM(rb_intern("block_first"));
|
|
677
1000
|
}
|
|
678
|
-
return
|
|
1001
|
+
return Qnil;
|
|
679
1002
|
}
|
|
680
1003
|
|
|
681
|
-
static
|
|
682
|
-
|
|
683
|
-
|
|
1004
|
+
static int zrb_reliability_arg(VALUE v) {
|
|
1005
|
+
ID id = zrb_sym_id(v);
|
|
1006
|
+
if (id == rb_intern("reliable")) {
|
|
1007
|
+
return Z_RELIABILITY_RELIABLE;
|
|
1008
|
+
}
|
|
1009
|
+
if (id == rb_intern("best_effort")) {
|
|
1010
|
+
return Z_RELIABILITY_BEST_EFFORT;
|
|
1011
|
+
}
|
|
1012
|
+
rb_raise(rb_eArgError, "reliability must be :reliable or :best_effort");
|
|
1013
|
+
return 0;
|
|
684
1014
|
}
|
|
685
1015
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
VALUE a1, a2 = Qnil, opts = Qnil;
|
|
691
|
-
int n = rb_scan_args(argc, argv, "11:", &a1, &a2, &opts);
|
|
692
|
-
VALUE kw[1] = {Qundef};
|
|
693
|
-
if (!NIL_P(opts)) {
|
|
694
|
-
rb_get_kwargs(opts, &id_attachment, 0, 1, kw);
|
|
1016
|
+
static int zrb_locality_arg(VALUE v) {
|
|
1017
|
+
ID id = zrb_sym_id(v);
|
|
1018
|
+
if (id == rb_intern("any")) {
|
|
1019
|
+
return Z_LOCALITY_ANY;
|
|
695
1020
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
VALUE key_v = (n == 1) ? Qnil : a1;
|
|
699
|
-
VALUE payload = (n == 1) ? a1 : a2;
|
|
700
|
-
if (!RB_TYPE_P(payload, T_STRING)) {
|
|
701
|
-
rb_raise(rb_eTypeError, "payload must be a String");
|
|
1021
|
+
if (id == rb_intern("remote")) {
|
|
1022
|
+
return Z_LOCALITY_REMOTE;
|
|
702
1023
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
if (NIL_P(key_v)) {
|
|
706
|
-
kp = z_query_keyexpr(z_loan(zq->query));
|
|
707
|
-
} else {
|
|
708
|
-
zrb_view_key(&ke, StringValueCStr(key_v));
|
|
709
|
-
kp = z_loan(ke);
|
|
1024
|
+
if (id == rb_intern("session_local")) {
|
|
1025
|
+
return Z_LOCALITY_SESSION_LOCAL;
|
|
710
1026
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
1027
|
+
rb_raise(rb_eArgError, "allowed_destination must be :any, :remote or :session_local");
|
|
1028
|
+
return 0;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
static VALUE zrb_str_or_nil_arg(VALUE v, const char *what) {
|
|
1032
|
+
if (v == Qundef || NIL_P(v)) {
|
|
1033
|
+
return Qnil;
|
|
717
1034
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
1035
|
+
if (!RB_TYPE_P(v, T_STRING)) {
|
|
1036
|
+
rb_raise(rb_eTypeError, "%s must be a String or nil", what);
|
|
1037
|
+
}
|
|
1038
|
+
return v;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
static bool zrb_is_timestamp(VALUE v);
|
|
1042
|
+
|
|
1043
|
+
/* names: the keywords the call accepts (unknown ones raise ArgumentError). */
|
|
1044
|
+
static void zrb_opts_parse(VALUE hash, const char *const *names, int n, zrb_opts *o) {
|
|
1045
|
+
o->attachment = o->encoding = o->timestamp = o->payload = Qnil;
|
|
1046
|
+
o->priority = o->congestion_control = o->express = o->reliability = o->destination = o->accept_replies = -1;
|
|
1047
|
+
o->target = o->consolidation = o->timeout = Qnil;
|
|
1048
|
+
o->has_target = o->has_consolidation = o->has_timeout = false;
|
|
1049
|
+
o->depth = Qnil;
|
|
1050
|
+
if (NIL_P(hash)) {
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
ID ids[16];
|
|
1054
|
+
VALUE kw[16];
|
|
1055
|
+
for (int i = 0; i < n; i++) {
|
|
1056
|
+
ids[i] = rb_intern(names[i]);
|
|
1057
|
+
}
|
|
1058
|
+
rb_get_kwargs(hash, ids, 0, n, kw);
|
|
1059
|
+
for (int i = 0; i < n; i++) {
|
|
1060
|
+
VALUE v = kw[i];
|
|
1061
|
+
if (v == Qundef) {
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
const char *k = names[i];
|
|
1065
|
+
if (strcmp(k, "attachment") == 0) {
|
|
1066
|
+
o->attachment = zrb_kw_attachment(v);
|
|
1067
|
+
} else if (strcmp(k, "payload") == 0) {
|
|
1068
|
+
o->payload = zrb_str_or_nil_arg(v, "payload");
|
|
1069
|
+
} else if (strcmp(k, "encoding") == 0) {
|
|
1070
|
+
if (!NIL_P(v)) {
|
|
1071
|
+
o->encoding = rb_String(v);
|
|
1072
|
+
}
|
|
1073
|
+
} else if (strcmp(k, "timestamp") == 0) {
|
|
1074
|
+
if (NIL_P(v) || v == Qfalse) {
|
|
1075
|
+
o->timestamp = Qnil;
|
|
1076
|
+
} else if (v == Qtrue || zrb_is_timestamp(v)) {
|
|
1077
|
+
o->timestamp = v;
|
|
1078
|
+
} else {
|
|
1079
|
+
rb_raise(rb_eTypeError, "timestamp must be true, nil or an Asterism::Zenoh::Timestamp");
|
|
1080
|
+
}
|
|
1081
|
+
} else if (NIL_P(v)) {
|
|
1082
|
+
/* nil: zenoh-c's default */
|
|
1083
|
+
} else if (strcmp(k, "priority") == 0) {
|
|
1084
|
+
o->priority = zrb_priority_arg(v);
|
|
1085
|
+
} else if (strcmp(k, "congestion_control") == 0) {
|
|
1086
|
+
o->congestion_control = zrb_cc_arg(v);
|
|
1087
|
+
} else if (strcmp(k, "express") == 0) {
|
|
1088
|
+
o->express = RTEST(v) ? 1 : 0;
|
|
1089
|
+
} else if (strcmp(k, "reliability") == 0) {
|
|
1090
|
+
o->reliability = zrb_reliability_arg(v);
|
|
1091
|
+
} else if (strcmp(k, "allowed_destination") == 0) {
|
|
1092
|
+
o->destination = zrb_locality_arg(v);
|
|
1093
|
+
} else if (strcmp(k, "accept_replies") == 0) {
|
|
1094
|
+
ID id = zrb_sym_id(v);
|
|
1095
|
+
if (id == rb_intern("any")) {
|
|
1096
|
+
o->accept_replies = Z_REPLY_KEYEXPR_ANY;
|
|
1097
|
+
} else if (id == rb_intern("matching_query")) {
|
|
1098
|
+
o->accept_replies = Z_REPLY_KEYEXPR_MATCHING_QUERY;
|
|
1099
|
+
} else {
|
|
1100
|
+
rb_raise(rb_eArgError, "accept_replies must be :matching_query or :any");
|
|
1101
|
+
}
|
|
1102
|
+
} else if (strcmp(k, "target") == 0) {
|
|
1103
|
+
o->target = v;
|
|
1104
|
+
o->has_target = true;
|
|
1105
|
+
} else if (strcmp(k, "consolidation") == 0) {
|
|
1106
|
+
o->consolidation = v;
|
|
1107
|
+
o->has_consolidation = true;
|
|
1108
|
+
} else if (strcmp(k, "timeout_ms") == 0) {
|
|
1109
|
+
o->timeout = v;
|
|
1110
|
+
o->has_timeout = true;
|
|
1111
|
+
} else if (strcmp(k, "depth") == 0) {
|
|
1112
|
+
o->depth = v;
|
|
722
1113
|
}
|
|
723
|
-
rb_raise(eZenohError, "cannot allocate the payload");
|
|
724
1114
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
/* ----------------------------------------------------------- encodings */
|
|
1118
|
+
|
|
1119
|
+
static VALUE zrb_encoding_value(const z_loaned_encoding_t *e) {
|
|
1120
|
+
if (e == NULL) {
|
|
1121
|
+
return Qnil;
|
|
728
1122
|
}
|
|
729
|
-
|
|
1123
|
+
z_owned_string_t s;
|
|
1124
|
+
z_encoding_to_string(e, &s);
|
|
1125
|
+
VALUE out = zrb_str_from_view(z_loan(s));
|
|
1126
|
+
z_drop(z_move(s));
|
|
1127
|
+
return out;
|
|
730
1128
|
}
|
|
731
1129
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
1130
|
+
/* An owned encoding from a String (already checked). false when there is
|
|
1131
|
+
* none to send. */
|
|
1132
|
+
static bool zrb_encoding_make(z_owned_encoding_t *out, VALUE str) {
|
|
1133
|
+
if (NIL_P(str)) {
|
|
1134
|
+
return false;
|
|
1135
|
+
}
|
|
1136
|
+
if (z_encoding_from_str(out, StringValueCStr(str)) != Z_OK) {
|
|
1137
|
+
rb_raise(rb_eArgError, "invalid encoding: %" PRIsVALUE, str);
|
|
1138
|
+
}
|
|
1139
|
+
return true;
|
|
735
1140
|
}
|
|
736
1141
|
|
|
737
|
-
|
|
1142
|
+
/* ---------------------------------------------------------- timestamps */
|
|
738
1143
|
|
|
739
|
-
|
|
1144
|
+
typedef struct {
|
|
1145
|
+
z_timestamp_t ts;
|
|
1146
|
+
} zrb_ts;
|
|
740
1147
|
|
|
741
|
-
static
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
1148
|
+
static size_t zrb_ts_size(const void *p) { return sizeof(zrb_ts); }
|
|
1149
|
+
|
|
1150
|
+
static const rb_data_type_t zrb_ts_type = {
|
|
1151
|
+
"Asterism::Zenoh::Timestamp", {NULL, RUBY_TYPED_DEFAULT_FREE, zrb_ts_size}, NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY};
|
|
1152
|
+
|
|
1153
|
+
static bool zrb_is_timestamp(VALUE v) { return rb_typeddata_is_kind_of(v, &zrb_ts_type); }
|
|
1154
|
+
|
|
1155
|
+
static VALUE zrb_ts_wrap(const z_timestamp_t *ts) {
|
|
1156
|
+
zrb_ts *t;
|
|
1157
|
+
VALUE obj = TypedData_Make_Struct(cTimestamp, zrb_ts, &zrb_ts_type, t);
|
|
1158
|
+
t->ts = *ts;
|
|
1159
|
+
return obj;
|
|
745
1160
|
}
|
|
746
1161
|
|
|
747
|
-
static
|
|
1162
|
+
static zrb_ts *zrb_ts_get(VALUE self) {
|
|
1163
|
+
zrb_ts *t;
|
|
1164
|
+
TypedData_Get_Struct(self, zrb_ts, &zrb_ts_type, t);
|
|
1165
|
+
return t;
|
|
1166
|
+
}
|
|
748
1167
|
|
|
749
|
-
|
|
1168
|
+
/* NTP64 of zenoh's HLC: seconds since the UNIX epoch in the upper 32 bits,
|
|
1169
|
+
* the fraction of a second in the lower 32. */
|
|
1170
|
+
static VALUE zrb_ts_ntp64(VALUE self) { return ULL2NUM(z_timestamp_ntp64_time(&zrb_ts_get(self)->ts)); }
|
|
750
1171
|
|
|
751
|
-
static
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
return g;
|
|
1172
|
+
static VALUE zrb_ts_id(VALUE self) {
|
|
1173
|
+
z_id_t id = z_timestamp_id(&zrb_ts_get(self)->ts);
|
|
1174
|
+
return zrb_zid_value(&id);
|
|
755
1175
|
}
|
|
756
1176
|
|
|
757
|
-
static VALUE
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
return obj;
|
|
1177
|
+
static VALUE zrb_ts_to_time(VALUE self) {
|
|
1178
|
+
uint64_t t = z_timestamp_ntp64_time(&zrb_ts_get(self)->ts);
|
|
1179
|
+
time_t sec = (time_t)(t >> 32);
|
|
1180
|
+
long nsec = (long)(((t & 0xffffffffULL) * 1000000000ULL) >> 32);
|
|
1181
|
+
return rb_time_nano_new(sec, nsec);
|
|
763
1182
|
}
|
|
764
1183
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
if (
|
|
778
|
-
|
|
779
|
-
}
|
|
780
|
-
VALUE vals[3];
|
|
781
|
-
const z_loaned_sample_t *sm = z_reply_ok(z_loan(r));
|
|
782
|
-
vals[0] = zrb_key_str(z_sample_keyexpr(sm));
|
|
783
|
-
vals[1] = zrb_str_from_bytes(z_sample_payload(sm));
|
|
784
|
-
vals[2] = zrb_attachment_value(z_sample_attachment(sm));
|
|
785
|
-
z_drop(z_move(r));
|
|
786
|
-
taken++;
|
|
787
|
-
if (collect) {
|
|
788
|
-
rb_ary_push(out, rb_ary_new_from_values(3, vals));
|
|
789
|
-
} else {
|
|
790
|
-
rb_yield_values2(3, vals);
|
|
1184
|
+
static VALUE zrb_ts_cmp(VALUE self, VALUE other) {
|
|
1185
|
+
if (!zrb_is_timestamp(other)) {
|
|
1186
|
+
return Qnil;
|
|
1187
|
+
}
|
|
1188
|
+
const z_timestamp_t *a = &zrb_ts_get(self)->ts, *b = &zrb_ts_get(other)->ts;
|
|
1189
|
+
uint64_t ta = z_timestamp_ntp64_time(a), tb = z_timestamp_ntp64_time(b);
|
|
1190
|
+
if (ta != tb) {
|
|
1191
|
+
return INT2FIX(ta < tb ? -1 : 1);
|
|
1192
|
+
}
|
|
1193
|
+
z_id_t ia = z_timestamp_id(a), ib = z_timestamp_id(b);
|
|
1194
|
+
/* LSB first: compare from the most significant byte. */
|
|
1195
|
+
for (int i = 15; i >= 0; i--) {
|
|
1196
|
+
if (ia.id[i] != ib.id[i]) {
|
|
1197
|
+
return INT2FIX(ia.id[i] < ib.id[i] ? -1 : 1);
|
|
791
1198
|
}
|
|
792
1199
|
}
|
|
793
|
-
return
|
|
1200
|
+
return INT2FIX(0);
|
|
794
1201
|
}
|
|
795
1202
|
|
|
796
|
-
static VALUE
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
static VALUE zrb_get_errors(VALUE self) { return UINT2NUM(atomic_load(&zrb_get_get(self)->ch->errors)); }
|
|
1203
|
+
static VALUE zrb_ts_eql(VALUE self, VALUE other) {
|
|
1204
|
+
VALUE c = zrb_ts_cmp(self, other);
|
|
1205
|
+
return (!NIL_P(c) && FIX2INT(c) == 0) ? Qtrue : Qfalse;
|
|
1206
|
+
}
|
|
801
1207
|
|
|
802
|
-
|
|
1208
|
+
static VALUE zrb_ts_hash(VALUE self) {
|
|
1209
|
+
return rb_funcall(rb_ary_new_from_args(2, zrb_ts_ntp64(self), zrb_ts_id(self)), rb_intern("hash"), 0);
|
|
1210
|
+
}
|
|
803
1211
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
zrb_token **pp = &t->owner->tokens;
|
|
811
|
-
while (*pp != NULL) {
|
|
812
|
-
if (*pp == t) {
|
|
813
|
-
*pp = t->next;
|
|
814
|
-
break;
|
|
815
|
-
}
|
|
816
|
-
pp = &(*pp)->next;
|
|
817
|
-
}
|
|
818
|
-
t->owner = NULL;
|
|
819
|
-
t->next = NULL;
|
|
820
|
-
}
|
|
1212
|
+
/* "<ntp64>/<id>" as zenoh prints it, with the time in seconds. */
|
|
1213
|
+
static VALUE zrb_ts_to_s(VALUE self) {
|
|
1214
|
+
VALUE t = zrb_ts_to_time(self);
|
|
1215
|
+
VALUE iso = rb_funcall(rb_funcall(t, rb_intern("utc"), 0), rb_intern("strftime"), 1,
|
|
1216
|
+
rb_str_new_cstr("%Y-%m-%dT%H:%M:%S.%9NZ"));
|
|
1217
|
+
return rb_sprintf("%" PRIsVALUE "/%" PRIsVALUE, iso, zrb_ts_id(self));
|
|
821
1218
|
}
|
|
822
1219
|
|
|
823
|
-
static
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
1220
|
+
static VALUE zrb_ts_inspect(VALUE self) { return rb_sprintf("#<Asterism::Zenoh::Timestamp %" PRIsVALUE ">", zrb_ts_to_s(self)); }
|
|
1221
|
+
|
|
1222
|
+
/* -------------------------------------------------------------- samples */
|
|
1223
|
+
|
|
1224
|
+
/* A sample as an Asterism::Zenoh::Sample (key, payload, attachment, kind,
|
|
1225
|
+
* encoding, timestamp, priority, congestion_control, express,
|
|
1226
|
+
* reliability, source_zid). */
|
|
1227
|
+
static VALUE zrb_sample_value(const z_loaned_sample_t *s) {
|
|
1228
|
+
VALUE h = rb_hash_new();
|
|
1229
|
+
zrb_hset(h, "key", zrb_key_str(z_sample_keyexpr(s)));
|
|
1230
|
+
zrb_hset(h, "payload", zrb_str_from_bytes(z_sample_payload(s)));
|
|
1231
|
+
zrb_hset(h, "attachment", zrb_attachment_value(z_sample_attachment(s)));
|
|
1232
|
+
zrb_hset(h, "kind", ID2SYM(rb_intern(z_sample_kind(s) == Z_SAMPLE_KIND_DELETE ? "delete" : "put")));
|
|
1233
|
+
zrb_hset(h, "encoding", zrb_encoding_value(z_sample_encoding(s)));
|
|
1234
|
+
const z_timestamp_t *ts = z_sample_timestamp(s);
|
|
1235
|
+
zrb_hset(h, "timestamp", ts != NULL ? zrb_ts_wrap(ts) : Qnil);
|
|
1236
|
+
zrb_hset(h, "priority", zrb_priority_sym((int)z_sample_priority(s)));
|
|
1237
|
+
zrb_hset(h, "congestion_control", zrb_cc_sym((int)z_sample_congestion_control(s)));
|
|
1238
|
+
zrb_hset(h, "express", z_sample_express(s) ? Qtrue : Qfalse);
|
|
1239
|
+
zrb_hset(h, "reliability", zrb_reliability_sym((int)z_sample_reliability(s)));
|
|
1240
|
+
const z_source_info_t *si = z_sample_source_info(s);
|
|
1241
|
+
if (si != NULL) {
|
|
1242
|
+
z_entity_global_id_t gid = z_source_info_id(si);
|
|
1243
|
+
z_id_t zid = z_entity_global_id_zid(&gid);
|
|
1244
|
+
zrb_hset(h, "source_zid", zrb_zid_value(&zid));
|
|
1245
|
+
}
|
|
1246
|
+
return zrb_new_value("Sample", h);
|
|
827
1247
|
}
|
|
828
1248
|
|
|
829
|
-
|
|
1249
|
+
/* A reply as an Asterism::Zenoh::Reply: an answer (the sample's fields)
|
|
1250
|
+
* or an error (error: true, payload and encoding of the error). */
|
|
1251
|
+
static VALUE zrb_reply_value(const z_loaned_reply_t *r) {
|
|
1252
|
+
VALUE h = rb_hash_new();
|
|
1253
|
+
if (z_reply_is_ok(r)) {
|
|
1254
|
+
const z_loaned_sample_t *s = z_reply_ok(r);
|
|
1255
|
+
zrb_hset(h, "key", zrb_key_str(z_sample_keyexpr(s)));
|
|
1256
|
+
zrb_hset(h, "payload", zrb_str_from_bytes(z_sample_payload(s)));
|
|
1257
|
+
zrb_hset(h, "attachment", zrb_attachment_value(z_sample_attachment(s)));
|
|
1258
|
+
zrb_hset(h, "kind", ID2SYM(rb_intern(z_sample_kind(s) == Z_SAMPLE_KIND_DELETE ? "delete" : "put")));
|
|
1259
|
+
zrb_hset(h, "encoding", zrb_encoding_value(z_sample_encoding(s)));
|
|
1260
|
+
const z_timestamp_t *ts = z_sample_timestamp(s);
|
|
1261
|
+
zrb_hset(h, "timestamp", ts != NULL ? zrb_ts_wrap(ts) : Qnil);
|
|
1262
|
+
zrb_hset(h, "error", Qfalse);
|
|
1263
|
+
} else {
|
|
1264
|
+
const z_loaned_reply_err_t *e = z_reply_err(r);
|
|
1265
|
+
zrb_hset(h, "key", Qnil);
|
|
1266
|
+
zrb_hset(h, "payload", zrb_str_from_bytes(z_reply_err_payload(e)));
|
|
1267
|
+
zrb_hset(h, "encoding", zrb_encoding_value(z_reply_err_encoding(e)));
|
|
1268
|
+
zrb_hset(h, "error", Qtrue);
|
|
1269
|
+
}
|
|
1270
|
+
z_entity_global_id_t gid;
|
|
1271
|
+
if (z_reply_replier_id(r, &gid)) {
|
|
1272
|
+
z_id_t zid = z_entity_global_id_zid(&gid);
|
|
1273
|
+
zrb_hset(h, "replier_zid", zrb_zid_value(&zid));
|
|
1274
|
+
}
|
|
1275
|
+
return zrb_new_value("Reply", h);
|
|
1276
|
+
}
|
|
830
1277
|
|
|
831
|
-
|
|
832
|
-
"Asterism::Zenoh::LivelinessToken", {NULL, zrb_token_free, zrb_token_size}, NULL, NULL, 0};
|
|
1278
|
+
/* -------------------------------------------------------- key expressions */
|
|
833
1279
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
1280
|
+
typedef struct {
|
|
1281
|
+
zrb_ent ent; /* declared ones only */
|
|
1282
|
+
z_owned_keyexpr_t ke; /* always valid */
|
|
1283
|
+
z_owned_keyexpr_t decl; /* valid while ent.declared */
|
|
1284
|
+
} zrb_ke;
|
|
1285
|
+
|
|
1286
|
+
static void zrb_ke_undeclare(zrb_ent *e) {
|
|
1287
|
+
zrb_ke *k = (zrb_ke *)e;
|
|
1288
|
+
if (e->owner != NULL && e->owner->live) {
|
|
1289
|
+
z_undeclare_keyexpr(z_loan(e->owner->session), z_move(k->decl));
|
|
1290
|
+
} else {
|
|
1291
|
+
z_drop(z_move(k->decl));
|
|
1292
|
+
}
|
|
838
1293
|
}
|
|
839
1294
|
|
|
840
|
-
static
|
|
841
|
-
|
|
842
|
-
|
|
1295
|
+
static void zrb_ke_free(void *p) {
|
|
1296
|
+
zrb_ke *k = (zrb_ke *)p;
|
|
1297
|
+
zrb_ent_detach(&k->ent);
|
|
1298
|
+
z_drop(z_move(k->ke));
|
|
1299
|
+
xfree(k);
|
|
843
1300
|
}
|
|
844
1301
|
|
|
845
|
-
static
|
|
1302
|
+
static size_t zrb_ke_size(const void *p) { return sizeof(zrb_ke); }
|
|
846
1303
|
|
|
847
|
-
|
|
1304
|
+
static const rb_data_type_t zrb_ke_type = {"Asterism::Zenoh::KeyExpr", {NULL, zrb_ke_free, zrb_ke_size}, NULL, NULL, 0};
|
|
848
1305
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
while (z->qables != NULL) {
|
|
853
|
-
zrb_qable_detach(z->qables); /* unlinks itself */
|
|
1306
|
+
static zrb_ke *zrb_ke_of(VALUE v) {
|
|
1307
|
+
if (!rb_typeddata_is_kind_of(v, &zrb_ke_type)) {
|
|
1308
|
+
return NULL;
|
|
854
1309
|
}
|
|
855
|
-
|
|
856
|
-
|
|
1310
|
+
return (zrb_ke *)RTYPEDDATA_DATA(v);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
static const z_loaned_keyexpr_t *zrb_ke_loan(zrb_ke *k) { return k->ent.declared ? z_loan(k->decl) : z_loan(k->ke); }
|
|
1314
|
+
|
|
1315
|
+
/* A key argument (String or KeyExpr) as a loaned key expression; view is
|
|
1316
|
+
* the storage for a String. */
|
|
1317
|
+
static const z_loaned_keyexpr_t *zrb_key_loan(VALUE v, z_view_keyexpr_t *view) {
|
|
1318
|
+
zrb_ke *k = zrb_ke_of(v);
|
|
1319
|
+
if (k != NULL) {
|
|
1320
|
+
return zrb_ke_loan(k);
|
|
857
1321
|
}
|
|
858
|
-
|
|
859
|
-
|
|
1322
|
+
zrb_view_key(view, StringValueCStr(v));
|
|
1323
|
+
return z_loan(*view);
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
/* An owned copy of a key argument, for calls without the GVL. A declared
|
|
1327
|
+
* KeyExpr keeps its declaration. */
|
|
1328
|
+
static void zrb_key_owned(VALUE v, z_owned_keyexpr_t *out) {
|
|
1329
|
+
zrb_ke *k = zrb_ke_of(v);
|
|
1330
|
+
if (k != NULL) {
|
|
1331
|
+
z_keyexpr_clone(out, zrb_ke_loan(k));
|
|
1332
|
+
return;
|
|
860
1333
|
}
|
|
1334
|
+
zrb_owned_key(out, StringValueCStr(v));
|
|
861
1335
|
}
|
|
862
1336
|
|
|
863
|
-
/*
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
if (z->live) {
|
|
869
|
-
z->live = false;
|
|
870
|
-
z_close(z_loan_mut(z->session), NULL);
|
|
871
|
-
z_drop(z_move(z->session));
|
|
1337
|
+
/* The key argument as a String (to keep on the Ruby objects). */
|
|
1338
|
+
static VALUE zrb_key_string(VALUE v) {
|
|
1339
|
+
zrb_ke *k = zrb_ke_of(v);
|
|
1340
|
+
if (k != NULL) {
|
|
1341
|
+
return zrb_key_str(z_loan(k->ke));
|
|
872
1342
|
}
|
|
873
|
-
|
|
874
|
-
return
|
|
1343
|
+
StringValueCStr(v);
|
|
1344
|
+
return v;
|
|
875
1345
|
}
|
|
876
1346
|
|
|
877
|
-
static
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1347
|
+
static VALUE zrb_ke_wrap_owned(z_owned_keyexpr_t *ke) {
|
|
1348
|
+
zrb_ke *k;
|
|
1349
|
+
VALUE obj = TypedData_Make_Struct(cKeyExpr, zrb_ke, &zrb_ke_type, k);
|
|
1350
|
+
k->ke = *ke;
|
|
1351
|
+
z_internal_keyexpr_null(ke);
|
|
1352
|
+
z_internal_keyexpr_null(&k->decl);
|
|
1353
|
+
return obj;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
/* KeyExpr.new(str, autocanonize: false). Raises ArgumentError for a key
|
|
1357
|
+
* expression that is not valid (or not canonical, without autocanonize). */
|
|
1358
|
+
static VALUE zrb_ke_s_new(int argc, VALUE *argv, VALUE klass) {
|
|
1359
|
+
VALUE str, opts = Qnil;
|
|
1360
|
+
rb_scan_args(argc, argv, "1:", &str, &opts);
|
|
1361
|
+
VALUE kw[1] = {Qundef};
|
|
1362
|
+
if (!NIL_P(opts)) {
|
|
1363
|
+
ID ids[1] = {rb_intern("autocanonize")};
|
|
1364
|
+
rb_get_kwargs(opts, ids, 0, 1, kw);
|
|
881
1365
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
z->open = false;
|
|
887
|
-
if (with_gvl_release) {
|
|
888
|
-
rb_thread_call_without_gvl(zrb_session_close_nogvl, z, RUBY_UBF_IO, NULL);
|
|
1366
|
+
zrb_ke *src = zrb_ke_of(str);
|
|
1367
|
+
z_owned_keyexpr_t ke;
|
|
1368
|
+
if (src != NULL) {
|
|
1369
|
+
z_keyexpr_clone(&ke, z_loan(src->ke));
|
|
889
1370
|
} else {
|
|
890
|
-
|
|
1371
|
+
const char *s = StringValueCStr(str);
|
|
1372
|
+
z_result_t r = (kw[0] != Qundef && RTEST(kw[0])) ? z_keyexpr_from_str_autocanonize(&ke, s)
|
|
1373
|
+
: z_keyexpr_from_str(&ke, s);
|
|
1374
|
+
if (r != Z_OK) {
|
|
1375
|
+
rb_raise(rb_eArgError, "invalid key expression: %s", s);
|
|
1376
|
+
}
|
|
891
1377
|
}
|
|
1378
|
+
return zrb_ke_wrap_owned(&ke);
|
|
892
1379
|
}
|
|
893
1380
|
|
|
894
|
-
static
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
xfree(z);
|
|
1381
|
+
static zrb_ke *zrb_ke_get(VALUE self) {
|
|
1382
|
+
zrb_ke *k;
|
|
1383
|
+
TypedData_Get_Struct(self, zrb_ke, &zrb_ke_type, k);
|
|
1384
|
+
return k;
|
|
899
1385
|
}
|
|
900
1386
|
|
|
901
|
-
static
|
|
1387
|
+
static VALUE zrb_ke_to_s(VALUE self) { return zrb_key_str(z_loan(zrb_ke_get(self)->ke)); }
|
|
902
1388
|
|
|
903
|
-
static
|
|
904
|
-
|
|
1389
|
+
static VALUE zrb_ke_inspect(VALUE self) {
|
|
1390
|
+
zrb_ke *k = zrb_ke_get(self);
|
|
1391
|
+
return rb_sprintf("#<Asterism::Zenoh::KeyExpr %" PRIsVALUE "%s>", zrb_ke_to_s(self),
|
|
1392
|
+
k->ent.declared ? " (declared)" : "");
|
|
1393
|
+
}
|
|
905
1394
|
|
|
906
|
-
static
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
return z;
|
|
1395
|
+
static VALUE zrb_ke_intersects_p(VALUE self, VALUE other) {
|
|
1396
|
+
z_view_keyexpr_t v;
|
|
1397
|
+
return z_keyexpr_intersects(z_loan(zrb_ke_get(self)->ke), zrb_key_loan(other, &v)) ? Qtrue : Qfalse;
|
|
910
1398
|
}
|
|
911
1399
|
|
|
912
|
-
static
|
|
913
|
-
|
|
914
|
-
(
|
|
1400
|
+
static VALUE zrb_ke_includes_p(VALUE self, VALUE other) {
|
|
1401
|
+
z_view_keyexpr_t v;
|
|
1402
|
+
return z_keyexpr_includes(z_loan(zrb_ke_get(self)->ke), zrb_key_loan(other, &v)) ? Qtrue : Qfalse;
|
|
915
1403
|
}
|
|
916
1404
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1405
|
+
static VALUE zrb_ke_relation_to(VALUE self, VALUE other) {
|
|
1406
|
+
z_view_keyexpr_t v;
|
|
1407
|
+
switch (z_keyexpr_relation_to(z_loan(zrb_ke_get(self)->ke), zrb_key_loan(other, &v))) {
|
|
1408
|
+
case Z_KEYEXPR_INTERSECTION_LEVEL_DISJOINT:
|
|
1409
|
+
return ID2SYM(rb_intern("disjoint"));
|
|
1410
|
+
case Z_KEYEXPR_INTERSECTION_LEVEL_INTERSECTS:
|
|
1411
|
+
return ID2SYM(rb_intern("intersects"));
|
|
1412
|
+
case Z_KEYEXPR_INTERSECTION_LEVEL_INCLUDES:
|
|
1413
|
+
return ID2SYM(rb_intern("includes"));
|
|
1414
|
+
case Z_KEYEXPR_INTERSECTION_LEVEL_EQUALS:
|
|
1415
|
+
return ID2SYM(rb_intern("equals"));
|
|
926
1416
|
}
|
|
927
|
-
return
|
|
1417
|
+
return Qnil;
|
|
928
1418
|
}
|
|
929
1419
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
if (!z->open) {
|
|
934
|
-
return true;
|
|
935
|
-
}
|
|
936
|
-
if (z_session_is_closed(z_loan(z->session))) {
|
|
937
|
-
zrb_session_shutdown(z, true);
|
|
938
|
-
return true;
|
|
1420
|
+
static VALUE zrb_ke_eq(VALUE self, VALUE other) {
|
|
1421
|
+
if (zrb_ke_of(other) == NULL && !RB_TYPE_P(other, T_STRING)) {
|
|
1422
|
+
return Qfalse;
|
|
939
1423
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
if (zrb_session_links(z) == 0) {
|
|
944
|
-
zrb_session_shutdown(z, true);
|
|
945
|
-
return true;
|
|
1424
|
+
z_view_keyexpr_t v;
|
|
1425
|
+
if (RB_TYPE_P(other, T_STRING) && z_view_keyexpr_from_str(&v, StringValueCStr(other)) != Z_OK) {
|
|
1426
|
+
return Qfalse;
|
|
946
1427
|
}
|
|
947
|
-
|
|
1428
|
+
const z_loaned_keyexpr_t *o = RB_TYPE_P(other, T_STRING) ? z_loan(v) : z_loan(zrb_ke_of(other)->ke);
|
|
1429
|
+
return z_keyexpr_equals(z_loan(zrb_ke_get(self)->ke), o) ? Qtrue : Qfalse;
|
|
948
1430
|
}
|
|
949
1431
|
|
|
950
|
-
static
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1432
|
+
static VALUE zrb_ke_hash(VALUE self) { return LONG2NUM((long)rb_str_hash(zrb_ke_to_s(self))); }
|
|
1433
|
+
|
|
1434
|
+
/* ke.join(other) -> KeyExpr: "a/b" join "c/d" is "a/b/c/d" (canonized). */
|
|
1435
|
+
static VALUE zrb_ke_join(VALUE self, VALUE other) {
|
|
1436
|
+
z_view_keyexpr_t v;
|
|
1437
|
+
const z_loaned_keyexpr_t *o = zrb_key_loan(other, &v);
|
|
1438
|
+
z_owned_keyexpr_t out;
|
|
1439
|
+
if (z_keyexpr_join(&out, z_loan(zrb_ke_get(self)->ke), o) != Z_OK) {
|
|
1440
|
+
rb_raise(rb_eArgError, "cannot join the key expressions");
|
|
954
1441
|
}
|
|
955
|
-
return
|
|
1442
|
+
return zrb_ke_wrap_owned(&out);
|
|
956
1443
|
}
|
|
957
1444
|
|
|
958
|
-
/*
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
rb_str_cat(out, p, 1);
|
|
1445
|
+
/* ke.concat(str) -> KeyExpr: the string appended as it is ("a/b" concat
|
|
1446
|
+
* "c" is "a/bc"); the result must be a valid key expression. */
|
|
1447
|
+
static VALUE zrb_ke_concat(VALUE self, VALUE str) {
|
|
1448
|
+
StringValue(str);
|
|
1449
|
+
z_owned_keyexpr_t out;
|
|
1450
|
+
if (z_keyexpr_concat(&out, z_loan(zrb_ke_get(self)->ke), RSTRING_PTR(str), (size_t)RSTRING_LEN(str)) != Z_OK) {
|
|
1451
|
+
rb_raise(rb_eArgError, "cannot concatenate %" PRIsVALUE, str);
|
|
966
1452
|
}
|
|
967
|
-
|
|
968
|
-
return out;
|
|
1453
|
+
return zrb_ke_wrap_owned(&out);
|
|
969
1454
|
}
|
|
970
1455
|
|
|
971
|
-
static
|
|
972
|
-
|
|
1456
|
+
static VALUE zrb_ke_declared_p(VALUE self) { return zrb_ke_get(self)->ent.declared ? Qtrue : Qfalse; }
|
|
1457
|
+
|
|
1458
|
+
/* Undeclares a declared key expression (it stays usable as a plain one). */
|
|
1459
|
+
static VALUE zrb_ke_undeclare_m(VALUE self) {
|
|
1460
|
+
zrb_ent_detach(&zrb_ke_get(self)->ent);
|
|
1461
|
+
return Qnil;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
/* KeyExpr.canonize(str) -> String in canonical form (for example two
|
|
1465
|
+
* "**" chunks in a row become one, a lone "$*" chunk becomes "*").
|
|
1466
|
+
* Raises ArgumentError when it cannot be made one. */
|
|
1467
|
+
static VALUE zrb_ke_s_canonize(VALUE klass, VALUE str) {
|
|
1468
|
+
VALUE out = rb_str_dup(StringValue(str));
|
|
1469
|
+
size_t len = (size_t)RSTRING_LEN(out);
|
|
1470
|
+
rb_str_modify(out);
|
|
1471
|
+
if (z_keyexpr_canonize(RSTRING_PTR(out), &len) != Z_OK) {
|
|
1472
|
+
rb_raise(rb_eArgError, "invalid key expression: %" PRIsVALUE, str);
|
|
1473
|
+
}
|
|
1474
|
+
rb_str_set_len(out, (long)len);
|
|
1475
|
+
return out;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
/* KeyExpr.valid?(str): a key expression in canonical form. */
|
|
1479
|
+
static VALUE zrb_ke_s_valid_p(VALUE klass, VALUE str) {
|
|
1480
|
+
StringValue(str);
|
|
1481
|
+
return z_keyexpr_is_canon(RSTRING_PTR(str), (size_t)RSTRING_LEN(str)) == Z_OK ? Qtrue : Qfalse;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
/* ----------------------------------------------------------- subscriber */
|
|
1485
|
+
|
|
1486
|
+
static void zrb_sub_detach(zrb_sub *s) {
|
|
1487
|
+
if (s->declared) {
|
|
1488
|
+
if (s->type == ZSUB_ADVANCED) {
|
|
1489
|
+
z_drop(z_move(s->u.adv));
|
|
1490
|
+
} else {
|
|
1491
|
+
z_drop(z_move(s->u.sub));
|
|
1492
|
+
}
|
|
1493
|
+
s->declared = false;
|
|
1494
|
+
}
|
|
1495
|
+
if (s->owner != NULL) {
|
|
1496
|
+
zrb_sub **pp = &s->owner->subs;
|
|
1497
|
+
while (*pp != NULL) {
|
|
1498
|
+
if (*pp == s) {
|
|
1499
|
+
*pp = s->next;
|
|
1500
|
+
break;
|
|
1501
|
+
}
|
|
1502
|
+
pp = &(*pp)->next;
|
|
1503
|
+
}
|
|
1504
|
+
s->owner = NULL;
|
|
1505
|
+
s->next = NULL;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
static void zrb_sub_free(void *p) {
|
|
1510
|
+
zrb_sub *s = (zrb_sub *)p;
|
|
1511
|
+
zrb_sub_detach(s);
|
|
1512
|
+
zch_unref(s->ch);
|
|
1513
|
+
xfree(s);
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
static size_t zrb_sub_size(const void *p) { return sizeof(zrb_sub); }
|
|
1517
|
+
|
|
1518
|
+
static const rb_data_type_t zrb_sub_type = {
|
|
1519
|
+
"Asterism::Zenoh::Subscriber", {NULL, zrb_sub_free, zrb_sub_size}, NULL, NULL, 0};
|
|
1520
|
+
|
|
1521
|
+
static zrb_sub *zrb_sub_get(VALUE self) {
|
|
1522
|
+
zrb_sub *s;
|
|
1523
|
+
TypedData_Get_Struct(self, zrb_sub, &zrb_sub_type, s);
|
|
1524
|
+
return s;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
/* Take out what is pending now, oldest first. Values that arrive while the
|
|
1528
|
+
* block runs are left for the next call. */
|
|
1529
|
+
static VALUE zrb_sub_each_pending(VALUE self) {
|
|
1530
|
+
zrb_sub *s = zrb_sub_get(self);
|
|
1531
|
+
bool collect = !rb_block_given_p();
|
|
1532
|
+
VALUE out = collect ? rb_ary_new() : Qnil;
|
|
1533
|
+
long taken = 0;
|
|
1534
|
+
unsigned todo = atomic_load(&s->ch->queued);
|
|
1535
|
+
while (todo > 0) {
|
|
1536
|
+
todo--;
|
|
1537
|
+
z_owned_sample_t sm;
|
|
1538
|
+
if (zch_take_sample(s->ch, &sm) != Z_OK) {
|
|
1539
|
+
break;
|
|
1540
|
+
}
|
|
1541
|
+
const z_loaned_sample_t *l = z_loan(sm);
|
|
1542
|
+
VALUE vals[3];
|
|
1543
|
+
int n;
|
|
1544
|
+
vals[0] = zrb_key_str(z_sample_keyexpr(l));
|
|
1545
|
+
if (s->liveliness) {
|
|
1546
|
+
/* A token appearing is a PUT, one going away a DELETE. */
|
|
1547
|
+
vals[1] = (z_sample_kind(l) == Z_SAMPLE_KIND_PUT) ? Qtrue : Qfalse;
|
|
1548
|
+
n = 2;
|
|
1549
|
+
} else {
|
|
1550
|
+
vals[1] = zrb_str_from_bytes(z_sample_payload(l));
|
|
1551
|
+
vals[2] = zrb_attachment_value(z_sample_attachment(l));
|
|
1552
|
+
n = 3;
|
|
1553
|
+
}
|
|
1554
|
+
z_drop(z_move(sm));
|
|
1555
|
+
taken++;
|
|
1556
|
+
if (collect) {
|
|
1557
|
+
rb_ary_push(out, rb_ary_new_from_values(n, vals));
|
|
1558
|
+
} else {
|
|
1559
|
+
rb_yield_values2(n, vals);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
return collect ? out : LONG2NUM(taken);
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
/* sub.each_sample { |sample| ... } -> Integer; without a block, Array of
|
|
1566
|
+
* Asterism::Zenoh::Sample (the payload with kind, encoding, timestamp,
|
|
1567
|
+
* priority and the other fields). Takes from the same queue as
|
|
1568
|
+
* each_pending. */
|
|
1569
|
+
static VALUE zrb_sub_each_sample(VALUE self) {
|
|
1570
|
+
zrb_sub *s = zrb_sub_get(self);
|
|
1571
|
+
bool collect = !rb_block_given_p();
|
|
1572
|
+
VALUE out = collect ? rb_ary_new() : Qnil;
|
|
1573
|
+
long taken = 0;
|
|
1574
|
+
unsigned todo = atomic_load(&s->ch->queued);
|
|
1575
|
+
while (todo > 0) {
|
|
1576
|
+
todo--;
|
|
1577
|
+
z_owned_sample_t sm;
|
|
1578
|
+
if (zch_take_sample(s->ch, &sm) != Z_OK) {
|
|
1579
|
+
break;
|
|
1580
|
+
}
|
|
1581
|
+
VALUE v = zrb_sample_value(z_loan(sm));
|
|
1582
|
+
z_drop(z_move(sm));
|
|
1583
|
+
taken++;
|
|
1584
|
+
if (collect) {
|
|
1585
|
+
rb_ary_push(out, v);
|
|
1586
|
+
} else {
|
|
1587
|
+
rb_yield(v);
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
return collect ? out : LONG2NUM(taken);
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
static VALUE zrb_sub_pending(VALUE self) { return UINT2NUM(atomic_load(&zrb_sub_get(self)->ch->queued)); }
|
|
1594
|
+
static VALUE zrb_sub_received(VALUE self) { return UINT2NUM(atomic_load(&zrb_sub_get(self)->ch->received)); }
|
|
1595
|
+
static VALUE zrb_sub_dropped(VALUE self) { return UINT2NUM(atomic_load(&zrb_sub_get(self)->ch->dropped)); }
|
|
1596
|
+
|
|
1597
|
+
static VALUE zrb_sub_close(VALUE self) {
|
|
1598
|
+
zrb_sub_detach(zrb_sub_get(self));
|
|
1599
|
+
return Qnil;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
static VALUE zrb_sub_closed_p(VALUE self) { return zrb_sub_get(self)->declared ? Qfalse : Qtrue; }
|
|
1603
|
+
|
|
1604
|
+
/* ------------------------------------------------------------ queryable */
|
|
1605
|
+
|
|
1606
|
+
static void zrb_qable_detach(zrb_qable *q) {
|
|
1607
|
+
/* Unanswered queries first: their final replies go out while the
|
|
1608
|
+
* session can still carry them. */
|
|
1609
|
+
zch_finish_queries(q->ch);
|
|
1610
|
+
if (q->declared) {
|
|
1611
|
+
z_drop(z_move(q->qable));
|
|
1612
|
+
q->declared = false;
|
|
1613
|
+
}
|
|
1614
|
+
if (q->owner != NULL) {
|
|
1615
|
+
zrb_qable **pp = &q->owner->qables;
|
|
1616
|
+
while (*pp != NULL) {
|
|
1617
|
+
if (*pp == q) {
|
|
1618
|
+
*pp = q->next;
|
|
1619
|
+
break;
|
|
1620
|
+
}
|
|
1621
|
+
pp = &(*pp)->next;
|
|
1622
|
+
}
|
|
1623
|
+
q->owner = NULL;
|
|
1624
|
+
q->next = NULL;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
static void zrb_qable_free(void *p) {
|
|
1629
|
+
zrb_qable *q = (zrb_qable *)p;
|
|
1630
|
+
zrb_qable_detach(q);
|
|
1631
|
+
zch_unref(q->ch);
|
|
1632
|
+
xfree(q);
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
static size_t zrb_qable_size(const void *p) { return sizeof(zrb_qable); }
|
|
1636
|
+
|
|
1637
|
+
static const rb_data_type_t zrb_qable_type = {
|
|
1638
|
+
"Asterism::Zenoh::Queryable", {NULL, zrb_qable_free, zrb_qable_size}, NULL, NULL, 0};
|
|
1639
|
+
|
|
1640
|
+
static zrb_qable *zrb_qable_get(VALUE self) {
|
|
1641
|
+
zrb_qable *q;
|
|
1642
|
+
TypedData_Get_Struct(self, zrb_qable, &zrb_qable_type, q);
|
|
1643
|
+
return q;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
/* ---------------------------------------------------------------- query */
|
|
1647
|
+
|
|
1648
|
+
static void zrb_query_finish(zrb_query *zq) {
|
|
1649
|
+
if (zq->live) {
|
|
1650
|
+
z_drop(z_move(zq->query));
|
|
1651
|
+
zq->live = false;
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
static void zrb_query_free(void *p) {
|
|
1656
|
+
zrb_query *zq = (zrb_query *)p;
|
|
1657
|
+
zrb_query_finish(zq);
|
|
1658
|
+
xfree(zq);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
static size_t zrb_query_size(const void *p) { return sizeof(zrb_query); }
|
|
1662
|
+
|
|
1663
|
+
static const rb_data_type_t zrb_query_type = {
|
|
1664
|
+
"Asterism::Zenoh::Query", {NULL, zrb_query_free, zrb_query_size}, NULL, NULL, 0};
|
|
1665
|
+
|
|
1666
|
+
static zrb_query *zrb_query_get(VALUE self) {
|
|
1667
|
+
zrb_query *zq;
|
|
1668
|
+
TypedData_Get_Struct(self, zrb_query, &zrb_query_type, zq);
|
|
1669
|
+
return zq;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
static zrb_query *zrb_query_get_live(VALUE self) {
|
|
1673
|
+
zrb_query *zq = zrb_query_get(self);
|
|
1674
|
+
if (!zq->live) {
|
|
1675
|
+
rb_raise(eZenohError, "the query is finished");
|
|
1676
|
+
}
|
|
1677
|
+
return zq;
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
/* Wraps the query (moved in) in a Query object. */
|
|
1681
|
+
static VALUE zrb_query_wrap(z_owned_query_t *q) {
|
|
1682
|
+
zrb_query *zq;
|
|
1683
|
+
VALUE obj = TypedData_Make_Struct(cQuery, zrb_query, &zrb_query_type, zq);
|
|
1684
|
+
zq->query = *q;
|
|
1685
|
+
zq->live = true;
|
|
1686
|
+
z_internal_query_null(q);
|
|
1687
|
+
return obj;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
static VALUE zrb_query_yield_body(VALUE obj) { return rb_yield(obj); }
|
|
1691
|
+
|
|
1692
|
+
static VALUE zrb_query_yield_ensure(VALUE obj) {
|
|
1693
|
+
zrb_query_finish(zrb_query_get(obj));
|
|
1694
|
+
return Qnil;
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
/* qa.each_pending { |q| ... } -> Integer (queries taken). Each query is
|
|
1698
|
+
* finished when the block returns (also when it raises).
|
|
1699
|
+
* qa.each_pending -> Array of Query; each stays open until Query#finish or
|
|
1700
|
+
* garbage collection. */
|
|
1701
|
+
static VALUE zrb_qable_each_pending(VALUE self) {
|
|
1702
|
+
zrb_qable *q = zrb_qable_get(self);
|
|
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);
|
|
1707
|
+
VALUE out = collect ? rb_ary_new() : Qnil;
|
|
1708
|
+
long taken = 0;
|
|
1709
|
+
unsigned todo = atomic_load(&q->ch->queued);
|
|
1710
|
+
while (todo > 0) {
|
|
1711
|
+
todo--;
|
|
1712
|
+
z_owned_query_t oq;
|
|
1713
|
+
if (zch_take_query(q->ch, &oq) != Z_OK) {
|
|
1714
|
+
break;
|
|
1715
|
+
}
|
|
1716
|
+
VALUE obj = zrb_query_wrap(&oq);
|
|
1717
|
+
if (!NIL_P(qkey)) {
|
|
1718
|
+
rb_ivar_set(obj, id_iv_qkey, qkey);
|
|
1719
|
+
}
|
|
1720
|
+
taken++;
|
|
1721
|
+
if (collect) {
|
|
1722
|
+
rb_ary_push(out, obj);
|
|
1723
|
+
} else {
|
|
1724
|
+
rb_ensure(zrb_query_yield_body, obj, zrb_query_yield_ensure, obj);
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
return collect ? out : LONG2NUM(taken);
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
static VALUE zrb_qable_pending(VALUE self) { return UINT2NUM(atomic_load(&zrb_qable_get(self)->ch->queued)); }
|
|
1731
|
+
static VALUE zrb_qable_received(VALUE self) { return UINT2NUM(atomic_load(&zrb_qable_get(self)->ch->received)); }
|
|
1732
|
+
static VALUE zrb_qable_dropped(VALUE self) { return UINT2NUM(atomic_load(&zrb_qable_get(self)->ch->dropped)); }
|
|
1733
|
+
|
|
1734
|
+
static VALUE zrb_qable_close(VALUE self) {
|
|
1735
|
+
zrb_qable_detach(zrb_qable_get(self));
|
|
1736
|
+
return Qnil;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
static VALUE zrb_qable_closed_p(VALUE self) { return zrb_qable_get(self)->declared ? Qfalse : Qtrue; }
|
|
1740
|
+
|
|
1741
|
+
static VALUE zrb_query_key(VALUE self) {
|
|
1742
|
+
zrb_query *zq = zrb_query_get_live(self);
|
|
1743
|
+
return zrb_key_str(z_query_keyexpr(z_loan(zq->query)));
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
static VALUE zrb_query_params(VALUE self) {
|
|
1747
|
+
zrb_query *zq = zrb_query_get_live(self);
|
|
1748
|
+
z_view_string_t ps;
|
|
1749
|
+
z_query_parameters(z_loan(zq->query), &ps);
|
|
1750
|
+
return zrb_str_from_view(z_loan(ps));
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
static VALUE zrb_query_payload(VALUE self) {
|
|
1754
|
+
zrb_query *zq = zrb_query_get_live(self);
|
|
1755
|
+
const z_loaned_bytes_t *b = z_query_payload(z_loan(zq->query));
|
|
1756
|
+
if (b == NULL) {
|
|
1757
|
+
return rb_str_new(NULL, 0);
|
|
1758
|
+
}
|
|
1759
|
+
return zrb_str_from_bytes(b);
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
static VALUE zrb_query_attachment(VALUE self) {
|
|
1763
|
+
zrb_query *zq = zrb_query_get_live(self);
|
|
1764
|
+
return zrb_attachment_value(z_query_attachment(z_loan(zq->query)));
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
/* The query's own key (key_v nil) or the given one (String or KeyExpr). */
|
|
1768
|
+
static const z_loaned_keyexpr_t *zrb_reply_key(zrb_query *zq, VALUE key_v, z_view_keyexpr_t *view) {
|
|
1769
|
+
if (NIL_P(key_v)) {
|
|
1770
|
+
return z_query_keyexpr(z_loan(zq->query));
|
|
1771
|
+
}
|
|
1772
|
+
return zrb_key_loan(key_v, view);
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
/* A timestamp option: true makes a new one (needs the session, which the
|
|
1776
|
+
* query does not carry: true is only accepted where there is a session). */
|
|
1777
|
+
static const z_timestamp_t *zrb_opts_timestamp(VALUE v, z_timestamp_t *store, const z_loaned_session_t *session) {
|
|
1778
|
+
if (NIL_P(v)) {
|
|
1779
|
+
return NULL;
|
|
1780
|
+
}
|
|
1781
|
+
if (v == Qtrue) {
|
|
1782
|
+
if (session == NULL || z_timestamp_new(store, session) != Z_OK) {
|
|
1783
|
+
rb_raise(eZenohError, "cannot make a timestamp");
|
|
1784
|
+
}
|
|
1785
|
+
return store;
|
|
1786
|
+
}
|
|
1787
|
+
*store = zrb_ts_get(v)->ts;
|
|
1788
|
+
return store;
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
static const char *const zrb_reply_kw[] = {"attachment", "encoding", "timestamp", "priority", "congestion_control",
|
|
1792
|
+
"express"};
|
|
1793
|
+
|
|
1794
|
+
/* q.reply(payload, **opts) / q.reply(key, payload, **opts) -> nil.
|
|
1795
|
+
* opts: attachment:, encoding: (a String such as "application/json"),
|
|
1796
|
+
* timestamp: (an Asterism::Zenoh::Timestamp), priority:,
|
|
1797
|
+
* congestion_control:, express:. The key defaults to the query's key; it
|
|
1798
|
+
* must match the query's key expression. May be called more than once
|
|
1799
|
+
* before the query is finished. */
|
|
1800
|
+
static VALUE zrb_query_reply(int argc, VALUE *argv, VALUE self) {
|
|
1801
|
+
VALUE a1, a2 = Qnil, opts = Qnil;
|
|
1802
|
+
int n = rb_scan_args(argc, argv, "11:", &a1, &a2, &opts);
|
|
1803
|
+
zrb_opts o;
|
|
1804
|
+
zrb_opts_parse(opts, zrb_reply_kw, 6, &o);
|
|
1805
|
+
if (o.timestamp == Qtrue) {
|
|
1806
|
+
rb_raise(rb_eArgError, "timestamp: needs a Timestamp here (session.new_timestamp)");
|
|
1807
|
+
}
|
|
1808
|
+
zrb_query *zq = zrb_query_get_live(self);
|
|
1809
|
+
VALUE key_v = (n == 1) ? Qnil : a1;
|
|
1810
|
+
VALUE payload = (n == 1) ? a1 : a2;
|
|
1811
|
+
if (!RB_TYPE_P(payload, T_STRING)) {
|
|
1812
|
+
rb_raise(rb_eTypeError, "payload must be a String");
|
|
1813
|
+
}
|
|
1814
|
+
z_view_keyexpr_t ke;
|
|
1815
|
+
const z_loaned_keyexpr_t *kp = zrb_reply_key(zq, key_v, &ke);
|
|
1816
|
+
z_timestamp_t ts;
|
|
1817
|
+
const z_timestamp_t *tsp = zrb_opts_timestamp(o.timestamp, &ts, NULL);
|
|
1818
|
+
z_query_reply_options_t ro;
|
|
1819
|
+
z_query_reply_options_default(&ro);
|
|
1820
|
+
if (o.priority >= 0) {
|
|
1821
|
+
ro.priority = (z_priority_t)o.priority;
|
|
1822
|
+
}
|
|
1823
|
+
if (o.congestion_control >= 0) {
|
|
1824
|
+
ro.congestion_control = (z_congestion_control_t)o.congestion_control;
|
|
1825
|
+
}
|
|
1826
|
+
if (o.express >= 0) {
|
|
1827
|
+
ro.is_express = o.express;
|
|
1828
|
+
}
|
|
1829
|
+
if (tsp != NULL) {
|
|
1830
|
+
ro.timestamp = &ts;
|
|
1831
|
+
}
|
|
1832
|
+
/* Nothing below raises before the reply takes the owned values. */
|
|
1833
|
+
z_owned_encoding_t enc;
|
|
1834
|
+
if (zrb_encoding_make(&enc, o.encoding)) {
|
|
1835
|
+
ro.encoding = z_move(enc);
|
|
1836
|
+
}
|
|
1837
|
+
z_owned_bytes_t att_bytes;
|
|
1838
|
+
if (!NIL_P(o.attachment)) {
|
|
1839
|
+
zrb_bytes_from_str(&att_bytes, o.attachment, "attachment");
|
|
1840
|
+
ro.attachment = z_move(att_bytes);
|
|
1841
|
+
}
|
|
1842
|
+
z_owned_bytes_t bytes;
|
|
1843
|
+
zrb_bytes_from_str(&bytes, payload, "payload");
|
|
1844
|
+
z_result_t ret = z_query_reply(z_loan(zq->query), kp, z_move(bytes), &ro);
|
|
1845
|
+
if (ret != Z_OK) {
|
|
1846
|
+
zrb_raise_code(eZenohError, (int)ret, "reply failed (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
|
|
1847
|
+
}
|
|
1848
|
+
return Qnil;
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
/* q.reply_err(payload, encoding: nil) -> nil: an error answer; the
|
|
1852
|
+
* requester sees it as an error (Get#errors, each_result's error?). */
|
|
1853
|
+
static VALUE zrb_query_reply_err(int argc, VALUE *argv, VALUE self) {
|
|
1854
|
+
VALUE payload, opts = Qnil;
|
|
1855
|
+
rb_scan_args(argc, argv, "1:", &payload, &opts);
|
|
1856
|
+
static const char *const kws[] = {"encoding"};
|
|
1857
|
+
zrb_opts o;
|
|
1858
|
+
zrb_opts_parse(opts, kws, 1, &o);
|
|
1859
|
+
if (!RB_TYPE_P(payload, T_STRING)) {
|
|
1860
|
+
rb_raise(rb_eTypeError, "payload must be a String");
|
|
1861
|
+
}
|
|
1862
|
+
zrb_query *zq = zrb_query_get_live(self);
|
|
1863
|
+
z_query_reply_err_options_t eo;
|
|
1864
|
+
z_query_reply_err_options_default(&eo);
|
|
1865
|
+
z_owned_encoding_t enc;
|
|
1866
|
+
if (zrb_encoding_make(&enc, o.encoding)) {
|
|
1867
|
+
eo.encoding = z_move(enc);
|
|
1868
|
+
}
|
|
1869
|
+
z_owned_bytes_t bytes;
|
|
1870
|
+
zrb_bytes_from_str(&bytes, payload, "payload");
|
|
1871
|
+
z_result_t ret = z_query_reply_err(z_loan(zq->query), z_move(bytes), &eo);
|
|
1872
|
+
if (ret != Z_OK) {
|
|
1873
|
+
zrb_raise_code(eZenohError, (int)ret, "reply_err failed (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
|
|
1874
|
+
}
|
|
1875
|
+
return Qnil;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
/* q.reply_del(key = nil, attachment:, timestamp:, priority:,
|
|
1879
|
+
* congestion_control:, express:) -> nil: answers that the key was
|
|
1880
|
+
* deleted (a DELETE sample). */
|
|
1881
|
+
static VALUE zrb_query_reply_del(int argc, VALUE *argv, VALUE self) {
|
|
1882
|
+
VALUE key_v = Qnil, opts = Qnil;
|
|
1883
|
+
rb_scan_args(argc, argv, "01:", &key_v, &opts);
|
|
1884
|
+
static const char *const kws[] = {"attachment", "timestamp", "priority", "congestion_control", "express"};
|
|
1885
|
+
zrb_opts o;
|
|
1886
|
+
zrb_opts_parse(opts, kws, 5, &o);
|
|
1887
|
+
if (o.timestamp == Qtrue) {
|
|
1888
|
+
rb_raise(rb_eArgError, "timestamp: needs a Timestamp here (session.new_timestamp)");
|
|
1889
|
+
}
|
|
1890
|
+
zrb_query *zq = zrb_query_get_live(self);
|
|
1891
|
+
z_view_keyexpr_t ke;
|
|
1892
|
+
const z_loaned_keyexpr_t *kp = zrb_reply_key(zq, key_v, &ke);
|
|
1893
|
+
z_timestamp_t ts;
|
|
1894
|
+
const z_timestamp_t *tsp = zrb_opts_timestamp(o.timestamp, &ts, NULL);
|
|
1895
|
+
z_query_reply_del_options_t d;
|
|
1896
|
+
z_query_reply_del_options_default(&d);
|
|
1897
|
+
if (o.priority >= 0) {
|
|
1898
|
+
d.priority = (z_priority_t)o.priority;
|
|
1899
|
+
}
|
|
1900
|
+
if (o.congestion_control >= 0) {
|
|
1901
|
+
d.congestion_control = (z_congestion_control_t)o.congestion_control;
|
|
1902
|
+
}
|
|
1903
|
+
if (o.express >= 0) {
|
|
1904
|
+
d.is_express = o.express;
|
|
1905
|
+
}
|
|
1906
|
+
if (tsp != NULL) {
|
|
1907
|
+
d.timestamp = &ts;
|
|
1908
|
+
}
|
|
1909
|
+
z_owned_bytes_t att_bytes;
|
|
1910
|
+
if (!NIL_P(o.attachment)) {
|
|
1911
|
+
zrb_bytes_from_str(&att_bytes, o.attachment, "attachment");
|
|
1912
|
+
d.attachment = z_move(att_bytes);
|
|
1913
|
+
}
|
|
1914
|
+
z_result_t ret = z_query_reply_del(z_loan(zq->query), kp, &d);
|
|
1915
|
+
if (ret != Z_OK) {
|
|
1916
|
+
zrb_raise_code(eZenohError, (int)ret, "reply_del failed (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
|
|
1917
|
+
}
|
|
1918
|
+
return Qnil;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
/* q.encoding -> String or nil: the encoding of the query's payload. */
|
|
1922
|
+
static VALUE zrb_query_encoding(VALUE self) {
|
|
1923
|
+
zrb_query *zq = zrb_query_get_live(self);
|
|
1924
|
+
if (z_query_payload(z_loan(zq->query)) == NULL) {
|
|
1925
|
+
return Qnil;
|
|
1926
|
+
}
|
|
1927
|
+
return zrb_encoding_value(z_query_encoding(z_loan(zq->query)));
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
static VALUE zrb_query_finish_m(VALUE self) {
|
|
1931
|
+
zrb_query_finish(zrb_query_get(self));
|
|
1932
|
+
return Qnil;
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
static VALUE zrb_query_finished_p(VALUE self) { return zrb_query_get(self)->live ? Qfalse : Qtrue; }
|
|
1936
|
+
|
|
1937
|
+
/* ------------------------------------------------------------------ get */
|
|
1938
|
+
|
|
1939
|
+
static void zrb_get_free(void *p) {
|
|
1940
|
+
zrb_get *g = (zrb_get *)p;
|
|
1941
|
+
zch_unref(g->ch); /* zenoh-c may still hold it until the get finishes */
|
|
1942
|
+
xfree(g);
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
static size_t zrb_get_size(const void *p) { return sizeof(zrb_get); }
|
|
1946
|
+
|
|
1947
|
+
static const rb_data_type_t zrb_get_type = {"Asterism::Zenoh::Get", {NULL, zrb_get_free, zrb_get_size}, NULL, NULL, 0};
|
|
1948
|
+
|
|
1949
|
+
static zrb_get *zrb_get_get(VALUE self) {
|
|
1950
|
+
zrb_get *g;
|
|
1951
|
+
TypedData_Get_Struct(self, zrb_get, &zrb_get_type, g);
|
|
1952
|
+
return g;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
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) {
|
|
1958
|
+
zrb_get *g;
|
|
1959
|
+
VALUE obj = TypedData_Make_Struct(cGet, zrb_get, &zrb_get_type, g);
|
|
1960
|
+
g->ch = zch_new(ZCH_REPLY, (uint32_t)depth);
|
|
1961
|
+
*out = g;
|
|
1962
|
+
return obj;
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
/* g.each_reply { |key, payload, attachment| ... } -> Integer; without a
|
|
1966
|
+
* block, Array of [key, payload, attachment]. Error replies are counted
|
|
1967
|
+
* (errors) and taken out, not yielded (each_result returns them). */
|
|
1968
|
+
static VALUE zrb_get_each_reply(VALUE self) {
|
|
1969
|
+
zrb_get *g = zrb_get_get(self);
|
|
1970
|
+
bool collect = !rb_block_given_p();
|
|
1971
|
+
VALUE out = collect ? rb_ary_new() : Qnil;
|
|
1972
|
+
long taken = 0;
|
|
1973
|
+
unsigned todo = atomic_load(&g->ch->queued);
|
|
1974
|
+
while (todo > 0) {
|
|
1975
|
+
todo--;
|
|
1976
|
+
z_owned_reply_t r;
|
|
1977
|
+
if (zch_take_reply(g->ch, &r) != Z_OK) {
|
|
1978
|
+
break;
|
|
1979
|
+
}
|
|
1980
|
+
if (!z_reply_is_ok(z_loan(r))) {
|
|
1981
|
+
/* Counted in errors; each_result returns them. */
|
|
1982
|
+
z_drop(z_move(r));
|
|
1983
|
+
continue;
|
|
1984
|
+
}
|
|
1985
|
+
VALUE vals[3];
|
|
1986
|
+
const z_loaned_sample_t *sm = z_reply_ok(z_loan(r));
|
|
1987
|
+
vals[0] = zrb_key_str(z_sample_keyexpr(sm));
|
|
1988
|
+
vals[1] = zrb_str_from_bytes(z_sample_payload(sm));
|
|
1989
|
+
vals[2] = zrb_attachment_value(z_sample_attachment(sm));
|
|
1990
|
+
z_drop(z_move(r));
|
|
1991
|
+
taken++;
|
|
1992
|
+
if (collect) {
|
|
1993
|
+
rb_ary_push(out, rb_ary_new_from_values(3, vals));
|
|
1994
|
+
} else {
|
|
1995
|
+
rb_yield_values2(3, vals);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
return collect ? out : LONG2NUM(taken);
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
/* g.each_result { |reply| ... } -> Integer; without a block, Array of
|
|
2002
|
+
* Asterism::Zenoh::Reply. Unlike each_reply, error replies are returned
|
|
2003
|
+
* too (reply.error?). Takes from the same queue as each_reply. */
|
|
2004
|
+
static VALUE zrb_get_each_result(VALUE self) {
|
|
2005
|
+
zrb_get *g = zrb_get_get(self);
|
|
2006
|
+
bool collect = !rb_block_given_p();
|
|
2007
|
+
VALUE out = collect ? rb_ary_new() : Qnil;
|
|
2008
|
+
long taken = 0;
|
|
2009
|
+
unsigned todo = atomic_load(&g->ch->queued);
|
|
2010
|
+
while (todo > 0) {
|
|
2011
|
+
todo--;
|
|
2012
|
+
z_owned_reply_t r;
|
|
2013
|
+
if (zch_take_reply(g->ch, &r) != Z_OK) {
|
|
2014
|
+
break;
|
|
2015
|
+
}
|
|
2016
|
+
VALUE v = zrb_reply_value(z_loan(r));
|
|
2017
|
+
z_drop(z_move(r));
|
|
2018
|
+
taken++;
|
|
2019
|
+
if (collect) {
|
|
2020
|
+
rb_ary_push(out, v);
|
|
2021
|
+
} else {
|
|
2022
|
+
rb_yield(v);
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
return collect ? out : LONG2NUM(taken);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
static VALUE zrb_get_done_p(VALUE self) { return atomic_load(&zrb_get_get(self)->ch->done) ? Qtrue : Qfalse; }
|
|
2029
|
+
static VALUE zrb_get_pending(VALUE self) { return UINT2NUM(atomic_load(&zrb_get_get(self)->ch->queued)); }
|
|
2030
|
+
static VALUE zrb_get_received(VALUE self) { return UINT2NUM(atomic_load(&zrb_get_get(self)->ch->received)); }
|
|
2031
|
+
static VALUE zrb_get_dropped(VALUE self) { return UINT2NUM(atomic_load(&zrb_get_get(self)->ch->dropped)); }
|
|
2032
|
+
static VALUE zrb_get_errors(VALUE self) { return UINT2NUM(atomic_load(&zrb_get_get(self)->ch->errors)); }
|
|
2033
|
+
|
|
2034
|
+
/* ---------------------------------------------------------------- token */
|
|
2035
|
+
|
|
2036
|
+
static void zrb_token_detach(zrb_token *t) {
|
|
2037
|
+
if (t->declared) {
|
|
2038
|
+
z_drop(z_move(t->token));
|
|
2039
|
+
t->declared = false;
|
|
2040
|
+
}
|
|
2041
|
+
if (t->owner != NULL) {
|
|
2042
|
+
zrb_token **pp = &t->owner->tokens;
|
|
2043
|
+
while (*pp != NULL) {
|
|
2044
|
+
if (*pp == t) {
|
|
2045
|
+
*pp = t->next;
|
|
2046
|
+
break;
|
|
2047
|
+
}
|
|
2048
|
+
pp = &(*pp)->next;
|
|
2049
|
+
}
|
|
2050
|
+
t->owner = NULL;
|
|
2051
|
+
t->next = NULL;
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
static void zrb_token_free(void *p) {
|
|
2056
|
+
zrb_token *t = (zrb_token *)p;
|
|
2057
|
+
zrb_token_detach(t);
|
|
2058
|
+
xfree(t);
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
static size_t zrb_token_size(const void *p) { return sizeof(zrb_token); }
|
|
2062
|
+
|
|
2063
|
+
static const rb_data_type_t zrb_token_type = {
|
|
2064
|
+
"Asterism::Zenoh::LivelinessToken", {NULL, zrb_token_free, zrb_token_size}, NULL, NULL, 0};
|
|
2065
|
+
|
|
2066
|
+
static zrb_token *zrb_token_get(VALUE self) {
|
|
2067
|
+
zrb_token *t;
|
|
2068
|
+
TypedData_Get_Struct(self, zrb_token, &zrb_token_type, t);
|
|
2069
|
+
return t;
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
static VALUE zrb_token_close(VALUE self) {
|
|
2073
|
+
zrb_token_detach(zrb_token_get(self));
|
|
2074
|
+
return Qnil;
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
static VALUE zrb_token_closed_p(VALUE self) { return zrb_token_get(self)->declared ? Qfalse : Qtrue; }
|
|
2078
|
+
|
|
2079
|
+
/* -------------------------------------------------------------- session */
|
|
2080
|
+
|
|
2081
|
+
/* Undeclares everything the session still has. Holds the GVL (the lists
|
|
2082
|
+
* are only touched with it). */
|
|
2083
|
+
static void zrb_session_detach_order(zrb_session *z, int order) {
|
|
2084
|
+
zrb_ent *e = z->ents;
|
|
2085
|
+
while (e != NULL) {
|
|
2086
|
+
zrb_ent *next = e->next;
|
|
2087
|
+
if (e->order == order) {
|
|
2088
|
+
zrb_ent_detach(e); /* unlinks itself */
|
|
2089
|
+
}
|
|
2090
|
+
e = next;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
static void zrb_session_detach_all(zrb_session *z) {
|
|
2095
|
+
/* Listeners before what they listen to, declared key expressions after
|
|
2096
|
+
* everything that may use them. */
|
|
2097
|
+
zrb_session_detach_order(z, ZENT_LISTENER);
|
|
2098
|
+
zrb_session_detach_order(z, ZENT_ENTITY);
|
|
2099
|
+
while (z->qables != NULL) {
|
|
2100
|
+
zrb_qable_detach(z->qables); /* unlinks itself */
|
|
2101
|
+
}
|
|
2102
|
+
while (z->tokens != NULL) {
|
|
2103
|
+
zrb_token_detach(z->tokens);
|
|
2104
|
+
}
|
|
2105
|
+
while (z->subs != NULL) {
|
|
2106
|
+
zrb_sub_detach(z->subs);
|
|
2107
|
+
}
|
|
2108
|
+
zrb_session_detach_order(z, ZENT_KEYEXPR);
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
/* Closes the zenoh-c session. Without the GVL when called from Ruby
|
|
2112
|
+
* methods (it waits for zenoh's tasks), with it from the GC. */
|
|
2113
|
+
static void *zrb_session_close_nogvl(void *p) {
|
|
2114
|
+
zrb_session *z = (zrb_session *)p;
|
|
2115
|
+
pthread_mutex_lock(&z->op_lock);
|
|
2116
|
+
if (z->live) {
|
|
2117
|
+
z->live = false;
|
|
2118
|
+
z_close(z_loan_mut(z->session), NULL);
|
|
2119
|
+
z_drop(z_move(z->session));
|
|
2120
|
+
}
|
|
2121
|
+
pthread_mutex_unlock(&z->op_lock);
|
|
2122
|
+
return NULL;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
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
|
+
}
|
|
2132
|
+
zrb_session_detach_all(z);
|
|
2133
|
+
if (!z->open) {
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
/* Closed for Ruby before the GVL is released: another Ruby thread that
|
|
2137
|
+
* runs while zenoh-c closes the session sees it closed and does not
|
|
2138
|
+
* touch the session any more (the calls without the GVL check live
|
|
2139
|
+
* under op_lock instead). */
|
|
2140
|
+
z->open = false;
|
|
2141
|
+
if (with_gvl_release) {
|
|
2142
|
+
rb_thread_call_without_gvl(zrb_session_close_nogvl, z, RUBY_UBF_IO, NULL);
|
|
2143
|
+
} else {
|
|
2144
|
+
zrb_session_close_nogvl(z);
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
static void zrb_session_free(void *p) {
|
|
2149
|
+
zrb_session *z = (zrb_session *)p;
|
|
2150
|
+
zrb_session_shutdown(z, false);
|
|
2151
|
+
pthread_mutex_destroy(&z->op_lock);
|
|
2152
|
+
xfree(z);
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
static size_t zrb_session_size(const void *p) { return sizeof(zrb_session); }
|
|
2156
|
+
|
|
2157
|
+
static const rb_data_type_t zrb_session_type = {
|
|
2158
|
+
"Asterism::Zenoh::Session", {NULL, zrb_session_free, zrb_session_size}, NULL, NULL, 0};
|
|
2159
|
+
|
|
2160
|
+
static zrb_session *zrb_session_get(VALUE self) {
|
|
2161
|
+
zrb_session *z;
|
|
2162
|
+
TypedData_Get_Struct(self, zrb_session, &zrb_session_type, z);
|
|
2163
|
+
return z;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
static void zrb_count_zid(const z_id_t *id, void *ctx) {
|
|
2167
|
+
(void)id;
|
|
2168
|
+
(*(int *)ctx)++;
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
/* Routers (client) or peers (peer mode) connected now. */
|
|
2172
|
+
static int zrb_session_links(zrb_session *z) {
|
|
2173
|
+
int n = 0;
|
|
2174
|
+
z_owned_closure_zid_t cb;
|
|
2175
|
+
z_closure(&cb, zrb_count_zid, NULL, &n);
|
|
2176
|
+
if (z->peer) {
|
|
2177
|
+
z_info_peers_zid(z_loan(z->session), z_move(cb));
|
|
2178
|
+
} else {
|
|
2179
|
+
z_info_routers_zid(z_loan(z->session), z_move(cb));
|
|
2180
|
+
}
|
|
2181
|
+
return n;
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
/* Close the session when its connection can no longer carry it (see the
|
|
2185
|
+
* comment at the top). Returns true when the session is (now) closed. */
|
|
2186
|
+
static bool zrb_session_check_link(zrb_session *z) {
|
|
2187
|
+
if (!z->open) {
|
|
2188
|
+
return true;
|
|
2189
|
+
}
|
|
2190
|
+
if (z->pid != getpid()) {
|
|
2191
|
+
return true;
|
|
2192
|
+
}
|
|
2193
|
+
if (z_session_is_closed(z_loan(z->session))) {
|
|
2194
|
+
zrb_session_shutdown(z, true);
|
|
2195
|
+
return true;
|
|
2196
|
+
}
|
|
2197
|
+
if (z->peer && z->listening) {
|
|
2198
|
+
return false;
|
|
2199
|
+
}
|
|
2200
|
+
if (zrb_session_links(z) == 0) {
|
|
2201
|
+
zrb_session_shutdown(z, true);
|
|
2202
|
+
return true;
|
|
2203
|
+
}
|
|
2204
|
+
return false;
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
static zrb_session *zrb_session_get_open(VALUE self) {
|
|
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
|
+
}
|
|
2213
|
+
if (zrb_session_check_link(z)) {
|
|
2214
|
+
rb_raise(eClosedError, "session is closed");
|
|
2215
|
+
}
|
|
2216
|
+
return z;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
/* A JSON5 string literal of s (for the configuration). */
|
|
2220
|
+
static VALUE zrb_json_str(const char *s) {
|
|
2221
|
+
VALUE out = rb_str_new_cstr("\"");
|
|
2222
|
+
for (const char *p = s; *p; p++) {
|
|
2223
|
+
if (*p == '"' || *p == '\\') {
|
|
2224
|
+
rb_str_cat(out, "\\", 1);
|
|
2225
|
+
}
|
|
2226
|
+
rb_str_cat(out, p, 1);
|
|
2227
|
+
}
|
|
2228
|
+
rb_str_cat(out, "\"", 1);
|
|
2229
|
+
return out;
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
static bool zrb_config_set(z_owned_config_t *config, const char *key, const char *json5) {
|
|
2233
|
+
return zc_config_insert_json5(z_loan_mut(*config), key, json5) == Z_OK;
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
typedef struct {
|
|
2237
|
+
zrb_session *z;
|
|
2238
|
+
z_owned_config_t config;
|
|
2239
|
+
z_result_t ret;
|
|
2240
|
+
} zrb_open_args;
|
|
2241
|
+
|
|
2242
|
+
static void *zrb_open_nogvl(void *p) {
|
|
2243
|
+
zrb_open_args *a = (zrb_open_args *)p;
|
|
2244
|
+
a->ret = z_open(&a->z->session, z_move(a->config), NULL);
|
|
2245
|
+
return NULL;
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
/* The value at key of a configuration as JSON (a Ruby String), or nil. */
|
|
2249
|
+
static VALUE zrb_config_get(const z_loaned_config_t *c, const char *key) {
|
|
2250
|
+
z_owned_string_t s;
|
|
2251
|
+
if (zc_config_get_from_str(c, key, &s) != Z_OK) {
|
|
2252
|
+
return Qnil;
|
|
2253
|
+
}
|
|
2254
|
+
VALUE out = zrb_str_from_view(z_loan(s));
|
|
2255
|
+
z_drop(z_move(s));
|
|
2256
|
+
return out;
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
/* A Ruby value as JSON text (for the config: Hash). */
|
|
2260
|
+
static VALUE zrb_to_json(VALUE v) {
|
|
2261
|
+
static bool loaded = false;
|
|
2262
|
+
if (!loaded) {
|
|
2263
|
+
rb_require("json");
|
|
2264
|
+
loaded = true;
|
|
2265
|
+
}
|
|
2266
|
+
return rb_funcall(rb_const_get(rb_cObject, rb_intern("JSON")), rb_intern("generate"), 1, v);
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
typedef struct {
|
|
2270
|
+
z_owned_config_t *config;
|
|
2271
|
+
z_owned_config_t *dflt; /* zenoh's defaults, when the user gave a file */
|
|
2272
|
+
} zrb_cfg;
|
|
2273
|
+
|
|
2274
|
+
/* One of the gem's own settings: applied unless the user's file (or
|
|
2275
|
+
* configuration String) set that key to something other than zenoh's
|
|
2276
|
+
* default. */
|
|
2277
|
+
static bool zrb_cfg_internal(zrb_cfg *c, const char *key, const char *json5) {
|
|
2278
|
+
if (c->dflt != NULL) {
|
|
2279
|
+
VALUE mine = zrb_config_get(z_loan(*c->config), key);
|
|
2280
|
+
VALUE def = zrb_config_get(z_loan(*c->dflt), key);
|
|
2281
|
+
if (!rb_equal(mine, def)) {
|
|
2282
|
+
return true; /* the user's */
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
return zrb_config_set(c->config, key, json5);
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
static VALUE zrb_json_endpoints(const char *ep) {
|
|
2289
|
+
return rb_str_concat(rb_str_concat(rb_str_new_cstr("["), zrb_json_str(ep)), rb_str_new_cstr("]"));
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
typedef struct {
|
|
2293
|
+
VALUE hash;
|
|
2294
|
+
z_owned_config_t *config;
|
|
2295
|
+
VALUE bad; /* the key that failed */
|
|
2296
|
+
} zrb_cfg_hash;
|
|
2297
|
+
|
|
2298
|
+
static int zrb_cfg_hash_i(VALUE key, VALUE val, VALUE arg) {
|
|
2299
|
+
zrb_cfg_hash *h = (zrb_cfg_hash *)arg;
|
|
2300
|
+
VALUE k = rb_obj_as_string(key);
|
|
2301
|
+
VALUE json = zrb_to_json(val);
|
|
2302
|
+
if (!zrb_config_set(h->config, StringValueCStr(k), StringValueCStr(json))) {
|
|
2303
|
+
h->bad = rb_sprintf("%" PRIsVALUE " = %" PRIsVALUE, k, json);
|
|
2304
|
+
return ST_STOP;
|
|
2305
|
+
}
|
|
2306
|
+
return ST_CONTINUE;
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
static VALUE zrb_cfg_hash_body(VALUE arg) {
|
|
2310
|
+
zrb_cfg_hash *h = (zrb_cfg_hash *)arg;
|
|
2311
|
+
rb_hash_foreach(h->hash, zrb_cfg_hash_i, arg);
|
|
2312
|
+
return Qnil;
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
/* Asterism::Zenoh::Session.open(locator = nil, mode: :client, listen: nil,
|
|
2316
|
+
* scouting: nil, config: nil, config_file: nil) -> Session
|
|
2317
|
+
* - client: connects to the router at locator.
|
|
2318
|
+
* - peer: connects to the peer at locator (if given) and/or listens on
|
|
2319
|
+
* listen (e.g. "tcp/0.0.0.0:7447").
|
|
2320
|
+
* - scouting: true turns multicast scouting (and gossip) on, so a peer or
|
|
2321
|
+
* client finds the others by itself (then no locator is needed).
|
|
2322
|
+
* - timestamping: true stamps every put of the session with its clock
|
|
2323
|
+
* (needed by an advanced publisher with a cache but no
|
|
2324
|
+
* sample_miss_detection; zenoh's default is on for routers only).
|
|
2325
|
+
* - config: a Hash of zenoh configuration keys and values
|
|
2326
|
+
* ({"transport/link/tls/root_ca_certificate" => "ca.pem"}; the values are
|
|
2327
|
+
* Ruby values, sent as JSON), or a String with a whole JSON5
|
|
2328
|
+
* configuration. config_file: a JSON5 configuration file.
|
|
2329
|
+
* What wins, lowest first: zenoh's defaults, the gem's own settings (no
|
|
2330
|
+
* scouting, CONNECT_TIMEOUT_MS, SEND_TIMEOUT_MS, a connecting peer does
|
|
2331
|
+
* not listen), the file or the configuration String, the arguments
|
|
2332
|
+
* (locator, mode, listen, scouting, timestamping), the config Hash.
|
|
2333
|
+
* Raises Asterism::Zenoh::Error when the session cannot be opened (no
|
|
2334
|
+
* router or peer answered within the connect timeout). */
|
|
2335
|
+
static VALUE zrb_session_s_open(int argc, VALUE *argv, VALUE klass) {
|
|
2336
|
+
VALUE locator_v = Qnil, opts = Qnil;
|
|
2337
|
+
rb_scan_args(argc, argv, "01:", &locator_v, &opts);
|
|
2338
|
+
VALUE kw[6] = {Qundef, Qundef, Qundef, Qundef, Qundef, Qundef};
|
|
2339
|
+
if (!NIL_P(opts)) {
|
|
2340
|
+
ID ids[6] = {id_mode, id_listen, id_scouting, id_config, id_config_file, rb_intern("timestamping")};
|
|
2341
|
+
rb_get_kwargs(opts, ids, 0, 6, kw);
|
|
2342
|
+
}
|
|
2343
|
+
int timestamping = (kw[5] == Qundef || NIL_P(kw[5])) ? -1 : (RTEST(kw[5]) ? 1 : 0);
|
|
2344
|
+
int mode_arg = -1; /* 0 client, 1 peer */
|
|
2345
|
+
if (kw[0] != Qundef && !NIL_P(kw[0])) {
|
|
2346
|
+
ID mode = zrb_sym_id(kw[0]);
|
|
2347
|
+
if (mode == id_peer) {
|
|
2348
|
+
mode_arg = 1;
|
|
2349
|
+
} else if (mode == id_client) {
|
|
2350
|
+
mode_arg = 0;
|
|
2351
|
+
} else {
|
|
2352
|
+
rb_raise(rb_eArgError, "mode must be :client or :peer");
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
const char *locator = NIL_P(locator_v) ? NULL : StringValueCStr(locator_v);
|
|
2356
|
+
VALUE listen_v = (kw[1] == Qundef) ? Qnil : kw[1];
|
|
2357
|
+
const char *listen = NIL_P(listen_v) ? NULL : StringValueCStr(listen_v);
|
|
2358
|
+
int scouting = (kw[2] == Qundef || NIL_P(kw[2])) ? -1 : (RTEST(kw[2]) ? 1 : 0);
|
|
2359
|
+
VALUE config_v = (kw[3] == Qundef) ? Qnil : kw[3];
|
|
2360
|
+
VALUE file_v = (kw[4] == Qundef) ? Qnil : kw[4];
|
|
2361
|
+
VALUE config_hash = Qnil, config_str = Qnil;
|
|
2362
|
+
if (!NIL_P(config_v)) {
|
|
2363
|
+
if (RB_TYPE_P(config_v, T_HASH)) {
|
|
2364
|
+
config_hash = config_v;
|
|
2365
|
+
} else if (RB_TYPE_P(config_v, T_STRING)) {
|
|
2366
|
+
config_str = config_v;
|
|
2367
|
+
} else {
|
|
2368
|
+
rb_raise(rb_eTypeError, "config must be a Hash or a String (JSON5)");
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
const char *file = NIL_P(file_v) ? NULL : StringValueCStr(file_v);
|
|
2372
|
+
if (file != NULL && !NIL_P(config_str)) {
|
|
2373
|
+
rb_raise(rb_eArgError, "config: (a String) and config_file: cannot be used together");
|
|
2374
|
+
}
|
|
2375
|
+
bool user_base = (file != NULL || !NIL_P(config_str));
|
|
2376
|
+
if (mode_arg != 1 && listen != NULL && !user_base && NIL_P(config_hash)) {
|
|
2377
|
+
rb_raise(rb_eArgError, "listen needs mode: :peer");
|
|
2378
|
+
}
|
|
2379
|
+
if (locator == NULL && listen == NULL && scouting != 1 && !user_base && NIL_P(config_hash)) {
|
|
2380
|
+
rb_raise(rb_eArgError, "a locator (or, for a peer, listen:) is needed");
|
|
2381
|
+
}
|
|
2382
|
+
if (!NIL_P(config_hash)) {
|
|
2383
|
+
zrb_to_json(Qnil); /* loads json now, before anything is allocated */
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
zrb_session *z;
|
|
2387
|
+
VALUE obj = TypedData_Make_Struct(klass, zrb_session, &zrb_session_type, z);
|
|
2388
|
+
pthread_mutex_init(&z->op_lock, NULL);
|
|
2389
|
+
|
|
2390
|
+
zrb_open_args a;
|
|
2391
|
+
a.z = z;
|
|
2392
|
+
z_owned_config_t dflt;
|
|
2393
|
+
z_result_t cr;
|
|
2394
|
+
if (file != NULL) {
|
|
2395
|
+
cr = zc_config_from_file(&a.config, file);
|
|
2396
|
+
} else if (!NIL_P(config_str)) {
|
|
2397
|
+
cr = zc_config_from_str(&a.config, StringValueCStr(config_str));
|
|
2398
|
+
} else {
|
|
2399
|
+
cr = z_config_default(&a.config);
|
|
2400
|
+
}
|
|
2401
|
+
if (cr != Z_OK) {
|
|
2402
|
+
if (file != NULL) {
|
|
2403
|
+
rb_raise(rb_eArgError, "cannot read the configuration file %s (%d)", file, (int)cr);
|
|
2404
|
+
}
|
|
2405
|
+
rb_raise(rb_eArgError, "invalid configuration (%d)", (int)cr);
|
|
2406
|
+
}
|
|
2407
|
+
if (user_base && z_config_default(&dflt) != Z_OK) {
|
|
2408
|
+
z_drop(z_move(a.config));
|
|
2409
|
+
rb_raise(eZenohError, "cannot create the configuration");
|
|
2410
|
+
}
|
|
2411
|
+
zrb_cfg c = {&a.config, user_base ? &dflt : NULL};
|
|
2412
|
+
|
|
2413
|
+
/* Peer or client, as far as the arguments and the file say (a config
|
|
2414
|
+
* Hash may still change it; the mode is read back below). */
|
|
2415
|
+
bool peer = (mode_arg == 1);
|
|
2416
|
+
if (mode_arg < 0 && user_base) {
|
|
2417
|
+
VALUE m = zrb_config_get(z_loan(a.config), "mode");
|
|
2418
|
+
peer = !NIL_P(m) && rb_str_equal(m, rb_str_new_cstr("\"peer\"")) == Qtrue;
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
/* The gem's own settings mirror the mruby gem's zenoh-pico build: no
|
|
2422
|
+
* scouting (the locator is given), a connect-only peer does not listen,
|
|
2423
|
+
* and the session fails to open when nobody answers in time. */
|
|
2424
|
+
char num[32];
|
|
2425
|
+
bool ok = true;
|
|
2426
|
+
if (mode_arg >= 0) {
|
|
2427
|
+
ok = zrb_config_set(&a.config, "mode", mode_arg == 1 ? "\"peer\"" : "\"client\"");
|
|
2428
|
+
} else {
|
|
2429
|
+
ok = zrb_cfg_internal(&c, "mode", "\"client\"");
|
|
2430
|
+
}
|
|
2431
|
+
if (ok && scouting >= 0) {
|
|
2432
|
+
ok = zrb_config_set(&a.config, "scouting/multicast/enabled", scouting ? "true" : "false") &&
|
|
2433
|
+
zrb_config_set(&a.config, "scouting/gossip/enabled", scouting ? "true" : "false");
|
|
2434
|
+
} else if (ok) {
|
|
2435
|
+
ok = zrb_cfg_internal(&c, "scouting/multicast/enabled", "false") &&
|
|
2436
|
+
zrb_cfg_internal(&c, "scouting/gossip/enabled", "false");
|
|
2437
|
+
}
|
|
2438
|
+
if (ok) {
|
|
2439
|
+
snprintf(num, sizeof(num), "%d", ZRB_CONNECT_TIMEOUT_MS);
|
|
2440
|
+
ok = zrb_cfg_internal(&c, "connect/timeout_ms", num) &&
|
|
2441
|
+
zrb_cfg_internal(&c, "connect/exit_on_failure", "true");
|
|
2442
|
+
}
|
|
2443
|
+
if (ok) {
|
|
2444
|
+
snprintf(num, sizeof(num), "%d", ZRB_SEND_TIMEOUT_MS * 1000);
|
|
2445
|
+
ok = zrb_cfg_internal(&c, "transport/link/tx/queue/congestion_control/block/wait_before_close", num);
|
|
2446
|
+
}
|
|
2447
|
+
if (ok && timestamping >= 0) {
|
|
2448
|
+
ok = zrb_config_set(&a.config, "timestamping/enabled", timestamping ? "true" : "false");
|
|
2449
|
+
}
|
|
2450
|
+
if (ok && locator != NULL) {
|
|
2451
|
+
VALUE ep = zrb_json_endpoints(locator);
|
|
2452
|
+
ok = zrb_config_set(&a.config, "connect/endpoints", StringValueCStr(ep));
|
|
2453
|
+
}
|
|
2454
|
+
if (ok) {
|
|
2455
|
+
if (listen != NULL) {
|
|
2456
|
+
VALUE ep = zrb_json_endpoints(listen);
|
|
2457
|
+
ok = zrb_config_set(&a.config, "listen/endpoints", StringValueCStr(ep));
|
|
2458
|
+
} else if (!(peer && scouting == 1)) {
|
|
2459
|
+
/* A scouting peer keeps zenoh's own listener, so the others can
|
|
2460
|
+
* connect to it. */
|
|
2461
|
+
ok = zrb_cfg_internal(&c, "listen/endpoints", "[]");
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
if (user_base) {
|
|
2465
|
+
z_drop(z_move(dflt));
|
|
2466
|
+
}
|
|
2467
|
+
if (!ok) {
|
|
2468
|
+
z_drop(z_move(a.config));
|
|
2469
|
+
rb_raise(eZenohError, "invalid locator");
|
|
2470
|
+
}
|
|
2471
|
+
if (!NIL_P(config_hash)) {
|
|
2472
|
+
zrb_cfg_hash h = {config_hash, &a.config, Qnil};
|
|
2473
|
+
int state = 0;
|
|
2474
|
+
rb_protect(zrb_cfg_hash_body, (VALUE)&h, &state);
|
|
2475
|
+
if (state != 0 || !NIL_P(h.bad)) {
|
|
2476
|
+
z_drop(z_move(a.config));
|
|
2477
|
+
if (state != 0) {
|
|
2478
|
+
rb_jump_tag(state);
|
|
2479
|
+
}
|
|
2480
|
+
rb_raise(rb_eArgError, "invalid configuration: %" PRIsVALUE, h.bad);
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
/* What the session will be, read back from the final configuration. */
|
|
2485
|
+
VALUE m = zrb_config_get(z_loan(a.config), "mode");
|
|
2486
|
+
bool is_router = !NIL_P(m) && rb_str_equal(m, rb_str_new_cstr("\"router\"")) == Qtrue;
|
|
2487
|
+
peer = is_router || (!NIL_P(m) && rb_str_equal(m, rb_str_new_cstr("\"peer\"")) == Qtrue);
|
|
2488
|
+
VALUE lst = zrb_config_get(z_loan(a.config), "listen/endpoints");
|
|
2489
|
+
VALUE mc = zrb_config_get(z_loan(a.config), "scouting/multicast/enabled");
|
|
2490
|
+
bool listens = !NIL_P(lst) && rb_str_equal(lst, rb_str_new_cstr("[]")) != Qtrue &&
|
|
2491
|
+
rb_str_equal(lst, rb_str_new_cstr("{}")) != Qtrue;
|
|
2492
|
+
bool scouts = !NIL_P(mc) && rb_str_equal(mc, rb_str_new_cstr("true")) == Qtrue;
|
|
2493
|
+
|
|
2494
|
+
rb_thread_call_without_gvl(zrb_open_nogvl, &a, RUBY_UBF_IO, NULL);
|
|
2495
|
+
if (a.ret != Z_OK) {
|
|
2496
|
+
zrb_raise_code(eZenohError, (int)a.ret, "cannot open a session to %s (%d)%" PRIsVALUE,
|
|
2497
|
+
locator != NULL ? locator : (listen != NULL ? listen : "the configured endpoints"), (int)a.ret,
|
|
2498
|
+
zrb_last_error());
|
|
2499
|
+
}
|
|
2500
|
+
z->open = true;
|
|
2501
|
+
z->live = true;
|
|
2502
|
+
z->peer = peer;
|
|
2503
|
+
z->pid = getpid();
|
|
2504
|
+
/* A peer that listens (or finds the others by scouting) stays open
|
|
2505
|
+
* without peers; one that only connects closes when it has none. */
|
|
2506
|
+
z->listening = peer && (is_router || listens || scouts);
|
|
2507
|
+
return obj;
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
static VALUE zrb_sub_new(VALUE self, zrb_session *z, VALUE key_v, long depth, bool liveliness) {
|
|
2511
|
+
const char *key = StringValueCStr(key_v);
|
|
2512
|
+
z_view_keyexpr_t ke;
|
|
2513
|
+
zrb_view_key(&ke, key);
|
|
2514
|
+
|
|
2515
|
+
zrb_sub *s;
|
|
2516
|
+
VALUE obj = TypedData_Make_Struct(liveliness ? cWatch : cSubscriber, zrb_sub, &zrb_sub_type, s);
|
|
2517
|
+
s->liveliness = liveliness;
|
|
2518
|
+
s->type = liveliness ? ZSUB_LIVELINESS : ZSUB_PLAIN;
|
|
2519
|
+
s->ch = zch_new(ZCH_SAMPLE, (uint32_t)depth);
|
|
2520
|
+
|
|
2521
|
+
z_owned_closure_sample_t cb;
|
|
2522
|
+
zch_closure_sample(s->ch, &cb);
|
|
2523
|
+
z_result_t ret;
|
|
2524
|
+
if (liveliness) {
|
|
2525
|
+
/* history: the tokens alive now are reported first, as appearing. */
|
|
2526
|
+
z_liveliness_subscriber_options_t lo;
|
|
2527
|
+
z_liveliness_subscriber_options_default(&lo);
|
|
2528
|
+
lo.history = true;
|
|
2529
|
+
ret = z_liveliness_declare_subscriber(z_loan(z->session), &s->u.sub, z_loan(ke), z_move(cb), &lo);
|
|
2530
|
+
} else {
|
|
2531
|
+
/* Remote samples only: zenoh-pico (the mruby gem) does not deliver a
|
|
2532
|
+
* session's own puts to its own subscribers either. */
|
|
2533
|
+
z_subscriber_options_t so;
|
|
2534
|
+
z_subscriber_options_default(&so);
|
|
2535
|
+
so.allowed_origin = Z_LOCALITY_REMOTE;
|
|
2536
|
+
ret = z_declare_subscriber(z_loan(z->session), &s->u.sub, z_loan(ke), z_move(cb), &so);
|
|
2537
|
+
}
|
|
2538
|
+
if (ret != Z_OK) {
|
|
2539
|
+
zrb_raise_code(eZenohError, (int)ret, "cannot subscribe to %s (%d)%" PRIsVALUE, key, (int)ret, zrb_last_error());
|
|
2540
|
+
}
|
|
2541
|
+
s->declared = true;
|
|
2542
|
+
s->owner = z;
|
|
2543
|
+
s->next = z->subs;
|
|
2544
|
+
z->subs = s;
|
|
2545
|
+
zrb_hold_session(obj, self, key_v);
|
|
2546
|
+
return obj;
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
/* session.subscribe(key, depth = 16) -> Subscriber */
|
|
2550
|
+
static VALUE zrb_session_subscribe(int argc, VALUE *argv, VALUE self) {
|
|
2551
|
+
VALUE key_v, depth_v = Qnil;
|
|
2552
|
+
rb_scan_args(argc, argv, "11", &key_v, &depth_v);
|
|
2553
|
+
long depth = zrb_check_depth(depth_v);
|
|
2554
|
+
StringValueCStr(key_v);
|
|
2555
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
2556
|
+
return zrb_sub_new(self, z, key_v, depth, false);
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
/* session.liveliness_watch(key, depth = 1024) -> LivelinessWatch. The
|
|
2560
|
+
* tokens alive when it is declared come in one burst. */
|
|
2561
|
+
static VALUE zrb_session_liveliness_watch(int argc, VALUE *argv, VALUE self) {
|
|
2562
|
+
VALUE key_v, depth_v = Qnil;
|
|
2563
|
+
rb_scan_args(argc, argv, "11", &key_v, &depth_v);
|
|
2564
|
+
long depth = zrb_check_depth_or(depth_v, ZRB_DEFAULT_WATCH_DEPTH);
|
|
2565
|
+
StringValueCStr(key_v);
|
|
2566
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
2567
|
+
return zrb_sub_new(self, z, key_v, depth, true);
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
/* session.queryable(key, depth = 16, complete: false) -> Queryable */
|
|
2571
|
+
static VALUE zrb_session_queryable(int argc, VALUE *argv, VALUE self) {
|
|
2572
|
+
VALUE key_v, depth_v = Qnil, opts = Qnil;
|
|
2573
|
+
rb_scan_args(argc, argv, "11:", &key_v, &depth_v, &opts);
|
|
2574
|
+
VALUE kw[1] = {Qundef};
|
|
2575
|
+
if (!NIL_P(opts)) {
|
|
2576
|
+
rb_get_kwargs(opts, &id_complete, 0, 1, kw);
|
|
2577
|
+
}
|
|
2578
|
+
bool complete = (kw[0] != Qundef) && RTEST(kw[0]);
|
|
2579
|
+
long depth = zrb_check_depth(depth_v);
|
|
2580
|
+
const char *key = StringValueCStr(key_v);
|
|
2581
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
2582
|
+
z_view_keyexpr_t ke;
|
|
2583
|
+
zrb_view_key(&ke, key);
|
|
2584
|
+
|
|
2585
|
+
zrb_qable *q;
|
|
2586
|
+
VALUE obj = TypedData_Make_Struct(cQueryable, zrb_qable, &zrb_qable_type, q);
|
|
2587
|
+
q->ch = zch_new(ZCH_QUERY, (uint32_t)depth);
|
|
2588
|
+
z_owned_closure_query_t cb;
|
|
2589
|
+
zch_closure_query(q->ch, &cb);
|
|
2590
|
+
z_queryable_options_t qo;
|
|
2591
|
+
z_queryable_options_default(&qo);
|
|
2592
|
+
qo.complete = complete;
|
|
2593
|
+
/* Remote queries only, as with zenoh-pico (Asterism answers calls to
|
|
2594
|
+
* its own objects in place). */
|
|
2595
|
+
qo.allowed_origin = Z_LOCALITY_REMOTE;
|
|
2596
|
+
z_result_t ret = z_declare_queryable(z_loan(z->session), &q->qable, z_loan(ke), z_move(cb), &qo);
|
|
2597
|
+
if (ret != Z_OK) {
|
|
2598
|
+
zrb_raise_code(eZenohError, (int)ret, "cannot declare a queryable on %s (%d)%" PRIsVALUE, key, (int)ret, zrb_last_error());
|
|
2599
|
+
}
|
|
2600
|
+
q->declared = true;
|
|
2601
|
+
q->owner = z;
|
|
2602
|
+
q->next = z->qables;
|
|
2603
|
+
z->qables = q;
|
|
2604
|
+
zrb_hold_session(obj, self, key_v);
|
|
2605
|
+
return obj;
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
static z_query_target_t zrb_get_target(VALUE v) {
|
|
2609
|
+
if (v == Qundef || NIL_P(v)) {
|
|
2610
|
+
return Z_QUERY_TARGET_ALL;
|
|
2611
|
+
}
|
|
2612
|
+
ID t = zrb_sym_id(v);
|
|
2613
|
+
if (t == id_all) {
|
|
2614
|
+
return Z_QUERY_TARGET_ALL;
|
|
2615
|
+
}
|
|
2616
|
+
if (t == id_all_complete) {
|
|
2617
|
+
return Z_QUERY_TARGET_ALL_COMPLETE;
|
|
2618
|
+
}
|
|
2619
|
+
if (t == id_best_matching) {
|
|
2620
|
+
return Z_QUERY_TARGET_BEST_MATCHING;
|
|
2621
|
+
}
|
|
2622
|
+
rb_raise(rb_eArgError, "target must be :all, :all_complete or :best_matching");
|
|
2623
|
+
return Z_QUERY_TARGET_ALL; /* not reached */
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
static z_query_consolidation_t zrb_get_consolidation(VALUE v) {
|
|
2627
|
+
if (v == Qundef || NIL_P(v)) {
|
|
2628
|
+
return z_query_consolidation_none();
|
|
2629
|
+
}
|
|
2630
|
+
ID c = zrb_sym_id(v);
|
|
2631
|
+
if (c == id_none) {
|
|
2632
|
+
return z_query_consolidation_none();
|
|
2633
|
+
}
|
|
2634
|
+
if (c == id_latest) {
|
|
2635
|
+
return z_query_consolidation_latest();
|
|
2636
|
+
}
|
|
2637
|
+
if (c == id_monotonic) {
|
|
2638
|
+
return z_query_consolidation_monotonic();
|
|
2639
|
+
}
|
|
2640
|
+
if (c == id_auto) {
|
|
2641
|
+
return z_query_consolidation_auto();
|
|
2642
|
+
}
|
|
2643
|
+
rb_raise(rb_eArgError, "consolidation must be :none, :latest, :monotonic or :auto");
|
|
2644
|
+
return z_query_consolidation_none(); /* not reached */
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
typedef struct {
|
|
2648
|
+
zrb_session *z;
|
|
2649
|
+
z_owned_keyexpr_t key;
|
|
2650
|
+
char *params; /* malloc'd copy, or NULL */
|
|
2651
|
+
bool liveliness;
|
|
2652
|
+
z_owned_closure_reply_t cb;
|
|
2653
|
+
z_get_options_t opts;
|
|
2654
|
+
z_liveliness_get_options_t lopts;
|
|
2655
|
+
z_result_t ret;
|
|
2656
|
+
} zrb_get_args;
|
|
2657
|
+
|
|
2658
|
+
static void *zrb_get_nogvl(void *p) {
|
|
2659
|
+
zrb_get_args *a = (zrb_get_args *)p;
|
|
2660
|
+
pthread_mutex_lock(&a->z->op_lock);
|
|
2661
|
+
if (a->z->live) {
|
|
2662
|
+
if (a->liveliness) {
|
|
2663
|
+
a->ret = z_liveliness_get(z_loan(a->z->session), z_loan(a->key), z_move(a->cb), &a->lopts);
|
|
2664
|
+
} else {
|
|
2665
|
+
a->ret = z_get(z_loan(a->z->session), z_loan(a->key), a->params != NULL ? a->params : "", z_move(a->cb),
|
|
2666
|
+
&a->opts);
|
|
2667
|
+
}
|
|
2668
|
+
} else {
|
|
2669
|
+
a->ret = Z_ESESSION_CLOSED;
|
|
2670
|
+
}
|
|
2671
|
+
pthread_mutex_unlock(&a->z->op_lock);
|
|
2672
|
+
/* A closure that was not taken (the session was closed) is dropped
|
|
2673
|
+
* here, which releases the channel's reference. */
|
|
2674
|
+
z_drop(z_move(a->cb));
|
|
2675
|
+
return NULL;
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
static VALUE zrb_run_get(VALUE self, zrb_session *z, zrb_get_args *a, VALUE obj, VALUE key_v, const char *what) {
|
|
2679
|
+
rb_thread_call_without_gvl(zrb_get_nogvl, a, RUBY_UBF_IO, NULL);
|
|
2680
|
+
z_drop(z_move(a->key));
|
|
2681
|
+
free(a->params);
|
|
2682
|
+
if (zrb_session_check_link(z)) {
|
|
2683
|
+
zrb_raise_code(eClosedError, (int)a->ret, "%s failed: the connection is lost (%d)", what, (int)a->ret);
|
|
2684
|
+
}
|
|
2685
|
+
if (a->ret != Z_OK) {
|
|
2686
|
+
zrb_raise_code(eZenohError, (int)a->ret, "%s failed (%d)", what, (int)a->ret);
|
|
2687
|
+
}
|
|
2688
|
+
zrb_hold_session(obj, self, key_v);
|
|
2689
|
+
return obj;
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
static const char *const zrb_get_kw[] = {"attachment", "target", "consolidation", "encoding", "priority",
|
|
2693
|
+
"congestion_control", "express", "accept_replies", "depth"};
|
|
2694
|
+
|
|
2695
|
+
/* session.get(key, timeout_ms = 2000, params = nil, payload = nil,
|
|
2696
|
+
* attachment: nil, target: :all, consolidation: :none,
|
|
2697
|
+
* encoding: nil, priority: nil, congestion_control: nil,
|
|
2698
|
+
* express: nil, accept_replies: nil, depth: 1024) -> Get.
|
|
2699
|
+
* Returns at once; the replies come in on zenoh's threads. key: a String
|
|
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). */
|
|
2702
|
+
static VALUE zrb_session_get_m(int argc, VALUE *argv, VALUE self) {
|
|
2703
|
+
VALUE key_v, timeout_v = Qnil, params_v = Qnil, payload = Qnil, opts = Qnil;
|
|
2704
|
+
rb_scan_args(argc, argv, "13:", &key_v, &timeout_v, ¶ms_v, &payload, &opts);
|
|
2705
|
+
zrb_opts o;
|
|
2706
|
+
zrb_opts_parse(opts, zrb_get_kw, 9, &o);
|
|
2707
|
+
long depth = zrb_check_depth_or(o.depth, ZRB_DEFAULT_GET_DEPTH);
|
|
2708
|
+
VALUE key_str = zrb_key_string(key_v);
|
|
2709
|
+
long timeout_ms = zrb_check_timeout(timeout_v);
|
|
2710
|
+
const char *params = NIL_P(params_v) ? NULL : StringValueCStr(params_v);
|
|
2711
|
+
if (!NIL_P(payload) && !RB_TYPE_P(payload, T_STRING)) {
|
|
2712
|
+
rb_raise(rb_eTypeError, "payload must be a String");
|
|
2713
|
+
}
|
|
2714
|
+
z_query_target_t target = zrb_get_target(o.has_target ? o.target : Qnil);
|
|
2715
|
+
z_query_consolidation_t consolidation = zrb_get_consolidation(o.has_consolidation ? o.consolidation : Qnil);
|
|
2716
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
2717
|
+
|
|
2718
|
+
zrb_get_args a;
|
|
2719
|
+
memset(&a, 0, sizeof(a));
|
|
2720
|
+
a.z = z;
|
|
2721
|
+
zrb_key_owned(key_v, &a.key);
|
|
2722
|
+
zrb_get *g;
|
|
2723
|
+
VALUE obj = zrb_get_new(depth, &g);
|
|
2724
|
+
z_get_options_default(&a.opts);
|
|
2725
|
+
a.opts.timeout_ms = (uint64_t)timeout_ms;
|
|
2726
|
+
a.opts.target = target;
|
|
2727
|
+
a.opts.consolidation = consolidation;
|
|
2728
|
+
/* Remote queryables only, as with zenoh-pico. */
|
|
2729
|
+
a.opts.allowed_destination = Z_LOCALITY_REMOTE;
|
|
2730
|
+
if (o.priority >= 0) {
|
|
2731
|
+
a.opts.priority = (z_priority_t)o.priority;
|
|
2732
|
+
}
|
|
2733
|
+
if (o.congestion_control >= 0) {
|
|
2734
|
+
a.opts.congestion_control = (z_congestion_control_t)o.congestion_control;
|
|
2735
|
+
}
|
|
2736
|
+
if (o.express >= 0) {
|
|
2737
|
+
a.opts.is_express = o.express;
|
|
2738
|
+
}
|
|
2739
|
+
if (o.accept_replies >= 0) {
|
|
2740
|
+
a.opts.accept_replies = (z_reply_keyexpr_t)o.accept_replies;
|
|
2741
|
+
}
|
|
2742
|
+
z_owned_bytes_t bytes;
|
|
2743
|
+
z_owned_bytes_t att_bytes;
|
|
2744
|
+
z_owned_encoding_t enc;
|
|
2745
|
+
if (!NIL_P(payload)) {
|
|
2746
|
+
zrb_bytes_from_str(&bytes, payload, "payload");
|
|
2747
|
+
a.opts.payload = z_move(bytes);
|
|
2748
|
+
}
|
|
2749
|
+
if (!NIL_P(o.attachment)) {
|
|
2750
|
+
zrb_bytes_from_str(&att_bytes, o.attachment, "attachment");
|
|
2751
|
+
a.opts.attachment = z_move(att_bytes);
|
|
2752
|
+
}
|
|
2753
|
+
if (zrb_encoding_make(&enc, o.encoding)) {
|
|
2754
|
+
a.opts.encoding = z_move(enc);
|
|
2755
|
+
}
|
|
2756
|
+
if (params != NULL) {
|
|
2757
|
+
a.params = strdup(params);
|
|
2758
|
+
}
|
|
2759
|
+
zch_closure_reply(g->ch, &a.cb);
|
|
2760
|
+
return zrb_run_get(self, z, &a, obj, key_str, "get");
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2763
|
+
/* session.liveliness(key) -> LivelinessToken */
|
|
2764
|
+
static VALUE zrb_session_liveliness(VALUE self, VALUE key_v) {
|
|
2765
|
+
const char *key = StringValueCStr(key_v);
|
|
2766
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
2767
|
+
z_view_keyexpr_t ke;
|
|
2768
|
+
zrb_view_key(&ke, key);
|
|
2769
|
+
zrb_token *t;
|
|
2770
|
+
VALUE obj = TypedData_Make_Struct(cToken, zrb_token, &zrb_token_type, t);
|
|
2771
|
+
z_result_t ret = z_liveliness_declare_token(z_loan(z->session), &t->token, z_loan(ke), NULL);
|
|
2772
|
+
if (ret != Z_OK) {
|
|
2773
|
+
zrb_raise_code(eZenohError, (int)ret, "cannot declare a liveliness token on %s (%d)%" PRIsVALUE, key, (int)ret, zrb_last_error());
|
|
2774
|
+
}
|
|
2775
|
+
t->declared = true;
|
|
2776
|
+
t->owner = z;
|
|
2777
|
+
t->next = z->tokens;
|
|
2778
|
+
z->tokens = t;
|
|
2779
|
+
zrb_hold_session(obj, self, key_v);
|
|
2780
|
+
return obj;
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
static const char *const zrb_lget_kw[] = {"depth"};
|
|
2784
|
+
|
|
2785
|
+
/* session.liveliness_get(key, timeout_ms = 2000, depth: 1024) -> Get */
|
|
2786
|
+
static VALUE zrb_session_liveliness_get(int argc, VALUE *argv, VALUE self) {
|
|
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);
|
|
2792
|
+
const char *key = StringValueCStr(key_v);
|
|
2793
|
+
long timeout_ms = zrb_check_timeout(timeout_v);
|
|
2794
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
2795
|
+
|
|
2796
|
+
zrb_get_args a;
|
|
2797
|
+
memset(&a, 0, sizeof(a));
|
|
2798
|
+
a.z = z;
|
|
2799
|
+
a.liveliness = true;
|
|
2800
|
+
zrb_owned_key(&a.key, key);
|
|
2801
|
+
zrb_get *g;
|
|
2802
|
+
VALUE obj = zrb_get_new(depth, &g);
|
|
2803
|
+
z_liveliness_get_options_default(&a.lopts);
|
|
2804
|
+
a.lopts.timeout_ms = (uint64_t)timeout_ms;
|
|
2805
|
+
zch_closure_reply(g->ch, &a.cb);
|
|
2806
|
+
return zrb_run_get(self, z, &a, obj, key_v, "liveliness_get");
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2809
|
+
/* session.poll(steps = 8) -> true while the session is open, false once
|
|
2810
|
+
* closed (by close, or because the connection was lost). zenoh-c receives
|
|
2811
|
+
* on its own threads, so this only checks the connection; steps is
|
|
2812
|
+
* accepted for the mruby gem's signature. Never waits. */
|
|
2813
|
+
static VALUE zrb_session_poll(int argc, VALUE *argv, VALUE self) {
|
|
2814
|
+
VALUE steps_v = Qnil;
|
|
2815
|
+
rb_scan_args(argc, argv, "01", &steps_v);
|
|
2816
|
+
if (!NIL_P(steps_v)) {
|
|
2817
|
+
NUM2LONG(steps_v);
|
|
2818
|
+
}
|
|
2819
|
+
return zrb_session_check_link(zrb_session_get(self)) ? Qfalse : Qtrue;
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
static VALUE zrb_session_closed_p(VALUE self) {
|
|
2823
|
+
return zrb_session_check_link(zrb_session_get(self)) ? Qtrue : Qfalse;
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
static VALUE zrb_session_close(VALUE self) {
|
|
2827
|
+
zrb_session_shutdown(zrb_session_get(self), true);
|
|
2828
|
+
return Qnil;
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2831
|
+
/* session.zid -> String: this session's Zenoh ID in hex. */
|
|
2832
|
+
static VALUE zrb_session_zid(VALUE self) {
|
|
2833
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
2834
|
+
z_id_t id = z_info_zid(z_loan(z->session));
|
|
2835
|
+
z_owned_string_t str;
|
|
2836
|
+
z_id_to_string(&id, &str);
|
|
2837
|
+
VALUE out = zrb_str_from_view(z_loan(str));
|
|
2838
|
+
z_drop(z_move(str));
|
|
2839
|
+
return out;
|
|
2840
|
+
}
|
|
2841
|
+
|
|
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.) */
|
|
2845
|
+
static VALUE zrb_session_peers(VALUE self) {
|
|
2846
|
+
zrb_session *z = zrb_session_get(self);
|
|
2847
|
+
if (zrb_session_check_link(z)) {
|
|
2848
|
+
return INT2FIX(0);
|
|
2849
|
+
}
|
|
2850
|
+
return INT2FIX(zrb_session_links(z));
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
/* The default of zenoh-c's transport/unicast/max_sessions (MAX_PEERS). */
|
|
2854
|
+
static long zrb_default_max_sessions(void) {
|
|
2855
|
+
long n = -1;
|
|
2856
|
+
z_owned_config_t c;
|
|
2857
|
+
if (z_config_default(&c) != Z_OK) {
|
|
2858
|
+
return n;
|
|
2859
|
+
}
|
|
2860
|
+
z_owned_string_t s;
|
|
2861
|
+
if (zc_config_get_from_str(z_loan(c), "transport/unicast/max_sessions", &s) == Z_OK) {
|
|
2862
|
+
char buf[32];
|
|
2863
|
+
size_t len = z_string_len(z_loan(s));
|
|
2864
|
+
if (len < sizeof(buf)) {
|
|
2865
|
+
memcpy(buf, z_string_data(z_loan(s)), len);
|
|
2866
|
+
buf[len] = '\0';
|
|
2867
|
+
n = strtol(buf, NULL, 10);
|
|
2868
|
+
}
|
|
2869
|
+
z_drop(z_move(s));
|
|
2870
|
+
}
|
|
2871
|
+
z_drop(z_move(c));
|
|
2872
|
+
return n;
|
|
973
2873
|
}
|
|
974
2874
|
|
|
2875
|
+
/* ------------------------------------------------- sending (0.3.0 path) */
|
|
2876
|
+
|
|
2877
|
+
typedef struct zrb_pub zrb_pub;
|
|
2878
|
+
|
|
2879
|
+
struct zrb_pub {
|
|
2880
|
+
zrb_ent ent;
|
|
2881
|
+
bool advanced;
|
|
2882
|
+
union {
|
|
2883
|
+
z_owned_publisher_t p;
|
|
2884
|
+
ze_owned_advanced_publisher_t a;
|
|
2885
|
+
} u;
|
|
2886
|
+
};
|
|
2887
|
+
|
|
2888
|
+
typedef enum { ZS_PUT, ZS_DEL, ZS_PPUT, ZS_PDEL, ZS_APUT, ZS_ADEL } zsend_op;
|
|
2889
|
+
|
|
2890
|
+
/* One put or delete, of the session or of a publisher, made without the
|
|
2891
|
+
* GVL. Everything owned is null until made, and dropped after the call
|
|
2892
|
+
* (a value zenoh-c took is left empty, so dropping it again is a no-op). */
|
|
975
2893
|
typedef struct {
|
|
976
2894
|
zrb_session *z;
|
|
977
|
-
|
|
2895
|
+
zrb_pub *pub;
|
|
2896
|
+
zsend_op op;
|
|
2897
|
+
z_owned_keyexpr_t key;
|
|
2898
|
+
z_owned_bytes_t payload;
|
|
2899
|
+
z_owned_bytes_t att;
|
|
2900
|
+
z_owned_encoding_t enc;
|
|
2901
|
+
z_timestamp_t ts;
|
|
2902
|
+
union {
|
|
2903
|
+
z_put_options_t put;
|
|
2904
|
+
z_delete_options_t del;
|
|
2905
|
+
z_publisher_put_options_t pput;
|
|
2906
|
+
z_publisher_delete_options_t pdel;
|
|
2907
|
+
ze_advanced_publisher_put_options_t aput;
|
|
2908
|
+
ze_advanced_publisher_delete_options_t adel;
|
|
2909
|
+
} o;
|
|
2910
|
+
bool undeclared; /* the publisher was closed */
|
|
978
2911
|
z_result_t ret;
|
|
979
|
-
}
|
|
2912
|
+
} zrb_send;
|
|
2913
|
+
|
|
2914
|
+
static void zrb_send_init(zrb_send *s, zrb_session *z, zrb_pub *pub, zsend_op op) {
|
|
2915
|
+
memset(s, 0, sizeof(*s));
|
|
2916
|
+
s->z = z;
|
|
2917
|
+
s->pub = pub;
|
|
2918
|
+
s->op = op;
|
|
2919
|
+
s->ret = Z_OK;
|
|
2920
|
+
z_internal_keyexpr_null(&s->key);
|
|
2921
|
+
z_internal_bytes_null(&s->payload);
|
|
2922
|
+
z_internal_bytes_null(&s->att);
|
|
2923
|
+
z_internal_encoding_null(&s->enc);
|
|
2924
|
+
}
|
|
980
2925
|
|
|
981
|
-
static void *
|
|
982
|
-
|
|
983
|
-
|
|
2926
|
+
static void *zrb_send_nogvl(void *p) {
|
|
2927
|
+
zrb_send *s = (zrb_send *)p;
|
|
2928
|
+
pthread_mutex_lock(&s->z->op_lock);
|
|
2929
|
+
if (!s->z->live) {
|
|
2930
|
+
s->ret = Z_ESESSION_CLOSED;
|
|
2931
|
+
} else if (s->pub != NULL && !s->pub->ent.declared) {
|
|
2932
|
+
s->undeclared = true;
|
|
2933
|
+
} else {
|
|
2934
|
+
switch (s->op) {
|
|
2935
|
+
case ZS_PUT:
|
|
2936
|
+
s->ret = z_put(z_loan(s->z->session), z_loan(s->key), z_move(s->payload), &s->o.put);
|
|
2937
|
+
break;
|
|
2938
|
+
case ZS_DEL:
|
|
2939
|
+
s->ret = z_delete(z_loan(s->z->session), z_loan(s->key), &s->o.del);
|
|
2940
|
+
break;
|
|
2941
|
+
case ZS_PPUT:
|
|
2942
|
+
s->ret = z_publisher_put(z_loan(s->pub->u.p), z_move(s->payload), &s->o.pput);
|
|
2943
|
+
break;
|
|
2944
|
+
case ZS_PDEL:
|
|
2945
|
+
s->ret = z_publisher_delete(z_loan(s->pub->u.p), &s->o.pdel);
|
|
2946
|
+
break;
|
|
2947
|
+
case ZS_APUT:
|
|
2948
|
+
s->ret = ze_advanced_publisher_put(z_loan(s->pub->u.a), z_move(s->payload), &s->o.aput);
|
|
2949
|
+
break;
|
|
2950
|
+
case ZS_ADEL:
|
|
2951
|
+
s->ret = ze_advanced_publisher_delete(z_loan(s->pub->u.a), &s->o.adel);
|
|
2952
|
+
break;
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
pthread_mutex_unlock(&s->z->op_lock);
|
|
984
2956
|
return NULL;
|
|
985
2957
|
}
|
|
986
2958
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
2959
|
+
static void zrb_send_run(zrb_send *s, const char *what) {
|
|
2960
|
+
rb_thread_call_without_gvl(zrb_send_nogvl, s, RUBY_UBF_IO, NULL);
|
|
2961
|
+
z_drop(z_move(s->key));
|
|
2962
|
+
z_drop(z_move(s->payload));
|
|
2963
|
+
z_drop(z_move(s->att));
|
|
2964
|
+
z_drop(z_move(s->enc));
|
|
2965
|
+
if (zrb_session_check_link(s->z)) {
|
|
2966
|
+
zrb_raise_code(eClosedError, (int)s->ret, "%s failed: the connection is lost (%d)", what, (int)s->ret);
|
|
2967
|
+
}
|
|
2968
|
+
if (s->undeclared) {
|
|
2969
|
+
rb_raise(eZenohError, "%s failed: the publisher is closed", what);
|
|
2970
|
+
}
|
|
2971
|
+
if (s->ret != Z_OK) {
|
|
2972
|
+
zrb_raise_code(eZenohError, (int)s->ret, "%s failed (%d)", what, (int)s->ret);
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
/* The timestamp option (nil, true for a new one, or a Timestamp). */
|
|
2977
|
+
static z_timestamp_t *zrb_send_timestamp(zrb_send *s, VALUE v) {
|
|
2978
|
+
if (NIL_P(v)) {
|
|
2979
|
+
return NULL;
|
|
2980
|
+
}
|
|
2981
|
+
if (v == Qtrue) {
|
|
2982
|
+
if (z_timestamp_new(&s->ts, z_loan(s->z->session)) != Z_OK) {
|
|
2983
|
+
rb_raise(eZenohError, "cannot make a timestamp");
|
|
2984
|
+
}
|
|
2985
|
+
} else {
|
|
2986
|
+
s->ts = zrb_ts_get(v)->ts;
|
|
2987
|
+
}
|
|
2988
|
+
return &s->ts;
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
/* Payload, attachment and encoding into s (after every check: only
|
|
2992
|
+
* allocation failures raise from here on). */
|
|
2993
|
+
static void zrb_send_values(zrb_send *s, VALUE payload, const zrb_opts *o) {
|
|
2994
|
+
if (!NIL_P(payload)) {
|
|
2995
|
+
zrb_bytes_from_str(&s->payload, payload, "payload");
|
|
2996
|
+
}
|
|
2997
|
+
if (!NIL_P(o->attachment)) {
|
|
2998
|
+
zrb_bytes_from_str(&s->att, o->attachment, "attachment");
|
|
2999
|
+
}
|
|
3000
|
+
zrb_encoding_make(&s->enc, o->encoding);
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
static const char *const zrb_put_kw[] = {"attachment", "encoding", "priority", "congestion_control",
|
|
3004
|
+
"express", "reliability", "timestamp", "allowed_destination"};
|
|
3005
|
+
static const char *const zrb_del_kw[] = {"priority", "congestion_control", "express",
|
|
3006
|
+
"reliability", "timestamp", "allowed_destination"};
|
|
3007
|
+
|
|
3008
|
+
/* session.put(key, payload, attachment: nil, encoding: nil, priority: nil,
|
|
3009
|
+
* congestion_control: nil, express: nil, reliability: nil,
|
|
3010
|
+
* timestamp: nil, allowed_destination: nil) -> nil.
|
|
3011
|
+
* key: a String or a KeyExpr. encoding: a String ("application/json").
|
|
3012
|
+
* priority: :real_time .. :background (or 1..7), congestion_control:
|
|
3013
|
+
* :drop / :block / :block_first, reliability: :reliable / :best_effort,
|
|
3014
|
+
* timestamp: true (a new one) or a Timestamp, allowed_destination: :any /
|
|
3015
|
+
* :remote / :session_local. nil (or left out) is zenoh-c's default. */
|
|
3016
|
+
static VALUE zrb_session_put(int argc, VALUE *argv, VALUE self) {
|
|
3017
|
+
VALUE key_v, payload, opts = Qnil;
|
|
3018
|
+
rb_scan_args(argc, argv, "2:", &key_v, &payload, &opts);
|
|
3019
|
+
zrb_opts o;
|
|
3020
|
+
zrb_opts_parse(opts, zrb_put_kw, 8, &o);
|
|
3021
|
+
StringValue(payload);
|
|
3022
|
+
zrb_key_string(key_v);
|
|
3023
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
3024
|
+
zrb_send s;
|
|
3025
|
+
zrb_send_init(&s, z, NULL, ZS_PUT);
|
|
3026
|
+
z_put_options_default(&s.o.put);
|
|
3027
|
+
s.o.put.timestamp = zrb_send_timestamp(&s, o.timestamp);
|
|
3028
|
+
if (o.priority >= 0) {
|
|
3029
|
+
s.o.put.priority = (z_priority_t)o.priority;
|
|
3030
|
+
}
|
|
3031
|
+
if (o.congestion_control >= 0) {
|
|
3032
|
+
s.o.put.congestion_control = (z_congestion_control_t)o.congestion_control;
|
|
3033
|
+
}
|
|
3034
|
+
if (o.express >= 0) {
|
|
3035
|
+
s.o.put.is_express = o.express;
|
|
3036
|
+
}
|
|
3037
|
+
if (o.reliability >= 0) {
|
|
3038
|
+
s.o.put.reliability = (z_reliability_t)o.reliability;
|
|
3039
|
+
}
|
|
3040
|
+
if (o.destination >= 0) {
|
|
3041
|
+
s.o.put.allowed_destination = (z_locality_t)o.destination;
|
|
3042
|
+
}
|
|
3043
|
+
zrb_key_owned(key_v, &s.key);
|
|
3044
|
+
zrb_send_values(&s, payload, &o);
|
|
3045
|
+
if (!NIL_P(o.attachment)) {
|
|
3046
|
+
s.o.put.attachment = z_move(s.att);
|
|
3047
|
+
}
|
|
3048
|
+
if (!NIL_P(o.encoding)) {
|
|
3049
|
+
s.o.put.encoding = z_move(s.enc);
|
|
3050
|
+
}
|
|
3051
|
+
zrb_send_run(&s, "put");
|
|
3052
|
+
return Qnil;
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
/* session.delete(key, priority:, congestion_control:, express:,
|
|
3056
|
+
* reliability:, timestamp:, allowed_destination:) -> nil.
|
|
3057
|
+
* Subscribers get a sample of kind :delete (each_pending gives it with an
|
|
3058
|
+
* empty payload). */
|
|
3059
|
+
static VALUE zrb_session_delete(int argc, VALUE *argv, VALUE self) {
|
|
3060
|
+
VALUE key_v, opts = Qnil;
|
|
3061
|
+
rb_scan_args(argc, argv, "1:", &key_v, &opts);
|
|
3062
|
+
zrb_opts o;
|
|
3063
|
+
zrb_opts_parse(opts, zrb_del_kw, 6, &o);
|
|
3064
|
+
zrb_key_string(key_v);
|
|
3065
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
3066
|
+
zrb_send s;
|
|
3067
|
+
zrb_send_init(&s, z, NULL, ZS_DEL);
|
|
3068
|
+
z_delete_options_default(&s.o.del);
|
|
3069
|
+
s.o.del.timestamp = zrb_send_timestamp(&s, o.timestamp);
|
|
3070
|
+
if (o.priority >= 0) {
|
|
3071
|
+
s.o.del.priority = (z_priority_t)o.priority;
|
|
3072
|
+
}
|
|
3073
|
+
if (o.congestion_control >= 0) {
|
|
3074
|
+
s.o.del.congestion_control = (z_congestion_control_t)o.congestion_control;
|
|
3075
|
+
}
|
|
3076
|
+
if (o.express >= 0) {
|
|
3077
|
+
s.o.del.is_express = o.express;
|
|
3078
|
+
}
|
|
3079
|
+
if (o.reliability >= 0) {
|
|
3080
|
+
s.o.del.reliability = (z_reliability_t)o.reliability;
|
|
3081
|
+
}
|
|
3082
|
+
if (o.destination >= 0) {
|
|
3083
|
+
s.o.del.allowed_destination = (z_locality_t)o.destination;
|
|
3084
|
+
}
|
|
3085
|
+
zrb_key_owned(key_v, &s.key);
|
|
3086
|
+
zrb_send_run(&s, "delete");
|
|
3087
|
+
return Qnil;
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
/* ----------------------------------------------------------- publishers */
|
|
3091
|
+
|
|
3092
|
+
static void zrb_pub_undeclare(zrb_ent *e) {
|
|
3093
|
+
zrb_pub *p = (zrb_pub *)e;
|
|
3094
|
+
if (p->advanced) {
|
|
3095
|
+
z_drop(z_move(p->u.a));
|
|
3096
|
+
} else {
|
|
3097
|
+
z_drop(z_move(p->u.p));
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
static void zrb_pub_free(void *ptr) {
|
|
3102
|
+
zrb_pub *p = (zrb_pub *)ptr;
|
|
3103
|
+
zrb_ent_detach(&p->ent);
|
|
3104
|
+
xfree(p);
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
static size_t zrb_pub_size(const void *p) { return sizeof(zrb_pub); }
|
|
3108
|
+
|
|
3109
|
+
static const rb_data_type_t zrb_pub_type = {"Asterism::Zenoh::Publisher", {NULL, zrb_pub_free, zrb_pub_size}, NULL, NULL, 0};
|
|
3110
|
+
|
|
3111
|
+
static zrb_pub *zrb_pub_get(VALUE self) {
|
|
3112
|
+
zrb_pub *p;
|
|
3113
|
+
TypedData_Get_Struct(self, zrb_pub, &zrb_pub_type, p);
|
|
3114
|
+
return p;
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
/* The publisher, declared, with its session open. */
|
|
3118
|
+
static zrb_pub *zrb_pub_get_open(VALUE self) {
|
|
3119
|
+
zrb_pub *p = zrb_pub_get(self);
|
|
3120
|
+
if (!p->ent.declared) {
|
|
3121
|
+
rb_raise(eZenohError, "the publisher is closed");
|
|
3122
|
+
}
|
|
3123
|
+
if (zrb_session_check_link(p->ent.owner)) {
|
|
3124
|
+
rb_raise(eClosedError, "session is closed");
|
|
3125
|
+
}
|
|
3126
|
+
return p;
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
static const char *const zrb_pub_kw[] = {"encoding", "priority", "congestion_control", "express",
|
|
3130
|
+
"reliability", "allowed_destination"};
|
|
3131
|
+
|
|
3132
|
+
static void zrb_pub_options(z_publisher_options_t *po, const zrb_opts *o) {
|
|
3133
|
+
if (o->priority >= 0) {
|
|
3134
|
+
po->priority = (z_priority_t)o->priority;
|
|
3135
|
+
}
|
|
3136
|
+
if (o->congestion_control >= 0) {
|
|
3137
|
+
po->congestion_control = (z_congestion_control_t)o->congestion_control;
|
|
3138
|
+
}
|
|
3139
|
+
if (o->express >= 0) {
|
|
3140
|
+
po->is_express = o->express;
|
|
3141
|
+
}
|
|
3142
|
+
if (o->reliability >= 0) {
|
|
3143
|
+
po->reliability = (z_reliability_t)o->reliability;
|
|
3144
|
+
}
|
|
3145
|
+
if (o->destination >= 0) {
|
|
3146
|
+
po->allowed_destination = (z_locality_t)o->destination;
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3150
|
+
/* A sub-option: v is nil / false (off), true (on with zenoh's defaults),
|
|
3151
|
+
* an Integer (for cache: the number of samples) or a Hash of the given
|
|
3152
|
+
* keys. Returns the Hash (or nil), raises for unknown keys. */
|
|
3153
|
+
static VALUE zrb_subopt_hash(VALUE v, const char *what, const char *const *keys, int n) {
|
|
3154
|
+
if (!RB_TYPE_P(v, T_HASH)) {
|
|
3155
|
+
return Qnil;
|
|
3156
|
+
}
|
|
3157
|
+
VALUE ks = rb_funcall(v, rb_intern("keys"), 0);
|
|
3158
|
+
for (long i = 0; i < RARRAY_LEN(ks); i++) {
|
|
3159
|
+
VALUE k = RARRAY_AREF(ks, i);
|
|
3160
|
+
bool known = false;
|
|
3161
|
+
if (SYMBOL_P(k)) {
|
|
3162
|
+
for (int j = 0; j < n; j++) {
|
|
3163
|
+
if (SYM2ID(k) == rb_intern(keys[j])) {
|
|
3164
|
+
known = true;
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
}
|
|
3168
|
+
if (!known) {
|
|
3169
|
+
rb_raise(rb_eArgError, "unknown key in %s: %" PRIsVALUE, what, k);
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
return v;
|
|
3173
|
+
}
|
|
3174
|
+
|
|
3175
|
+
static VALUE zrb_hget(VALUE h, const char *key) {
|
|
3176
|
+
if (NIL_P(h)) {
|
|
3177
|
+
return Qnil;
|
|
3178
|
+
}
|
|
3179
|
+
return rb_hash_lookup2(h, ID2SYM(rb_intern(key)), Qnil);
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
static uint64_t zrb_ms_arg(VALUE v, const char *what) {
|
|
3183
|
+
long long ms = NUM2LL(v);
|
|
3184
|
+
if (ms < 0) {
|
|
3185
|
+
rb_raise(rb_eArgError, "%s must be 0 or more", what);
|
|
3186
|
+
}
|
|
3187
|
+
return (uint64_t)ms;
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
static VALUE zrb_pub_wrap(VALUE self, zrb_session *z, zrb_pub *p, VALUE obj, VALUE key_str) {
|
|
3191
|
+
zrb_ent_link(&p->ent, z, ZENT_ENTITY, true, zrb_pub_undeclare);
|
|
3192
|
+
zrb_hold_session(obj, self, key_str);
|
|
3193
|
+
return obj;
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
/* session.publisher(key, encoding:, priority:, congestion_control:,
|
|
3197
|
+
* express:, reliability:, allowed_destination:) -> Publisher */
|
|
3198
|
+
static VALUE zrb_session_publisher(int argc, VALUE *argv, VALUE self) {
|
|
3199
|
+
VALUE key_v, opts = Qnil;
|
|
3200
|
+
rb_scan_args(argc, argv, "1:", &key_v, &opts);
|
|
3201
|
+
zrb_opts o;
|
|
3202
|
+
zrb_opts_parse(opts, zrb_pub_kw, 6, &o);
|
|
3203
|
+
VALUE key_str = zrb_key_string(key_v);
|
|
3204
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
3205
|
+
z_view_keyexpr_t view;
|
|
3206
|
+
const z_loaned_keyexpr_t *ke = zrb_key_loan(key_v, &view);
|
|
3207
|
+
zrb_pub *p;
|
|
3208
|
+
VALUE obj = TypedData_Make_Struct(cPublisher, zrb_pub, &zrb_pub_type, p);
|
|
3209
|
+
z_publisher_options_t po;
|
|
3210
|
+
z_publisher_options_default(&po);
|
|
3211
|
+
zrb_pub_options(&po, &o);
|
|
3212
|
+
z_owned_encoding_t enc;
|
|
3213
|
+
if (zrb_encoding_make(&enc, o.encoding)) {
|
|
3214
|
+
po.encoding = z_move(enc);
|
|
3215
|
+
}
|
|
3216
|
+
z_result_t ret = z_declare_publisher(z_loan(z->session), &p->u.p, ke, &po);
|
|
3217
|
+
if (ret != Z_OK) {
|
|
3218
|
+
zrb_raise_code(eZenohError, (int)ret, "cannot declare a publisher on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
|
|
3219
|
+
}
|
|
3220
|
+
return zrb_pub_wrap(self, z, p, obj, key_str);
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3223
|
+
static const char *const zrb_cache_keys[] = {"max_samples", "priority", "congestion_control", "express"};
|
|
3224
|
+
static const char *const zrb_smd_keys[] = {"heartbeat", "heartbeat_ms"};
|
|
3225
|
+
|
|
3226
|
+
/* session.advanced_publisher(key, cache: nil, sample_miss_detection: nil,
|
|
3227
|
+
* publisher_detection: false, **publisher options) -> AdvancedPublisher
|
|
3228
|
+
* cache: N (keep the last N samples for late subscribers, the history of
|
|
3229
|
+
* an advanced subscriber), true (zenoh's default size) or a Hash
|
|
3230
|
+
* {max_samples:, priority:, congestion_control:, express:}.
|
|
3231
|
+
* sample_miss_detection: true or {heartbeat: :periodic / :sporadic,
|
|
3232
|
+
* heartbeat_ms:} (lets advanced subscribers notice and recover lost
|
|
3233
|
+
* samples). publisher_detection: true declares a liveliness token that
|
|
3234
|
+
* advanced subscribers can watch (detect_publishers). A cache without
|
|
3235
|
+
* sample_miss_detection orders the samples by their timestamps: the
|
|
3236
|
+
* session needs timestamping (Session.open(..., timestamping: true)). */
|
|
3237
|
+
static VALUE zrb_session_advanced_publisher(int argc, VALUE *argv, VALUE self) {
|
|
3238
|
+
VALUE key_v, opts = Qnil;
|
|
3239
|
+
rb_scan_args(argc, argv, "1:", &key_v, &opts);
|
|
3240
|
+
static const char *const kws[] = {"encoding", "priority", "congestion_control", "express", "reliability",
|
|
3241
|
+
"allowed_destination", "cache", "sample_miss_detection",
|
|
3242
|
+
"publisher_detection"};
|
|
3243
|
+
VALUE extra[3] = {Qnil, Qnil, Qnil};
|
|
3244
|
+
VALUE base = Qnil;
|
|
997
3245
|
if (!NIL_P(opts)) {
|
|
998
|
-
|
|
999
|
-
|
|
3246
|
+
/* Split our three keywords from the publisher's ones. */
|
|
3247
|
+
base = rb_hash_dup(opts);
|
|
3248
|
+
for (int i = 0; i < 3; i++) {
|
|
3249
|
+
extra[i] = rb_hash_delete(base, ID2SYM(rb_intern(kws[6 + i])));
|
|
3250
|
+
}
|
|
1000
3251
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
3252
|
+
zrb_opts o;
|
|
3253
|
+
zrb_opts_parse(base, kws, 6, &o);
|
|
3254
|
+
VALUE cache_h = zrb_subopt_hash(extra[0], "cache", zrb_cache_keys, 4);
|
|
3255
|
+
VALUE smd_h = zrb_subopt_hash(extra[1], "sample_miss_detection", zrb_smd_keys, 2);
|
|
3256
|
+
|
|
3257
|
+
ze_advanced_publisher_options_t ao;
|
|
3258
|
+
ze_advanced_publisher_options_default(&ao);
|
|
3259
|
+
zrb_pub_options(&ao.publisher_options, &o);
|
|
3260
|
+
if (RTEST(extra[0])) {
|
|
3261
|
+
ao.cache.is_enabled = true;
|
|
3262
|
+
if (RB_INTEGER_TYPE_P(extra[0])) {
|
|
3263
|
+
long n = NUM2LONG(extra[0]);
|
|
3264
|
+
if (n < 1) {
|
|
3265
|
+
rb_raise(rb_eArgError, "cache must be 1 or more samples");
|
|
3266
|
+
}
|
|
3267
|
+
ao.cache.max_samples = (size_t)n;
|
|
3268
|
+
} else if (!NIL_P(cache_h)) {
|
|
3269
|
+
VALUE v;
|
|
3270
|
+
if (!NIL_P(v = zrb_hget(cache_h, "max_samples"))) {
|
|
3271
|
+
ao.cache.max_samples = (size_t)NUM2ULONG(v);
|
|
3272
|
+
}
|
|
3273
|
+
if (!NIL_P(v = zrb_hget(cache_h, "priority"))) {
|
|
3274
|
+
ao.cache.priority = (z_priority_t)zrb_priority_arg(v);
|
|
3275
|
+
}
|
|
3276
|
+
if (!NIL_P(v = zrb_hget(cache_h, "congestion_control"))) {
|
|
3277
|
+
ao.cache.congestion_control = (z_congestion_control_t)zrb_cc_arg(v);
|
|
3278
|
+
}
|
|
3279
|
+
if (!NIL_P(v = zrb_hget(cache_h, "express"))) {
|
|
3280
|
+
ao.cache.is_express = RTEST(v);
|
|
3281
|
+
}
|
|
3282
|
+
} else if (extra[0] != Qtrue) {
|
|
3283
|
+
rb_raise(rb_eTypeError, "cache must be an Integer, true or a Hash");
|
|
1008
3284
|
}
|
|
1009
3285
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
3286
|
+
if (RTEST(extra[1])) {
|
|
3287
|
+
ao.sample_miss_detection.is_enabled = true;
|
|
3288
|
+
if (!NIL_P(smd_h)) {
|
|
3289
|
+
VALUE v;
|
|
3290
|
+
if (!NIL_P(v = zrb_hget(smd_h, "heartbeat"))) {
|
|
3291
|
+
ID hb = zrb_sym_id(v);
|
|
3292
|
+
if (hb == rb_intern("periodic")) {
|
|
3293
|
+
ao.sample_miss_detection.heartbeat_mode = ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_PERIODIC;
|
|
3294
|
+
} else if (hb == rb_intern("sporadic")) {
|
|
3295
|
+
ao.sample_miss_detection.heartbeat_mode = ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_SPORADIC;
|
|
3296
|
+
} else if (hb == id_none) {
|
|
3297
|
+
ao.sample_miss_detection.heartbeat_mode = ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE;
|
|
3298
|
+
} else {
|
|
3299
|
+
rb_raise(rb_eArgError, "heartbeat must be :periodic, :sporadic or :none");
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
if (!NIL_P(v = zrb_hget(smd_h, "heartbeat_ms"))) {
|
|
3303
|
+
ao.sample_miss_detection.heartbeat_period_ms = zrb_ms_arg(v, "heartbeat_ms");
|
|
3304
|
+
}
|
|
3305
|
+
} else if (extra[1] != Qtrue) {
|
|
3306
|
+
rb_raise(rb_eTypeError, "sample_miss_detection must be true or a Hash");
|
|
3307
|
+
}
|
|
1015
3308
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
3309
|
+
ao.publisher_detection = RTEST(extra[2]);
|
|
3310
|
+
|
|
3311
|
+
VALUE key_str = zrb_key_string(key_v);
|
|
3312
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
3313
|
+
z_view_keyexpr_t view;
|
|
3314
|
+
const z_loaned_keyexpr_t *ke = zrb_key_loan(key_v, &view);
|
|
3315
|
+
zrb_pub *p;
|
|
3316
|
+
VALUE obj = TypedData_Make_Struct(cAdvPublisher, zrb_pub, &zrb_pub_type, p);
|
|
3317
|
+
p->advanced = true;
|
|
3318
|
+
z_owned_encoding_t enc;
|
|
3319
|
+
if (zrb_encoding_make(&enc, o.encoding)) {
|
|
3320
|
+
ao.publisher_options.encoding = z_move(enc);
|
|
1018
3321
|
}
|
|
3322
|
+
z_result_t ret = ze_declare_advanced_publisher(z_loan(z->session), &p->u.a, ke, &ao);
|
|
3323
|
+
if (ret != Z_OK) {
|
|
3324
|
+
zrb_raise_code(eZenohError, (int)ret, "cannot declare an advanced publisher on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
|
|
3325
|
+
}
|
|
3326
|
+
return zrb_pub_wrap(self, z, p, obj, key_str);
|
|
3327
|
+
}
|
|
1019
3328
|
|
|
1020
|
-
|
|
1021
|
-
VALUE obj = TypedData_Make_Struct(klass, zrb_session, &zrb_session_type, z);
|
|
1022
|
-
pthread_mutex_init(&z->op_lock, NULL);
|
|
3329
|
+
static const char *const zrb_pput_kw[] = {"attachment", "encoding", "timestamp"};
|
|
1023
3330
|
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
3331
|
+
/* pub.put(payload, attachment: nil, encoding: nil, timestamp: nil) -> nil */
|
|
3332
|
+
static VALUE zrb_pub_put(int argc, VALUE *argv, VALUE self) {
|
|
3333
|
+
VALUE payload, opts = Qnil;
|
|
3334
|
+
rb_scan_args(argc, argv, "1:", &payload, &opts);
|
|
3335
|
+
zrb_opts o;
|
|
3336
|
+
zrb_opts_parse(opts, zrb_pput_kw, 3, &o);
|
|
3337
|
+
StringValue(payload);
|
|
3338
|
+
zrb_pub *p = zrb_pub_get_open(self);
|
|
3339
|
+
zrb_send s;
|
|
3340
|
+
zrb_send_init(&s, p->ent.owner, p, p->advanced ? ZS_APUT : ZS_PPUT);
|
|
3341
|
+
z_publisher_put_options_t *po;
|
|
3342
|
+
if (p->advanced) {
|
|
3343
|
+
ze_advanced_publisher_put_options_default(&s.o.aput);
|
|
3344
|
+
po = &s.o.aput.put_options;
|
|
3345
|
+
} else {
|
|
3346
|
+
z_publisher_put_options_default(&s.o.pput);
|
|
3347
|
+
po = &s.o.pput;
|
|
1031
3348
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
zrb_config_set(&a.config, "scouting/gossip/enabled", "false") &&
|
|
1037
|
-
zrb_config_set(&a.config, "connect/timeout_ms", num) &&
|
|
1038
|
-
zrb_config_set(&a.config, "connect/exit_on_failure", "true");
|
|
1039
|
-
if (ok) {
|
|
1040
|
-
snprintf(num, sizeof(num), "%d", ZRB_SEND_TIMEOUT_MS * 1000);
|
|
1041
|
-
ok = zrb_config_set(&a.config, "transport/link/tx/queue/congestion_control/block/wait_before_close", num);
|
|
3349
|
+
po->timestamp = zrb_send_timestamp(&s, o.timestamp);
|
|
3350
|
+
zrb_send_values(&s, payload, &o);
|
|
3351
|
+
if (!NIL_P(o.attachment)) {
|
|
3352
|
+
po->attachment = z_move(s.att);
|
|
1042
3353
|
}
|
|
1043
|
-
if (
|
|
1044
|
-
|
|
1045
|
-
ok = zrb_config_set(&a.config, "connect/endpoints", StringValueCStr(ep));
|
|
3354
|
+
if (!NIL_P(o.encoding)) {
|
|
3355
|
+
po->encoding = z_move(s.enc);
|
|
1046
3356
|
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
3357
|
+
zrb_send_run(&s, "put");
|
|
3358
|
+
return Qnil;
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
/* pub.delete(timestamp: nil) -> nil */
|
|
3362
|
+
static VALUE zrb_pub_delete(int argc, VALUE *argv, VALUE self) {
|
|
3363
|
+
VALUE opts = Qnil;
|
|
3364
|
+
rb_scan_args(argc, argv, "0:", &opts);
|
|
3365
|
+
static const char *const kws[] = {"timestamp"};
|
|
3366
|
+
zrb_opts o;
|
|
3367
|
+
zrb_opts_parse(opts, kws, 1, &o);
|
|
3368
|
+
zrb_pub *p = zrb_pub_get_open(self);
|
|
3369
|
+
zrb_send s;
|
|
3370
|
+
zrb_send_init(&s, p->ent.owner, p, p->advanced ? ZS_ADEL : ZS_PDEL);
|
|
3371
|
+
z_publisher_delete_options_t *po;
|
|
3372
|
+
if (p->advanced) {
|
|
3373
|
+
ze_advanced_publisher_delete_options_default(&s.o.adel);
|
|
3374
|
+
po = &s.o.adel.delete_options;
|
|
3375
|
+
} else {
|
|
3376
|
+
z_publisher_delete_options_default(&s.o.pdel);
|
|
3377
|
+
po = &s.o.pdel;
|
|
1054
3378
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
3379
|
+
po->timestamp = zrb_send_timestamp(&s, o.timestamp);
|
|
3380
|
+
zrb_send_run(&s, "delete");
|
|
3381
|
+
return Qnil;
|
|
3382
|
+
}
|
|
3383
|
+
|
|
3384
|
+
/* pub.matching? -> true when at least one subscriber matches the key now. */
|
|
3385
|
+
static VALUE zrb_pub_matching_p(VALUE self) {
|
|
3386
|
+
zrb_pub *p = zrb_pub_get_open(self);
|
|
3387
|
+
z_matching_status_t st = {false};
|
|
3388
|
+
z_result_t r = p->advanced ? ze_advanced_publisher_get_matching_status(z_loan(p->u.a), &st)
|
|
3389
|
+
: z_publisher_get_matching_status(z_loan(p->u.p), &st);
|
|
3390
|
+
if (r != Z_OK) {
|
|
3391
|
+
zrb_raise_code(eZenohError, (int)r, "cannot get the matching status (%d)%" PRIsVALUE, (int)r, zrb_last_error());
|
|
1058
3392
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
3393
|
+
return st.matching ? Qtrue : Qfalse;
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
static VALUE zrb_pub_close(VALUE self) {
|
|
3397
|
+
zrb_ent_detach(&zrb_pub_get(self)->ent);
|
|
3398
|
+
return Qnil;
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3401
|
+
static VALUE zrb_pub_closed_p(VALUE self) { return zrb_pub_get(self)->ent.declared ? Qfalse : Qtrue; }
|
|
3402
|
+
|
|
3403
|
+
/* ------------------------------------------------------------- queriers */
|
|
3404
|
+
|
|
3405
|
+
typedef struct {
|
|
3406
|
+
zrb_ent ent;
|
|
3407
|
+
z_owned_querier_t q;
|
|
3408
|
+
} zrb_querier;
|
|
3409
|
+
|
|
3410
|
+
static void zrb_querier_undeclare(zrb_ent *e) { z_drop(z_move(((zrb_querier *)e)->q)); }
|
|
3411
|
+
|
|
3412
|
+
static void zrb_querier_free(void *ptr) {
|
|
3413
|
+
zrb_querier *q = (zrb_querier *)ptr;
|
|
3414
|
+
zrb_ent_detach(&q->ent);
|
|
3415
|
+
xfree(q);
|
|
3416
|
+
}
|
|
3417
|
+
|
|
3418
|
+
static size_t zrb_querier_size(const void *p) { return sizeof(zrb_querier); }
|
|
3419
|
+
|
|
3420
|
+
static const rb_data_type_t zrb_querier_type = {
|
|
3421
|
+
"Asterism::Zenoh::Querier", {NULL, zrb_querier_free, zrb_querier_size}, NULL, NULL, 0};
|
|
3422
|
+
|
|
3423
|
+
static zrb_querier *zrb_querier_get(VALUE self) {
|
|
3424
|
+
zrb_querier *q;
|
|
3425
|
+
TypedData_Get_Struct(self, zrb_querier, &zrb_querier_type, q);
|
|
3426
|
+
return q;
|
|
3427
|
+
}
|
|
3428
|
+
|
|
3429
|
+
static zrb_querier *zrb_querier_get_open(VALUE self) {
|
|
3430
|
+
zrb_querier *q = zrb_querier_get(self);
|
|
3431
|
+
if (!q->ent.declared) {
|
|
3432
|
+
rb_raise(eZenohError, "the querier is closed");
|
|
1062
3433
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
3434
|
+
if (zrb_session_check_link(q->ent.owner)) {
|
|
3435
|
+
rb_raise(eClosedError, "session is closed");
|
|
3436
|
+
}
|
|
3437
|
+
return q;
|
|
3438
|
+
}
|
|
3439
|
+
|
|
3440
|
+
static const char *const zrb_querier_kw[] = {"target", "consolidation", "timeout_ms", "congestion_control",
|
|
3441
|
+
"priority", "express", "accept_replies", "allowed_destination"};
|
|
3442
|
+
|
|
3443
|
+
/* session.querier(key, target: :all, consolidation: :none,
|
|
3444
|
+
* timeout_ms: 2000, congestion_control:, priority:,
|
|
3445
|
+
* express:, accept_replies: :matching_query,
|
|
3446
|
+
* allowed_destination: :remote) -> Querier.
|
|
3447
|
+
* A declared get: q.get(...) sends the same query again and again. */
|
|
3448
|
+
static VALUE zrb_session_querier(int argc, VALUE *argv, VALUE self) {
|
|
3449
|
+
VALUE key_v, opts = Qnil;
|
|
3450
|
+
rb_scan_args(argc, argv, "1:", &key_v, &opts);
|
|
3451
|
+
zrb_opts o;
|
|
3452
|
+
zrb_opts_parse(opts, zrb_querier_kw, 8, &o);
|
|
3453
|
+
z_querier_options_t qo;
|
|
3454
|
+
z_querier_options_default(&qo);
|
|
3455
|
+
qo.target = zrb_get_target(o.has_target ? o.target : Qnil);
|
|
3456
|
+
qo.consolidation = zrb_get_consolidation(o.has_consolidation ? o.consolidation : Qnil);
|
|
3457
|
+
qo.timeout_ms = (uint64_t)zrb_check_timeout(o.has_timeout ? o.timeout : Qnil);
|
|
3458
|
+
/* Remote queryables only by default, as with get. */
|
|
3459
|
+
qo.allowed_destination = o.destination >= 0 ? (z_locality_t)o.destination : Z_LOCALITY_REMOTE;
|
|
3460
|
+
if (o.congestion_control >= 0) {
|
|
3461
|
+
qo.congestion_control = (z_congestion_control_t)o.congestion_control;
|
|
3462
|
+
}
|
|
3463
|
+
if (o.priority >= 0) {
|
|
3464
|
+
qo.priority = (z_priority_t)o.priority;
|
|
3465
|
+
}
|
|
3466
|
+
if (o.express >= 0) {
|
|
3467
|
+
qo.is_express = o.express;
|
|
3468
|
+
}
|
|
3469
|
+
if (o.accept_replies >= 0) {
|
|
3470
|
+
qo.accept_replies = (z_reply_keyexpr_t)o.accept_replies;
|
|
3471
|
+
}
|
|
3472
|
+
VALUE key_str = zrb_key_string(key_v);
|
|
3473
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
3474
|
+
z_view_keyexpr_t view;
|
|
3475
|
+
const z_loaned_keyexpr_t *ke = zrb_key_loan(key_v, &view);
|
|
3476
|
+
zrb_querier *q;
|
|
3477
|
+
VALUE obj = TypedData_Make_Struct(cQuerier, zrb_querier, &zrb_querier_type, q);
|
|
3478
|
+
z_result_t ret = z_declare_querier(z_loan(z->session), &q->q, ke, &qo);
|
|
3479
|
+
if (ret != Z_OK) {
|
|
3480
|
+
zrb_raise_code(eZenohError, (int)ret, "cannot declare a querier on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
|
|
3481
|
+
}
|
|
3482
|
+
zrb_ent_link(&q->ent, z, ZENT_ENTITY, true, zrb_querier_undeclare);
|
|
3483
|
+
zrb_hold_session(obj, self, key_str);
|
|
1067
3484
|
return obj;
|
|
1068
3485
|
}
|
|
1069
3486
|
|
|
1070
3487
|
typedef struct {
|
|
1071
3488
|
zrb_session *z;
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
3489
|
+
zrb_querier *q;
|
|
3490
|
+
char *params;
|
|
3491
|
+
z_owned_closure_reply_t cb;
|
|
3492
|
+
z_owned_bytes_t payload, att;
|
|
3493
|
+
z_owned_encoding_t enc;
|
|
3494
|
+
z_querier_get_options_t opts;
|
|
3495
|
+
bool undeclared;
|
|
1075
3496
|
z_result_t ret;
|
|
1076
|
-
}
|
|
3497
|
+
} zrb_qget_args;
|
|
1077
3498
|
|
|
1078
|
-
static void *
|
|
1079
|
-
|
|
3499
|
+
static void *zrb_qget_nogvl(void *p) {
|
|
3500
|
+
zrb_qget_args *a = (zrb_qget_args *)p;
|
|
1080
3501
|
pthread_mutex_lock(&a->z->op_lock);
|
|
1081
|
-
if (a->z->live) {
|
|
1082
|
-
a->ret = z_put(z_loan(a->z->session), z_loan(a->key), z_move(a->payload), &a->opts);
|
|
1083
|
-
} else {
|
|
3502
|
+
if (!a->z->live) {
|
|
1084
3503
|
a->ret = Z_ESESSION_CLOSED;
|
|
3504
|
+
} else if (!a->q->ent.declared) {
|
|
3505
|
+
a->undeclared = true;
|
|
3506
|
+
} else {
|
|
3507
|
+
a->ret = z_querier_get(z_loan(a->q->q), a->params != NULL ? a->params : "", z_move(a->cb), &a->opts);
|
|
1085
3508
|
}
|
|
1086
3509
|
pthread_mutex_unlock(&a->z->op_lock);
|
|
3510
|
+
z_drop(z_move(a->cb));
|
|
1087
3511
|
return NULL;
|
|
1088
3512
|
}
|
|
1089
3513
|
|
|
1090
|
-
|
|
1091
|
-
static VALUE zrb_session_put(int argc, VALUE *argv, VALUE self) {
|
|
1092
|
-
VALUE key_v, payload, opts = Qnil;
|
|
1093
|
-
rb_scan_args(argc, argv, "2:", &key_v, &payload, &opts);
|
|
1094
|
-
VALUE kw[1] = {Qundef};
|
|
1095
|
-
if (!NIL_P(opts)) {
|
|
1096
|
-
rb_get_kwargs(opts, &id_attachment, 0, 1, kw);
|
|
1097
|
-
}
|
|
1098
|
-
const char *key = StringValueCStr(key_v);
|
|
1099
|
-
StringValue(payload);
|
|
1100
|
-
VALUE att = zrb_kw_attachment(kw[0]);
|
|
1101
|
-
zrb_session *z = zrb_session_get_open(self);
|
|
3514
|
+
static const char *const zrb_qget_kw[] = {"attachment", "encoding", "depth"};
|
|
1102
3515
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
3516
|
+
/* querier.get(params = nil, payload = nil, attachment: nil, encoding: nil,
|
|
3517
|
+
* depth: 1024) -> Get */
|
|
3518
|
+
static VALUE zrb_querier_get_m(int argc, VALUE *argv, VALUE self) {
|
|
3519
|
+
VALUE params_v = Qnil, payload = Qnil, opts = Qnil;
|
|
3520
|
+
rb_scan_args(argc, argv, "02:", ¶ms_v, &payload, &opts);
|
|
3521
|
+
zrb_opts o;
|
|
3522
|
+
zrb_opts_parse(opts, zrb_qget_kw, 3, &o);
|
|
3523
|
+
long depth = zrb_check_depth_or(o.depth, ZRB_DEFAULT_GET_DEPTH);
|
|
3524
|
+
const char *params = NIL_P(params_v) ? NULL : StringValueCStr(params_v);
|
|
3525
|
+
if (!NIL_P(payload) && !RB_TYPE_P(payload, T_STRING)) {
|
|
3526
|
+
rb_raise(rb_eTypeError, "payload must be a String");
|
|
1111
3527
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
3528
|
+
zrb_querier *q = zrb_querier_get_open(self);
|
|
3529
|
+
zrb_qget_args a;
|
|
3530
|
+
memset(&a, 0, sizeof(a));
|
|
3531
|
+
a.z = q->ent.owner;
|
|
3532
|
+
a.q = q;
|
|
3533
|
+
z_internal_bytes_null(&a.payload);
|
|
3534
|
+
z_internal_bytes_null(&a.att);
|
|
3535
|
+
z_internal_encoding_null(&a.enc);
|
|
3536
|
+
zrb_get *g;
|
|
3537
|
+
VALUE obj = zrb_get_new(depth, &g);
|
|
3538
|
+
z_querier_get_options_default(&a.opts);
|
|
3539
|
+
if (!NIL_P(payload)) {
|
|
3540
|
+
zrb_bytes_from_str(&a.payload, payload, "payload");
|
|
3541
|
+
a.opts.payload = z_move(a.payload);
|
|
1121
3542
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
rb_raise(eZenohError, "put failed: the connection is lost (%d)", (int)a.ret);
|
|
3543
|
+
if (!NIL_P(o.attachment)) {
|
|
3544
|
+
zrb_bytes_from_str(&a.att, o.attachment, "attachment");
|
|
3545
|
+
a.opts.attachment = z_move(a.att);
|
|
1126
3546
|
}
|
|
1127
|
-
if (a.
|
|
1128
|
-
|
|
3547
|
+
if (zrb_encoding_make(&a.enc, o.encoding)) {
|
|
3548
|
+
a.opts.encoding = z_move(a.enc);
|
|
1129
3549
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
static VALUE zrb_sub_new(VALUE self, zrb_session *z, VALUE key_v, long depth, bool liveliness) {
|
|
1134
|
-
const char *key = StringValueCStr(key_v);
|
|
1135
|
-
z_view_keyexpr_t ke;
|
|
1136
|
-
zrb_view_key(&ke, key);
|
|
1137
|
-
|
|
1138
|
-
zrb_sub *s;
|
|
1139
|
-
VALUE obj = TypedData_Make_Struct(liveliness ? cWatch : cSubscriber, zrb_sub, &zrb_sub_type, s);
|
|
1140
|
-
s->liveliness = liveliness;
|
|
1141
|
-
s->ch = zch_new(ZCH_SAMPLE, (uint32_t)depth);
|
|
1142
|
-
|
|
1143
|
-
z_owned_closure_sample_t cb;
|
|
1144
|
-
zch_closure_sample(s->ch, &cb);
|
|
1145
|
-
z_result_t ret;
|
|
1146
|
-
if (liveliness) {
|
|
1147
|
-
/* history: the tokens alive now are reported first, as appearing. */
|
|
1148
|
-
z_liveliness_subscriber_options_t lo;
|
|
1149
|
-
z_liveliness_subscriber_options_default(&lo);
|
|
1150
|
-
lo.history = true;
|
|
1151
|
-
ret = z_liveliness_declare_subscriber(z_loan(z->session), &s->sub, z_loan(ke), z_move(cb), &lo);
|
|
1152
|
-
} else {
|
|
1153
|
-
/* Remote samples only: zenoh-pico (the mruby gem) does not deliver a
|
|
1154
|
-
* session's own puts to its own subscribers either. */
|
|
1155
|
-
z_subscriber_options_t so;
|
|
1156
|
-
z_subscriber_options_default(&so);
|
|
1157
|
-
so.allowed_origin = Z_LOCALITY_REMOTE;
|
|
1158
|
-
ret = z_declare_subscriber(z_loan(z->session), &s->sub, z_loan(ke), z_move(cb), &so);
|
|
3550
|
+
if (params != NULL) {
|
|
3551
|
+
a.params = strdup(params);
|
|
1159
3552
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
3553
|
+
zch_closure_reply(g->ch, &a.cb);
|
|
3554
|
+
rb_thread_call_without_gvl(zrb_qget_nogvl, &a, RUBY_UBF_IO, NULL);
|
|
3555
|
+
free(a.params);
|
|
3556
|
+
z_drop(z_move(a.payload));
|
|
3557
|
+
z_drop(z_move(a.att));
|
|
3558
|
+
z_drop(z_move(a.enc));
|
|
3559
|
+
if (zrb_session_check_link(a.z)) {
|
|
3560
|
+
zrb_raise_code(eClosedError, (int)a.ret, "get failed: the connection is lost (%d)", (int)a.ret);
|
|
1162
3561
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
3562
|
+
if (a.undeclared) {
|
|
3563
|
+
rb_raise(eZenohError, "get failed: the querier is closed");
|
|
3564
|
+
}
|
|
3565
|
+
if (a.ret != Z_OK) {
|
|
3566
|
+
zrb_raise_code(eZenohError, (int)a.ret, "get failed (%d)", (int)a.ret);
|
|
3567
|
+
}
|
|
3568
|
+
rb_ivar_set(obj, id_iv_session, rb_ivar_get(self, id_iv_session));
|
|
1168
3569
|
return obj;
|
|
1169
3570
|
}
|
|
1170
3571
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
return
|
|
3572
|
+
static VALUE zrb_querier_matching_p(VALUE self) {
|
|
3573
|
+
zrb_querier *q = zrb_querier_get_open(self);
|
|
3574
|
+
z_matching_status_t st = {false};
|
|
3575
|
+
z_result_t r = z_querier_get_matching_status(z_loan(q->q), &st);
|
|
3576
|
+
if (r != Z_OK) {
|
|
3577
|
+
zrb_raise_code(eZenohError, (int)r, "cannot get the matching status (%d)%" PRIsVALUE, (int)r, zrb_last_error());
|
|
3578
|
+
}
|
|
3579
|
+
return st.matching ? Qtrue : Qfalse;
|
|
1179
3580
|
}
|
|
1180
3581
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
rb_scan_args(argc, argv, "11", &key_v, &depth_v);
|
|
1185
|
-
long depth = zrb_check_depth(depth_v);
|
|
1186
|
-
StringValueCStr(key_v);
|
|
1187
|
-
zrb_session *z = zrb_session_get_open(self);
|
|
1188
|
-
return zrb_sub_new(self, z, key_v, depth, true);
|
|
3582
|
+
static VALUE zrb_querier_close(VALUE self) {
|
|
3583
|
+
zrb_ent_detach(&zrb_querier_get(self)->ent);
|
|
3584
|
+
return Qnil;
|
|
1189
3585
|
}
|
|
1190
3586
|
|
|
1191
|
-
|
|
1192
|
-
static VALUE zrb_session_queryable(int argc, VALUE *argv, VALUE self) {
|
|
1193
|
-
VALUE key_v, depth_v = Qnil, opts = Qnil;
|
|
1194
|
-
rb_scan_args(argc, argv, "11:", &key_v, &depth_v, &opts);
|
|
1195
|
-
VALUE kw[1] = {Qundef};
|
|
1196
|
-
if (!NIL_P(opts)) {
|
|
1197
|
-
rb_get_kwargs(opts, &id_complete, 0, 1, kw);
|
|
1198
|
-
}
|
|
1199
|
-
bool complete = (kw[0] != Qundef) && RTEST(kw[0]);
|
|
1200
|
-
long depth = zrb_check_depth(depth_v);
|
|
1201
|
-
const char *key = StringValueCStr(key_v);
|
|
1202
|
-
zrb_session *z = zrb_session_get_open(self);
|
|
1203
|
-
z_view_keyexpr_t ke;
|
|
1204
|
-
zrb_view_key(&ke, key);
|
|
3587
|
+
static VALUE zrb_querier_closed_p(VALUE self) { return zrb_querier_get(self)->ent.declared ? Qfalse : Qtrue; }
|
|
1205
3588
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
3589
|
+
/* ------------------------------------------------------------ listeners */
|
|
3590
|
+
|
|
3591
|
+
typedef enum { ZLST_MATCHING, ZLST_TRANSPORT, ZLST_LINK, ZLST_MISS } zlst_type;
|
|
3592
|
+
|
|
3593
|
+
typedef struct {
|
|
3594
|
+
zrb_ent ent;
|
|
3595
|
+
zlst_type type;
|
|
3596
|
+
union {
|
|
3597
|
+
z_owned_matching_listener_t m;
|
|
3598
|
+
z_owned_transport_events_listener_t t;
|
|
3599
|
+
z_owned_link_events_listener_t l;
|
|
3600
|
+
ze_owned_sample_miss_listener_t s;
|
|
3601
|
+
} u;
|
|
3602
|
+
zevq *q;
|
|
3603
|
+
} zrb_lst;
|
|
3604
|
+
|
|
3605
|
+
static void zrb_lst_undeclare(zrb_ent *e) {
|
|
3606
|
+
zrb_lst *l = (zrb_lst *)e;
|
|
3607
|
+
switch (l->type) {
|
|
3608
|
+
case ZLST_MATCHING:
|
|
3609
|
+
z_drop(z_move(l->u.m));
|
|
3610
|
+
break;
|
|
3611
|
+
case ZLST_TRANSPORT:
|
|
3612
|
+
z_drop(z_move(l->u.t));
|
|
3613
|
+
break;
|
|
3614
|
+
case ZLST_LINK:
|
|
3615
|
+
z_drop(z_move(l->u.l));
|
|
3616
|
+
break;
|
|
3617
|
+
case ZLST_MISS:
|
|
3618
|
+
z_drop(z_move(l->u.s));
|
|
3619
|
+
break;
|
|
1220
3620
|
}
|
|
1221
|
-
q->declared = true;
|
|
1222
|
-
q->owner = z;
|
|
1223
|
-
q->next = z->qables;
|
|
1224
|
-
z->qables = q;
|
|
1225
|
-
zrb_hold_session(obj, self, key_v);
|
|
1226
|
-
return obj;
|
|
1227
3621
|
}
|
|
1228
3622
|
|
|
1229
|
-
static
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
if (t == id_all) {
|
|
1235
|
-
return Z_QUERY_TARGET_ALL;
|
|
1236
|
-
}
|
|
1237
|
-
if (t == id_all_complete) {
|
|
1238
|
-
return Z_QUERY_TARGET_ALL_COMPLETE;
|
|
1239
|
-
}
|
|
1240
|
-
if (t == id_best_matching) {
|
|
1241
|
-
return Z_QUERY_TARGET_BEST_MATCHING;
|
|
1242
|
-
}
|
|
1243
|
-
rb_raise(rb_eArgError, "target must be :all, :all_complete or :best_matching");
|
|
1244
|
-
return Z_QUERY_TARGET_ALL; /* not reached */
|
|
3623
|
+
static void zrb_lst_free(void *p) {
|
|
3624
|
+
zrb_lst *l = (zrb_lst *)p;
|
|
3625
|
+
zrb_ent_detach(&l->ent);
|
|
3626
|
+
zevq_unref(l->q);
|
|
3627
|
+
xfree(l);
|
|
1245
3628
|
}
|
|
1246
3629
|
|
|
1247
|
-
static
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
3630
|
+
static size_t zrb_lst_size(const void *p) { return sizeof(zrb_lst); }
|
|
3631
|
+
|
|
3632
|
+
static const rb_data_type_t zrb_lst_type = {"Asterism::Zenoh::Listener", {NULL, zrb_lst_free, zrb_lst_size}, NULL, NULL, 0};
|
|
3633
|
+
|
|
3634
|
+
static zrb_lst *zrb_lst_get(VALUE self) {
|
|
3635
|
+
zrb_lst *l;
|
|
3636
|
+
TypedData_Get_Struct(self, zrb_lst, &zrb_lst_type, l);
|
|
3637
|
+
return l;
|
|
3638
|
+
}
|
|
3639
|
+
|
|
3640
|
+
static VALUE zrb_lst_new(VALUE klass, zlst_type type, zev_kind kind, VALUE depth_v, zrb_lst **out) {
|
|
3641
|
+
long depth = zrb_check_depth(depth_v);
|
|
3642
|
+
zrb_lst *l;
|
|
3643
|
+
VALUE obj = TypedData_Make_Struct(klass, zrb_lst, &zrb_lst_type, l);
|
|
3644
|
+
l->type = type;
|
|
3645
|
+
l->q = zevq_new(kind, (uint32_t)depth);
|
|
3646
|
+
*out = l;
|
|
3647
|
+
return obj;
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3650
|
+
static void zrb_lst_linked(VALUE obj, zrb_lst *l, zrb_session *z, VALUE parent) {
|
|
3651
|
+
zrb_ent_link(&l->ent, z, ZENT_LISTENER, false, zrb_lst_undeclare);
|
|
3652
|
+
rb_ivar_set(obj, id_iv_parent, parent);
|
|
3653
|
+
}
|
|
3654
|
+
|
|
3655
|
+
/* listener.each_pending { |value| } -> Integer; without a block, an Array.
|
|
3656
|
+
* A MatchingListener gives true / false (a subscriber matches or not any
|
|
3657
|
+
* more); an EventListener gives TransportEvent, LinkEvent or Miss values. */
|
|
3658
|
+
static VALUE zrb_lst_each_pending(VALUE self) { return zevq_each_pending(zrb_lst_get(self)->q, true); }
|
|
3659
|
+
static VALUE zrb_lst_pending(VALUE self) { return UINT2NUM(atomic_load(&zrb_lst_get(self)->q->queued)); }
|
|
3660
|
+
static VALUE zrb_lst_received(VALUE self) { return UINT2NUM(atomic_load(&zrb_lst_get(self)->q->received)); }
|
|
3661
|
+
static VALUE zrb_lst_dropped(VALUE self) { return UINT2NUM(atomic_load(&zrb_lst_get(self)->q->dropped)); }
|
|
3662
|
+
|
|
3663
|
+
static VALUE zrb_lst_close(VALUE self) {
|
|
3664
|
+
zrb_ent_detach(&zrb_lst_get(self)->ent);
|
|
3665
|
+
return Qnil;
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3668
|
+
static VALUE zrb_lst_closed_p(VALUE self) { return zrb_lst_get(self)->ent.declared ? Qfalse : Qtrue; }
|
|
3669
|
+
|
|
3670
|
+
/* pub.matching_listener(depth = 16) -> MatchingListener: each change of
|
|
3671
|
+
* the matching status (true when the first subscriber appears, false when
|
|
3672
|
+
* the last goes). Also for queriers (queryables) and advanced publishers. */
|
|
3673
|
+
static VALUE zrb_pub_matching_listener(int argc, VALUE *argv, VALUE self) {
|
|
3674
|
+
VALUE depth_v = Qnil;
|
|
3675
|
+
rb_scan_args(argc, argv, "01", &depth_v);
|
|
3676
|
+
zrb_pub *p = zrb_pub_get_open(self);
|
|
3677
|
+
zrb_lst *l;
|
|
3678
|
+
VALUE obj = zrb_lst_new(cMatchingListener, ZLST_MATCHING, ZEV_MATCHING, depth_v, &l);
|
|
3679
|
+
z_owned_closure_matching_status_t cb;
|
|
3680
|
+
z_closure_matching_status(&cb, zev_on_matching, zevq_on_drop, zevq_ref(l->q));
|
|
3681
|
+
z_result_t r = p->advanced
|
|
3682
|
+
? ze_advanced_publisher_declare_matching_listener(z_loan(p->u.a), &l->u.m, z_move(cb))
|
|
3683
|
+
: z_publisher_declare_matching_listener(z_loan(p->u.p), &l->u.m, z_move(cb));
|
|
3684
|
+
if (r != Z_OK) {
|
|
3685
|
+
zrb_raise_code(eZenohError, (int)r, "cannot declare a matching listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
|
|
1263
3686
|
}
|
|
1264
|
-
|
|
1265
|
-
return
|
|
3687
|
+
zrb_lst_linked(obj, l, p->ent.owner, self);
|
|
3688
|
+
return obj;
|
|
1266
3689
|
}
|
|
1267
3690
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
z_result_t
|
|
1277
|
-
|
|
3691
|
+
static VALUE zrb_querier_matching_listener(int argc, VALUE *argv, VALUE self) {
|
|
3692
|
+
VALUE depth_v = Qnil;
|
|
3693
|
+
rb_scan_args(argc, argv, "01", &depth_v);
|
|
3694
|
+
zrb_querier *q = zrb_querier_get_open(self);
|
|
3695
|
+
zrb_lst *l;
|
|
3696
|
+
VALUE obj = zrb_lst_new(cMatchingListener, ZLST_MATCHING, ZEV_MATCHING, depth_v, &l);
|
|
3697
|
+
z_owned_closure_matching_status_t cb;
|
|
3698
|
+
z_closure_matching_status(&cb, zev_on_matching, zevq_on_drop, zevq_ref(l->q));
|
|
3699
|
+
z_result_t r = z_querier_declare_matching_listener(z_loan(q->q), &l->u.m, z_move(cb));
|
|
3700
|
+
if (r != Z_OK) {
|
|
3701
|
+
zrb_raise_code(eZenohError, (int)r, "cannot declare a matching listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
|
|
3702
|
+
}
|
|
3703
|
+
zrb_lst_linked(obj, l, q->ent.owner, self);
|
|
3704
|
+
return obj;
|
|
3705
|
+
}
|
|
1278
3706
|
|
|
1279
|
-
static
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
if (a->liveliness) {
|
|
1284
|
-
a->ret = z_liveliness_get(z_loan(a->z->session), z_loan(a->key), z_move(a->cb), &a->lopts);
|
|
1285
|
-
} else {
|
|
1286
|
-
a->ret = z_get(z_loan(a->z->session), z_loan(a->key), a->params != NULL ? a->params : "", z_move(a->cb),
|
|
1287
|
-
&a->opts);
|
|
1288
|
-
}
|
|
1289
|
-
} else {
|
|
1290
|
-
a->ret = Z_ESESSION_CLOSED;
|
|
3707
|
+
static bool zrb_history_kw(VALUE opts) {
|
|
3708
|
+
VALUE kw[1] = {Qundef};
|
|
3709
|
+
if (!NIL_P(opts)) {
|
|
3710
|
+
rb_get_kwargs(opts, &id_history, 0, 1, kw);
|
|
1291
3711
|
}
|
|
1292
|
-
|
|
1293
|
-
/* A closure that was not taken (the session was closed) is dropped
|
|
1294
|
-
* here, which releases the channel's reference. */
|
|
1295
|
-
z_drop(z_move(a->cb));
|
|
1296
|
-
return NULL;
|
|
3712
|
+
return kw[0] != Qundef && RTEST(kw[0]);
|
|
1297
3713
|
}
|
|
1298
3714
|
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
3715
|
+
/* session.transport_events(depth = 16, history: false) -> EventListener:
|
|
3716
|
+
* a TransportEvent (kind :added / :removed, zid, whatami, qos, multicast)
|
|
3717
|
+
* each time a peer or router connects or goes. history: true reports the
|
|
3718
|
+
* ones connected now first. */
|
|
3719
|
+
static VALUE zrb_session_transport_events(int argc, VALUE *argv, VALUE self) {
|
|
3720
|
+
VALUE depth_v = Qnil, opts = Qnil;
|
|
3721
|
+
rb_scan_args(argc, argv, "01:", &depth_v, &opts);
|
|
3722
|
+
bool history = zrb_history_kw(opts);
|
|
3723
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
3724
|
+
zrb_lst *l;
|
|
3725
|
+
VALUE obj = zrb_lst_new(cEventListener, ZLST_TRANSPORT, ZEV_TRANSPORT, depth_v, &l);
|
|
3726
|
+
z_owned_closure_transport_event_t cb;
|
|
3727
|
+
z_closure_transport_event(&cb, zev_on_transport_event, zevq_on_drop, zevq_ref(l->q));
|
|
3728
|
+
z_transport_events_listener_options_t to;
|
|
3729
|
+
z_transport_events_listener_options_default(&to);
|
|
3730
|
+
to.history = history;
|
|
3731
|
+
z_result_t r = z_declare_transport_events_listener(z_loan(z->session), &l->u.t, z_move(cb), &to);
|
|
3732
|
+
if (r != Z_OK) {
|
|
3733
|
+
zrb_raise_code(eZenohError, (int)r, "cannot declare a transport events listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
|
|
1305
3734
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
3735
|
+
zrb_lst_linked(obj, l, z, self);
|
|
3736
|
+
return obj;
|
|
3737
|
+
}
|
|
3738
|
+
|
|
3739
|
+
/* session.link_events(depth = 16, history: false) -> EventListener: a
|
|
3740
|
+
* LinkEvent (kind, zid, src, dst, mtu, streamed, reliability, interfaces,
|
|
3741
|
+
* group, auth_identifier) each time a link opens or closes. */
|
|
3742
|
+
static VALUE zrb_session_link_events(int argc, VALUE *argv, VALUE self) {
|
|
3743
|
+
VALUE depth_v = Qnil, opts = Qnil;
|
|
3744
|
+
rb_scan_args(argc, argv, "01:", &depth_v, &opts);
|
|
3745
|
+
bool history = zrb_history_kw(opts);
|
|
3746
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
3747
|
+
zrb_lst *l;
|
|
3748
|
+
VALUE obj = zrb_lst_new(cEventListener, ZLST_LINK, ZEV_LINK, depth_v, &l);
|
|
3749
|
+
z_owned_closure_link_event_t cb;
|
|
3750
|
+
z_closure_link_event(&cb, zev_on_link_event, zevq_on_drop, zevq_ref(l->q));
|
|
3751
|
+
z_link_events_listener_options_t lo;
|
|
3752
|
+
z_link_events_listener_options_default(&lo);
|
|
3753
|
+
lo.history = history;
|
|
3754
|
+
z_result_t r = z_declare_link_events_listener(z_loan(z->session), &l->u.l, z_move(cb), &lo);
|
|
3755
|
+
if (r != Z_OK) {
|
|
3756
|
+
zrb_raise_code(eZenohError, (int)r, "cannot declare a link events listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
|
|
1308
3757
|
}
|
|
1309
|
-
|
|
3758
|
+
zrb_lst_linked(obj, l, z, self);
|
|
1310
3759
|
return obj;
|
|
1311
3760
|
}
|
|
1312
3761
|
|
|
1313
|
-
/*
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
static
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
3762
|
+
/* ---------------------------------------------------- advanced subscriber */
|
|
3763
|
+
|
|
3764
|
+
static const char *const zrb_history_keys[] = {"max_samples", "max_age", "detect_late_publishers"};
|
|
3765
|
+
static const char *const zrb_recovery_keys[] = {"periodic_queries_ms", "heartbeat"};
|
|
3766
|
+
|
|
3767
|
+
/* session.advanced_subscriber(key, depth = 16, history: nil, recovery: nil,
|
|
3768
|
+
* subscriber_detection: false, query_timeout_ms: nil) -> AdvancedSubscriber
|
|
3769
|
+
* history: true or {max_samples:, max_age: (seconds), detect_late_publishers:}
|
|
3770
|
+
* asks the advanced publishers' caches for what they kept (late joiners get
|
|
3771
|
+
* the last values; ROS 2's transient local). recovery: true or
|
|
3772
|
+
* {periodic_queries_ms:} (or {heartbeat: true}) asks again for samples
|
|
3773
|
+
* that were missed. The rest is the same as subscribe. */
|
|
3774
|
+
static VALUE zrb_session_advanced_subscriber(int argc, VALUE *argv, VALUE self) {
|
|
3775
|
+
VALUE key_v, depth_v = Qnil, opts = Qnil;
|
|
3776
|
+
rb_scan_args(argc, argv, "11:", &key_v, &depth_v, &opts);
|
|
3777
|
+
VALUE kw[4] = {Qundef, Qundef, Qundef, Qundef};
|
|
1320
3778
|
if (!NIL_P(opts)) {
|
|
1321
|
-
ID ids[
|
|
1322
|
-
|
|
3779
|
+
ID ids[4] = {id_history, rb_intern("recovery"), rb_intern("subscriber_detection"),
|
|
3780
|
+
rb_intern("query_timeout_ms")};
|
|
3781
|
+
rb_get_kwargs(opts, ids, 0, 4, kw);
|
|
1323
3782
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
3783
|
+
long depth = zrb_check_depth(depth_v);
|
|
3784
|
+
ze_advanced_subscriber_options_t ao;
|
|
3785
|
+
ze_advanced_subscriber_options_default(&ao);
|
|
3786
|
+
ao.subscriber_options.allowed_origin = Z_LOCALITY_REMOTE;
|
|
3787
|
+
VALUE hist = kw[0] == Qundef ? Qnil : kw[0];
|
|
3788
|
+
VALUE rec = kw[1] == Qundef ? Qnil : kw[1];
|
|
3789
|
+
if (RTEST(hist)) {
|
|
3790
|
+
VALUE h = zrb_subopt_hash(hist, "history", zrb_history_keys, 3);
|
|
3791
|
+
if (NIL_P(h) && hist != Qtrue) {
|
|
3792
|
+
rb_raise(rb_eTypeError, "history must be true or a Hash");
|
|
3793
|
+
}
|
|
3794
|
+
ao.history.is_enabled = true;
|
|
3795
|
+
VALUE v;
|
|
3796
|
+
if (!NIL_P(v = zrb_hget(h, "max_samples"))) {
|
|
3797
|
+
ao.history.max_samples = (size_t)NUM2ULONG(v);
|
|
3798
|
+
}
|
|
3799
|
+
if (!NIL_P(v = zrb_hget(h, "max_age"))) {
|
|
3800
|
+
double s = NUM2DBL(v);
|
|
3801
|
+
if (s < 0) {
|
|
3802
|
+
rb_raise(rb_eArgError, "max_age must be 0 or more");
|
|
3803
|
+
}
|
|
3804
|
+
ao.history.max_age_ms = (uint64_t)(s * 1000.0);
|
|
3805
|
+
}
|
|
3806
|
+
if (!NIL_P(v = zrb_hget(h, "detect_late_publishers"))) {
|
|
3807
|
+
ao.history.detect_late_publishers = RTEST(v);
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
if (RTEST(rec)) {
|
|
3811
|
+
VALUE h = zrb_subopt_hash(rec, "recovery", zrb_recovery_keys, 2);
|
|
3812
|
+
if (NIL_P(h) && rec != Qtrue) {
|
|
3813
|
+
rb_raise(rb_eTypeError, "recovery must be true or a Hash");
|
|
3814
|
+
}
|
|
3815
|
+
ao.recovery.is_enabled = true;
|
|
3816
|
+
VALUE v;
|
|
3817
|
+
if (!NIL_P(v = zrb_hget(h, "periodic_queries_ms"))) {
|
|
3818
|
+
ao.recovery.last_sample_miss_detection.is_enabled = true;
|
|
3819
|
+
ao.recovery.last_sample_miss_detection.periodic_queries_period_ms = zrb_ms_arg(v, "periodic_queries_ms");
|
|
3820
|
+
} else if (RTEST(zrb_hget(h, "heartbeat"))) {
|
|
3821
|
+
ao.recovery.last_sample_miss_detection.is_enabled = true;
|
|
3822
|
+
ao.recovery.last_sample_miss_detection.periodic_queries_period_ms = 0;
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
if (kw[2] != Qundef) {
|
|
3826
|
+
ao.subscriber_detection = RTEST(kw[2]);
|
|
1329
3827
|
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
3828
|
+
if (kw[3] != Qundef && !NIL_P(kw[3])) {
|
|
3829
|
+
ao.query_timeout_ms = zrb_ms_arg(kw[3], "query_timeout_ms");
|
|
3830
|
+
}
|
|
3831
|
+
VALUE key_str = zrb_key_string(key_v);
|
|
1333
3832
|
zrb_session *z = zrb_session_get_open(self);
|
|
3833
|
+
z_view_keyexpr_t view;
|
|
3834
|
+
const z_loaned_keyexpr_t *ke = zrb_key_loan(key_v, &view);
|
|
1334
3835
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
a.opts.consolidation = consolidation;
|
|
1345
|
-
/* Remote queryables only, as with zenoh-pico. */
|
|
1346
|
-
a.opts.allowed_destination = Z_LOCALITY_REMOTE;
|
|
1347
|
-
z_owned_bytes_t bytes;
|
|
1348
|
-
z_owned_bytes_t att_bytes;
|
|
1349
|
-
if (!NIL_P(payload)) {
|
|
1350
|
-
zrb_bytes_from_str(&bytes, payload, "payload");
|
|
1351
|
-
a.opts.payload = z_move(bytes);
|
|
3836
|
+
zrb_sub *s;
|
|
3837
|
+
VALUE obj = TypedData_Make_Struct(cAdvSubscriber, zrb_sub, &zrb_sub_type, s);
|
|
3838
|
+
s->type = ZSUB_ADVANCED;
|
|
3839
|
+
s->ch = zch_new(ZCH_SAMPLE, (uint32_t)depth);
|
|
3840
|
+
z_owned_closure_sample_t cb;
|
|
3841
|
+
zch_closure_sample(s->ch, &cb);
|
|
3842
|
+
z_result_t ret = ze_declare_advanced_subscriber(z_loan(z->session), &s->u.adv, ke, z_move(cb), &ao);
|
|
3843
|
+
if (ret != Z_OK) {
|
|
3844
|
+
zrb_raise_code(eZenohError, (int)ret, "cannot declare an advanced subscriber on %" PRIsVALUE " (%d)%" PRIsVALUE, key_str, (int)ret, zrb_last_error());
|
|
1352
3845
|
}
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
3846
|
+
s->declared = true;
|
|
3847
|
+
s->owner = z;
|
|
3848
|
+
s->next = z->subs;
|
|
3849
|
+
z->subs = s;
|
|
3850
|
+
zrb_hold_session(obj, self, key_str);
|
|
3851
|
+
return obj;
|
|
3852
|
+
}
|
|
3853
|
+
|
|
3854
|
+
static zrb_sub *zrb_advsub_get_open(VALUE self) {
|
|
3855
|
+
zrb_sub *s = zrb_sub_get(self);
|
|
3856
|
+
if (s->type != ZSUB_ADVANCED || !s->declared) {
|
|
3857
|
+
rb_raise(eZenohError, "the subscriber is closed");
|
|
1356
3858
|
}
|
|
1357
|
-
if (
|
|
1358
|
-
|
|
3859
|
+
if (zrb_session_check_link(s->owner)) {
|
|
3860
|
+
rb_raise(eClosedError, "session is closed");
|
|
1359
3861
|
}
|
|
1360
|
-
|
|
1361
|
-
return zrb_run_get(self, z, &a, obj, key_v, "get");
|
|
3862
|
+
return s;
|
|
1362
3863
|
}
|
|
1363
3864
|
|
|
1364
|
-
/*
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
3865
|
+
/* advsub.miss_listener(depth = 16) -> EventListener of Miss (source_zid,
|
|
3866
|
+
* source_eid, count): samples a publisher sent that never came (needs
|
|
3867
|
+
* sample_miss_detection on the advanced publisher). */
|
|
3868
|
+
static VALUE zrb_advsub_miss_listener(int argc, VALUE *argv, VALUE self) {
|
|
3869
|
+
VALUE depth_v = Qnil;
|
|
3870
|
+
rb_scan_args(argc, argv, "01", &depth_v);
|
|
3871
|
+
zrb_sub *s = zrb_advsub_get_open(self);
|
|
3872
|
+
zrb_lst *l;
|
|
3873
|
+
VALUE obj = zrb_lst_new(cEventListener, ZLST_MISS, ZEV_MISS, depth_v, &l);
|
|
3874
|
+
ze_owned_closure_miss_t cb;
|
|
3875
|
+
ze_closure_miss(&cb, zev_on_miss, zevq_on_drop, zevq_ref(l->q));
|
|
3876
|
+
z_result_t r = ze_advanced_subscriber_declare_sample_miss_listener(z_loan(s->u.adv), &l->u.s, z_move(cb));
|
|
3877
|
+
if (r != Z_OK) {
|
|
3878
|
+
zrb_raise_code(eZenohError, (int)r, "cannot declare a sample miss listener (%d)%" PRIsVALUE, (int)r, zrb_last_error());
|
|
3879
|
+
}
|
|
3880
|
+
zrb_lst_linked(obj, l, s->owner, self);
|
|
3881
|
+
return obj;
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3884
|
+
/* advsub.detect_publishers(depth = 16, history: true) -> LivelinessWatch:
|
|
3885
|
+
* each_pending { |key, alive| } for the advanced publishers on the key
|
|
3886
|
+
* (those declared with publisher_detection: true). */
|
|
3887
|
+
static VALUE zrb_advsub_detect_publishers(int argc, VALUE *argv, VALUE self) {
|
|
3888
|
+
VALUE depth_v = Qnil, opts = Qnil;
|
|
3889
|
+
rb_scan_args(argc, argv, "01:", &depth_v, &opts);
|
|
3890
|
+
VALUE kw[1] = {Qundef};
|
|
3891
|
+
if (!NIL_P(opts)) {
|
|
3892
|
+
rb_get_kwargs(opts, &id_history, 0, 1, kw);
|
|
3893
|
+
}
|
|
3894
|
+
bool history = (kw[0] == Qundef) ? true : RTEST(kw[0]);
|
|
3895
|
+
long depth = zrb_check_depth(depth_v);
|
|
3896
|
+
zrb_sub *as = zrb_advsub_get_open(self);
|
|
3897
|
+
zrb_sub *s;
|
|
3898
|
+
VALUE obj = TypedData_Make_Struct(cWatch, zrb_sub, &zrb_sub_type, s);
|
|
3899
|
+
s->liveliness = true;
|
|
3900
|
+
s->type = ZSUB_LIVELINESS;
|
|
3901
|
+
s->ch = zch_new(ZCH_SAMPLE, (uint32_t)depth);
|
|
3902
|
+
z_owned_closure_sample_t cb;
|
|
3903
|
+
zch_closure_sample(s->ch, &cb);
|
|
3904
|
+
z_liveliness_subscriber_options_t lo;
|
|
3905
|
+
z_liveliness_subscriber_options_default(&lo);
|
|
3906
|
+
lo.history = history;
|
|
3907
|
+
z_result_t ret = ze_advanced_subscriber_detect_publishers(z_loan(as->u.adv), &s->u.sub, z_move(cb), &lo);
|
|
1373
3908
|
if (ret != Z_OK) {
|
|
1374
|
-
|
|
3909
|
+
zrb_raise_code(eZenohError, (int)ret, "cannot detect publishers (%d)%" PRIsVALUE, (int)ret, zrb_last_error());
|
|
1375
3910
|
}
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
3911
|
+
s->declared = true;
|
|
3912
|
+
s->owner = as->owner;
|
|
3913
|
+
s->next = as->owner->subs;
|
|
3914
|
+
as->owner->subs = s;
|
|
3915
|
+
rb_ivar_set(obj, id_iv_session, rb_ivar_get(self, id_iv_session));
|
|
3916
|
+
rb_ivar_set(obj, id_iv_parent, self);
|
|
1381
3917
|
return obj;
|
|
1382
3918
|
}
|
|
1383
3919
|
|
|
1384
|
-
/* session
|
|
1385
|
-
static VALUE zrb_session_liveliness_get(int argc, VALUE *argv, VALUE self) {
|
|
1386
|
-
VALUE key_v, timeout_v = Qnil;
|
|
1387
|
-
rb_scan_args(argc, argv, "11", &key_v, &timeout_v);
|
|
1388
|
-
const char *key = StringValueCStr(key_v);
|
|
1389
|
-
long timeout_ms = zrb_check_timeout(timeout_v);
|
|
1390
|
-
zrb_session *z = zrb_session_get_open(self);
|
|
3920
|
+
/* ------------------------------------------------- session information */
|
|
1391
3921
|
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
return zrb_run_get(self, z, &a, obj, key_v, "liveliness_get");
|
|
3922
|
+
/* Everything queued, as an Array (a snapshot's queue). */
|
|
3923
|
+
static VALUE zevq_each_pending_noblock(zevq *q, bool event) {
|
|
3924
|
+
VALUE out = rb_ary_new();
|
|
3925
|
+
zev *e;
|
|
3926
|
+
while ((e = zevq_take(q)) != NULL) {
|
|
3927
|
+
VALUE v = zev_to_ruby(q->kind, e, event);
|
|
3928
|
+
zev_free(e);
|
|
3929
|
+
rb_ary_push(out, v);
|
|
3930
|
+
}
|
|
3931
|
+
return out;
|
|
1403
3932
|
}
|
|
1404
3933
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
*
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
3934
|
+
typedef struct {
|
|
3935
|
+
pthread_mutex_t lock;
|
|
3936
|
+
z_id_t *ids;
|
|
3937
|
+
size_t n, cap;
|
|
3938
|
+
} zrb_zids;
|
|
3939
|
+
|
|
3940
|
+
static void zrb_collect_zid(const z_id_t *id, void *ctx) {
|
|
3941
|
+
zrb_zids *c = (zrb_zids *)ctx;
|
|
3942
|
+
pthread_mutex_lock(&c->lock);
|
|
3943
|
+
if (c->n == c->cap) {
|
|
3944
|
+
size_t cap = c->cap ? c->cap * 2 : 8;
|
|
3945
|
+
z_id_t *ids = (z_id_t *)realloc(c->ids, cap * sizeof(z_id_t));
|
|
3946
|
+
if (ids == NULL) {
|
|
3947
|
+
pthread_mutex_unlock(&c->lock);
|
|
3948
|
+
return;
|
|
3949
|
+
}
|
|
3950
|
+
c->ids = ids;
|
|
3951
|
+
c->cap = cap;
|
|
1414
3952
|
}
|
|
1415
|
-
|
|
3953
|
+
c->ids[c->n++] = *id;
|
|
3954
|
+
pthread_mutex_unlock(&c->lock);
|
|
1416
3955
|
}
|
|
1417
3956
|
|
|
1418
|
-
static VALUE
|
|
1419
|
-
|
|
3957
|
+
static VALUE zrb_session_zids(VALUE self, bool routers) {
|
|
3958
|
+
zrb_session *z = zrb_session_get(self);
|
|
3959
|
+
if (zrb_session_check_link(z)) {
|
|
3960
|
+
return rb_ary_new();
|
|
3961
|
+
}
|
|
3962
|
+
zrb_zids c;
|
|
3963
|
+
memset(&c, 0, sizeof(c));
|
|
3964
|
+
pthread_mutex_init(&c.lock, NULL);
|
|
3965
|
+
z_owned_closure_zid_t cb;
|
|
3966
|
+
z_closure_zid(&cb, zrb_collect_zid, NULL, &c);
|
|
3967
|
+
if (routers) {
|
|
3968
|
+
z_info_routers_zid(z_loan(z->session), z_move(cb));
|
|
3969
|
+
} else {
|
|
3970
|
+
z_info_peers_zid(z_loan(z->session), z_move(cb));
|
|
3971
|
+
}
|
|
3972
|
+
VALUE out = rb_ary_new_capa((long)c.n);
|
|
3973
|
+
for (size_t i = 0; i < c.n; i++) {
|
|
3974
|
+
rb_ary_push(out, zrb_zid_value(&c.ids[i]));
|
|
3975
|
+
}
|
|
3976
|
+
free(c.ids);
|
|
3977
|
+
pthread_mutex_destroy(&c.lock);
|
|
3978
|
+
return out;
|
|
1420
3979
|
}
|
|
1421
3980
|
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
3981
|
+
/* session.peer_zids / router_zids -> Array of String: the Zenoh IDs of the
|
|
3982
|
+
* peers / routers connected now (session.peers stays the count). */
|
|
3983
|
+
static VALUE zrb_session_peer_zids(VALUE self) { return zrb_session_zids(self, false); }
|
|
3984
|
+
static VALUE zrb_session_router_zids(VALUE self) { return zrb_session_zids(self, true); }
|
|
3985
|
+
|
|
3986
|
+
/* session.transports -> Array of Transport (zid, whatami, qos, multicast) */
|
|
3987
|
+
static VALUE zrb_session_transports(VALUE self) {
|
|
3988
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
3989
|
+
zevq *q = zevq_new(ZEV_TRANSPORT, ZRB_MAX_DEPTH);
|
|
3990
|
+
z_owned_closure_transport_t cb;
|
|
3991
|
+
z_closure_transport(&cb, zev_on_transport, zevq_on_drop, zevq_ref(q));
|
|
3992
|
+
z_info_transports(z_loan(z->session), z_move(cb));
|
|
3993
|
+
VALUE out = zevq_each_pending_noblock(q, false);
|
|
3994
|
+
zevq_unref(q);
|
|
3995
|
+
return out;
|
|
1425
3996
|
}
|
|
1426
3997
|
|
|
1427
|
-
/* session.
|
|
1428
|
-
static VALUE
|
|
3998
|
+
/* session.links -> Array of Link (zid, src, dst, mtu, streamed, ...) */
|
|
3999
|
+
static VALUE zrb_session_links_m(VALUE self) {
|
|
1429
4000
|
zrb_session *z = zrb_session_get_open(self);
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
4001
|
+
zevq *q = zevq_new(ZEV_LINK, ZRB_MAX_DEPTH);
|
|
4002
|
+
z_owned_closure_link_t cb;
|
|
4003
|
+
z_closure_link(&cb, zev_on_link, zevq_on_drop, zevq_ref(q));
|
|
4004
|
+
z_info_links_options_t lo;
|
|
4005
|
+
z_info_links_options_default(&lo);
|
|
4006
|
+
z_info_links(z_loan(z->session), z_move(cb), &lo);
|
|
4007
|
+
VALUE out = zevq_each_pending_noblock(q, false);
|
|
4008
|
+
zevq_unref(q);
|
|
1435
4009
|
return out;
|
|
1436
4010
|
}
|
|
1437
4011
|
|
|
1438
|
-
/* session.
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
if (
|
|
1443
|
-
|
|
4012
|
+
/* session.new_timestamp -> Timestamp (from the session's clock and ID) */
|
|
4013
|
+
static VALUE zrb_session_new_timestamp(VALUE self) {
|
|
4014
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
4015
|
+
z_timestamp_t ts;
|
|
4016
|
+
if (z_timestamp_new(&ts, z_loan(z->session)) != Z_OK) {
|
|
4017
|
+
rb_raise(eZenohError, "cannot make a timestamp");
|
|
1444
4018
|
}
|
|
1445
|
-
return
|
|
4019
|
+
return zrb_ts_wrap(&ts);
|
|
1446
4020
|
}
|
|
1447
4021
|
|
|
1448
|
-
/*
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
4022
|
+
/* session.declare_keyexpr(key) -> KeyExpr, declared on the session: the
|
|
4023
|
+
* key goes over the wire as a short number afterwards. Pass it to put,
|
|
4024
|
+
* delete, publisher, querier and the advanced ones of the same session.
|
|
4025
|
+
* Undeclared by KeyExpr#undeclare or when the session closes. */
|
|
4026
|
+
static VALUE zrb_session_declare_keyexpr(VALUE self, VALUE key_v) {
|
|
4027
|
+
zrb_key_string(key_v);
|
|
4028
|
+
zrb_session *z = zrb_session_get_open(self);
|
|
4029
|
+
z_view_keyexpr_t view;
|
|
4030
|
+
const z_loaned_keyexpr_t *ke = zrb_key_loan(key_v, &view);
|
|
4031
|
+
zrb_ke *k;
|
|
4032
|
+
VALUE obj = TypedData_Make_Struct(cKeyExpr, zrb_ke, &zrb_ke_type, k);
|
|
4033
|
+
z_keyexpr_clone(&k->ke, ke);
|
|
4034
|
+
z_internal_keyexpr_null(&k->decl);
|
|
4035
|
+
z_result_t r = z_declare_keyexpr(z_loan(z->session), &k->decl, ke);
|
|
4036
|
+
if (r != Z_OK) {
|
|
4037
|
+
zrb_raise_code(eZenohError, (int)r, "cannot declare the key expression (%d)%" PRIsVALUE, (int)r, zrb_last_error());
|
|
1454
4038
|
}
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
4039
|
+
zrb_ent_link(&k->ent, z, ZENT_KEYEXPR, true, zrb_ke_undeclare);
|
|
4040
|
+
rb_ivar_set(obj, id_iv_session, self);
|
|
4041
|
+
return obj;
|
|
4042
|
+
}
|
|
4043
|
+
|
|
4044
|
+
/* ------------------------------------------------------ scouting, logs */
|
|
4045
|
+
|
|
4046
|
+
typedef struct {
|
|
4047
|
+
z_owned_config_t config;
|
|
4048
|
+
z_owned_closure_hello_t cb;
|
|
4049
|
+
z_scout_options_t opts;
|
|
4050
|
+
z_result_t ret;
|
|
4051
|
+
} zrb_scout_args;
|
|
4052
|
+
|
|
4053
|
+
static void *zrb_scout_nogvl(void *p) {
|
|
4054
|
+
zrb_scout_args *a = (zrb_scout_args *)p;
|
|
4055
|
+
a->ret = z_scout(z_move(a->config), z_move(a->cb), &a->opts);
|
|
4056
|
+
return NULL;
|
|
4057
|
+
}
|
|
4058
|
+
|
|
4059
|
+
/* Asterism::Zenoh._scout(what, timeout_ms, config) -> Array of Hello.
|
|
4060
|
+
* what: the bits of z_what_t (1 router, 2 peer, 4 client). config: nil or
|
|
4061
|
+
* a Hash as for Session.open. Waits timeout_ms (without the GVL). The
|
|
4062
|
+
* Ruby wrapper is Asterism::Zenoh.scout. */
|
|
4063
|
+
static VALUE zrb_s_scout(VALUE mod, VALUE what_v, VALUE timeout_v, VALUE config_v) {
|
|
4064
|
+
int what = NUM2INT(what_v);
|
|
4065
|
+
if (what < 1 || what > 7) {
|
|
4066
|
+
rb_raise(rb_eArgError, "what must be 1..7");
|
|
4067
|
+
}
|
|
4068
|
+
long timeout = zrb_check_timeout(timeout_v);
|
|
4069
|
+
if (!NIL_P(config_v)) {
|
|
4070
|
+
Check_Type(config_v, T_HASH);
|
|
4071
|
+
zrb_to_json(Qnil);
|
|
4072
|
+
}
|
|
4073
|
+
zrb_scout_args a;
|
|
4074
|
+
if (z_config_default(&a.config) != Z_OK) {
|
|
4075
|
+
rb_raise(eZenohError, "cannot create the configuration");
|
|
4076
|
+
}
|
|
4077
|
+
zrb_config_set(&a.config, "scouting/multicast/enabled", "true");
|
|
4078
|
+
if (!NIL_P(config_v)) {
|
|
4079
|
+
zrb_cfg_hash h = {config_v, &a.config, Qnil};
|
|
4080
|
+
int state = 0;
|
|
4081
|
+
rb_protect(zrb_cfg_hash_body, (VALUE)&h, &state);
|
|
4082
|
+
if (state != 0 || !NIL_P(h.bad)) {
|
|
4083
|
+
z_drop(z_move(a.config));
|
|
4084
|
+
if (state != 0) {
|
|
4085
|
+
rb_jump_tag(state);
|
|
4086
|
+
}
|
|
4087
|
+
rb_raise(rb_eArgError, "invalid configuration: %" PRIsVALUE, h.bad);
|
|
1463
4088
|
}
|
|
1464
|
-
z_drop(z_move(s));
|
|
1465
4089
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
4090
|
+
zevq *q = zevq_new(ZEV_HELLO, ZRB_MAX_DEPTH);
|
|
4091
|
+
z_closure_hello(&a.cb, zev_on_hello, zevq_on_drop, zevq_ref(q));
|
|
4092
|
+
z_scout_options_default(&a.opts);
|
|
4093
|
+
a.opts.timeout_ms = (uint64_t)timeout;
|
|
4094
|
+
a.opts.what = (z_what_t)what;
|
|
4095
|
+
rb_thread_call_without_gvl(zrb_scout_nogvl, &a, RUBY_UBF_IO, NULL);
|
|
4096
|
+
VALUE out = zevq_each_pending_noblock(q, false);
|
|
4097
|
+
zevq_unref(q);
|
|
4098
|
+
if (a.ret != Z_OK) {
|
|
4099
|
+
zrb_raise_code(eZenohError, (int)a.ret, "scouting failed (%d)", (int)a.ret);
|
|
4100
|
+
}
|
|
4101
|
+
return out;
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4104
|
+
/* Asterism::Zenoh.init_log(level = nil) -> nil: zenoh-c's log, written to
|
|
4105
|
+
* standard output (zenoh-c's own logger).
|
|
4106
|
+
* level: "error", "warn", "info", "debug", "trace" (or a filter such as
|
|
4107
|
+
* "zenoh::net=debug"); RUST_LOG, when set, wins. nil: only RUST_LOG. Once
|
|
4108
|
+
* per process: later calls change nothing. */
|
|
4109
|
+
static VALUE zrb_s_init_log(int argc, VALUE *argv, VALUE mod) {
|
|
4110
|
+
VALUE level = Qnil;
|
|
4111
|
+
rb_scan_args(argc, argv, "01", &level);
|
|
4112
|
+
if (NIL_P(level)) {
|
|
4113
|
+
zc_try_init_log_from_env();
|
|
4114
|
+
return Qnil;
|
|
4115
|
+
}
|
|
4116
|
+
VALUE s = rb_obj_as_string(level);
|
|
4117
|
+
z_result_t r = zc_init_log_from_env_or(StringValueCStr(s));
|
|
4118
|
+
if (r != Z_OK) {
|
|
4119
|
+
rb_raise(rb_eArgError, "invalid log level: %" PRIsVALUE, s);
|
|
4120
|
+
}
|
|
4121
|
+
return Qnil;
|
|
1468
4122
|
}
|
|
1469
4123
|
|
|
1470
4124
|
/* ----------------------------------------------------------------- init */
|
|
@@ -1473,11 +4127,23 @@ void Init_asterism_zenoh(void) {
|
|
|
1473
4127
|
/* Asterism::Zenoh. No top-level Zenoh (require "asterism/zenoh/global"). */
|
|
1474
4128
|
mAsterism = rb_define_module("Asterism");
|
|
1475
4129
|
mZenoh = rb_define_module_under(mAsterism, "Zenoh");
|
|
1476
|
-
|
|
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);
|
|
1477
4136
|
rb_define_const(mZenoh, "C_VERSION", rb_str_freeze(rb_str_new_cstr(ZENOH_C)));
|
|
1478
4137
|
rb_define_const(mZenoh, "CONNECT_TIMEOUT_MS", INT2FIX(ZRB_CONNECT_TIMEOUT_MS));
|
|
1479
4138
|
rb_define_const(mZenoh, "SEND_TIMEOUT_MS", INT2FIX(ZRB_SEND_TIMEOUT_MS));
|
|
1480
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));
|
|
1481
4147
|
rb_define_const(mZenoh, "MAX_PEERS", LONG2NUM(zrb_default_max_sessions()));
|
|
1482
4148
|
|
|
1483
4149
|
id_attachment = rb_intern("attachment");
|
|
@@ -1488,8 +4154,17 @@ void Init_asterism_zenoh(void) {
|
|
|
1488
4154
|
id_listen = rb_intern("listen");
|
|
1489
4155
|
id_iv_session = rb_intern("@session");
|
|
1490
4156
|
id_iv_key = rb_intern("@key");
|
|
4157
|
+
id_iv_code = rb_intern("@code");
|
|
4158
|
+
id_iv_qkey = rb_intern("@asterism_queryable_key");
|
|
4159
|
+
id_iv_parent = rb_intern("@parent");
|
|
4160
|
+
id_config = rb_intern("config");
|
|
4161
|
+
id_config_file = rb_intern("config_file");
|
|
4162
|
+
id_scouting = rb_intern("scouting");
|
|
4163
|
+
id_history = rb_intern("history");
|
|
4164
|
+
id_new = rb_intern("new");
|
|
1491
4165
|
id_client = rb_intern("client");
|
|
1492
4166
|
id_peer = rb_intern("peer");
|
|
4167
|
+
id_router = rb_intern("router");
|
|
1493
4168
|
id_all = rb_intern("all");
|
|
1494
4169
|
id_all_complete = rb_intern("all_complete");
|
|
1495
4170
|
id_best_matching = rb_intern("best_matching");
|
|
@@ -1502,6 +4177,19 @@ void Init_asterism_zenoh(void) {
|
|
|
1502
4177
|
zrb_no_new(cSession);
|
|
1503
4178
|
rb_define_singleton_method(cSession, "open", zrb_session_s_open, -1);
|
|
1504
4179
|
rb_define_method(cSession, "put", zrb_session_put, -1);
|
|
4180
|
+
rb_define_method(cSession, "delete", zrb_session_delete, -1);
|
|
4181
|
+
rb_define_method(cSession, "publisher", zrb_session_publisher, -1);
|
|
4182
|
+
rb_define_method(cSession, "advanced_publisher", zrb_session_advanced_publisher, -1);
|
|
4183
|
+
rb_define_method(cSession, "advanced_subscriber", zrb_session_advanced_subscriber, -1);
|
|
4184
|
+
rb_define_method(cSession, "querier", zrb_session_querier, -1);
|
|
4185
|
+
rb_define_method(cSession, "transport_events", zrb_session_transport_events, -1);
|
|
4186
|
+
rb_define_method(cSession, "link_events", zrb_session_link_events, -1);
|
|
4187
|
+
rb_define_method(cSession, "peer_zids", zrb_session_peer_zids, 0);
|
|
4188
|
+
rb_define_method(cSession, "router_zids", zrb_session_router_zids, 0);
|
|
4189
|
+
rb_define_method(cSession, "transports", zrb_session_transports, 0);
|
|
4190
|
+
rb_define_method(cSession, "links", zrb_session_links_m, 0);
|
|
4191
|
+
rb_define_method(cSession, "new_timestamp", zrb_session_new_timestamp, 0);
|
|
4192
|
+
rb_define_method(cSession, "declare_keyexpr", zrb_session_declare_keyexpr, 1);
|
|
1505
4193
|
rb_define_method(cSession, "subscribe", zrb_session_subscribe, -1);
|
|
1506
4194
|
rb_define_method(cSession, "get", zrb_session_get_m, -1);
|
|
1507
4195
|
rb_define_method(cSession, "queryable", zrb_session_queryable, -1);
|
|
@@ -1509,7 +4197,7 @@ void Init_asterism_zenoh(void) {
|
|
|
1509
4197
|
rb_define_method(cSession, "liveliness_watch", zrb_session_liveliness_watch, -1);
|
|
1510
4198
|
rb_define_method(cSession, "liveliness_get", zrb_session_liveliness_get, -1);
|
|
1511
4199
|
rb_define_method(cSession, "poll", zrb_session_poll, -1);
|
|
1512
|
-
rb_define_method(cSession, "
|
|
4200
|
+
rb_define_method(cSession, "connection_count", zrb_session_peers, 0);
|
|
1513
4201
|
rb_define_method(cSession, "zid", zrb_session_zid, 0);
|
|
1514
4202
|
rb_define_method(cSession, "closed?", zrb_session_closed_p, 0);
|
|
1515
4203
|
rb_define_method(cSession, "close", zrb_session_close, 0);
|
|
@@ -1527,6 +4215,91 @@ void Init_asterism_zenoh(void) {
|
|
|
1527
4215
|
rb_define_method(both[i], "close", zrb_sub_close, 0);
|
|
1528
4216
|
rb_define_method(both[i], "closed?", zrb_sub_closed_p, 0);
|
|
1529
4217
|
}
|
|
4218
|
+
rb_define_method(cSubscriber, "each_sample", zrb_sub_each_sample, 0);
|
|
4219
|
+
|
|
4220
|
+
/* AdvancedSubscriber: a Subscriber with history, recovery, missed
|
|
4221
|
+
* samples and publisher detection. */
|
|
4222
|
+
cAdvSubscriber = rb_define_class_under(mZenoh, "AdvancedSubscriber", rb_cObject);
|
|
4223
|
+
zrb_no_new(cAdvSubscriber);
|
|
4224
|
+
rb_define_method(cAdvSubscriber, "each_pending", zrb_sub_each_pending, 0);
|
|
4225
|
+
rb_define_method(cAdvSubscriber, "each_sample", zrb_sub_each_sample, 0);
|
|
4226
|
+
rb_define_method(cAdvSubscriber, "pending", zrb_sub_pending, 0);
|
|
4227
|
+
rb_define_method(cAdvSubscriber, "received", zrb_sub_received, 0);
|
|
4228
|
+
rb_define_method(cAdvSubscriber, "dropped", zrb_sub_dropped, 0);
|
|
4229
|
+
rb_define_method(cAdvSubscriber, "close", zrb_sub_close, 0);
|
|
4230
|
+
rb_define_method(cAdvSubscriber, "closed?", zrb_sub_closed_p, 0);
|
|
4231
|
+
rb_define_method(cAdvSubscriber, "miss_listener", zrb_advsub_miss_listener, -1);
|
|
4232
|
+
rb_define_method(cAdvSubscriber, "detect_publishers", zrb_advsub_detect_publishers, -1);
|
|
4233
|
+
|
|
4234
|
+
/* Publisher and AdvancedPublisher share one C structure. */
|
|
4235
|
+
cPublisher = rb_define_class_under(mZenoh, "Publisher", rb_cObject);
|
|
4236
|
+
cAdvPublisher = rb_define_class_under(mZenoh, "AdvancedPublisher", rb_cObject);
|
|
4237
|
+
VALUE pubs[2] = {cPublisher, cAdvPublisher};
|
|
4238
|
+
for (int i = 0; i < 2; i++) {
|
|
4239
|
+
zrb_no_new(pubs[i]);
|
|
4240
|
+
rb_define_method(pubs[i], "put", zrb_pub_put, -1);
|
|
4241
|
+
rb_define_method(pubs[i], "delete", zrb_pub_delete, -1);
|
|
4242
|
+
rb_define_method(pubs[i], "matching?", zrb_pub_matching_p, 0);
|
|
4243
|
+
rb_define_method(pubs[i], "matching_listener", zrb_pub_matching_listener, -1);
|
|
4244
|
+
rb_define_method(pubs[i], "close", zrb_pub_close, 0);
|
|
4245
|
+
rb_define_method(pubs[i], "closed?", zrb_pub_closed_p, 0);
|
|
4246
|
+
}
|
|
4247
|
+
|
|
4248
|
+
cQuerier = rb_define_class_under(mZenoh, "Querier", rb_cObject);
|
|
4249
|
+
zrb_no_new(cQuerier);
|
|
4250
|
+
rb_define_method(cQuerier, "get", zrb_querier_get_m, -1);
|
|
4251
|
+
rb_define_method(cQuerier, "matching?", zrb_querier_matching_p, 0);
|
|
4252
|
+
rb_define_method(cQuerier, "matching_listener", zrb_querier_matching_listener, -1);
|
|
4253
|
+
rb_define_method(cQuerier, "close", zrb_querier_close, 0);
|
|
4254
|
+
rb_define_method(cQuerier, "closed?", zrb_querier_closed_p, 0);
|
|
4255
|
+
|
|
4256
|
+
cMatchingListener = rb_define_class_under(mZenoh, "MatchingListener", rb_cObject);
|
|
4257
|
+
cEventListener = rb_define_class_under(mZenoh, "EventListener", rb_cObject);
|
|
4258
|
+
VALUE lsts[2] = {cMatchingListener, cEventListener};
|
|
4259
|
+
for (int i = 0; i < 2; i++) {
|
|
4260
|
+
zrb_no_new(lsts[i]);
|
|
4261
|
+
rb_define_method(lsts[i], "each_pending", zrb_lst_each_pending, 0);
|
|
4262
|
+
rb_define_method(lsts[i], "pending", zrb_lst_pending, 0);
|
|
4263
|
+
rb_define_method(lsts[i], "received", zrb_lst_received, 0);
|
|
4264
|
+
rb_define_method(lsts[i], "dropped", zrb_lst_dropped, 0);
|
|
4265
|
+
rb_define_method(lsts[i], "close", zrb_lst_close, 0);
|
|
4266
|
+
rb_define_method(lsts[i], "closed?", zrb_lst_closed_p, 0);
|
|
4267
|
+
}
|
|
4268
|
+
|
|
4269
|
+
cKeyExpr = rb_define_class_under(mZenoh, "KeyExpr", rb_cObject);
|
|
4270
|
+
rb_undef_alloc_func(cKeyExpr);
|
|
4271
|
+
rb_define_singleton_method(cKeyExpr, "new", zrb_ke_s_new, -1);
|
|
4272
|
+
rb_define_singleton_method(cKeyExpr, "canonize", zrb_ke_s_canonize, 1);
|
|
4273
|
+
rb_define_singleton_method(cKeyExpr, "valid?", zrb_ke_s_valid_p, 1);
|
|
4274
|
+
rb_define_method(cKeyExpr, "to_s", zrb_ke_to_s, 0);
|
|
4275
|
+
rb_define_method(cKeyExpr, "to_str", zrb_ke_to_s, 0);
|
|
4276
|
+
rb_define_method(cKeyExpr, "inspect", zrb_ke_inspect, 0);
|
|
4277
|
+
rb_define_method(cKeyExpr, "intersects?", zrb_ke_intersects_p, 1);
|
|
4278
|
+
rb_define_method(cKeyExpr, "includes?", zrb_ke_includes_p, 1);
|
|
4279
|
+
rb_define_method(cKeyExpr, "relation_to", zrb_ke_relation_to, 1);
|
|
4280
|
+
rb_define_method(cKeyExpr, "join", zrb_ke_join, 1);
|
|
4281
|
+
rb_define_method(cKeyExpr, "concat", zrb_ke_concat, 1);
|
|
4282
|
+
rb_define_method(cKeyExpr, "==", zrb_ke_eq, 1);
|
|
4283
|
+
rb_define_method(cKeyExpr, "eql?", zrb_ke_eq, 1);
|
|
4284
|
+
rb_define_method(cKeyExpr, "hash", zrb_ke_hash, 0);
|
|
4285
|
+
rb_define_method(cKeyExpr, "declared?", zrb_ke_declared_p, 0);
|
|
4286
|
+
rb_define_method(cKeyExpr, "undeclare", zrb_ke_undeclare_m, 0);
|
|
4287
|
+
|
|
4288
|
+
cTimestamp = rb_define_class_under(mZenoh, "Timestamp", rb_cObject);
|
|
4289
|
+
zrb_no_new(cTimestamp);
|
|
4290
|
+
rb_include_module(cTimestamp, rb_mComparable);
|
|
4291
|
+
rb_define_method(cTimestamp, "ntp64", zrb_ts_ntp64, 0);
|
|
4292
|
+
rb_define_method(cTimestamp, "id", zrb_ts_id, 0);
|
|
4293
|
+
rb_define_method(cTimestamp, "to_time", zrb_ts_to_time, 0);
|
|
4294
|
+
rb_define_method(cTimestamp, "<=>", zrb_ts_cmp, 1);
|
|
4295
|
+
rb_define_method(cTimestamp, "==", zrb_ts_eql, 1);
|
|
4296
|
+
rb_define_method(cTimestamp, "eql?", zrb_ts_eql, 1);
|
|
4297
|
+
rb_define_method(cTimestamp, "hash", zrb_ts_hash, 0);
|
|
4298
|
+
rb_define_method(cTimestamp, "to_s", zrb_ts_to_s, 0);
|
|
4299
|
+
rb_define_method(cTimestamp, "inspect", zrb_ts_inspect, 0);
|
|
4300
|
+
|
|
4301
|
+
rb_define_module_function(mZenoh, "_scout", zrb_s_scout, 3);
|
|
4302
|
+
rb_define_module_function(mZenoh, "init_log", zrb_s_init_log, -1);
|
|
1530
4303
|
|
|
1531
4304
|
cQueryable = rb_define_class_under(mZenoh, "Queryable", rb_cObject);
|
|
1532
4305
|
zrb_no_new(cQueryable);
|
|
@@ -1544,12 +4317,16 @@ void Init_asterism_zenoh(void) {
|
|
|
1544
4317
|
rb_define_method(cQuery, "payload", zrb_query_payload, 0);
|
|
1545
4318
|
rb_define_method(cQuery, "attachment", zrb_query_attachment, 0);
|
|
1546
4319
|
rb_define_method(cQuery, "reply", zrb_query_reply, -1);
|
|
4320
|
+
rb_define_method(cQuery, "reply_err", zrb_query_reply_err, -1);
|
|
4321
|
+
rb_define_method(cQuery, "reply_del", zrb_query_reply_del, -1);
|
|
4322
|
+
rb_define_method(cQuery, "encoding", zrb_query_encoding, 0);
|
|
1547
4323
|
rb_define_method(cQuery, "finish", zrb_query_finish_m, 0);
|
|
1548
4324
|
rb_define_method(cQuery, "finished?", zrb_query_finished_p, 0);
|
|
1549
4325
|
|
|
1550
4326
|
cGet = rb_define_class_under(mZenoh, "Get", rb_cObject);
|
|
1551
4327
|
zrb_no_new(cGet);
|
|
1552
4328
|
rb_define_method(cGet, "each_reply", zrb_get_each_reply, 0);
|
|
4329
|
+
rb_define_method(cGet, "each_result", zrb_get_each_result, 0);
|
|
1553
4330
|
rb_define_method(cGet, "done?", zrb_get_done_p, 0);
|
|
1554
4331
|
rb_define_method(cGet, "pending", zrb_get_pending, 0);
|
|
1555
4332
|
rb_define_method(cGet, "received", zrb_get_received, 0);
|