[web] Start work on a framework for serving static files

This commit is contained in:
Emi Simpson 2021-10-26 13:49:24 -04:00
parent 48dd31ec38
commit 9176a5a0b8
Signed by: Emi
GPG key ID: A12F2C2FFDC3D847
5 changed files with 75 additions and 3 deletions

View file

@ -21,4 +21,12 @@ lazy_static = { version = "1.4.0", optional = true }
# that supports OGP, the card will include a visual of their pronouns.
ogp_images = ["rusttype", "image", "lazy_static"]
default = ["ogp_images"]
# Several assets are unchanging static assets, which by default can be served directly
# from the binary. If so, these assets will be embeded into the binary and copied into
# memory when the binary runs. To improve performance, you may elect to serve these
# binaries using a webserver and reverse proxy. If you choose to do so, you may
# optionally disable this feature. Doing so will remove the --dump-static-assets feature
# flag, and will remove the ability to serve any static assets.
embed_static_assets = []
default = ["ogp_images", "embed_static_assets"]

View file

@ -1,5 +1,6 @@
pub mod ogp_images;
pub mod contrast;
pub mod statics;
use std::collections::HashMap;
use std::fmt::{self, Display};

View file

@ -1,6 +1,7 @@
#![cfg(feature = "ogp_images")]
use crate::contrast::generate_color_pair_rgba;
use crate::statics;
use image::{DynamicImage, ImageBuffer, Pixel, Rgb, Rgba};
use lazy_static::lazy_static;
@ -9,9 +10,8 @@ use rusttype::{Font, Scale, point};
const SCALE: u32 = 400;
const FONT_SCALE: f32 = 250.0;
const FONT_DATA: &[u8] = include_bytes!("../assets/LeagueGothic.otf");
lazy_static! {
static ref FONT: Font<'static> = Font::try_from_bytes(FONT_DATA)
static ref FONT: Font<'static> = Font::try_from_bytes(statics::FONT.bytes)
.expect("Invalid font data in build. This build and binary is invalid, and cannot be used.");
}

63
web/src/statics.rs Normal file
View file

@ -0,0 +1,63 @@
use actix_web::http::StatusCode;
use actix_web::HttpResponse;
use actix_web::HttpRequest;
use actix_web::web::resource;
use actix_web::Resource;
/// Represents a single static asset
///
/// Each asset is embeded into the binary, and can be served under the
/// `/static/{filename}` route. All static assets should be embeded in this way, and can
/// be referenced from this module.
pub struct StaticAsset {
/// The filename of this asset relative to `:/web/assets/` and the `/static/` route
pub filename: &'static str,
/// The content of the file
pub bytes: &'static [u8],
}
impl StaticAsset {
/// Generate a actix resource for serving this asset
///
/// The resource will handle requests at `/static/{filename}`. Caching headers are
/// applied to allow the content to be considered fresh up to one day, and are
/// validated against the crate version after that.
pub fn generate_resource(&self) -> Resource {
let bytes = self.bytes;
resource(self.filename).to(move|req: HttpRequest| async move {
let mut response = HttpResponse::Ok();
response
.header("Etag", env!("CARGO_PKG_VERSION"))
.header("Cache-Control", "max-age=86400");
let req_etag = req.headers().get("If-None-Match");
match req_etag {
Some(etag) if etag == env!("CARGO_PKG_VERSION") => {
response.status(StatusCode::from_u16(304).unwrap()).finish()
}
_ => {
response.body(bytes)
}
}
})
}
}
/// Generate a [`StaticAsset`] at compiletime from a filename.
#[cfg(any(feature = "embed_static_assets", feature = "ogp_images"))]
macro_rules! static_asset {
( $filename: expr ) => {
StaticAsset {
filename: concat!("../assets/", $filename),
bytes: include_bytes!(concat!("../assets/", $filename)),
}
}
}
/// The decorative font to be used for pronouns displayed at a very large size
#[cfg(any(feature = "embed_static_assets", feature = "ogp_images"))]
pub const FONT: StaticAsset = static_asset!("font.otf");