Skip to content

Commit 6492159

Browse files
committed
feat(wasmtime-cli): add UDS/WebTransport/QUIC support
1 parent 7b02ba9 commit 6492159

File tree

6 files changed

+267
-0
lines changed

6 files changed

+267
-0
lines changed

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/wasmtime-cli/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ clap = { workspace = true, features = [
2424
] }
2525
futures = { workspace = true }
2626
humantime = { workspace = true }
27+
quinn = { workspace = true, features = [
28+
"log",
29+
"platform-verifier",
30+
"ring",
31+
"runtime-tokio",
32+
"rustls",
33+
] }
2734
reqwest = { workspace = true }
2835
tokio = { workspace = true, features = ["fs"] }
2936
tokio-util = { workspace = true, features = ["codec"] }
@@ -46,7 +53,10 @@ wasmtime = { workspace = true, features = [
4653
] }
4754
wasmtime-wasi = { workspace = true }
4855
wit-component = { workspace = true }
56+
wtransport = { workspace = true, features = ["self-signed"] }
4957
wrpc-cli = { workspace = true, features = ["nats"] }
5058
wrpc-transport-nats = { workspace = true, features = ["async-nats-0_37"] }
59+
wrpc-transport-quic = { workspace = true }
60+
wrpc-transport-web = { workspace = true }
5161
wrpc-transport = { workspace = true, features = ["net"] }
5262
wrpc-runtime-wasmtime = { workspace = true }

