mirror of
https://codeberg.org/slatian/service.echoip-slatecave.git
synced 2025-01-27 10:25:02 +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 lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize,Serialize};
|
use serde::{Deserialize,Serialize};
|
||||||
use tera::Tera;
|
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
use tower_http::services::ServeDir;
|
use tower_http::services::ServeDir;
|
||||||
use trust_dns_resolver::Name;
|
use trust_dns_resolver::Name;
|
||||||
@ -32,7 +31,6 @@ use tokio::signal::unix::{
|
|||||||
use tokio::task;
|
use tokio::task;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -54,6 +52,8 @@ use crate::geoip::{
|
|||||||
};
|
};
|
||||||
use crate::idna::IdnaName;
|
use crate::idna::IdnaName;
|
||||||
use crate::mycelium::MycEngine;
|
use crate::mycelium::MycEngine;
|
||||||
|
use crate::mycelium::TemplateEngineLoader;
|
||||||
|
use crate::mycelium::read_toml_from_file;
|
||||||
use crate::simple_dns::DnsLookupResult;
|
use crate::simple_dns::DnsLookupResult;
|
||||||
use crate::settings::*;
|
use crate::settings::*;
|
||||||
use crate::view::View;
|
use crate::view::View;
|
||||||
@ -137,23 +137,6 @@ fn match_domain_hidden_list(domain: &String, hidden_list: &Vec<String>) -> bool
|
|||||||
return false;
|
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]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
// Parse Command line arguments
|
// Parse Command line arguments
|
||||||
@ -163,9 +146,11 @@ async fn main() {
|
|||||||
let config: config::EchoIpServiceConfig = match cli_args.config {
|
let config: config::EchoIpServiceConfig = match cli_args.config {
|
||||||
Some(config_path) => {
|
Some(config_path) => {
|
||||||
match read_toml_from_file::<config::EchoIpServiceConfig>(&config_path) {
|
match read_toml_from_file::<config::EchoIpServiceConfig>(&config_path) {
|
||||||
Some(c) => c,
|
Ok(c) => c,
|
||||||
None => {
|
Err(e) => {
|
||||||
println!("Could not read confuration file, exiting.");
|
println!("Could not read confuration file!");
|
||||||
|
println!("{e}");
|
||||||
|
println!("Exiting ...");
|
||||||
::std::process::exit(1);
|
::std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,47 +159,25 @@ async fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Initalize Tera templates
|
// Initalize Tera templates
|
||||||
let mut template_base_dir = match cli_args.template_location {
|
let template_loader = TemplateEngineLoader::new(
|
||||||
Some(template_base_dir) => template_base_dir,
|
config.template.template_location.clone(),
|
||||||
None => (&config.template.template_location).to_owned(),
|
config.template.extra_config.clone()
|
||||||
};
|
)
|
||||||
if !template_base_dir.ends_with("/") {
|
.cli_template_location(cli_args.template_location)
|
||||||
template_base_dir = template_base_dir + "/";
|
.cli_extra_config_location(cli_args.extra_config);
|
||||||
}
|
|
||||||
let template_extra_config = match &cli_args.extra_config {
|
|
||||||
Some(path) => read_toml_from_file(path),
|
let templating_engine = match template_loader.load_templates() {
|
||||||
None => match &config.template.extra_config {
|
Ok(t) => t.into(),
|
||||||
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,
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Template parsing error(s): {}", e);
|
println!("{e}");
|
||||||
::std::process::exit(1);
|
::std::process::exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let templating_engine = TemplatingEngine::new(
|
|
||||||
tera,
|
|
||||||
template_extra_config,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Static file directory
|
// Static file directory
|
||||||
|
|
||||||
let static_file_directory = cli_args.static_location.unwrap_or(
|
let static_file_directory = template_loader.base_dir()+"/static";
|
||||||
config.server.static_location.clone().unwrap_or(
|
|
||||||
template_base_dir+"/static"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
println!("Static files will be served from: {static_file_directory}");
|
println!("Static files will be served from: {static_file_directory}");
|
||||||
|
|
||||||
|
@ -20,6 +20,14 @@ use crate::mycelium::MycQuerySettings;
|
|||||||
|
|
||||||
/* The engine itself */
|
/* 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)]
|
#[derive(Clone)]
|
||||||
pub struct MycEngine<V, S, F>
|
pub struct MycEngine<V, S, F>
|
||||||
where V: MycView<S, F>, S: MycQuerySettings<F>, F: MycFormat {
|
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 engine;
|
||||||
mod format;
|
mod format;
|
||||||
mod query_settings;
|
mod query_settings;
|
||||||
|
mod template_loader;
|
||||||
|
mod toml_helper;
|
||||||
mod view;
|
mod view;
|
||||||
|
|
||||||
pub use self::engine::MycEngine;
|
pub use self::engine::MycEngine;
|
||||||
|
pub use self::engine::MycProtoEngine;
|
||||||
pub use self::format::HtmlTextJsonFormat;
|
pub use self::format::HtmlTextJsonFormat;
|
||||||
pub use self::format::MycFormat;
|
pub use self::format::MycFormat;
|
||||||
pub use self::format::MycFormatFamily;
|
pub use self::format::MycFormatFamily;
|
||||||
pub use self::query_settings::MycQuerySettings;
|
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;
|
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…
x
Reference in New Issue
Block a user