1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//! A client for the YTsaurus **RPC proxy**.
//!
//! HTTP API v4 — which [`ytsaurus-client`](https://docs.rs/ytsaurus-client) speaks —
//! can already reach every dynamic-table command. This crate exists for
//! latency and throughput under concurrency, never for capability: one
//! connection multiplexes many in-flight requests, where HTTP pays its
//! per-request cost every time.
//!
//! # The protocol is four layers, and only the top one looks familiar
//!
//! | Layer | What it is | Module |
//! | --- | --- | --- |
//! | 1 | **Bus** — framed, checksummed packets over TCP | [`bus`] |
//! | 2 | **RPC envelope** — request and response headers, `TError` | [`rpc`] |
//! | 3 | **API surface** — generated protobuf | [`proto`] |
//! | 4 | **Row wire format** — rows in attachments, not protobuf fields | [`wire`] |
//!
//! Layer 4 is the one that surprises people: rows do **not** travel as
//! protobuf. `api_service.proto` says outright that "actual data is passed via
//! attachments in the wire protocol", and that format is neither YSON nor
//! Skiff — it is a third one, mandatory for every dynamic-table read and write.
//!
//! # Shape of the code
//!
//! The parsers are **sans-io**: [`crc64`], [`bus::packet`], [`rpc`] and
//! [`wire`] are pure functions from bytes to values, with no `async` anywhere,
//! so every one of them is testable without a runtime — and fuzzable, though
//! they are not yet fuzzed (gate E in `docs/rpc-compatibility.md`). `async`
//! appears only at the I/O edges — [`bus::Bus`] and
//! [`connection::Connection`].
//!
//! # Example
//!
//! ```no_run
//! use ytsaurus_rpc::client::{Client, LookupOptions};
//! use ytsaurus_rpc::wire::{UnversionedValue, Value};
//!
//! # async fn example() -> ytsaurus_rpc::error::Result<()> {
//! let client = Client::connect("localhost:8011").await?;
//!
//! let key = vec![UnversionedValue::new(0, Value::Int64(42))];
//! let rows = client
//! .lookup_rows("//tmp/table", &["key"], &[key], LookupOptions::default())
//! .await?;
//!
//! // One entry per key asked for, in order; `None` where the key had no row.
//! for row in rows {
//! println!("{row:?}");
//! }
//! # Ok(())
//! # }
//! ```
//!
//! # Status
//!
//! **Pre-release**, and published from 0.3.0. The ship gates are not all green
//! and the API may change in a patch release. What is implemented, what is
//! deliberately left out and what has actually been run against a cluster are
//! listed in [`docs/rpc-compatibility.md`][compat] in the repository.
//!
//! [compat]: https://github.com/sshaplygin/ytsaurus-rs/blob/main/docs/rpc-compatibility.md
pub use ;
pub use ;
pub use Guid;
pub use ;