crates/wasmtime-cli/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ use wrpc_runtime_wasmtime::{
2727
use wrpc_transport::{Invoke, Serve};
2828

2929
mod nats;
30+
mod quic;
3031
mod tcp;
32+
#[cfg(unix)]
33+
mod unix;
34+
mod web;
3135

3236
const DEFAULT_TIMEOUT: &str = "10s";
3337

@@ -37,7 +41,14 @@ enum Command {
3741
#[command(subcommand)]
3842
Nats(nats::Command),
3943
#[command(subcommand)]
44+
Quic(quic::Command),
45+
#[command(subcommand)]
4046
Tcp(tcp::Command),
47+
#[cfg(unix)]
48+
#[command(subcommand)]
49+
Unix(unix::Command),
50+
#[command(subcommand)]
51+
Web(web::Command),
4152
}
4253

4354
pub enum Workload {
@@ -637,6 +648,10 @@ pub async fn run() -> anyhow::Result<()> {
637648
wrpc_cli::tracing::init();
638649
match Command::parse() {
639650
Command::Nats(args) => nats::run(args).await,
651+
Command::Quic(args) => quic::run(args).await,
640652
Command::Tcp(args) => tcp::run(args).await,
653+
#[cfg(unix)]
654+
Command::Unix(args) => unix::run(args).await,
655+
Command::Web(args) => web::run(args).await,
641656
}
642657
}

crates/wasmtime-cli/src/quic.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use core::net::{Ipv6Addr, SocketAddr};
2+
3+
use anyhow::Context as _;
4+
use clap::Parser;
5+
use quinn::{ClientConfig, Endpoint};
6+
use tracing::instrument;
7+
8+
pub const DEFAULT_ADDR: &str = "[::1]:4433";
9+
10+
/// QUIC transport
11+
#[derive(Parser, Debug)]
12+
pub enum Command {
13+
Run(RunArgs),
14+
}
15+
16+
/// Run a command component
17+
#[derive(Parser, Debug)]
18+
pub struct RunArgs {
19+
/// Invocation timeout
20+
#[arg(long, default_value = crate::DEFAULT_TIMEOUT)]
21+
timeout: humantime::Duration,
22+
23+
/// Address to send import invocations to
24+
#[arg(long, default_value = DEFAULT_ADDR)]
25+
import_addr: SocketAddr,
26+
27+
/// Server name to use for import connection
28+
#[arg(long)]
29+
import_san: String,
30+
31+
/// Path or URL to Wasm command component
32+
workload: String,
33+
}
34+
35+
#[instrument(level = "trace", ret(level = "trace"))]
36+
pub async fn handle_run(
37+
RunArgs {
38+
timeout,
39+
import_addr,
40+
import_san,
41+
ref workload,
42+
}: RunArgs,
43+
) -> anyhow::Result<()> {
44+
let mut ep = Endpoint::client((Ipv6Addr::UNSPECIFIED, 0).into())
45+
.context("failed to create QUIC endpoint")?;
46+
// TODO: Allow TLS configuration via runtime flags
47+
// TODO: Support WebPKI
48+
ep.set_default_client_config(ClientConfig::with_platform_verifier());
49+
let conn = ep
50+
.connect(import_addr, &import_san)
51+
.context("failed to connect using QUIC")?;
52+
let conn = conn.await.context("failed to establish QUIC connection")?;
53+
crate::handle_run(
54+
wrpc_transport_quic::Client::from(conn),
55+
(),
56+
*timeout,
57+
workload,
58+
)
59+
.await
60+
}
61+
62+
#[instrument(level = "trace", ret(level = "trace"))]
63+
pub async fn run(cmd: Command) -> anyhow::Result<()> {
64+
match cmd {
65+
Command::Run(args) => handle_run(args).await,
66+
// TODO: Implement serving
67+
}
68+
}

crates/wasmtime-cli/src/unix.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use std::path::PathBuf;
2+
use std::sync::Arc;
3+
4+
use anyhow::Context as _;
5+
use clap::Parser;
6+
use tracing::{error, instrument};
7+
8+
/// Unix Domain Socket transport
9+
#[derive(Parser, Debug)]
10+
pub enum Command {
11+
Run(RunArgs),
12+
Serve(ServeArgs),
13+
}
14+
15+
/// Run a command component
16+
#[derive(Parser, Debug)]
17+
pub struct RunArgs {
18+
/// Invocation timeout
19+
#[arg(long, default_value = crate::DEFAULT_TIMEOUT)]
20+
timeout: humantime::Duration,
21+
22+
/// Path to send import invocations to
23+
#[arg(long)]
24+
import: PathBuf,
25+
26+
/// Path or URL to Wasm command component
27+
workload: String,
28+
}
29+
30+
/// Serve a reactor component
31+
#[derive(Parser, Debug)]
32+
pub struct ServeArgs {
33+
/// Invocation timeout
34+
#[arg(long, default_value = crate::DEFAULT_TIMEOUT)]
35+
timeout: humantime::Duration,
36+
37+
/// Path to send import invocations to
38+
#[arg(long)]
39+
import: PathBuf,
40+
41+
/// Path to listen for export invocations on
42+
#[arg(long)]
43+
export: PathBuf,
44+
45+
/// Path or URL to Wasm command component
46+
workload: String,
47+
}
48+
49+
#[instrument(level = "trace", ret(level = "trace"))]
50+
pub async fn handle_run(
51+
RunArgs {
52+
timeout,
53+
import,
54+
ref workload,
55+
}: RunArgs,
56+
) -> anyhow::Result<()> {
57+
crate::handle_run(
58+
wrpc_transport::unix::Client::from(import),
59+
(),
60+
*timeout,
61+
workload,
62+
)
63+
.await
64+
}
65+
66+
#[instrument(level = "trace", ret(level = "trace"))]
67+
pub async fn handle_serve(
68+
ServeArgs {
69+
timeout,
70+
export,
71+
import,
72+
ref workload,
73+
}: ServeArgs,
74+
) -> anyhow::Result<()> {
75+
let lis = tokio::net::UnixListener::bind(&export).with_context(|| {
76+
format!(
77+
"failed to bind Unix socket listener on `{}`",
78+
export.display()
79+
)
80+
})?;
81+
let srv = Arc::new(wrpc_transport::Server::default());
82+
let accept = tokio::spawn({
83+
let srv = Arc::clone(&srv);
84+
async move {
85+
loop {
86+
if let Err(err) = srv.accept(&lis).await {
87+
error!(?err, "failed to accept Unix socket connection");
88+
}
89+
}
90+
}
91+
});
92+
let res = crate::handle_serve(
93+
srv.as_ref(),
94+
wrpc_transport::unix::Client::from(import),
95+
(),
96+
*timeout,
97+
workload,
98+
)
99+
.await;
100+
accept.abort();
101+
res
102+
}
103+
104+
#[instrument(level = "trace", ret(level = "trace"))]
105+
pub async fn run(cmd: Command) -> anyhow::Result<()> {
106+
match cmd {
107+
Command::Run(args) => handle_run(args).await,
108+
Command::Serve(args) => handle_serve(args).await,
109+
}
110+
}

crates/wasmtime-cli/src/web.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use anyhow::Context as _;
2+
use clap::Parser;
3+
use tracing::instrument;
4+
use wtransport::{ClientConfig, Endpoint};
5+
6+
pub const DEFAULT_ADDR: &str = "https://localhost:4433";
7+
8+
/// WebTransport transport
9+
#[derive(Parser, Debug)]
10+
pub enum Command {
11+
Run(RunArgs),
12+
}
13+
14+
/// Run a command component
15+
#[derive(Parser, Debug)]
16+
pub struct RunArgs {
17+
/// Invocation timeout
18+
#[arg(long, default_value = crate::DEFAULT_TIMEOUT)]
19+
timeout: humantime::Duration,
20+
21+
/// Address to send import invocations to
22+
#[arg(long, default_value = DEFAULT_ADDR)]
23+
import: String,
24+
25+
/// Path or URL to Wasm command component
26+
workload: String,
27+
}
28+
29+
#[instrument(level = "trace", ret(level = "trace"))]
30+
pub async fn handle_run(
31+
RunArgs {
32+
timeout,
33+
import,
34+
ref workload,
35+
}: RunArgs,
36+
) -> anyhow::Result<()> {
37+
let ep = Endpoint::client(ClientConfig::default())
38+
.context("failed to create WebTransport endpoint")?;
39+
// TODO: Allow TLS configuration via runtime flags
40+
// TODO: Support WebPKI
41+
let conn = ep
42+
.connect(import)
43+
.await
44+
.context("failed to connect using WebTransport")?;
45+
crate::handle_run(
46+
wrpc_transport_web::Client::from(conn),
47+
(),
48+
*timeout,
49+
workload,
50+
)
51+
.await
52+
}
53+
54+
#[instrument(level = "trace", ret(level = "trace"))]
55+
pub async fn run(cmd: Command) -> anyhow::Result<()> {
56+
match cmd {
57+
Command::Run(args) => handle_run(args).await,
58+
// TODO: Implement serving
59+
}
60+
}

0 commit comments

Comments
 (0)