diff --git a/crates/engram-server/Cargo.toml b/crates/engram-server/Cargo.toml index 5edada8..80d32f6 100644 --- a/crates/engram-server/Cargo.toml +++ b/crates/engram-server/Cargo.toml @@ -16,6 +16,8 @@ axum = { version = "0.7", features = ["json"] } tokio = { version = "1", features = ["full"] } tower = "0.4" tower-http = { version = "0.5", features = ["cors", "fs"] } +rust-embed = { version = "8", features = ["axum"] } +mime_guess = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" uuid = { version = "1", features = ["v4", "serde"] } diff --git a/crates/engram-server/src/main.rs b/crates/engram-server/src/main.rs index 7825301..1f49645 100644 --- a/crates/engram-server/src/main.rs +++ b/crates/engram-server/src/main.rs @@ -28,17 +28,58 @@ use std::sync::{Arc, Mutex}; use std::time::Duration; use axum::{ + body::Body, + http::{header, StatusCode}, middleware, + response::{IntoResponse, Response}, routing::{delete, get, post}, Router, }; use engram_core::EngramDb; use engram_sync::{SyncConfig, SyncEngine}; +use mime_guess::from_path; +use rust_embed::RustEmbed; use tokio::time::interval; use tower_http::cors::CorsLayer; use tracing::info; use tracing_subscriber::EnvFilter; +#[derive(RustEmbed)] +#[folder = "../../studio/"] +struct Studio; + +async fn serve_studio_index() -> impl IntoResponse { + match Studio::get("index.html") { + Some(content) => Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_TYPE, "text/html; charset=utf-8") + .body(Body::from(content.data.into_owned())) + .unwrap(), + None => Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::from("Studio not found")) + .unwrap(), + } +} + +async fn serve_studio_asset(uri: axum::extract::Path) -> impl IntoResponse { + let path = uri.0; + match Studio::get(&path) { + Some(content) => { + let mime = from_path(&path).first_or_octet_stream(); + Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_TYPE, mime.as_ref()) + .body(Body::from(content.data.into_owned())) + .unwrap() + } + None => Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::from("Not found")) + .unwrap(), + } +} + mod auth; mod routes; mod state; @@ -151,7 +192,13 @@ async fn main() -> anyhow::Result<()> { .route("/decay", post(routes::core::decay)) .route("/consolidate", post(routes::core::consolidate)); + let studio_routes = Router::new() + .route("/", get(serve_studio_index)) + .route("/studio", get(serve_studio_index)) + .route("/studio/{*path}", get(serve_studio_asset)); + let app = Router::new() + .merge(studio_routes) .merge(core_routes) .merge(sync_routes) .layer(CorsLayer::permissive())