Skip to content

Commit 68c6e20

Browse files
committed
feat: Basic Runtime demos
1 parent e4bb2ce commit 68c6e20

File tree

31 files changed

+486
-119
lines changed

31 files changed

+486
-119
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
[workspace]
22
members = [
3-
"rust/example-crate",
43
"rust/usuba",
54
"rust/usuba-compat"
65
]
@@ -14,6 +13,7 @@ async-trait = { version = "0.1" }
1413
axum = { version = "0.7" }
1514
blake3 = { version = "1.5" }
1615
bytes = { version = "1" }
16+
hyper-util = { version = "0.1", features = ["client", "client-legacy"] }
1717
js-component-bindgen = { version = "1", features = ["transpile-bindgen"] }
1818
js-sys = { version = "0.3" }
1919
mime_guess = { version = "2" }
@@ -24,6 +24,7 @@ serde_json = { version = "1" }
2424
tempfile = { version = "3" }
2525
thiserror = { version = "1" }
2626
tokio = { version = "1" }
27+
tower-http = { version = "0.5" }
2728
tracing = { version = "0.1" }
2829
tracing-subscriber = { version = "0.3", features = ["env-filter", "tracing-log", "json"] }
2930
tracing-web = { version = "0.1" }
@@ -37,4 +38,4 @@ wit-parser = { version = "0.208" }
3738

3839
[profile.release]
3940
opt-level = 'z'
40-
lto = true
41+
lto = true

rust/usuba/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ async-trait = { workspace = true }
1212
axum = { workspace = true, features = ["multipart"] }
1313
blake3 = { workspace = true }
1414
bytes = { workspace = true }
15+
hyper-util = { workspace = true }
1516
mime_guess = { workspace = true }
1617
redb = { workspace = true }
1718
rust-embed = { workspace = true }
@@ -20,6 +21,7 @@ serde_json = { workspace = true }
2021
tempfile = { workspace = true }
2122
thiserror = { workspace = true }
2223
tokio = { workspace = true, features = ["rt-multi-thread", "io-util", "process", "fs"] }
24+
tower-http = { workspace = true, features = ["cors"] }
2325
tracing = { workspace = true }
2426
tracing-subscriber = { workspace = true }
2527
utoipa = { workspace = true, features = ["axum_extras"] }

rust/usuba/src/bake/bake.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ pub trait Bake {
99
world: &str,
1010
wit: Vec<Bytes>,
1111
source_code: Bytes,
12+
library: Vec<Bytes>,
1213
) -> Result<Bytes, UsubaError>;
1314
}

