Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
715 changes: 648 additions & 67 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ members = [
"crates/metrics",
"crates/proto",
"crates/server",
"crates/web-frontend",
]

[workspace.lints.rust]
Expand Down
1 change: 1 addition & 0 deletions crates/server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ zbus = { version = "3", default-features = false, features = ["tokio"] }

hex = "0.4"
humansize = "2"
include_dir = "0.7"
lazy_static = "1"
mime = "0.3"
mime_guess = "2"
Expand Down
40 changes: 40 additions & 0 deletions crates/server/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use std::{
path::{Path, PathBuf},
process,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
let web_frontend_index_file_source =
[std::env::var("CARGO_MANIFEST_DIR")?.as_str(), "..", "web-frontend", "Cargo.toml"]
.into_iter()
.collect::<PathBuf>();

let web_frontend_dist_dir_path =
[std::env::var("OUT_DIR")?.as_str(), "frontend-dist"].into_iter().collect::<PathBuf>();

let web_frontend_index_file_path =
[web_frontend_dist_dir_path.as_path(), Path::new("index.html")]
.into_iter()
.collect::<PathBuf>();

match web_frontend_index_file_path.try_exists() {
Ok(false) | Err(_) => {
// NOTE: flag `--release` makes the build process stuck.
// FIXME: enable `--release`
let _result = process::Command::new("trunk")
.arg("build")
.arg("--frozen")
.arg("--locked")
.arg("--offline")
.arg("--public-url=/")
.arg(&format!("--dist={}", web_frontend_dist_dir_path.display()))
.arg(web_frontend_index_file_source)
.stdout(process::Stdio::piped())
.stderr(process::Stdio::piped())
.spawn()?
.wait_with_output()?;
Ok(())
}
_ => Ok(()),
}
}
5 changes: 5 additions & 0 deletions crates/server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::{future::Future, net::SocketAddr, path::PathBuf, pin::Pin};

use caracal_engine::{DownloaderFactory, TaskScheduler, MINIMUM_CHUNK_SIZE};
use futures::FutureExt;
use include_dir::include_dir;
use sigfinn::{ExitStatus, LifecycleManager, Shutdown};
use snafu::ResultExt;
use tokio::{
Expand All @@ -22,6 +23,9 @@ pub use self::{
};
use crate::metrics::Metrics;

pub static FRONTEND_STATIC_ASSETS_DIR: include_dir::Dir<'_> =
include_dir!("$OUT_DIR/frontend-dist");

/// # Errors
///
/// This function will return an error if the server fails to start.
Expand Down Expand Up @@ -234,6 +238,7 @@ fn create_web_server_future(

let router = axum::Router::new()
.merge(web::controller::api_v1_router())
.merge(web::controller::static_assets_router())
.layer(axum::Extension(task_scheduler))
.layer(middleware_stack)
.into_make_service_with_connect_info::<SocketAddr>();
Expand Down
7 changes: 6 additions & 1 deletion crates/server/src/web/controller/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
mod static_assets;
mod system;
mod task;

use axum::Router;
use axum::{routing, Router};

pub fn api_v1_router() -> Router {
Router::new().nest("/api", Router::new().merge(self::task::v1()).merge(self::system::v1()))
}

pub fn static_assets_router() -> Router {
Router::new().route("/*path", routing::get(static_assets::static_path))
}
28 changes: 28 additions & 0 deletions crates/server/src/web/controller/static_assets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use axum::{
body,
extract::Path,
response::{IntoResponse, Response},
};
use http::{header, HeaderValue, StatusCode};

pub async fn static_path(Path(path): Path<String>) -> impl IntoResponse {
let path = path.trim_start_matches('/');
let mime_type = mime_guess::from_path(path).first_or_text_plain();
crate::FRONTEND_STATIC_ASSETS_DIR.get_file(path).map_or_else(
|| {
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(body::Body::from(()))
.expect("building response with empty body should always success")
},
|file| {
let content_type =
HeaderValue::from_str(mime_type.as_ref()).expect("`mime_type` is valid string");
Response::builder()
.status(StatusCode::OK)
.header(header::CONTENT_TYPE, content_type)
.body(body::Body::from(file.contents()))
.expect("building response with such contents should always success")
},
)
}
20 changes: 20 additions & 0 deletions crates/web-frontend/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "caracal-web-frontend"
description = "Caracal Web Frontend"
version.workspace = true
authors.workspace = true
homepage.workspace = true
readme.workspace = true
repository.workspace = true
license.workspace = true
edition.workspace = true
categories.workspace = true
keywords.workspace = true

[dependencies]
gloo-net = "0.5"
wasm-bindgen-futures = "0.4"
yew = { version = "0.21", features = ["csr"] }

[lints]
workspace = true
9 changes: 9 additions & 0 deletions crates/web-frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Caracal - File Downloader</title>
</head>

<body></body>
</html>
27 changes: 27 additions & 0 deletions crates/web-frontend/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use gloo_net::http::Request;
use yew::prelude::*;

#[function_component]
fn App() -> Html {
let version = use_state(String::new);
{
let version = version.clone();
use_effect_with((), move |()| {
wasm_bindgen_futures::spawn_local(async move {
if let Ok(resp) = Request::get("/api/v1/system/version").send().await {
let fetched_version = resp.text().await.unwrap_or_default();
version.set(fetched_version);
}
});
|| ()
});
}

html! {
<div>
<p>{ format!("Caracal {}", version.as_str()) }</p>
</div>
}
}

fn main() { let _render = yew::Renderer::<App>::new().render(); }
4 changes: 4 additions & 0 deletions devshell/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ pkgs.mkShell {
cargo-nextest
rustToolchain

binaryen
trunk
wasm-bindgen-cli

tokei

protobuf
Expand Down
7 changes: 7 additions & 0 deletions devshell/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
, lib
, rustPlatform
, protobuf
, trunk
, binaryen
, wasm-bindgen-cli
, installShellFiles
}:

Expand All @@ -19,6 +22,10 @@ rustPlatform.buildRustPackage {
nativeBuildInputs = [
protobuf

binaryen
trunk
wasm-bindgen-cli

installShellFiles
];

Expand Down
2 changes: 2 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
stable.rust-src
stable.rust-std

targets.wasm32-unknown-unknown.stable.rust-std

default.rustfmt
];

Expand Down