2 Commits

Author SHA1 Message Date
b5a8cf91f4 feat: add workflows for testing, linting, compiling 2025-07-10 19:41:21 -05:00
5af4e3b9b7 feat: add favicon.png route 2025-07-10 19:09:00 -05:00
4 changed files with 167 additions and 2 deletions

121
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,121 @@
name: CI
on:
push:
branches: [master, develop]
pull_request:
branches: [master, develop]
env:
CARGO_TERM_COLOR: always
jobs:
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-index-
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-target-
- name: Run clippy
run: cargo clippy --all-targets --all-features -- -D warnings
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-index-
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-target-
- name: Run tests
run: cargo test --verbose
build:
name: Build (Linux Debug)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-index-
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-target-
- name: Build project
run: cargo build --verbose

22
.github/workflows/format.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Format Check
on:
push:
branches: [master, develop]
pull_request:
branches: [master, develop]
jobs:
format:
name: Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check

View File

@@ -1,8 +1,8 @@
use std::net::SocketAddr;
use crate::routes::{
absolute_handler, fallback_handler, favicon_handler, implicit_handler, index_handler,
relative_handler,
absolute_handler, fallback_handler, favicon_handler, favicon_png_handler, implicit_handler,
index_handler, relative_handler,
};
use axum::{http::HeaderValue, response::Response, routing::get, Router};
use config::Configuration;
@@ -36,6 +36,7 @@ async fn main() {
let app = Router::new()
.route("/", get(index_handler))
.route("/favicon.ico", get(favicon_handler))
.route("/favicon.png", get(favicon_png_handler))
.route("/{path}", get(implicit_handler))
.route("/rel/{path}", get(relative_handler))
.route("/relative/{path}", get(relative_handler))

View File

@@ -83,6 +83,27 @@ pub async fn favicon_handler(ConnectInfo(addr): ConnectInfo<SocketAddr>) -> impl
}
}
/// Handles `/favicon.png` - generates a dynamic clock favicon showing the current time.
///
/// Logs the client IP address and returns a PNG image of an analog clock.
pub async fn favicon_png_handler(ConnectInfo(addr): ConnectInfo<SocketAddr>) -> impl IntoResponse {
let now = chrono::Utc::now();
// Log the IP address for the favicon request
tracing::info!("Favicon PNG request from IP: {}", addr.ip());
// Generate PNG bytes directly
match generate_favicon_png_bytes(now) {
Ok(png_bytes) => (
StatusCode::OK,
[(header::CONTENT_TYPE, "image/png")],
png_bytes,
)
.into_response(),
Err(e) => get_error_response(e).into_response(),
}
}
/// Fallback handler for unmatched routes.
pub async fn fallback_handler() -> impl IntoResponse {
get_error_response(TimeBannerError::NotFound).into_response()