imag/src/storage/backend.rs

175 lines
4.6 KiB
Rust
Raw Normal View History

2015-11-10 18:27:54 +00:00
use std::error::Error;
use std::fmt::Display;
2015-11-10 18:51:43 +00:00
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
2015-11-23 17:22:02 +00:00
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::io::Read;
2015-11-24 09:48:30 +00:00
use std::io::Write;
use glob::glob;
2015-11-23 17:22:02 +00:00
use glob::Paths;
2015-11-10 18:27:54 +00:00
2015-11-23 17:42:55 +00:00
use storage::file::File;
use storage::file_id::*;
2015-11-24 09:27:42 +00:00
use storage::parser::{FileHeaderParser, Parser, ParserError};
2015-11-10 18:27:54 +00:00
2015-11-23 18:54:08 +00:00
use module::Module;
use runtime::Runtime;
2015-11-23 18:25:27 +00:00
pub type BackendOperationResult = Result<(), StorageBackendError>;
2015-11-10 18:27:54 +00:00
2015-11-23 17:45:31 +00:00
pub struct StorageBackend {
2015-11-10 18:27:54 +00:00
basepath: String,
}
2015-11-23 17:45:31 +00:00
impl StorageBackend {
2015-11-10 18:27:54 +00:00
2015-11-23 18:54:08 +00:00
pub fn new(basepath: String) -> StorageBackend {
2015-11-10 19:53:35 +00:00
StorageBackend {
basepath: basepath,
}
2015-11-10 18:27:54 +00:00
}
2015-11-23 18:54:08 +00:00
fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
let path = rt.get_rtp() + m.name() + "/store";
StorageBackend::new(path)
}
2015-11-23 18:26:02 +00:00
fn get_file_ids(&self) -> Option<Vec<FileID>> {
2015-11-23 17:22:02 +00:00
let list = glob(&self.basepath[..]);
if let Ok(globlist) = list {
let mut v = vec![];
for entry in globlist {
if let Ok(path) = entry {
2015-11-23 17:42:55 +00:00
v.push(from_pathbuf(&path));
2015-11-23 17:22:02 +00:00
} else {
// Entry is not a path
}
}
Some(v)
} else {
None
}
2015-11-10 18:27:54 +00:00
}
2015-11-23 18:25:27 +00:00
/*
* Write a file to disk.
*
* The file is moved to this function as the file won't be edited afterwards
*/
2015-11-24 09:27:42 +00:00
pub fn put_file<'a, HP>(&self, f: File, p: &Parser<HP>) ->
Result<BackendOperationResult, ParserError>
where HP: FileHeaderParser<'a>
{
let written = p.write(f.contents());
if let Ok(string) = written {
2015-11-24 09:30:52 +00:00
let path = self.build_filepath(&f);
2015-11-24 09:27:42 +00:00
debug!("Writing file: {}", path);
Ok(Ok(()))
} else {
Err(written.err().unwrap())
}
2015-11-10 18:27:54 +00:00
}
2015-11-23 18:25:27 +00:00
/*
* Update a file. We have the UUID and can find the file on FS with it and
* then replace its contents with the contents of the passed file object
*/
2015-11-24 09:48:30 +00:00
pub fn update_file<'a, HP>(&self, f: File, p: &Parser<HP>)
-> Result<BackendOperationResult, ParserError>
where HP: FileHeaderParser<'a>
{
let contents = p.write(f.contents());
if contents.is_err() {
return Err(contents.err().unwrap());
}
let content = contents.unwrap();
let path = self.build_filepath(&f);
if let Err(_) = FSFile::open(path) {
return Ok(Err(StorageBackendError::new(
"File::open()",
&format!("Tried to open '{}'", path)[..],
"Tried to update contents of this file, though file doesn't exist",
None)))
}
if let Ok(mut file) = FSFile::create(path) {
if let Err(writeerr) = file.write_all(&content.into_bytes()) {
return Ok(Err(StorageBackendError::new(
"File::write()",
&format!("Tried to write '{}'", path)[..],
"Tried to write contents of this file, though operation did not succeed",
Some(content))))
}
}
Ok(Ok(()))
2015-11-10 18:27:54 +00:00
}
2015-11-23 18:25:27 +00:00
/*
* Find a file by its ID and return it if found. Return nothing if not
* found, of course.
*
* TODO: Needs refactoring, as there might be an error when reading from
* disk OR the id just does not exist.
*/
pub fn get_file_by_id(id: FileID) -> Option<File> {
}
2015-11-24 09:30:52 +00:00
fn build_filepath(&self, f: &File) -> String {
self.basepath + &f.id()[..]
}
2015-11-10 18:27:54 +00:00
}
#[derive(Debug)]
2015-11-10 18:51:43 +00:00
pub struct StorageBackendError {
pub action: String, // The file system action in words
pub desc: String, // A short description
pub explanation: String, // A long, user friendly description
pub dataDump: Option<String> // Data dump, if any
}
2015-11-10 18:27:54 +00:00
impl StorageBackendError {
2015-11-10 18:51:43 +00:00
fn new(action: &'static str,
desc : &'static str,
explan: &'static str,
data : Option<String>) -> StorageBackendError
{
StorageBackendError {
action: String::from(action),
desc: String::from(desc),
explanation: String::from(explan),
dataDump: data,
}
}
2015-11-10 18:27:54 +00:00
}
impl Error for StorageBackendError {
2015-11-10 18:51:43 +00:00
fn description(&self) -> &str {
&self.desc[..]
}
fn cause(&self) -> Option<&Error> {
None
}
2015-11-10 18:27:54 +00:00
}
impl Display for StorageBackendError {
2015-11-10 18:51:43 +00:00
fn fmt(&self, f: &mut Formatter) -> FMTResult {
write!(f, "StorageBackendError[{}]: {}\n\n{}",
self.action, self.desc, self.explanation)
}
2015-11-10 18:27:54 +00:00
}