static-filez 0.1.0

Build compressed archives for static files and serve them over HTTP
Documentation
use std::fs::File;
use std::path::Path;
use std::result::Result;

use quicli::prelude::*;

use fst::Map;
use memmap::Mmap;

use slice;

pub struct Site {
    index: Map,
    archive: Mmap,
}

impl Site {
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Site, Error> {
        let path = path.as_ref();
        let index_path = path.with_extension("index");
        let archive_path = path.with_extension("archive");

        let index_content = ::std::fs::read(&index_path).with_context(|e| {
            format!("Could not read index file {}: {}", index_path.display(), e)
        })?;
        let index = Map::from_bytes(index_content).with_context(|e| {
            format!("Could not parse index file {}: {}", index_path.display(), e)
        })?;

        let archive_file = File::open(&archive_path).with_context(|e| {
            format!(
                "Could not read archive file {}: {}",
                archive_path.display(),
                e
            )
        })?;
        let archive = unsafe { Mmap::map(&archive_file) }.with_context(|e| {
            format!(
                "Could not open archive file {}: {}",
                archive_path.display(),
                e
            )
        })?;

        Ok(Site { index, archive })
    }

    pub fn get(&self, path: &str) -> Option<&[u8]> {
        let raw_slice = self
            .index
            .get(path)
            .or_else(|| self.index.get(format!("{}index.html", path)))
            .or_else(|| self.index.get(format!("{}/index.html", path)))?;
        let (offset, len) = slice::unpack_from_u64(raw_slice);
        let content = self.archive.get(offset..offset + len)?;

        Some(content)
    }
}