You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
genmarkov/src/config.rs

142 lines
3.4 KiB

//! Server config
use super::*;
use std::{
net::SocketAddr,
path::Path,
io,
borrow::Cow,
num::NonZeroU64,
};
use tokio::{
fs::OpenOptions,
prelude::*,
time::Duration,
io::BufReader,
};
pub const DEFAULT_FILE_LOCATION: &'static str = "markov.toml";
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)]
pub struct Config
{
pub bindpoint: String,
pub file: String,
pub max_content_length: u64,
pub max_gen_size: usize,
pub save_interval_secs: Option<NonZeroU64>,
pub trust_x_forwarded_for: bool,
#[serde(default)]
pub filter: FilterConfig,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)]
pub struct FilterConfig
{
inbound: String,
#[serde(default)]
outbound: String,
}
impl FilterConfig
{
pub fn get_inbound_filter(&self) -> sanitise::filter::Filter
{
let filt: sanitise::filter::Filter = self.inbound.parse().unwrap();
if !filt.is_empty()
{
info!("Loaded inbound filter: {:?}", filt.iter().collect::<String>());
}
filt
}
pub fn get_outbound_filter(&self) -> sanitise::filter::Filter
{
let filt: sanitise::filter::Filter = self.outbound.parse().unwrap();
if !filt.is_empty()
{
info!("Loaded outbound filter: {:?}", filt.iter().collect::<String>());
}
filt
}
}
impl Default for Config
{
#[inline]
fn default() -> Self
{
Self {
bindpoint: SocketAddr::from(([127,0,0,1], 8001)).to_string(),
file: "chain.dat".to_owned(),
max_content_length: 1024 * 1024 * 4,
max_gen_size: 256,
save_interval_secs: Some(unsafe{NonZeroU64::new_unchecked(2)}),
trust_x_forwarded_for: false,
filter: Default::default(),
}
}
}
impl Config
{
pub fn save_interval(&self) -> Option<Duration>
{
self.save_interval_secs.map(|x| Duration::from_secs(x.into()))
}
pub async fn load(from: impl AsRef<Path>) -> io::Result<Self>
{
let file = OpenOptions::new()
.read(true)
.open(from).await?;
let mut buffer= String::new();
let reader = BufReader::new(file);
let mut lines = reader.lines();
while let Some(line) = lines.next_line().await? {
buffer.push_str(&line[..]);
buffer.push('\n');
}
toml::de::from_str(&buffer[..]).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
}
pub async fn save(&self, to: impl AsRef<Path>) -> io::Result<()>
{
let config = toml::ser::to_string_pretty(self).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(to).await?;
file.write_all(config.as_bytes()).await?;
file.shutdown().await?;
Ok(())
}
}
/// Try to load config file specified by args, or default config file
pub fn load() -> impl futures::future::Future<Output =Option<Config>>
{
load_args(std::env::args().skip(1))
}
async fn load_args<I: Iterator<Item=String>>(mut from: I) -> Option<Config>
{
let place = if let Some(arg) = from.next() {
trace!("File {:?} provided", arg);
Cow::Owned(arg)
} else {
warn!("No config file provided. Using default location {:?}", DEFAULT_FILE_LOCATION);
Cow::Borrowed(DEFAULT_FILE_LOCATION)
};
match Config::load(place.as_ref()).await {
Ok(cfg) => {
info!("Loaded config file {:?}", place);
Some(cfg)
},
Err(err) => {
error!("Failed to load config file from {:?}: {}", place, err);
None
},
}
}