diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..dbf0343 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git +.github +target diff --git a/Cargo.toml b/Cargo.toml index bd02366..3756211 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "waifu-calendar" version = "0.1.0" edition = "2021" +build = "build.rs" authors = ["Rosa Richter"] description = "A tool to fetch your favorite characters' birthdays from AniList" repository = "https://github.com/Cantido/waifu-calendar" @@ -18,7 +19,7 @@ name = "waifucal" required-features = ["cli"] [features] -default = ["cli"] +default = ["cli", "http"] http = [ "ics", "dep:axum", diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d30c7a9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +FROM docker.io/rust:1-slim-bullseye AS build +WORKDIR /app + +RUN apt update && apt upgrade && apt install -y pkg-config libssl-dev + +COPY src /app/src +COPY build.rs Cargo.toml Cargo.lock /app/ + +RUN cargo build --locked --release --features http +RUN cp ./target/release/waifu-server /bin/server + +FROM docker.io/debian:bullseye-slim AS final + +RUN apt update && apt upgrade && apt install -y ca-certificates curl && apt-get clean + +# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ +ARG UID=10001 +RUN adduser \ + --disabled-password \ + --gecos "" \ + --home "/nonexistent" \ + --shell "/sbin/nologin" \ + --no-create-home \ + --uid "${UID}" \ + appuser +USER appuser + +COPY --from=build /bin/server /bin/ + +COPY assets /usr/local/share/waifu/assets +COPY templates /usr/local/share/waifu/templates + +EXPOSE 8080 + +ENV WAIFU_ASSETS=/usr/local/share/waifu +ENV RUST_LOG=info + +CMD ["/bin/server"] diff --git a/fly.toml b/fly.toml new file mode 100644 index 0000000..a1b3ef3 --- /dev/null +++ b/fly.toml @@ -0,0 +1,22 @@ +# fly.toml app configuration file generated for waifu-calendar on 2024-01-20T21:55:32-07:00 +# +# See https://fly.io/docs/reference/configuration/ for information about how to use this file. +# + +app = "waifu-calendar" +primary_region = "ord" + +[build] + +[http_service] + internal_port = 8080 + force_https = true + auto_stop_machines = true + auto_start_machines = true + min_machines_running = 0 + processes = ["app"] + +[[vm]] + cpu_kind = "shared" + cpus = 1 + memory_mb = 1024 diff --git a/src/http.rs b/src/http.rs index 1f5a1ff..5b86569 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,7 +1,8 @@ -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, sync::Arc, path::PathBuf}; use axum::{Router, extract::{Query, State}, response::{Response, IntoResponse, Html}, http::{StatusCode, header}, routing::get}; use handlebars::{Handlebars, DirectorySourceOptions, to_json}; +use log::{info, error}; use moka::future::Cache; use recloser::{AsyncRecloser, Recloser}; use serde::Serialize; @@ -31,9 +32,14 @@ impl<'a> AppState<'a> { } pub fn router() -> Result { + let mut assets_path = PathBuf::new(); + assets_path.push(std::env::var("WAIFU_ASSETS").unwrap_or(".".to_string())); + + info!("Loading assets from {:?}", assets_path); + let mut handlebars = Handlebars::new(); handlebars.set_strict_mode(true); - handlebars.register_templates_directory("templates", DirectorySourceOptions::default())?; + handlebars.register_templates_directory(assets_path.join("templates"), DirectorySourceOptions::default())?; let circuit_breaker = AsyncRecloser::from(Recloser::default()); @@ -48,8 +54,8 @@ pub fn router() -> Result { let router = Router::new() .route("/", get(get_index)) - .route_service("/assets/pico.min.css", ServeFile::new("assets/pico.min.css")) - .route_service("/humans.txt", ServeFile::new("assets/humans.txt")) + .route_service("/assets/pico.min.css", ServeFile::new(assets_path.join("assets/pico.min.css"))) + .route_service("/humans.txt", ServeFile::new(assets_path.join("assets/humans.txt"))) .route("/ics", get(get_birthday_ics)) .route("/cal", get(get_birthday_html)) .with_state(Arc::new(AppState::new(cache, handlebars, circuit_breaker))); @@ -140,12 +146,43 @@ async fn get_birthday_html(State(state): State>>, Query(query): } else { state.circuit_breaker.call_with(should_melt, crate::get_waifu_birthdays(&username)).await } - .map_err(|_| { - let body = state.handlebars.render("user_not_found", &NoHandlebarsData {}).unwrap(); - ( - StatusCode::NOT_FOUND, - Html::from(body), - ).into_response() + .map_err(|e| { + match e { + recloser::Error::Inner(err) => { + match err.downcast::() { + Ok(crate::Error::UserNotFound(_)) => { + let body = state.handlebars.render("user_not_found", &NoHandlebarsData {}).unwrap(); + ( + StatusCode::NOT_FOUND, + Html::from(body), + ).into_response() + } + Err(err) => { + error!("Error contacting AniList: {:?}", err); + let body = state.handlebars.render("internal_server_error", &NoHandlebarsData {}).unwrap(); + ( + StatusCode::INTERNAL_SERVER_ERROR, + Html::from(body), + ).into_response() + } + Ok(crate::Error::BadResponse) => { + error!("Unknown error fetching from AniList"); + let body = state.handlebars.render("internal_server_error", &NoHandlebarsData {}).unwrap(); + ( + StatusCode::INTERNAL_SERVER_ERROR, + Html::from(body), + ).into_response() + } + } + } + recloser::Error::Rejected => { + let body = state.handlebars.render("internal_server_error", &NoHandlebarsData {}).unwrap(); + ( + StatusCode::INTERNAL_SERVER_ERROR, + Html::from(body), + ).into_response() + } + } })?; characters.sort_by_upcoming(&now); diff --git a/src/lib.rs b/src/lib.rs index 18b1acf..3355978 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -204,7 +204,7 @@ pub async fn get_waifu_birthdays(username: &str) -> Result> { let request_body = BirthdaysQuery::build_query(variables); let client = reqwest::Client::new(); - let res = client.post("https://graphql.anilist.co").json(&request_body).send().await?; + let res = client.post("https://graphql.anilist.co").header("User-Agent", "WaifuCalendar").json(&request_body).send().await?; let response_body: Response = res.json().await?; let data = response_body.data.ok_or(Error::BadResponse).with_context(|| "Missing response data")?; diff --git a/templates/index.hbs b/templates/index.hbs index a30f0f3..716c073 100644 --- a/templates/index.hbs +++ b/templates/index.hbs @@ -39,7 +39,7 @@ pre code { }

-http://localhost:8080/ics?username=Owldown
+https://waifu-calendar.fly.dev/ics?username=Owldown
 

Of course, replacing the username with your own username. @@ -48,7 +48,7 @@ http://localhost:8080/ics?username=Owldown