-
Notifications
You must be signed in to change notification settings - Fork 9
feat: Implement basic Module Build Server #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
cdata
merged 9 commits into
rfc/on-demand-isolated-components
from
feat/on-demand-isolated-components/build-server
May 23, 2024
Merged
Changes from 1 commit
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
de74b10
feat: Implement basic Module Build Server
cdata 29091c3
cleanup: Remove vestigial file
cdata d9f571d
feat: On-demand Isolated Modules SW polyfill
cdata b0bc8f2
fix: Specify logging in Cloud Build
cdata d41a44f
fix: Correct builder scheme in Cloud Build config
cdata 2f3cba8
fix: Specific Cloud Run deploy at end of build
cdata 9c13e80
fix: Listen on all interfaces
cdata aae56e8
feat: Add a simple UI to the build server
cdata 5f50018
Merge pull request #11 from commontoolsinc/feat/on-demand-isolated-co…
cdata File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| [package] | ||
| name = "usuba" | ||
| description = "An anything-to-Common-Wasm build server" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
|
|
||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
|
||
| [dependencies] | ||
| async-trait = { workspace = true } | ||
| axum = { workspace = true, features = ["multipart"] } | ||
| blake3 = { workspace = true } | ||
| bytes = { workspace = true } | ||
| redb = { workspace = true } | ||
| serde = { workspace = true } | ||
| serde_json = { workspace = true } | ||
| tempfile = { workspace = true } | ||
| thiserror = { workspace = true } | ||
| tokio = { workspace = true, features = ["rt-multi-thread", "io-util", "process", "fs"] } | ||
| tracing = { workspace = true } | ||
| tracing-subscriber = { workspace = true } | ||
| utoipa = { workspace = true, features = ["axum_extras"] } | ||
| utoipa-swagger-ui = { workspace = true, features = ["axum"] } | ||
| # gcloud-sdk = { version = "0.24.6", features = ["google-cloud-aiplatform-v1"] } | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| FROM rust:1.75 as builder | ||
|
|
||
| WORKDIR /build-root | ||
|
|
||
| COPY "./Cargo.toml" "./Cargo.lock" ./ | ||
| COPY ./rust ./rust | ||
| RUN cargo build --release --bin usuba | ||
|
|
||
| FROM node:latest | ||
|
|
||
| WORKDIR /usuba | ||
|
|
||
| EXPOSE 8888 | ||
|
|
||
| RUN apt-get update && apt-get install -y libssl-dev ca-certificates | ||
| RUN npm install -g @bytecodealliance/jco | ||
|
|
||
| COPY --from=builder /build-root/target/release/usuba /usr/bin/usuba | ||
|
|
||
| ENV RUST_LOG="debug" | ||
|
|
||
| ENTRYPOINT ["/usr/bin/usuba"] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Usuba | ||
|
|
||
| An anything-to-Common-Wasm build server. | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| use crate::UsubaError; | ||
| use async_trait::async_trait; | ||
| use bytes::Bytes; | ||
|
|
||
| #[async_trait] | ||
| pub trait Bake { | ||
| async fn bake(&self, wit: Bytes, source_code: Bytes) -> Result<Bytes, UsubaError>; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| use std::io::Cursor; | ||
| use tracing::instrument; | ||
|
|
||
| use super::Bake; | ||
| use async_trait::async_trait; | ||
| use bytes::Bytes; | ||
| use tempfile::TempDir; | ||
|
|
||
| use tokio::process::Command; | ||
|
|
||
| #[derive(Debug)] | ||
| pub struct JavaScriptBaker {} | ||
|
|
||
| #[async_trait] | ||
| impl Bake for JavaScriptBaker { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧑🍳 |
||
| #[instrument] | ||
| async fn bake(&self, wit: Bytes, source_code: Bytes) -> Result<Bytes, crate::UsubaError> { | ||
| let workspace = TempDir::new()?; | ||
| debug!( | ||
| "Created temporary workspace in {}", | ||
| workspace.path().display() | ||
| ); | ||
|
|
||
| let wasm_path = workspace.path().join("module.wasm"); | ||
| let js_path = workspace.path().join("module.js"); | ||
| let wit_path = workspace.path().join("module.wit"); | ||
|
|
||
| let (mut wit_file, mut js_file) = tokio::try_join!( | ||
| tokio::fs::File::create(&wit_path), | ||
| tokio::fs::File::create(&js_path), | ||
| )?; | ||
|
|
||
| debug!(?wit_path, ?js_path, "Created temporary input files"); | ||
|
|
||
| let mut wit_cursor = Cursor::new(wit); | ||
| let mut js_cursor = Cursor::new(source_code); | ||
|
|
||
| tokio::try_join!( | ||
| tokio::io::copy(&mut wit_cursor, &mut wit_file), | ||
| tokio::io::copy(&mut js_cursor, &mut js_file), | ||
| )?; | ||
|
|
||
| debug!(?wit_path, ?js_path, "Populated temporary input files"); | ||
|
|
||
| let mut command = Command::new("jco"); | ||
|
|
||
| command | ||
| .arg("componentize") | ||
| .arg("-w") | ||
| .arg(wit_path.display().to_string()) | ||
| .arg("-o") | ||
| .arg(wasm_path.display().to_string()) | ||
| .arg(js_path.display().to_string()); | ||
|
|
||
| let child = command.spawn()?; | ||
| let output = child.wait_with_output().await?; | ||
|
|
||
| if output.stderr.len() > 0 { | ||
| warn!("{}", String::from_utf8_lossy(&output.stderr)); | ||
| } | ||
|
|
||
| debug!("Finished building with jco"); | ||
|
|
||
| let wasm_bytes = tokio::fs::read(&wasm_path).await?; | ||
|
|
||
| Ok(wasm_bytes.into()) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| mod bake; | ||
| mod javascript; | ||
|
|
||
| pub use bake::*; | ||
| pub use javascript::*; | ||
|
|
||
| use async_trait::async_trait; | ||
| use bytes::Bytes; | ||
|
|
||
| pub enum Baker { | ||
| JavaScript, | ||
| } | ||
|
|
||
| #[async_trait] | ||
| impl Bake for Baker { | ||
| async fn bake(&self, wit: Bytes, source_code: Bytes) -> Result<Bytes, crate::UsubaError> { | ||
| match self { | ||
| Baker::JavaScript => (JavaScriptBaker {}).bake(wit, source_code).await, | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| #[macro_use] | ||
| extern crate tracing; | ||
|
|
||
| use std::net::SocketAddr; | ||
|
|
||
| use tracing::Level; | ||
| use tracing_subscriber::{fmt::Layer, layer::SubscriberExt, FmtSubscriber}; | ||
| use usuba::{serve, UsubaError}; | ||
|
|
||
| #[tokio::main] | ||
| pub async fn main() -> Result<(), UsubaError> { | ||
| let subscriber = FmtSubscriber::builder() | ||
| .with_max_level(Level::TRACE) | ||
| .finish(); | ||
| tracing::subscriber::set_global_default(subscriber.with(Layer::default().pretty()))?; | ||
|
|
||
| let socket_address: SocketAddr = "127.0.0.1:8080".parse()?; | ||
| let listener = tokio::net::TcpListener::bind(socket_address).await?; | ||
|
|
||
| info!("Server listening on {}", socket_address); | ||
|
|
||
| serve(listener).await?; | ||
|
|
||
| Ok(()) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| // use std::fmt::Display; | ||
|
|
||
| use axum::{extract::multipart::MultipartError, http::StatusCode, response::IntoResponse, Json}; | ||
| use blake3::HexError; | ||
| use redb::{CommitError, DatabaseError, StorageError, TableError, TransactionError}; | ||
| use serde::{Deserialize, Serialize}; | ||
| use thiserror::Error; | ||
| use tracing::subscriber::SetGlobalDefaultError; | ||
| use utoipa::ToSchema; | ||
|
|
||
| #[derive(Debug, Error)] | ||
| pub enum UsubaError { | ||
| #[error("Bad request body")] | ||
| BadRequest, | ||
| #[error("Failed to bake the module: {0}")] | ||
| BakeFailure(String), | ||
| #[error("Invalid configuration: {0}")] | ||
| InvalidConfiguration(String), | ||
| #[error("Module not found")] | ||
| ModuleNotFound, | ||
| #[error("An internal error occurred")] | ||
| Internal(String), | ||
| } | ||
|
|
||
| impl From<std::net::AddrParseError> for UsubaError { | ||
| fn from(value: std::net::AddrParseError) -> Self { | ||
| UsubaError::InvalidConfiguration(format!("{}", value)) | ||
| } | ||
| } | ||
|
|
||
| impl From<std::io::Error> for UsubaError { | ||
| fn from(value: std::io::Error) -> Self { | ||
| error!("{}", value); | ||
| UsubaError::Internal(format!("{}", value)) | ||
| } | ||
| } | ||
|
|
||
| impl From<MultipartError> for UsubaError { | ||
| fn from(_value: MultipartError) -> Self { | ||
| UsubaError::BadRequest | ||
| } | ||
| } | ||
|
|
||
| impl From<SetGlobalDefaultError> for UsubaError { | ||
| fn from(value: SetGlobalDefaultError) -> Self { | ||
| error!("{}", value); | ||
| UsubaError::Internal(format!("{}", value)) | ||
| } | ||
| } | ||
|
|
||
| impl From<StorageError> for UsubaError { | ||
| fn from(value: StorageError) -> Self { | ||
| error!("{}", value); | ||
| UsubaError::ModuleNotFound | ||
| } | ||
| } | ||
|
|
||
| impl From<TransactionError> for UsubaError { | ||
| fn from(value: TransactionError) -> Self { | ||
| error!("{}", value); | ||
| UsubaError::Internal(format!("{}", value)) | ||
| } | ||
| } | ||
|
|
||
| impl From<TableError> for UsubaError { | ||
| fn from(value: TableError) -> Self { | ||
| error!("{}", value); | ||
| UsubaError::Internal(format!("{}", value)) | ||
| } | ||
| } | ||
|
|
||
| impl From<CommitError> for UsubaError { | ||
| fn from(value: CommitError) -> Self { | ||
| error!("{}", value); | ||
| UsubaError::Internal(format!("{}", value)) | ||
| } | ||
| } | ||
|
|
||
| impl From<DatabaseError> for UsubaError { | ||
| fn from(value: DatabaseError) -> Self { | ||
| error!("{}", value); | ||
| UsubaError::Internal(format!("{}", value)) | ||
| } | ||
| } | ||
|
|
||
| impl From<HexError> for UsubaError { | ||
| fn from(_value: HexError) -> Self { | ||
| UsubaError::BadRequest | ||
| } | ||
| } | ||
|
|
||
| impl IntoResponse for UsubaError { | ||
| fn into_response(self) -> axum::response::Response { | ||
| let status = match self { | ||
| UsubaError::BadRequest => StatusCode::BAD_REQUEST, | ||
| UsubaError::BakeFailure(_) => StatusCode::INTERNAL_SERVER_ERROR, | ||
| UsubaError::InvalidConfiguration(_) => StatusCode::BAD_REQUEST, | ||
| UsubaError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, | ||
| UsubaError::ModuleNotFound => StatusCode::NOT_FOUND, | ||
| }; | ||
|
|
||
| ( | ||
| status, | ||
| Json(ErrorResponse { | ||
| error: self.to_string(), | ||
| }), | ||
| ) | ||
| .into_response() | ||
| } | ||
| } | ||
|
|
||
| #[derive(Serialize, Deserialize, ToSchema)] | ||
| pub struct ErrorResponse { | ||
| error: String, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| #[macro_use] | ||
| extern crate tracing; | ||
|
|
||
| mod bake; | ||
| mod error; | ||
| pub mod openapi; | ||
| pub mod routes; | ||
| mod serve; | ||
| mod storage; | ||
|
|
||
| pub use bake::*; | ||
| pub use error::*; | ||
| pub use serve::*; | ||
| pub use storage::*; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| use utoipa::OpenApi; | ||
|
|
||
| use crate::{ | ||
| routes::{BuildModuleRequest, BuildModuleResponse}, | ||
| ErrorResponse, | ||
| }; | ||
|
|
||
| #[derive(OpenApi)] | ||
| #[openapi( | ||
| paths(crate::routes::build_module, crate::routes::retrieve_module), | ||
| components( | ||
| schemas(BuildModuleResponse), | ||
| schemas(ErrorResponse), | ||
| schemas(BuildModuleRequest) | ||
| ) | ||
| )] | ||
| pub struct OpenApiDocs; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
8080is used elsewhere