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.
142 lines
3.4 KiB
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
|
|
},
|
|
}
|
|
}
|