Skip to main content

laser_wire/
clients.rs

1use serde::{Deserialize, Serialize};
2
3/// The discovery read request (`AGDX_GET_CLIENTS_METADATA`). Filtered and
4/// paginated, because a busy server may hold thousands of connections and a
5/// caller must not have to pull them all at once. The server orders connections
6/// by `client_id`, applies the filters, skips past `after_client_id`, and returns
7/// up to `limit` entries plus a cursor when more remain.
8#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
9pub struct ClientMetadataQuery {
10    pub v: u32,
11    /// Only return connections that advertised metadata. The common case for
12    /// discovery, where unannounced connections are noise.
13    #[serde(default, skip_serializing_if = "is_false")]
14    pub with_metadata_only: bool,
15    /// Only return connections authenticated as this principal.
16    #[serde(default, skip_serializing_if = "Option::is_none")]
17    pub user_id: Option<u32>,
18    /// Pagination cursor: return only connections whose `client_id` is strictly
19    /// greater than this. `None` starts from the beginning.
20    #[serde(default, skip_serializing_if = "Option::is_none")]
21    pub after_client_id: Option<u32>,
22    /// Max entries to return. Clamped server-side to the page cap.
23    pub limit: u32,
24}
25
26fn is_false(value: &bool) -> bool {
27    !*value
28}
29
30/// One connection's discovery record: the connection identity the streaming
31/// server holds plus the opaque metadata the client advertised. A LaserData-owned
32/// type, deliberately distinct from the upstream Apache Iggy `ClientInfo` (which
33/// stays byte-identical so an Apache Iggy SDK keeps working against LaserData
34/// Cloud). The metadata is opaque: an agent advertises its card, a regular app
35/// sets any blob the consumer interprets.
36#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
37pub struct ClientMetadata {
38    pub client_id: u32,
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    pub user_id: Option<u32>,
41    /// Transport code (1 Tcp, 2 Quic, 3 Http, 4 WebSocket), the same dictionary
42    /// the upstream binding uses.
43    pub transport: u8,
44    pub address: String,
45    pub consumer_groups_count: u32,
46    #[serde(
47        default,
48        skip_serializing_if = "Option::is_none",
49        with = "crate::encoding::opt_bin_bytes"
50    )]
51    pub metadata: Option<Vec<u8>>,
52}
53
54/// The reply to `AGDX_GET_CLIENTS_METADATA`: one page of connections with their
55/// advertised metadata, plus `next_cursor` (the last `client_id` in the page) when
56/// more connections remain, so the caller pages by passing it as the next
57/// `after_client_id`. `None` means the last page.
58#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
59pub struct ClientMetadataList {
60    pub clients: Vec<ClientMetadata>,
61    #[serde(default, skip_serializing_if = "Option::is_none")]
62    pub next_cursor: Option<u32>,
63}
64
65#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
66pub struct ProducerPresence {
67    pub producer_presence_version: u32,
68    pub observed_at_millis: u64,
69    pub expires_after_millis: u64,
70    pub producers: Vec<ProducerStatistics>,
71}
72
73#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
74pub struct ProducerStatistics {
75    pub instance_id: String,
76    pub stream: String,
77    pub topic: String,
78    pub first_activity_millis: u64,
79    pub last_activity_millis: u64,
80    pub submitted_records: u64,
81    pub submitted_payload_bytes: u64,
82    pub confirmed_records: Option<u64>,
83    pub confirmed_payload_bytes: Option<u64>,
84    pub retries: Option<u64>,
85    pub failed_calls: u64,
86    pub last_success_millis: Option<u64>,
87    pub latency: ProducerLatency,
88}
89
90#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
91pub struct ProducerLatency {
92    pub samples: u64,
93    pub p50_micros: Option<u64>,
94    pub p99_micros: Option<u64>,
95    pub p999_micros: Option<u64>,
96}