Newer
Older
use crate::website::Page;
use std::io::prelude::*;
#[derive(Clone, Debug)]
const STATIC_ASSETS_DIRECTORIES: [&'static str; 6] = [
"images",
"sounds",
"videos",
"docs",
"source_code",
"default",
];
pub fn new(app_state: &AppState) -> Result<Self, String> {
match Self::create_dir_tree(&app_state.config.storage_dir) {
Ok(dir) => Ok(StaticFilesManager {
index: Vec::new(),
dir,
}),
Err(msg) => Err(msg),
}
}
#[cfg(test)]
pub fn testing_new(test_dir: &PathBuf) -> Result<Self, String> {
match Self::create_dir_tree(test_dir) {
Ok(dir) => Ok(StaticFilesManager {
index: Vec::new(),
dir,
}),
Err(msg) => Err(msg),
}
}
fn create_dir_tree(dir: &PathBuf) -> Result<PathBuf, String> {
if !dir.exists() {
if let Err(err) = std::fs::create_dir_all(&dir) {
return Err(format!("{}", err));
};
}
if let Err(err) = Self::create_assets_directories_structure(&dir) {
return Err(format!("{}", err));
};
if let Err(err) = Self::copy_default_files(&dir) {
return Err(format!("{}", err));
fn create_assets_directories_structure(root: &PathBuf) -> Result<(), std::io::Error> {
for d in STATIC_ASSETS_DIRECTORIES {
let p = root.join(d);
if !p.exists() {
std::fs::create_dir(p)?;
}
fn copy_default_files(static_dir: &PathBuf) -> Result<(), String> {
let local_default_static = std::env::current_dir().unwrap().join("default_static");
let default_static = static_dir.join("default");
let mut cpy_options = fs_extra::dir::CopyOptions::new();
cpy_options.content_only = true;
cpy_options.overwrite = true;
match fs_extra::dir::copy(local_default_static, default_static, &cpy_options) {
fn rec_read_dir(&mut self, root: &Path, strip_from: &Path) {
for entry in root.read_dir().unwrap() {
if let Ok(entry) = entry {
if entry.path().is_dir() {
self.rec_read_dir(&entry.path(), strip_from);
} else {
self.push_path(&entry.path().strip_prefix(strip_from).unwrap());
fn validate_path(&self, path: &Path) -> bool {
self.dir.join(self.clean_relative_path(path)).exists()
}
fn clean_relative_path(&self, path: &Path) -> PathBuf {
match path.starts_with("/") {
true => path.strip_prefix("/").unwrap().to_path_buf(),
false => path.to_path_buf(),
}
}
pub fn push_path(&mut self, path: &Path) -> Vec<PathBuf> {
if self.validate_path(path) {
self.index
.push(self.clean_relative_path(path).to_str().unwrap().to_owned());
vec![path.to_path_buf()]
} else {
println!(
"[WARNING] Error building static file index. The file {:?} doesn't exist and will be removed from the index.",
self.dir.join(self.clean_relative_path(path)),
);
Vec::new()
}
pub fn add_pathes(&mut self, pathes: &Vec<String>) -> Vec<PathBuf> {
let mut added: Vec<PathBuf> = Vec::new();
for pth in pathes.iter() {
let p = self.push_path(Path::new(pth));
added.extend(p.iter().map(|pb| pb.clone()));
}
added
}
pub fn build(&mut self) -> Self {
self.index = Vec::new();
self.rec_read_dir(&self.dir.clone(), &self.dir.clone());
pub fn remove_path(&mut self, strpath: String) {
self.index = self
.index
.iter()
.filter(|url| !strpath.eq(*url))
.map(|s| s.to_owned())
.collect();
}
pub fn get_index(&self) -> Vec<String> {
self.index.clone()
}
pub fn write_html_page(&self, url: &PathBuf, page: &Page) -> std::io::Result<()> {
let dir = self.dir.join(self.clean_relative_path(url));
if !dir.exists() {
std::fs::create_dir_all(&dir)?;
}
let mut file = std::fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&dir.join("index.html"))?;
file.write_all(page.html.to_string().as_bytes())?;
file.flush()?;
Ok(())
}
#[cfg(test)]
mod test_static_files_manager {
use super::*;
fn create_test_dir() -> PathBuf {
let pth = PathBuf::from("./test");
let _ = std::fs::create_dir(&pth);
pth
}
fn remove_test_dir(pth: &PathBuf) {
let _ = std::fs::remove_dir_all(pth);
}
#[test]
fn test_directory_structure() {
let test_dir = create_test_dir();
let _manager = StaticFilesManager::testing_new(&test_dir).unwrap();
for d in STATIC_ASSETS_DIRECTORIES {
let exists = p.exists();
assert!(
exists,
"{} doesn't exist\n{:?}",
p.display(),
remove_test_dir(&test_dir)
);
}
remove_test_dir(&test_dir);
}
#[test]
fn test_indexation() {
let test_dir = create_test_dir();
let mut manager = StaticFilesManager::testing_new(&test_dir).unwrap();
let file_pth = test_dir.join("docs").join("testing.txt");
std::fs::File::create(&file_pth).unwrap();
manager = manager.build();
assert!(
manager.index.contains(&"docs/testing.txt".to_string()),
"Index doesn't contain path /docs/testing.txt\n{:?}",
remove_test_dir(&test_dir)
);
remove_test_dir(&test_dir);
}
#[test]
fn test_pushd_and_remove_path() {
let test_dir = create_test_dir();
let mut manager = StaticFilesManager::testing_new(&test_dir).unwrap().build();
let file_pth = test_dir.join("docs").join("testing.txt");
std::fs::File::create(&file_pth).unwrap();
let indexed_path = Path::new("docs/testing.txt");
let added = manager.push_path(&indexed_path);
assert_eq!(
added,
vec![PathBuf::from("docs/testing.txt")],
"Path was not added\n{:?}",
remove_test_dir(&test_dir)
);
assert!(
manager.index.contains(&"docs/testing.txt".to_string()),
"Index doesn't contain path /docs/testing.txt\n{:?}",
remove_test_dir(&test_dir)
);
manager.remove_path("docs/testing.txt".to_string());
assert!(
!manager.index.contains(&"docs/testing.txt".to_string()),
"Path docs/testing.txt should have been removed\n{:?}",
remove_test_dir(&test_dir)
);
remove_test_dir(&test_dir);
}
#[test]
fn test_push_unexisting_path() {
let test_dir = create_test_dir();
let mut manager = StaticFilesManager::testing_new(&test_dir).unwrap().build();
let indexed_path = Path::new("images/unexisting.png");
let added = manager.push_path(&indexed_path);
assert_eq!(
added.len(),
0,
"No path should have been added\n{:?}",
remove_test_dir(&test_dir)
);
assert!(
!manager.index.contains(&"images/unexisting.png".to_string()),
"Index shouldn't container unexisting path\n{:?}",
remove_test_dir(&test_dir)
);
remove_test_dir(&test_dir);
}
}