mylloon.fr/src/config.rs

178 lines
5 KiB
Rust
Raw Normal View History

2023-02-08 20:49:05 +01:00
use serde::Deserialize;
2023-04-09 19:44:24 +02:00
use std::{fs, path::PathBuf};
use glob::glob;
use minify_html::{minify, Cfg};
use std::{fs::File, io::Write, path::Path};
2023-02-08 20:49:05 +01:00
2023-04-09 19:26:20 +02:00
use crate::template::Template;
2023-04-21 19:47:47 +02:00
/// Store the configuration of config/config.toml
2023-02-09 11:42:33 +01:00
#[derive(Deserialize, Clone, Default)]
2023-04-09 15:19:23 +02:00
pub struct FileConfig {
2023-04-21 19:47:47 +02:00
/// http/https
2023-02-09 11:36:22 +01:00
pub scheme: Option<String>,
2023-04-21 19:47:47 +02:00
/// Port used
2023-02-09 11:36:22 +01:00
pub port: Option<u16>,
2023-04-21 19:47:47 +02:00
/// Mail of owner
2023-02-08 22:14:57 +01:00
pub mail: Option<String>,
2023-04-21 19:47:47 +02:00
/// Lang used
2023-02-08 22:14:57 +01:00
pub lang: Option<String>,
2023-04-21 19:47:47 +02:00
/// Adress .onion for Tor
2023-02-16 21:59:04 +01:00
pub onion: Option<String>,
2023-04-21 19:47:47 +02:00
/// App name
2023-04-11 00:57:30 +02:00
pub app_name: Option<String>,
2023-02-08 20:49:05 +01:00
}
2023-04-09 15:19:23 +02:00
impl FileConfig {
2023-04-21 19:47:47 +02:00
/// Initialize with default values
fn new() -> Self {
Self {
2023-04-21 19:22:00 +02:00
scheme: Some("http".to_owned()),
port: Some(8080),
2023-04-21 19:22:00 +02:00
app_name: Some("EWP".to_owned()),
2023-04-09 15:19:23 +02:00
..FileConfig::default()
}
}
2023-04-21 19:47:47 +02:00
/// Complete default structure with an existing one
fn complete(a: Self) -> Self {
// Default config
2023-04-09 15:19:23 +02:00
let d = FileConfig::new();
/// Return the default value if nothing is value is none
fn test<T>(val: Option<T>, default: Option<T>) -> Option<T> {
if val.is_some() {
val
} else {
default
}
}
Self {
scheme: test(a.scheme, d.scheme),
port: test(a.port, d.port),
mail: test(a.mail, d.mail),
lang: test(a.lang, d.lang),
2023-02-16 21:59:04 +01:00
onion: test(a.onion, d.onion),
2023-04-11 00:57:30 +02:00
app_name: test(a.app_name, d.app_name),
}
}
}
2023-04-21 19:47:47 +02:00
/// Configuration used internally in the app
2023-04-09 19:26:20 +02:00
#[derive(Clone)]
pub struct Config {
2023-04-21 19:47:47 +02:00
/// Information given in the config file
2023-04-09 19:26:20 +02:00
pub fc: FileConfig,
2023-04-21 19:47:47 +02:00
/// Location where the static files are stored
2023-04-09 19:26:20 +02:00
pub static_location: String,
2023-04-21 19:47:47 +02:00
/// Informations about templates
2023-04-09 19:26:20 +02:00
pub tmpl: Template,
}
2023-04-21 19:47:47 +02:00
/// Load the config file
2023-04-09 15:19:23 +02:00
fn get_file_config(file_path: &str) -> FileConfig {
2023-02-09 11:42:33 +01:00
match fs::read_to_string(file_path) {
2023-02-08 20:49:05 +01:00
Ok(file) => match toml::from_str(&file) {
2023-04-09 15:19:23 +02:00
Ok(stored_config) => FileConfig::complete(stored_config),
2023-02-08 20:49:05 +01:00
Err(file_error) => {
panic!("Error in config file: {file_error}");
}
},
2023-04-21 19:47:47 +02:00
Err(_) => {
// No config file
2023-04-09 15:19:23 +02:00
FileConfig::new()
2023-02-08 20:49:05 +01:00
}
}
}
2023-04-09 15:19:23 +02:00
2023-04-21 19:47:47 +02:00
/// Build the configuration
2023-04-09 15:19:23 +02:00
pub fn get_config(file_path: &str) -> Config {
let internal_config = get_file_config(file_path);
2023-04-21 19:22:00 +02:00
let static_dir = "static".to_owned();
let templates_dir = "templates".to_owned();
let files_root = init("dist".to_owned(), static_dir.clone(), templates_dir.clone());
2023-04-09 15:19:23 +02:00
Config {
2023-04-11 01:08:07 +02:00
fc: internal_config.clone(),
static_location: format!("{}/{}", files_root, static_dir),
2023-04-09 19:26:20 +02:00
tmpl: Template {
directory: format!("{}/{}", files_root, templates_dir),
2023-04-11 01:08:07 +02:00
app_name: internal_config.app_name.unwrap(),
2023-04-09 19:26:20 +02:00
},
}
}
2023-04-21 19:47:47 +02:00
/// Preparation before running the http server
2023-04-09 17:01:30 +02:00
fn init(dist_dir: String, static_dir: String, templates_dir: String) -> String {
// The static folder is minimized only in release mode
if cfg!(debug_assertions) {
2023-04-21 19:22:00 +02:00
".".to_owned()
} else {
let cfg = Cfg {
keep_closing_tags: true,
minify_css: true,
minify_js: true,
..Cfg::spec_compliant()
};
// Static files
for entry in glob(&format!("{static_dir}/**/*.*")).unwrap() {
let path = entry.unwrap();
let path_with_dist = path
.to_string_lossy()
.replace(&static_dir, &format!("{dist_dir}/{static_dir}"));
minify_and_copy(&cfg, path, path_with_dist);
}
// Template files
for entry in glob(&format!("{templates_dir}/**/*.*")).unwrap() {
let path = entry.unwrap();
let path_with_dist = path
.to_string_lossy()
.replace(&templates_dir, &format!("{dist_dir}/{templates_dir}"));
2023-04-09 17:35:15 +02:00
minify_and_copy(&cfg, path, path_with_dist);
}
2023-04-09 17:35:15 +02:00
dist_dir
2023-04-09 17:35:15 +02:00
}
}
2023-04-21 19:47:47 +02:00
/// Minify some assets for production
fn minify_and_copy(cfg: &Cfg, path: PathBuf, path_with_dist: String) {
// Create folders
let new_path = Path::new(&path_with_dist);
fs::create_dir_all(new_path.parent().unwrap()).unwrap();
let mut copy = true;
if let Some(ext) = path.extension() {
// List of files who should be minified
if ["html", "css", "js", "svg", "webmanifest", "xml"]
.iter()
.any(|item| ext.to_string_lossy().to_lowercase().contains(item))
{
// We won't copy, we'll minify
copy = false;
// Minify
let data = fs::read(&path).unwrap();
let minified = minify(&data, cfg);
// Write files
let file = File::create(&path_with_dist);
file.expect("Error when minify the file")
.write_all(&minified)
.unwrap();
}
}
if copy {
// If no minification is needed
fs::copy(path, path_with_dist).unwrap();
2023-04-09 15:19:23 +02:00
}
}