0.15.0: simple builder API, v2.1 framing, stream lane, benches
- omnivox::server::<T>()/client::<T>() builders; plain closures, enum in, match in the callback — the original C++ UX with the ceremony removed - serde + bincode replace the hand-rolled Cereal codec (vectors.rs still governs the crypto leaves via the C++ golden oracles) - v2.1 frames: u32 len | type | ct | tag; nonce derived from the sequence counter (no wire nonce), type byte authenticated as AAD; any frame-level failure is fatal, authenticated-but-undecodable payloads are skipped - stream lane: send_stream/on_stream, 1 MiB frames, shared sequence with messages (exact sender interleaving preserved); see dump-agent/viewer - per-connection bounded queues + writer tasks; reply/reply_stream are non-blocking try_send lanes for callbacks - benches: seal/open criterion group + transport harness (spray msg/s, stream GiB/s, raw loopback baseline) - profile.dev.package scrypt/pbkdf2 opt-level 3: golden-vector scrypt at N=2^17 was unusable in debug builds - PROTOCOL-V2.md and README rewritten for v2.1
This commit is contained in:
+33
-62
@@ -1,12 +1,17 @@
|
||||
//! Port of OmniVox-client.cpp: connects, sends "Hello", prints what the
|
||||
//! server echoes, then stops after 15 seconds like the C++ example.
|
||||
//! The minimal OmniVox client: connect, talk, done.
|
||||
//!
|
||||
//! Companion to `omnivox-server`. Sends `Hello`, prints the echo, then
|
||||
//! exchanges two more notes and stops.
|
||||
|
||||
#[path = "common/mod.rs"]
|
||||
mod common;
|
||||
use omnivox::ConnectionStatus;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
||||
use common::{DatagramPayload, PASSWORD, SALT, SERVER_ADDR, SERVER_PORT};
|
||||
use omnivox::{Config, ConnectionContext, ConnectionStatus, OmniVox, derive_encrypt_key};
|
||||
use std::sync::Arc;
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
enum ChatMsg {
|
||||
Hello,
|
||||
Note(String),
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -15,63 +20,29 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.without_time()
|
||||
.init();
|
||||
|
||||
tracing::info!("Connecting to server at {SERVER_ADDR}:{SERVER_PORT}");
|
||||
|
||||
let client = Arc::new(OmniVox::<DatagramPayload>::new());
|
||||
let key = derive_encrypt_key(PASSWORD.as_bytes(), SALT, 17, 8, 1)?;
|
||||
client.set_encrypt_key(key);
|
||||
|
||||
let data_cb = Arc::new(|_data: &DatagramPayload, ctx: &ConnectionContext| {
|
||||
tracing::info!("Server ID: {}, sent data!", ctx.id);
|
||||
});
|
||||
|
||||
let connector = Arc::clone(&client);
|
||||
let connection_cb = Arc::new(move |ctx: &ConnectionContext| match ctx.connected {
|
||||
ConnectionStatus::Connected => {
|
||||
tracing::info!(
|
||||
"[onConnect] Successfully connected to: {}:{}",
|
||||
ctx.ip,
|
||||
ctx.port
|
||||
);
|
||||
let client = Arc::clone(&connector);
|
||||
tokio::spawn(async move {
|
||||
let payload = DatagramPayload {
|
||||
id: 1,
|
||||
v1: 0,
|
||||
payload: b"Hello".to_vec(),
|
||||
};
|
||||
if client.send_to_server(&payload).await {
|
||||
tracing::info!("Sent initial data to server");
|
||||
}
|
||||
});
|
||||
}
|
||||
ConnectionStatus::ConnectionFailed => {
|
||||
tracing::info!(
|
||||
"[onConnect] Connection failed or timed out to: {}:{}",
|
||||
ctx.ip,
|
||||
ctx.port
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
tracing::info!(
|
||||
"[onConnect] Unexpected connection status to: {}:{}",
|
||||
ctx.ip,
|
||||
ctx.port
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
client
|
||||
.connect_to_server(
|
||||
SERVER_ADDR,
|
||||
SERVER_PORT,
|
||||
Config::default(),
|
||||
Some(data_cb),
|
||||
connection_cb,
|
||||
)
|
||||
let client = omnivox::client::<ChatMsg>()
|
||||
// Same password + salt as the server — they derive the same PSK.
|
||||
.password("SecurePassword123", b"static-demo-salt")
|
||||
.on_data(|msg, _ctx| match msg {
|
||||
ChatMsg::Hello => tracing::info!("server greeted us unprompted?"),
|
||||
ChatMsg::Note(text) => tracing::info!("server note: {text}"),
|
||||
})
|
||||
// Fires on Connected, ConnectionFailed, and later NotConnected.
|
||||
.on_state(|ctx| {
|
||||
tracing::info!("state: {:?}", ctx.status());
|
||||
if ctx.status() == ConnectionStatus::ConnectionFailed {
|
||||
tracing::error!("is the server running? (cargo run --example omnivox-server)");
|
||||
}
|
||||
})
|
||||
.connect("127.0.0.1", 8080)
|
||||
.await?;
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_secs(15)).await;
|
||||
client.send(&ChatMsg::Hello).await;
|
||||
tokio::time::sleep(Duration::from_millis(300)).await;
|
||||
client.send(&ChatMsg::Note("first note".into())).await;
|
||||
client.send(&ChatMsg::Note("second note".into())).await;
|
||||
tokio::time::sleep(Duration::from_millis(300)).await;
|
||||
|
||||
client.stop().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user