9db748e8dd
* Improve SDK rustdoc and add ARCHITECTURE.md files - Rewrite lib.rs module docs with quick-start example and module overview - Add stream example and include_str! ARCHITECTURE.md to mixnet module - Add ARCHITECTURE.md for mixnet, client_pool, and stream modules - Add rustdoc to MixnetClientBuilder, MixnetClientSender, MixnetMessageSender - Add cancel safety and drop behavior annotations to async methods - Add TcpProxy deprecation notice pointing to stream module * Fix rustdoc errors and add stepwise comments to remaining examples Rustdoc fixes: - Add missing .unwrap() on connect_new example - Replace broken turbofish intra-doc link in MixnetClientBuilder - Fix NymProxyServer::new args in tcp_proxy example - Wrap BandwidthImporter example in scoped block to fix borrow-then-move - Change misleading "5-hop routing" to "multi-hop routing" - Fix copy-paste "forget me" in send_remember_me error message - Fix wrong cargo run command in stream_simple_read_write - Fix DecayWrapper description * Cut down doc comment length * Trimmed down SDK ARCHITECTURE files * Slim Rust SDK docs and rename opener to dialer - Merge tour page into SDK landing page, delete tour.mdx - Trim all three tutorials: cut boilerplate, duplicated code, and misplaced content - Make FFI page evergreen with Go and C++ snippets, link to repo examples - Rename "opener" to "dialer" in stream docs, source ARCHITECTURE.md, and rustdoc - Add reply-to-open arrow in stream mermaid diagram - Replace remaining Unicode dashes in mermaid flowchart * - elevate streams in rustdoc: examples on lib.rs, MixnetClient, open_stream, listener - add stream quick reference to mixnet ARCHITECTURE.md - add stream types to key types list in ARCHITECTURE.md - add docs.rs links for AsyncRead/AsyncWrite and stream submodule - tcp_proxy: replace bold deprecation with warning box * - replace individual example doc pages with GitHub-linked tables - add step-by-step inline comments to all SDK example source files - add doc comments to examples missing them (simple, surb_reply, builder, etc.) - expand mixnet tutorial with persistent identity and split_sender sections - add tcpproxy tutorial - rename "API Reference" to "TypeDoc Reference" in TS SDK sidebar - rename "Misc" to "Extras" in developer sidebar, move VPN CLI up - remove echo server from tools - update message-queue callout to reference actual modules - fix mixnet/examples redirect collision * Add missing mut to example code * Update ARCHITECTURE.md with LP Framing + stream examples with sequencing * Update doc comment in utils.rs * Standardise commenting style across Rust SDK examples * Fix inline doc examples and trim re-export boilerplate * Update sdk/rust/nym-sdk/examples/bandwidth.rs Co-authored-by: Simon Wicky <simon@nymtech.net> * Fix review comments --------- Co-authored-by: Simon Wicky <simon@nymtech.net>
92 lines
3.1 KiB
Rust
92 lines
3.1 KiB
Rust
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
//! Sends 1 MiB of random data over a MixnetStream and verifies integrity.
|
|
//!
|
|
//! Uses `write_all` on the sender and `read_exact` on the receiver.
|
|
//! `read_exact` is needed because there is no close/EOF signal — streams
|
|
//! clean up via `Drop` and idle timeout, so the receiver must know the
|
|
//! expected size up front.
|
|
//!
|
|
//! Messages are reordered by sequence number in the stream layer, so
|
|
//! large payloads spanning multiple Sphinx packets are reassembled
|
|
//! correctly.
|
|
//!
|
|
//! Run with: cargo run --example stream_throughput
|
|
|
|
use nym_sdk::mixnet;
|
|
use rand::RngCore;
|
|
use std::time::Duration;
|
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
|
|
const SIZE: usize = 1024 * 1024; // 1 MiB
|
|
const TIMEOUT: Duration = Duration::from_secs(300);
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
nym_bin_common::logging::setup_tracing_logger();
|
|
|
|
// Generate 1 MiB of random data to send.
|
|
let mut payload = vec![0u8; SIZE];
|
|
rand::rngs::OsRng.fill_bytes(&mut payload);
|
|
println!("Generated {} bytes of random data", payload.len());
|
|
|
|
// Connect two clients and establish a stream.
|
|
println!("Connecting sender...");
|
|
let mut sender = mixnet::MixnetClient::connect_new().await.unwrap();
|
|
println!("{}", sender.nym_address());
|
|
|
|
println!("Connecting receiver...");
|
|
let mut receiver = mixnet::MixnetClient::connect_new().await.unwrap();
|
|
let recv_addr = *receiver.nym_address();
|
|
println!("{recv_addr}");
|
|
|
|
let mut listener = receiver.listener().unwrap();
|
|
let mut tx = sender.open_stream(recv_addr, None).await.unwrap();
|
|
let mut rx = tokio::time::timeout(TIMEOUT, listener.accept())
|
|
.await
|
|
.expect("accept timed out")
|
|
.expect("listener closed");
|
|
println!("Stream established\n");
|
|
|
|
// Send the payload. write_all splits it across multiple
|
|
// Sphinx packets automatically.
|
|
let data = payload.clone();
|
|
let send_task = tokio::spawn(async move {
|
|
tx.write_all(&data).await.unwrap();
|
|
tx.flush().await.unwrap();
|
|
println!("Sent {} bytes", data.len());
|
|
});
|
|
|
|
// Receive exactly SIZE bytes using read_exact.
|
|
// We use read_exact (not read-until-EOF) because there is no
|
|
// close/EOF signal — streams clean up via Drop and idle timeout.
|
|
let recv_task = tokio::spawn(async move {
|
|
let mut buf = vec![0u8; SIZE];
|
|
tokio::time::timeout(TIMEOUT, rx.read_exact(&mut buf))
|
|
.await
|
|
.expect("receive timed out")
|
|
.unwrap();
|
|
println!("Received {} bytes", buf.len());
|
|
buf
|
|
});
|
|
|
|
// Verify integrity — the received bytes must match exactly.
|
|
let (_, received) = tokio::join!(send_task, recv_task);
|
|
let received = received.unwrap();
|
|
|
|
if received == payload {
|
|
println!("\nIntegrity OK");
|
|
} else {
|
|
eprintln!(
|
|
"\nMISMATCH — sent {} bytes, got {}",
|
|
payload.len(),
|
|
received.len()
|
|
);
|
|
std::process::exit(1);
|
|
}
|
|
|
|
sender.disconnect().await;
|
|
receiver.disconnect().await;
|
|
}
|