diff options
| author | Daniel Schadt <kingdread@gmx.de> | 2025-06-26 22:10:31 +0200 | 
|---|---|---|
| committer | Daniel Schadt <kingdread@gmx.de> | 2025-06-26 22:10:31 +0200 | 
| commit | 99150875308e0cac89f4de2996cfd1954305dcfe (patch) | |
| tree | f19224064543aed367522b05778a992d7385c712 /src/storage.rs | |
| parent | 6adcd94a6747fe7ec6f1ad1073453636847a0bff (diff) | |
| download | hittekaart-99150875308e0cac89f4de2996cfd1954305dcfe.tar.gz hittekaart-99150875308e0cac89f4de2996cfd1954305dcfe.tar.bz2 hittekaart-99150875308e0cac89f4de2996cfd1954305dcfe.zip  | |
split crate into core and cli
Diffstat (limited to 'src/storage.rs')
| -rw-r--r-- | src/storage.rs | 165 | 
1 files changed, 0 insertions, 165 deletions
diff --git a/src/storage.rs b/src/storage.rs deleted file mode 100644 index 9e6b270..0000000 --- a/src/storage.rs +++ /dev/null @@ -1,165 +0,0 @@ -//! Abstractions over different storage backends. -//! -//! The main trait to use here is [`Storage`], which provides the necessary interface to store -//! tiles. Usually you want to have a `dyn Storage`, and then instantiate it with a concrete -//! implementation (either [`Folder`] or [`Sqlite`]), depending on the command line flags or -//! similar. -use color_eyre::{ -    eyre::{bail, WrapErr}, -    Result, -}; -use rusqlite::{params, Connection}; -use std::{ -    fs, -    io::ErrorKind, -    path::{Path, PathBuf}, -}; - -/// The trait that provides the interface for storing tiles. -pub trait Storage { -    /// Prepare the storage. -    /// -    /// This can be used to e.g. ensure the directory exists, or to create the database. -    fn prepare(&mut self) -> Result<()>; -    /// Prepare for a given zoom level. -    /// -    /// This function is called once per zoom, and can be used e.g. to set up the inner folder for -    /// the level. This can avoid unnecesary syscalls if this setup would be done in -    /// [`Storage::store`] instead. -    fn prepare_zoom(&mut self, zoom: u32) -> Result<()>; -    /// Store the given data for the tile. -    fn store(&mut self, zoom: u32, x: u64, y: u64, data: &[u8]) -> Result<()>; -    /// Finish the storing operation. -    /// -    /// This can flush any buffers, commit database changes, and so on. -    fn finish(&mut self) -> Result<()>; -} - -/// Folder-based storage. -/// -/// This stores the tiles according to the [slippy map -/// tilenames](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames). -#[derive(Debug)] -pub struct Folder { -    base_dir: PathBuf, -} - -impl Folder { -    /// Create a new folder based storage. -    /// -    /// The given directory is the "root" directory, so a tile would be saved as -    /// `base_dir/{zoom}/{x}/{y}.png`. -    pub fn new(base_dir: PathBuf) -> Self { -        Folder { base_dir } -    } -} - -impl Storage for Folder { -    fn prepare(&mut self) -> Result<()> { -        let path = &self.base_dir; -        let metadata = fs::metadata(path); -        match metadata { -            Err(e) if e.kind() == ErrorKind::NotFound => { -                let parent = path.parent().unwrap_or_else(|| Path::new("/")); -                fs::create_dir(path) -                    .context(format!("Could not create output directory at {parent:?}"))? -            } -            Err(e) => Err(e).context("Error while checking output directory")?, -            Ok(m) if m.is_dir() => (), -            Ok(_) => bail!("Output directory is not a directory"), -        } -        Ok(()) -    } - -    fn prepare_zoom(&mut self, zoom: u32) -> Result<()> { -        let target = [&self.base_dir, &zoom.to_string().into()] -            .iter() -            .collect::<PathBuf>(); -        fs::create_dir(target)?; -        Ok(()) -    } - -    fn store(&mut self, zoom: u32, x: u64, y: u64, data: &[u8]) -> Result<()> { -        let folder = self.base_dir.join(zoom.to_string()).join(x.to_string()); -        let metadata = folder.metadata(); -        match metadata { -            Err(_) => fs::create_dir(&folder)?, -            Ok(m) if !m.is_dir() => bail!("Output path is not a directory"), -            _ => {} -        } -        let file = folder.join(format!("{y}.png")); -        fs::write(file, data)?; -        Ok(()) -    } - -    fn finish(&mut self) -> Result<()> { -        Ok(()) -    } -} - -/// SQLite based storage. -/// -/// This stores tiles in a SQLite database. The database will have a single table: -/// -/// ```sql -/// CREATE TABLE tiles ( -///     zoom INTEGER, -///     x INTEGER, -///     y INTEGER, -///     data BLOB, -///     PRIMARY KEY (zoom, x, y) -/// ); -/// ``` -#[derive(Debug)] -pub struct Sqlite { -    connection: Connection, -} - -impl Sqlite { -    /// Create a new SQLite backed tile store. -    /// -    /// The database will be saved at the given location. Note that the database must not yet -    /// exist. -    pub fn connect<P: AsRef<Path>>(file: P) -> Result<Self> { -        let path = file.as_ref(); -        if fs::metadata(path).is_ok() { -            bail!("Path {path:?} already exists, refusing to open") -        } -        let connection = Connection::open(path)?; -        Ok(Sqlite { connection }) -    } -} - -impl Storage for Sqlite { -    fn prepare(&mut self) -> Result<()> { -        self.connection.execute( -            "CREATE TABLE tiles ( -            zoom INTEGER, -            x INTEGER, -            y INTEGER, -            data BLOB, -            PRIMARY KEY (zoom, x, y) -        );", -            (), -        )?; -        self.connection.execute("BEGIN;", ())?; -        Ok(()) -    } - -    fn prepare_zoom(&mut self, _zoom: u32) -> Result<()> { -        Ok(()) -    } - -    fn store(&mut self, zoom: u32, x: u64, y: u64, data: &[u8]) -> Result<()> { -        self.connection.execute( -            "INSERT INTO tiles (zoom, x, y, data) VALUES (?, ?, ?, ?)", -            params![zoom, x, y, data], -        )?; -        Ok(()) -    } - -    fn finish(&mut self) -> Result<()> { -        self.connection.execute("COMMIT;", ())?; -        Ok(()) -    } -}  | 
