use std::collections::HashMap;
use std::sync::OnceLock;
static PACK_ZST: &[u8] = include_bytes!("../../../bench/webui/app/1.18.31.pack.zst");
pub const APP_TAG: &str = "1.18.31";
static FILES: OnceLock<HashMap<String, Vec<u8>>> = OnceLock::new();
fn files() -> &'static HashMap<String, Vec<u8>> {
FILES.get_or_init(|| {
let raw = match zstd::stream::decode_all(PACK_ZST) {
Ok(r) => r,
Err(e) => {
tracing::warn!("embedded UI pack: zstd decode failed: {e:#}");
return HashMap::new();
}
};
parse_pack(&raw).unwrap_or_else(|e| {
tracing::warn!("embedded UI pack: parse failed: {e}");
HashMap::new()
})
})
}
fn parse_pack(raw: &[u8]) -> Result<HashMap<String, Vec<u8>>, String> {
if raw.len() < 6 || &raw[..6] != b"OCAP1\n" {
return Err("bad magic".into());
}
let mut i = 6usize;
let count = read_u32(raw, &mut i)? as usize;
let mut map = HashMap::with_capacity(count);
for _ in 0..count {
let plen = read_u16(raw, &mut i)? as usize;
if i + plen > raw.len() {
return Err("path overruns".into());
}
let path = String::from_utf8(raw[i..i + plen].to_vec()).map_err(|_| "bad path utf8")?;
i += plen;
let dlen = read_u64(raw, &mut i)? as usize;
if i + dlen > raw.len() {
return Err("data overruns".into());
}
let data = raw[i..i + dlen].to_vec();
i += dlen;
map.insert(path, data);
}
Ok(map)
}
fn read_u16(b: &[u8], i: &mut usize) -> Result<u16, String> {
if *i + 2 > b.len() {
return Err("eof u16".into());
}
let v = u16::from_le_bytes([b[*i], b[*i + 1]]);
*i += 2;
Ok(v)
}
fn read_u32(b: &[u8], i: &mut usize) -> Result<u32, String> {
if *i + 4 > b.len() {
return Err("eof u32".into());
}
let v = u32::from_le_bytes([b[*i], b[*i + 1], b[*i + 2], b[*i + 3]]);
*i += 4;
Ok(v)
}
fn read_u64(b: &[u8], i: &mut usize) -> Result<u64, String> {
if *i + 8 > b.len() {
return Err("eof u64".into());
}
let v = u64::from_le_bytes(b[*i..*i + 8].try_into().map_err(|_| "u64")?);
*i += 8;
Ok(v)
}
pub fn available() -> bool {
!files().is_empty()
}
pub fn lookup(path: &str) -> Option<(&'static str, &'static [u8])> {
let map = files();
let key = path.trim_start_matches('/');
if let Some((k, data)) = map.get_key_value(key) {
return Some((k.as_str(), data));
}
if !path.starts_with("/assets/")
&& let Some(data) = map.get("index.html")
{
return Some(("index.html", data));
}
None
}
pub fn mime_for(path: &str) -> &'static str {
let p = path.split('?').next().unwrap_or(path);
match p.rsplit('.').next().unwrap_or("") {
"html" => "text/html",
"js" | "mjs" => "text/javascript",
"css" => "text/css",
"json" | "webmanifest" => "application/json",
"svg" => "image/svg+xml",
"png" => "image/png",
"ico" => "image/x-icon",
"ttf" => "font/ttf",
"woff" => "font/woff",
"woff2" => "font/woff2",
"mp4" => "video/mp4",
"wasm" => "application/wasm",
"txt" => "text/plain",
_ => "application/octet-stream",
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pack_parses_and_has_entrypoints() {
assert!(available(), "embedded pack did not parse");
let map = files();
assert!(map.contains_key("index.html"), "no index.html");
assert!(
map.keys()
.any(|k| k.starts_with("assets/index-") && k.ends_with(".js")),
"no entry JS"
);
}
#[test]
fn spa_fallback_only_for_non_assets() {
let (resolved, idx) = lookup("/some/spa/route").expect("spa fallback");
assert_eq!(resolved, "index.html");
assert!(String::from_utf8_lossy(idx).contains("<"));
assert!(lookup("/assets/does-not-exist-xyz.js").is_none());
}
#[test]
fn mime_table() {
assert_eq!(mime_for("/assets/index-abc.js"), "text/javascript");
assert_eq!(mime_for("/assets/index-abc.css"), "text/css");
assert_eq!(mime_for("/assets/font.woff2"), "font/woff2");
assert_eq!(mime_for("/"), "application/octet-stream");
assert_eq!(mime_for("/index.html"), "text/html");
}
}