sleepytunny/src/config.rs

197 lines
6.2 KiB
Rust

use anyhow::Context;
use serde::{Deserialize, Serialize};
use std::fs;
use std::io::Write;
use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs};
//TODO: use Arc<str> instead of String for all this stuff that needs to be cloned and last forever
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Server {
pub daemonize: bool,
pub endpoint: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub server_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stdout: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stderr: Option<String>,
}
impl Server {
pub fn new() -> Self {
Self {
daemonize: true,
endpoint: String::from("127.0.0.1:9092"),
server_name: Some(String::from("alphamethyl.barr0w.net")),
user: Some(String::from("nobody")),
group: Some(String::from("daemon")),
stdout: Some(String::from("/tmp/sleepyserver")),
stderr: Some(String::from("/tmp/sleepyserver.err")),
}
}
pub fn user(&self) -> anyhow::Result<String> {
match &self.user {
Some(u) => Ok(u.clone()),
None => Ok(String::from("nobody")),
}
}
pub fn group(&self) -> anyhow::Result<String> {
match &self.group {
Some(g) => Ok(g.clone()),
None => Ok(String::from("daemon")),
}
}
pub fn stdout(&self) -> anyhow::Result<String> {
match &self.stdout {
Some(s) => Ok(s.clone()),
None => Ok(String::from("/tmp/sleepyserver")),
}
}
pub fn stderr(&self) -> anyhow::Result<String> {
match &self.stderr {
Some(s) => Ok(s.clone()),
None => Ok(String::from("/tmp/sleepyserver.err")),
}
}
/// Returns the socketaddr our endpoint should bind to
pub fn endpoint(&self) -> anyhow::Result<SocketAddr> {
self.endpoint
.to_socket_addrs()?
.next()
.context("bad server socketaddr")
}
/// Returns the server name for SNI
pub fn server_name(&self) -> anyhow::Result<Option<&String>> {
Ok(self.server_name.as_ref())
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Client {
pub endpoint: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub server_name: Option<String>,
}
impl Client {
pub fn new() -> Self {
Self {
endpoint: String::from("alphamethyl.barr0w.net:9092"),
server_name: Some(String::from("alphamethyl.barr0w.net")),
}
}
/// Returns the socketaddr that our udp socket should bind to
pub fn local_bind_addr(&self) -> anyhow::Result<SocketAddr> {
Ok("0.0.0.0:0".parse().unwrap())
}
/// Returns the socketaddr of the server's endpoint
pub fn endpoint(&self) -> anyhow::Result<SocketAddr> {
self.endpoint
.to_socket_addrs()?
.next()
.context("bad server socketaddr")
}
/// Returns the server name for SNI
pub fn server_name(&self) -> anyhow::Result<Option<&String>> {
Ok(self.server_name.as_ref())
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TLS {
pub cert_file: String,
#[serde(skip_serializing)]
pub cert: Option<String>, // Eventually maybe an actual cert object
pub key_file: String,
#[serde(skip_serializing)]
pub key: Option<String>, // Eventually maybe an actual key object
}
impl TLS {
pub fn new() -> Self {
Self {
cert_file: String::from("/etc/sleepytunny/tls.crt"),
key_file: String::from("/etc/sleepytunny/tls.key"),
cert: None,
key: None,
}
}
pub fn load(&mut self) -> anyhow::Result<()> {
let k = fs::read_to_string(&self.key_file)?;
let c = fs::read_to_string(&self.cert_file)?;
self.cert = Some(c);
self.key = Some(k);
Ok(())
}
pub fn cert(&self) -> anyhow::Result<String> {
Ok(self.cert.clone().unwrap())
}
pub fn key(&self) -> anyhow::Result<String> {
Ok(self.key.clone().unwrap())
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Interface {
pub address: Ipv4Addr,
pub netmask: Ipv4Addr,
}
impl Interface {
pub fn new() -> Self {
Self {
address: Ipv4Addr::from([192, 168, 255, 1]),
netmask: Ipv4Addr::from([255, 255, 255, 255]),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Configuration {
#[serde(skip_serializing_if = "Option::is_none")]
pub server: Option<Server>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client: Option<Client>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tls: Option<TLS>,
pub interface: Interface,
}
impl Configuration {
pub fn new() -> Self {
Self {
server: Some(Server::new()),
client: Some(Client::new()),
tls: Some(TLS::new()),
interface: Interface::new(),
}
}
/// Loads configuration file f and returns a struct of all parsed values
pub fn load_config(f: &str) -> anyhow::Result<Self> {
let config = fs::read_to_string(f);
match config {
Ok(c) => Ok(toml::from_str(&c)?),
Err(_) => Ok(Self::new()),
}
}
/// Generates new configuration file f with default values
pub fn generate_config(f: &str) -> anyhow::Result<()> {
let config = Self::new();
let mut config_file = fs::File::create(&f)?;
config_file.write(toml::to_string(&config)?.as_bytes())?;
Ok(())
}
/// Returns the server config or an appropriate error
pub fn server(&self) -> anyhow::Result<&Server> {
self.server
.as_ref()
.context("this config is not a server config")
}
/// Returns the client config or an appropriate error
pub fn client(&self) -> anyhow::Result<&Client> {
self.client
.as_ref()
.context("this config is not a client config")
}
}