Newer
Older
use crate::website::Page;
use std::io::prelude::*;
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
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!(
"Error creating StaticFilesManager root directory - {}",
err
));
if let Err(err) = Self::create_assets_directories_structure(&dir) {
return Err(format!(
"Error creating StaticFilesManager assets directory structure - {}",
err
));
if let Err(err) = Self::copy_default_files(&dir) {
return Err(format!(
"Error copying StaticFilesManager default assets directory- {}",
err
));
fn create_assets_directories_structure(root: &PathBuf) -> Result<(), std::io::Error> {
let assets_dir = root.join("assets");
if !assets_dir.exists() {
std::fs::create_dir(&assets_dir)?;
}
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("assets").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_asset_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_asset_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_assets_pathes(&mut self, pathes: &Vec<String>) -> Vec<PathBuf> {
let mut added: Vec<PathBuf> = Vec::new();
for pth in pathes.iter() {
let p = self.push_asset_path(Path::new(pth));
added.extend(p.iter().map(|pb| pb.clone()));
}
added
pub fn build_assets_index(&mut self) -> Self {
self.rec_read_dir(&self.assets_dir(), &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_assets_index(&self) -> Vec<String> {
pub fn assets_dir(&self) -> PathBuf {
self.dir.join("assets")
}
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 p = test_dir.join("assets").join(d);
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("assets").join("docs").join("testing.txt");
manager = manager.build_assets_index();
manager
.index
.contains(&"assets/docs/testing.txt".to_string()),
"Index doesn't contain path /assets/docs/testing.txt\n{:?}",
remove_test_dir(&test_dir)
);
remove_test_dir(&test_dir);
}
#[test]
fn test_push_and_remove_path() {
let mut manager = StaticFilesManager::testing_new(&test_dir)
.unwrap()
.build_assets_index();
let file_pth = test_dir.join("assets").join("docs").join("testing.txt");
let indexed_path = Path::new("assets/docs/testing.txt");
let added = manager.push_asset_path(&indexed_path);
vec![PathBuf::from("assets/docs/testing.txt")],
"Path was not added\n{:?}",
remove_test_dir(&test_dir)
);
assert!(
manager
.index
.contains(&"assets/docs/testing.txt".to_string()),
"Index doesn't contain path /assets/docs/testing.txt\n{:?}",
manager.remove_path("assets/docs/testing.txt".to_string());
!manager
.index
.contains(&"assets/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_assets_index();
let indexed_path = Path::new("assets/images/unexisting.png");
let added = manager.push_asset_path(&indexed_path);
assert_eq!(
added.len(),
0,
"No path should have been added\n{:?}",
remove_test_dir(&test_dir)
);
assert!(
!manager
.index
.contains(&"assets/images/unexisting.png".to_string()),
"Index shouldn't container unexisting path\n{:?}",
remove_test_dir(&test_dir)
);
remove_test_dir(&test_dir);
}
}