Skip to content

Commit 4a95455

Browse files
committed
feat: embed static files in binary
1 parent 2dcbc04 commit 4a95455

3 files changed

Lines changed: 88 additions & 2 deletions

File tree

Cargo.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ edition = "2021"
99
chrono = { version = "0.4.38", features = ["serde"] }
1010
clap = { version = "4.5.6", features = ["derive"] }
1111
color-eyre = "0.6.3"
12+
include_dir = "0.7.3"
1213
rusqlite = { version = "0.31.0", features = ["bundled"] }
1314
serde = { version = "1.0.203", features = ["derive"] }
1415
serde_json = "1.0.117"

src/main.rs

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,80 @@ async fn main() -> color_eyre::Result<()> {
3636

3737
let api = warp::path("api")
3838
.and(handlers::routes(db))
39-
.recover(rejections::handle_rejection)
4039
.with(warp::cors().allow_any_origin());
40+
let homepage = warp::get().and_then(statics::homepage);
41+
let statics = statics::routes();
42+
43+
let routes = api
44+
.or(statics)
45+
.or(homepage)
46+
.recover(rejections::handle_rejection);
4147

4248
let address = args.address.parse::<std::net::SocketAddr>()?;
43-
warp::serve(api).run(address).await;
49+
warp::serve(routes).run(address).await;
4450

4551
Ok(())
4652
}
4753

54+
mod statics {
55+
use std::path::Path;
56+
57+
use include_dir::{include_dir, Dir};
58+
use warp::{
59+
http::{
60+
header::{CACHE_CONTROL, CONTENT_TYPE},
61+
Response,
62+
},
63+
Filter,
64+
};
65+
66+
static STATIC_DIR: Dir = include_dir!("ui/dist");
67+
68+
async fn send_file(path: warp::path::Tail) -> Result<impl warp::Reply, warp::Rejection> {
69+
let path = Path::new(path.as_str());
70+
let file = STATIC_DIR
71+
.get_file(path)
72+
.ok_or_else(warp::reject::not_found)?;
73+
74+
let content_type = match file.path().extension() {
75+
Some(ext) if ext == "css" => "text/css",
76+
Some(ext) if ext == "svg" => "image/svg+xml",
77+
Some(ext) if ext == "js" => "text/javascript",
78+
Some(ext) if ext == "html" => "text/html",
79+
_ => "application/octet-stream",
80+
};
81+
82+
let resp = Response::builder()
83+
.header(CONTENT_TYPE, content_type)
84+
.header(CACHE_CONTROL, "max-age=3600, must-revalidate")
85+
.body(file.contents())
86+
.unwrap();
87+
88+
Ok(resp)
89+
}
90+
91+
pub async fn homepage() -> Result<impl warp::Reply, warp::Rejection> {
92+
let file = STATIC_DIR
93+
.get_file("index.html")
94+
.ok_or_else(warp::reject::not_found)?;
95+
96+
let resp = Response::builder()
97+
.header(CONTENT_TYPE, "text/html")
98+
.header(CACHE_CONTROL, "max-age=3600, must-revalidate")
99+
.body(file.contents())
100+
.unwrap();
101+
102+
Ok(resp)
103+
}
104+
105+
pub fn routes() -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
106+
let index = warp::path::end().and_then(homepage);
107+
let other = warp::path::tail().and_then(send_file);
108+
109+
index.or(other)
110+
}
111+
}
112+
48113
#[derive(Clone)]
49114
struct TheDB {
50115
path: String,

0 commit comments

Comments
 (0)