static_filez/
site.rs

1use std::fs::File;
2use std::path::Path;
3use std::result::Result;
4
5use quicli::prelude::*;
6
7use fst::Map;
8use memmap::Mmap;
9
10use slice;
11
12pub struct Site {
13    index: Map,
14    archive: Mmap,
15}
16
17impl Site {
18    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Site, Error> {
19        let path = path.as_ref();
20        let index_path = path.with_extension("index");
21        let archive_path = path.with_extension("archive");
22
23        let index_content = ::std::fs::read(&index_path).with_context(|e| {
24            format!("Could not read index file {}: {}", index_path.display(), e)
25        })?;
26        let index = Map::from_bytes(index_content).with_context(|e| {
27            format!("Could not parse index file {}: {}", index_path.display(), e)
28        })?;
29
30        let archive_file = File::open(&archive_path).with_context(|e| {
31            format!(
32                "Could not read archive file {}: {}",
33                archive_path.display(),
34                e
35            )
36        })?;
37        let archive = unsafe { Mmap::map(&archive_file) }.with_context(|e| {
38            format!(
39                "Could not open archive file {}: {}",
40                archive_path.display(),
41                e
42            )
43        })?;
44
45        Ok(Site { index, archive })
46    }
47
48    pub fn get(&self, path: &str) -> Option<&[u8]> {
49        let raw_slice = self
50            .index
51            .get(path)
52            .or_else(|| self.index.get(format!("{}index.html", path)))
53            .or_else(|| self.index.get(format!("{}/index.html", path)))?;
54        let (offset, len) = slice::unpack_from_u64(raw_slice);
55        let content = self.archive.get(offset..offset + len)?;
56
57        Some(content)
58    }
59}