mirror of
https://codeberg.org/slatian/service.echoip-slatecave.git
synced 2024-11-10 00:27:21 +01:00
Made template loading logic reuseable
This commit is contained in:
parent
5adca4fb80
commit
912a119361
75
src/main.rs
75
src/main.rs
@ -19,7 +19,6 @@ use clap::Parser;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize,Serialize};
|
||||
use tera::Tera;
|
||||
use tower::ServiceBuilder;
|
||||
use tower_http::services::ServeDir;
|
||||
use trust_dns_resolver::Name;
|
||||
@ -32,7 +31,6 @@ use tokio::signal::unix::{
|
||||
use tokio::task;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::net::IpAddr;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -54,6 +52,8 @@ use crate::geoip::{
|
||||
};
|
||||
use crate::idna::IdnaName;
|
||||
use crate::mycelium::MycEngine;
|
||||
use crate::mycelium::TemplateEngineLoader;
|
||||
use crate::mycelium::read_toml_from_file;
|
||||
use crate::simple_dns::DnsLookupResult;
|
||||
use crate::settings::*;
|
||||
use crate::view::View;
|
||||
@ -137,23 +137,6 @@ fn match_domain_hidden_list(domain: &String, hidden_list: &Vec<String>) -> bool
|
||||
return false;
|
||||
}
|
||||
|
||||
fn read_toml_from_file<T: for<'de> serde::Deserialize<'de>>(path: &String) -> Option<T> {
|
||||
let text = match fs::read_to_string(path) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
println!("Error while reading file '{path}': {e}");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
match toml::from_str(&text) {
|
||||
Ok(t) => Some(t),
|
||||
Err(e) => {
|
||||
println!("Unable to parse file '{path}':\n{e}");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Parse Command line arguments
|
||||
@ -163,9 +146,11 @@ async fn main() {
|
||||
let config: config::EchoIpServiceConfig = match cli_args.config {
|
||||
Some(config_path) => {
|
||||
match read_toml_from_file::<config::EchoIpServiceConfig>(&config_path) {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
println!("Could not read confuration file, exiting.");
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
println!("Could not read confuration file!");
|
||||
println!("{e}");
|
||||
println!("Exiting ...");
|
||||
::std::process::exit(1);
|
||||
}
|
||||
}
|
||||
@ -174,47 +159,25 @@ async fn main() {
|
||||
};
|
||||
|
||||
// Initalize Tera templates
|
||||
let mut template_base_dir = match cli_args.template_location {
|
||||
Some(template_base_dir) => template_base_dir,
|
||||
None => (&config.template.template_location).to_owned(),
|
||||
};
|
||||
if !template_base_dir.ends_with("/") {
|
||||
template_base_dir = template_base_dir + "/";
|
||||
}
|
||||
let template_extra_config = match &cli_args.extra_config {
|
||||
Some(path) => read_toml_from_file(path),
|
||||
None => match &config.template.extra_config {
|
||||
Some(path) => read_toml_from_file(path),
|
||||
None => {
|
||||
println!("Trying to read default template configuration ...");
|
||||
println!("(If this fails that may be ok, depending on your template)");
|
||||
read_toml_from_file(&(template_base_dir.clone()+"extra.toml"))
|
||||
},
|
||||
},
|
||||
};
|
||||
let template_glob = template_base_dir.clone()+"*";
|
||||
println!("Parsing Templates from '{}' ...", &template_glob);
|
||||
let res = Tera::new((template_glob).as_str());
|
||||
let tera = match res {
|
||||
Ok(t) => t,
|
||||
let template_loader = TemplateEngineLoader::new(
|
||||
config.template.template_location.clone(),
|
||||
config.template.extra_config.clone()
|
||||
)
|
||||
.cli_template_location(cli_args.template_location)
|
||||
.cli_extra_config_location(cli_args.extra_config);
|
||||
|
||||
|
||||
let templating_engine = match template_loader.load_templates() {
|
||||
Ok(t) => t.into(),
|
||||
Err(e) => {
|
||||
println!("Template parsing error(s): {}", e);
|
||||
println!("{e}");
|
||||
::std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let templating_engine = TemplatingEngine::new(
|
||||
tera,
|
||||
template_extra_config,
|
||||
);
|
||||
|
||||
// Static file directory
|
||||
|
||||
let static_file_directory = cli_args.static_location.unwrap_or(
|
||||
config.server.static_location.clone().unwrap_or(
|
||||
template_base_dir+"/static"
|
||||
)
|
||||
);
|
||||
let static_file_directory = template_loader.base_dir()+"/static";
|
||||
|
||||
println!("Static files will be served from: {static_file_directory}");
|
||||
|
||||
|
@ -20,6 +20,14 @@ use crate::mycelium::MycQuerySettings;
|
||||
|
||||
/* The engine itself */
|
||||
|
||||
/// A constructable version of MycEngine without the types attached.
|
||||
///
|
||||
/// Can be converted to a MycEngine using `into()`.
|
||||
pub struct MycProtoEngine {
|
||||
pub tera: Tera,
|
||||
pub template_config: Option<Table>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MycEngine<V, S, F>
|
||||
where V: MycView<S, F>, S: MycQuerySettings<F>, F: MycFormat {
|
||||
@ -120,3 +128,19 @@ where V: MycView<S, F>, S: MycQuerySettings<F>, F: MycFormat {
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, S, F> From<MycProtoEngine> for MycEngine<V, S, F>
|
||||
where V: MycView<S, F>, S: MycQuerySettings<F>, F: MycFormat {
|
||||
fn from(e: MycProtoEngine) -> Self {
|
||||
Self::new(e.tera, e.template_config)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, S, F> From<MycEngine<V, S, F>> for MycProtoEngine
|
||||
where V: MycView<S, F>, S: MycQuerySettings<F>, F: MycFormat {
|
||||
fn from(e: MycEngine<V, S, F>) -> Self {
|
||||
Self {
|
||||
tera: e.tera,
|
||||
template_config: e.template_config,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
mod engine;
|
||||
mod format;
|
||||
mod query_settings;
|
||||
mod template_loader;
|
||||
mod toml_helper;
|
||||
mod view;
|
||||
|
||||
pub use self::engine::MycEngine;
|
||||
pub use self::engine::MycProtoEngine;
|
||||
pub use self::format::HtmlTextJsonFormat;
|
||||
pub use self::format::MycFormat;
|
||||
pub use self::format::MycFormatFamily;
|
||||
pub use self::query_settings::MycQuerySettings;
|
||||
pub use self::template_loader::TemplateEngineLoader;
|
||||
pub use self::toml_helper::read_toml_from_file;
|
||||
pub use self::toml_helper::TomlError;
|
||||
pub use self::view::MycView;
|
||||
|
114
src/mycelium/template_loader.rs
Normal file
114
src/mycelium/template_loader.rs
Normal file
@ -0,0 +1,114 @@
|
||||
|
||||
use tera::Tera;
|
||||
use serde::Deserialize;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use crate::mycelium::MycProtoEngine;
|
||||
use crate::mycelium::read_toml_from_file;
|
||||
use crate::mycelium::TomlError;
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
pub struct TemplateEngineLoader {
|
||||
pub template_location: String,
|
||||
pub extra_config_location: Option<String>,
|
||||
}
|
||||
|
||||
impl TemplateEngineLoader {
|
||||
|
||||
pub fn new(
|
||||
template_location: String,
|
||||
extra_config_location: Option<String>
|
||||
) -> Self {
|
||||
Self {
|
||||
template_location: template_location,
|
||||
extra_config_location: extra_config_location,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cli_template_location(mut self, location: Option<String>) -> Self {
|
||||
if let Some(location) = location {
|
||||
self.template_location = location;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cli_extra_config_location(mut self, location: Option<String>) -> Self {
|
||||
if let Some(location) = location {
|
||||
self.extra_config_location = Some(location);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
// Returns the template base directory.
|
||||
//
|
||||
// Contructed by ensuring the template_location ends in a "/".
|
||||
pub fn base_dir(&self) -> String {
|
||||
if self.template_location.ends_with("/") {
|
||||
self.template_location.clone()
|
||||
} else {
|
||||
self.template_location.clone()+"/"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_templates(
|
||||
&self
|
||||
) -> Result<MycProtoEngine,TemplateEngineLoaderError> {
|
||||
let template_base_dir = self.base_dir();
|
||||
let template_extra_config_res = match &self.extra_config_location {
|
||||
Some(path) => read_toml_from_file(path),
|
||||
None => {
|
||||
read_toml_from_file(&(template_base_dir.clone()+"extra.toml"))
|
||||
}
|
||||
};
|
||||
let template_extra_config = match template_extra_config_res {
|
||||
Ok(c) => Some(c),
|
||||
Err(e) => match &e {
|
||||
TomlError::FileError{..} => {
|
||||
// Only fatal if the file was explicitly requested.
|
||||
// An implicit request could also mean that
|
||||
// the template doesn't need a config file.
|
||||
if self.extra_config_location.is_some() {
|
||||
return Err(TemplateEngineLoaderError::TomlError(e));
|
||||
}
|
||||
None
|
||||
},
|
||||
TomlError::ParseError{..} => {
|
||||
return Err(TemplateEngineLoaderError::TomlError(e));
|
||||
}
|
||||
},
|
||||
};
|
||||
let template_glob = template_base_dir.clone()+"*";
|
||||
println!("Parsing Templates from '{}' ...", &template_glob);
|
||||
let res = Tera::new((template_glob).as_str());
|
||||
let tera = match res {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
return Err(TemplateEngineLoaderError::TemplateParseError{
|
||||
path: template_glob,
|
||||
tera_error: e,
|
||||
});
|
||||
}
|
||||
};
|
||||
Ok(MycProtoEngine {
|
||||
tera: tera,
|
||||
template_config: template_extra_config,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub enum TemplateEngineLoaderError {
|
||||
TomlError(TomlError),
|
||||
TemplateParseError{path: String, tera_error: tera::Error },
|
||||
}
|
||||
|
||||
impl fmt::Display for TemplateEngineLoaderError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::TomlError(e) =>
|
||||
write!(f,"Error with template extra configuration:\n(Depending on you template the file not being found might be okay)\n{e}"),
|
||||
Self::TemplateParseError{path, tera_error} =>
|
||||
write!(f,"Error parsing template '{path}':\n{tera_error}"),
|
||||
}
|
||||
}
|
||||
}
|
42
src/mycelium/toml_helper.rs
Normal file
42
src/mycelium/toml_helper.rs
Normal file
@ -0,0 +1,42 @@
|
||||
use serde::Deserialize;
|
||||
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
|
||||
pub fn read_toml_from_file<T>(path: &String) -> Result<T,TomlError>
|
||||
where T: for<'de> Deserialize<'de> {
|
||||
let text = match fs::read_to_string(path) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
return Err(TomlError::FileError{
|
||||
path: path.clone(),
|
||||
io_error: e
|
||||
});
|
||||
}
|
||||
};
|
||||
match toml::from_str(&text) {
|
||||
Ok(t) => Ok(t),
|
||||
Err(e) => {
|
||||
return Err(TomlError::ParseError{
|
||||
path: path.clone(),
|
||||
toml_error: e
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum TomlError {
|
||||
FileError{ path: String, io_error: std::io::Error },
|
||||
ParseError{ path: String, toml_error: toml::de::Error },
|
||||
}
|
||||
|
||||
impl fmt::Display for TomlError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::FileError{path, io_error} =>
|
||||
write!(f,"Error while reading file '{path}': {io_error}"),
|
||||
Self::ParseError{path, toml_error} =>
|
||||
write!(f,"Unable to parse file as toml '{path}':\n{toml_error}"),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user