197 lines
6.2 KiB
Rust
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")
|
|
}
|
|
}
|