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}