weida: a QUIC-native messaging framework.
This crate hosts the runtime, the native QUIC transport, the raw stream core
and the brokerless messaging patterns: Req/Rep, Push/Pull, Pub/Sub, PAIR,
SURVEY and BUS — the whole nanomsg set, none of which adds wire
vocabulary. A completion is a cursor: a level plus an absolute byte
offset, reported on a unidirectional stream of its own
([Cursors], [Reporter]).
docs/ARCHITECTURE.md describes the layer model,
docs/PROTOCOL.md is the normative wire specification, and
docs/FAILURE_MODEL.md defines what each outcome means.
use weida::{Runtime, RuntimeConfig, TransferMeta, Trust};
# async fn example() -> weida::Result<()> {
let runtime = Runtime::new(RuntimeConfig::default())?;
// Trust belongs to the dialling endpoint, not to the runtime. Here the
// address itself names the peer's public key, so nothing else is needed.
let requester = runtime.requester(Trust::by_address());
requester
.connect("weida://sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08@127.0.0.1:7443/transform")
.await?;
// One bidirectional stream: the request half and the reply half. The
// stream is the correlation, so nothing on the wire names the exchange.
let (mut transfer, reply) = requester.open(TransferMeta::default()).await?;
transfer.write_all(b"hello weida").await?;
transfer.finish()?;
let body = reply.recv().await?.collect(64 * 1024).await?;
println!("{}", String::from_utf8_lossy(&body));
# Ok(())
# }
The example above runs on the caller's ambient Tokio reactor. A caller
that has none — or whose executor is not Tokio at all — uses
[Runtime::owned] instead: the runtime then owns the reactor quinn
needs, and every task, timer and name lookup weida performs runs there,
while the futures it hands back may be driven by any executor. Transfer
payloads implement both the tokio::io and the futures-io traits for
the same reason.