Group pubsub¶
Public Functions¶
| Type | Name |
|---|---|
| dp_pub_t * | dp_pub_create (const char * endpoint, dp_sample_type_t sample_type) Create a Publisher and connect to endpoint . |
| dp_pub_t * | dp_pub_create_tlm (const char * endpoint) Create a Publisher that emits telemetry frames. |
| void | dp_pub_destroy (dp_pub_t * ctx) Destroy a Publisher context and release all resources. |
| int | dp_pub_flush (dp_pub_t * ctx, int timeout_ms) Wait until the server has everything published so far. |
| int | dp_pub_send_cf32 (dp_pub_t * ctx, const float _Complex * samples, size_t num_samples, double sample_rate, double center_freq) Send an array of CF32 samples via a Publisher. |
| int | dp_pub_send_cf64 (dp_pub_t * ctx, const double _Complex * samples, size_t num_samples, double sample_rate, double center_freq) Send an array of CF64 samples via a Publisher. |
| int | dp_pub_send_ci16 (dp_pub_t * ctx, const int16_t * samples, size_t num_samples, double sample_rate, double center_freq) Send an array of CI16 samples via a Publisher. |
| int | dp_pub_send_ci32 (dp_pub_t * ctx, const int32_t * samples, size_t num_samples, double sample_rate, double center_freq) Send an array of CI32 samples via a Publisher. |
| int | dp_pub_send_ci8 (dp_pub_t * ctx, const int8_t * samples, size_t num_samples, double sample_rate, double center_freq) Send an array of CI8 samples via a Publisher. |
| int | dp_pub_send_eos (dp_pub_t * ctx) Tell subscribers the stream has ended. |
| int | dp_pub_send_tlm16 (dp_pub_t * ctx, const void * records, size_t num_records, double sample_rate, double center_freq) Send an array of 16-byte telemetry records via a Publisher. |
| int | dp_stream_drain (dp_pub_t * ctx, int timeout_ms) Shut a context down gracefully: drain, then closed. |
| dp_sub_t * | dp_sub_create (const char * endpoint) Create a Subscriber and connect to endpoint . |
| void | dp_sub_destroy (dp_sub_t * ctx) Destroy a Subscriber context and release all resources. |
| int | dp_sub_recv (dp_sub_t * ctx, dp_msg_t ** msg, dp_header_t * header) Receive one frame from a Subscriber socket (zero-copy). |
| void | dp_sub_set_timeout (dp_sub_t * ctx, int timeout_ms) Set receive timeout for a Subscriber socket. |
Detailed Description¶
The Publisher publishes to a subject and fans out every message to all connected Subscribers. Subscribers subscribe and receive every frame published after they connect — a slow or absent subscriber simply misses frames (core NATS PUB/SUB has no queuing/replay).
Public Functions Documentation¶
function dp_pub_create¶
Create a Publisher and connect to endpoint .
Parameters:
endpointNATS endpoint, e.g."nats://127.0.0.1:4222/iq".sample_typeSample format that will be sent.
Returns:
Non-NULL context on success, NULL on failure.
function dp_pub_create_tlm¶
Create a Publisher that emits telemetry frames.
A separate constructor because DP_KIND_TLM is a frame kind rather than a sample format: there is no BLUE code to pass to dp_pub_create(), and a publisher that emits records does not also emit I/Q. Send with dp_pub_send_tlm16().
Parameters:
endpointnats://host:port/subject.
Returns:
Publisher handle, or NULL on failure.
function dp_pub_destroy¶
Destroy a Publisher context and release all resources.
Parameters:
ctxPublisher context (may be NULL).
function dp_pub_flush¶
Wait until the server has everything published so far.
dp_pub_send_* hands the frame to the client and returns; the client writes it in the background. That is what makes publishing fast, and it means "the send returned" is not "the server has it". This waits for a round trip, so when it returns DP_OK everything published before it has arrived.
You do NOT need this before destroy: the NATS client flushes what is buffered when the connection closes. But it does so best-effort with a 500 ms cap and no way to report failure, so a backlog that cannot drain in half a second is dropped silently — and on a link slower than loopback that is not a large backlog. Call this when losing the tail would matter, and you get a budget you chose and an answer you can act on.
It is also the only way to ask the question WITHOUT closing: a long-lived publisher that wants "everything up to here is on the server" has nothing else to call. (PUSH does not need it — the JetStream publish is server-acked before it returns — and REQ/REP flush on every message already.)
A drained shutdown does not need one. dp_stream_drain() ends with this same flush as its final phase, so flush belongs at checkpoints a drain does not cover — confirming a batch is on the server before treating it as complete — not in front of a drain.
Parameters:
ctxAny send-capable context (dp_pub_t / dp_push_t / dp_req_t / dp_rep_t are the same underlying type).timeout_msHow long to wait; <= 0 uses 2000 ms.
Returns:
DP_OK when the server has it, DP_ERR_TIMEOUT if the budget ran out with data still pending, DP_ERR_INVALID for a NULL context.
function dp_pub_send_cf32¶
Send an array of CF32 samples via a Publisher.
int dp_pub_send_cf32 (
dp_pub_t * ctx,
const float _Complex * samples,
size_t num_samples,
double sample_rate,
double center_freq
)
Parameters:
ctxPublisher context.samplesInterleaved int32_t I/Q pairs; length 2×num_samples.num_samplesNumber of complex samples.sample_rateSample rate in Hz.center_freqCentre frequency in Hz.
Returns:
DP_OK (0) on success, negative error code on failure.
function dp_pub_send_cf64¶
Send an array of CF64 samples via a Publisher.
int dp_pub_send_cf64 (
dp_pub_t * ctx,
const double _Complex * samples,
size_t num_samples,
double sample_rate,
double center_freq
)
Parameters:
ctxPublisher context.samplesInterleaved int32_t I/Q pairs; length 2×num_samples.num_samplesNumber of complex samples.sample_rateSample rate in Hz.center_freqCentre frequency in Hz.
Returns:
DP_OK (0) on success, negative error code on failure.
function dp_pub_send_ci16¶
Send an array of CI16 samples via a Publisher.
int dp_pub_send_ci16 (
dp_pub_t * ctx,
const int16_t * samples,
size_t num_samples,
double sample_rate,
double center_freq
)
Parameters:
ctxPublisher context.samplesInterleaved int32_t I/Q pairs; length 2×num_samples.num_samplesNumber of complex samples.sample_rateSample rate in Hz.center_freqCentre frequency in Hz.
Returns:
DP_OK (0) on success, negative error code on failure.
function dp_pub_send_ci32¶
Send an array of CI32 samples via a Publisher.
int dp_pub_send_ci32 (
dp_pub_t * ctx,
const int32_t * samples,
size_t num_samples,
double sample_rate,
double center_freq
)
Parameters:
ctxPublisher context.samplesInterleaved int32_t I/Q pairs; length 2×num_samples.num_samplesNumber of complex samples.sample_rateSample rate in Hz.center_freqCentre frequency in Hz.
Returns:
DP_OK (0) on success, negative error code on failure.
function dp_pub_send_ci8¶
Send an array of CI8 samples via a Publisher.
int dp_pub_send_ci8 (
dp_pub_t * ctx,
const int8_t * samples,
size_t num_samples,
double sample_rate,
double center_freq
)
Parameters:
ctxPublisher context.samplesInterleaved int32_t I/Q pairs; length 2×num_samples.num_samplesNumber of complex samples.sample_rateSample rate in Hz.center_freqCentre frequency in Hz.
Returns:
DP_OK (0) on success, negative error code on failure.
function dp_pub_send_eos¶
Tell subscribers the stream has ended.
Publishes a zero-payload DP_KIND_EOS frame. A receiving *_recv reports DP_ERR_EOF instead of handing back an empty frame, so a consumer learns the sender finished rather than inferring it from silence — which is the inference this whole contract exists to remove.
Send it before dp_stream_drain(), not after. A drain cannot be reversed and refuses sends once it reaches its publish-flushing phase, so an EOS issued after one may simply not go. The ordered shutdown is: stop producing, send EOS, drain, destroy.
What it does NOT promise. PUB/SUB is at-most-once (§9), so this frame can be dropped like any other: it turns the common case from "wait forever" into "finish promptly", not from unreliable into guaranteed, and a subscriber that must not hang on a lost marker still needs a timeout. PUSH/PULL delivers it at-least-once, so it may arrive more than once and a handler must be idempotent.
Parameters:
ctxAny send-capable context.
Returns:
DP_OK once handed to the client, DP_ERR_INVALID for a NULL context, DP_ERR_CLOSED if the context is already draining or closed.
function dp_pub_send_tlm16¶
Send an array of 16-byte telemetry records via a Publisher.
int dp_pub_send_tlm16 (
dp_pub_t * ctx,
const void * records,
size_t num_records,
double sample_rate,
double center_freq
)
The payload is num_records packed dp_tlm_rec_t (see dp_tlm/dp_tlm_core.h) — the header's num_samples counts records and sample_type is TLM16. Kept const void * so the wire layer stays decoupled from the telemetry component; the dp_tlm_sink_* helper (stream/tlm_sink.h) is the intended caller.
Parameters:
ctxPublisher context.recordsPacked 16-byte records.num_recordsRecord count.sample_rateWire-header field; 0.0 if not meaningful.center_freqWire-header field; 0.0 if not meaningful.
Returns:
DP_OK (0) on success, negative error code on failure.
function dp_stream_drain¶
Shut a context down gracefully: drain, then closed.
The ordered shutdown, and the one a signal handler's exit path wants. The client stops accepting new deliveries, lets what is in flight finish, flushes everything pending, and then closes.
It waits for the connection to reach CLOSED before returning, and that is the part worth having in the library rather than in every caller: natsConnection_Drain returns immediately and does the work in the background, so a process that exits when it returns abandons exactly the work the drain was for. Getting that wrong looks like success.
Against dp_pub_flush(): flush answers "does the server have what I
published", and the context keeps working afterwards. Drain answers "let everything finish, then stop", and the context is finished when it returns — call the matching *_destroy next, which is then just the free.
Drain last, after your application has stopped producing. A drain cannot be reversed, and a send issued while one is in progress is racing its phases: it may slip through while subscriptions drain, or be refused once the connection reaches its publish-flushing phase. Do not publish a "shutting down" notice after calling this and assume it went.
Because this waits for CLOSED, a single-threaded caller does not have to reason about that race: once it has returned, a send is refused with DP_ERR_CLOSED, deterministically. The race is real only for a thread still publishing while another drains.
Size timeout_ms to the slowest thing the drain has to wait for, with margin: cutting a drain off mid-write every deploy is worse than waiting. doppler's own receive is synchronous — there is no message handler to finish — so the wait is dominated by flushing whatever is still buffered, and the 5 s default is generous for a link that is keeping up. A slow or congested link, or a large backlog, wants more.
Parameters:
ctxAny context.timeout_msHow long to wait for CLOSED; <= 0 uses 5000 ms.
Returns:
DP_OK once closed, DP_ERR_TIMEOUT if the budget ran out with the drain still in progress (the context is still safe to destroy), DP_ERR_INVALID for a NULL context.
function dp_sub_create¶
Create a Subscriber and connect to endpoint .
Subscribes to all topics (empty topic filter).
Parameters:
endpointNATS endpoint, e.g."nats://127.0.0.1:4222/iq".
Returns:
Non-NULL context on success, NULL on failure.
function dp_sub_destroy¶
Destroy a Subscriber context and release all resources.
Parameters:
ctxSubscriber context (may be NULL).
function dp_sub_recv¶
Receive one frame from a Subscriber socket (zero-copy).
On success, *msg is set to a message handle whose data buffer is valid until dp_msg_free() is called. Use dp_msg_data() to access the sample pointer.
Parameters:
ctxSubscriber context.msgSet to a zero-copy message handle.headerSet to the frame metadata.
Returns:
DP_OK on success, DP_ERR_TIMEOUT on timeout, DP_ERR_EOF when the sender has finished (no message is produced, so there is nothing to free), negative on error.
function dp_sub_set_timeout¶
Set receive timeout for a Subscriber socket.
Parameters:
ctxSubscriber context.timeout_msTimeout in milliseconds (-1 = infinite, 0 = non-blocking).