rust/usuba/src/bake/javascript.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ impl Bake for JavaScriptBaker {
3232
world: &str,
3333
wit: Vec<Bytes>,
3434
source_code: Bytes,
35+
library: Vec<Bytes>,
3536
) -> Result<Bytes, crate::UsubaError> {
3637
let workspace = TempDir::new()?;
3738
debug!(
@@ -44,12 +45,22 @@ impl Bake for JavaScriptBaker {
4445

4546
debug!(?workspace, "Created temporary workspace");
4647

48+
let wit_path = workspace.path().join("wit");
49+
let wit_deps_path = wit_path.join("deps");
50+
51+
tokio::fs::create_dir_all(&wit_deps_path).await?;
52+
4753
let mut writes = JoinSet::new();
4854

4955
wit.into_iter()
5056
.enumerate()
51-
.map(|(i, wit)| write_file(workspace.path().join(format!("module{}.wit", i)), wit))
57+
.map(|(i, wit)| write_file(wit_path.join(format!("module{}.wit", i)), wit))
5258
.chain([write_file(js_path.clone(), source_code)])
59+
.chain(
60+
library.into_iter().enumerate().map(|(i, wit)| {
61+
write_file(wit_deps_path.join(format!("library{}.wit", i)), wit)
62+
}),
63+
)
5364
.for_each(|fut| {
5465
writes.spawn(fut);
5566
});
@@ -66,7 +77,7 @@ impl Bake for JavaScriptBaker {
6677
command
6778
.arg("componentize")
6879
.arg("-w")
69-
.arg(workspace.path())
80+
.arg(wit_path)
7081
.arg("-o")
7182
.arg(wasm_path.display().to_string())
7283
.arg(js_path.display().to_string());

rust/usuba/src/bake/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,14 @@ impl Bake for Baker {
1818
world: &str,
1919
wit: Vec<Bytes>,
2020
source_code: Bytes,
21+
library: Vec<Bytes>,
2122
) -> Result<Bytes, crate::UsubaError> {
2223
match self {
23-
Baker::JavaScript => (JavaScriptBaker {}).bake(world, wit, source_code).await,
24+
Baker::JavaScript => {
25+
(JavaScriptBaker {})
26+
.bake(world, wit, source_code, library)
27+
.await
28+
}
2429
}
2530
}
2631
}

rust/usuba/src/bin/usuba.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@ pub async fn main() -> Result<(), UsubaError> {
1717
let port = std::option_env!("PORT").unwrap_or("8080");
1818
let socket_address: SocketAddr = format!("0.0.0.0:{port}").parse()?;
1919
let listener = tokio::net::TcpListener::bind(socket_address).await?;
20+
let upstream = std::option_env!("UPSTREAM")
21+
.map(|upstream| upstream.parse().ok())
22+
.unwrap_or(None);
2023

2124
info!("Server listening on {}", socket_address);
25+
if let Some(upstream) = &upstream {
26+
info!("Reverse proxying requests to {}", upstream);
27+
}
2228

23-
serve(listener).await?;
29+
serve(listener, upstream).await?;
2430

2531
Ok(())
2632
}

rust/usuba/src/error.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
// use std::fmt::Display;
22

3-
use axum::{extract::multipart::MultipartError, http::StatusCode, response::IntoResponse, Json};
3+
use axum::{
4+
extract::multipart::MultipartError,
5+
http::{uri::InvalidUri, StatusCode},
6+
response::IntoResponse,
7+
Json,
8+
};
49
use blake3::HexError;
510
use redb::{CommitError, DatabaseError, StorageError, TableError, TransactionError};
611
use serde::{Deserialize, Serialize};
@@ -21,6 +26,8 @@ pub enum UsubaError {
2126
InvalidModule(String),
2227
#[error("Module not found")]
2328
ModuleNotFound,
29+
#[error("Upstream request failed: {0}")]
30+
UpstreamError(String),
2431
#[error("An internal error occurred")]
2532
Internal(String),
2633
}
@@ -100,7 +107,20 @@ impl From<JoinError> for UsubaError {
100107

101108
impl From<anyhow::Error> for UsubaError {
102109
fn from(value: anyhow::Error) -> Self {
103-
todo!()
110+
UsubaError::Internal(format!("{}", value))
111+
}
112+
}
113+
114+
impl From<hyper_util::client::legacy::Error> for UsubaError {
115+
fn from(value: hyper_util::client::legacy::Error) -> Self {
116+
UsubaError::UpstreamError(format!("{}", value))
117+
}
118+
}
119+
120+
impl From<InvalidUri> for UsubaError {
121+
fn from(value: InvalidUri) -> Self {
122+
warn!("{}", value);
123+
UsubaError::BadRequest
104124
}
105125
}
106126

@@ -113,6 +133,7 @@ impl IntoResponse for UsubaError {
113133
UsubaError::InvalidConfiguration(_) => StatusCode::BAD_REQUEST,
114134
UsubaError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
115135
UsubaError::ModuleNotFound => StatusCode::NOT_FOUND,
136+
UsubaError::UpstreamError(_) => StatusCode::BAD_GATEWAY,
116137
};
117138

118139
(

rust/usuba/src/routes/module/build.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,12 @@ impl IntoResponse for BuildModuleResponse {
4242
)
4343
)]
4444
pub async fn build_module(
45-
State(UsubaState { mut storage }): State<UsubaState>,
45+
State(UsubaState { mut storage, .. }): State<UsubaState>,
4646
mut form_data: Multipart,
4747
) -> Result<BuildModuleResponse, UsubaError> {
4848
let mut world_name: Option<String> = None;
4949
let mut wit: Vec<Bytes> = Vec::new();
50+
let mut library: Vec<Bytes> = Vec::new();
5051
let mut source_code: Option<Bytes> = None;
5152
let mut baker: Option<Baker> = None;
5253

@@ -89,7 +90,7 @@ pub async fn build_module(
8990
}
9091
}
9192
Some("library") => {
92-
wit.push(field.bytes().await?);
93+
library.push(field.bytes().await?);
9394
}
9495
Some(name) => warn!("Unexpected multipart content: {name}"),
9596
_ => warn!("Skipping unnamed multipart content"),
@@ -98,7 +99,7 @@ pub async fn build_module(
9899
}
99100

100101
if let (Some(world_name), Some(source_code), Some(baker)) = (world_name, source_code, baker) {
101-
let wasm = baker.bake(&world_name, wit, source_code).await?;
102+
let wasm = baker.bake(&world_name, wit, source_code, library).await?;
102103
let hash = storage.write(wasm).await?;
103104

104105
Ok(BuildModuleResponse {

rust/usuba/src/routes/module/retrieve.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{HashStorage, UsubaError, UsubaState};
1515
)
1616
)]
1717
pub async fn retrieve_module(
18-
State(UsubaState { storage }): State<UsubaState>,
18+
State(UsubaState { storage, .. }): State<UsubaState>,
1919
Path((id,)): Path<(String,)>,
2020
) -> Result<Bytes, UsubaError> {
2121
let hash = Hash::from_str(&id)?;

0 commit comments

Comments
 (0)