diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 54fea74..19f8f54 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -5,6 +5,10 @@ on: branches: [ "master" ] pull_request: branches: [ "master" ] + workflow_dispatch: + +permissions: + contents: write env: CARGO_TERM_COLOR: always @@ -14,90 +18,75 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt, clippy - - - uses: Swatinem/rust-cache@v2 - - - name: Check formatting - run: cargo fmt --all -- --check - - - name: Clippy - run: cargo clippy --all-targets --all-features + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 + - name: Check formatting + run: cargo fmt --all -- --check + - name: Clippy + run: cargo clippy --all-targets --all-features test: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + os: [ ubuntu-latest, windows-latest ] steps: - - uses: actions/checkout@v4 - - - uses: dtolnay/rust-toolchain@stable - - - uses: Swatinem/rust-cache@v2 - - - name: Run tests - run: cargo test --release + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - name: Run tests + run: cargo test --release build: - needs: [check, test] + needs: [ check, test ] runs-on: ${{ matrix.os }} strategy: matrix: include: + # --- Linux 64-bit --- - os: ubuntu-latest target: x86_64-unknown-linux-gnu artifact_name: rust_rest_api asset_name: rust_rest_api-linux-x86_64 + # --- Windows 64-bit --- - os: windows-latest target: x86_64-pc-windows-msvc artifact_name: rust_rest_api.exe asset_name: rust_rest_api-windows-x86_64.exe - - os: macos-latest - target: x86_64-apple-darwin - artifact_name: rust_rest_api - asset_name: rust_rest_api-macos-x86_64 - - os: macos-latest - target: aarch64-apple-darwin - artifact_name: rust_rest_api - asset_name: rust_rest_api-macos-aarch64 steps: - - uses: actions/checkout@v4 - - - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.target }} - - - uses: Swatinem/rust-cache@v2 - - - name: Build release binary - run: cargo build --release --target ${{ matrix.target }} - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.asset_name }} - path: target/${{ matrix.target }}/release/${{ matrix.artifact_name }} + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + - uses: Swatinem/rust-cache@v2 + - name: Build release binary + run: cargo build --release --target ${{ matrix.target }} + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.asset_name }} + path: target/${{ matrix.target }}/release/${{ matrix.artifact_name }} release: - if: startsWith(github.ref, 'refs/tags/') + if: github.ref == 'refs/heads/master' needs: build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - - - name: Create release - uses: softprops/action-gh-release@v1 - with: - files: artifacts/**/* - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: false + - name: Create draft release (nightly) + uses: softprops/action-gh-release@v1 + with: + draft: true + tag_name: nightly-${{ github.run_number }} + name: Nightly ${{ github.run_number }} + generate_release_notes: true + files: artifacts/**/* + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Cargo.lock b/Cargo.lock index 7bb44ee..0d963f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1169,12 +1169,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-range-header" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" - [[package]] name = "httparse" version = "1.10.1" @@ -2140,7 +2134,7 @@ dependencies = [ [[package]] name = "rust_rest_api" -version = "0.2.0" +version = "0.2.1" dependencies = [ "askama", "axum", @@ -2149,13 +2143,13 @@ dependencies = [ "dotenvy", "http", "migration", + "mime_guess", "once_cell", "rust-embed", "sea-orm", "serde", "serde_json", "tokio", - "tower-http", ] [[package]] @@ -3014,19 +3008,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-util" -version = "0.7.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - [[package]] name = "toml_datetime" version = "0.7.2" @@ -3073,32 +3054,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tower-http" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" -dependencies = [ - "bitflags", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-body-util", - "http-range-header", - "httpdate", - "mime", - "mime_guess", - "percent-encoding", - "pin-project-lite", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower-layer" version = "0.3.3" diff --git a/Cargo.toml b/Cargo.toml index 25f55f1..ada93b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust_rest_api" -version = "0.2.0" +version = "0.2.1" edition = "2024" license = "MIT" authors = ["Habibi-Dev"] @@ -22,8 +22,8 @@ sea-orm = { version = "1.1.16", features = ["sqlx-sqlite", "runtime-tokio-rustls once_cell = "1.21.3" rust-embed = "8.7.2" askama = { version = "0.14", features = ["full"] } -tower-http = { version = "0.6.6", features = ["fs"] } http = "1.3.1" +mime_guess = "2.0.5" [dependencies.migration] path = "./migration" diff --git a/src/services/routes.rs b/src/services/routes.rs index 666b75c..4ad6170 100644 --- a/src/services/routes.rs +++ b/src/services/routes.rs @@ -2,14 +2,20 @@ use crate::middleware::visit_event; use crate::services::index::index_handler; use crate::services::{AppState, country, health, ip, time}; use axum::routing::{MethodRouter, get}; -use axum::{Router, middleware}; -use std::path::PathBuf; -use tower_http::services::fs::ServeDir; +use axum::{Router, middleware, body::Body}; +use axum::extract::Path; +use axum::response::{IntoResponse, Response}; +use http::{header, StatusCode}; +use rust_embed::RustEmbed; + + +#[derive(RustEmbed)] +#[folder = "src/assets/"] +struct Assets; pub struct Routes; impl Routes { pub fn routes(app_state: AppState) -> Router { - let assets_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src/assets"); // routes that need state let stateful_routes = Router::new() @@ -26,7 +32,7 @@ impl Routes { Router::new() .merge(stateful_routes) .merge(health::routers(app_state.clone())) - .nest_service("/assets", ServeDir::new(assets_path)) + .route("/assets/{*path}", get(Self::serve_embedded_assets)) // Changed from /*path to /{*path} .nest("/api/v1", api) .route_layer(middleware::from_fn_with_state( app_state.clone(), @@ -41,4 +47,24 @@ impl Routes { } app } + + pub async fn serve_embedded_assets(Path(path): Path) -> impl IntoResponse { + let path = path.trim_start_matches('/'); + + match Assets::get(path) { + Some(content) => { + let mime = mime_guess::from_path(path).first_or_octet_stream(); + + Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_TYPE, mime.as_ref()) + .body(Body::from(content.data.to_vec())) + .unwrap() + } + None => Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::from("404 Not Found")) + .unwrap(), + } + } }