pub mod client;
pub mod schema;
pub mod server;
#[cfg(test)]
mod tests;
pub use client::ClientConfig;
pub use schema::{PortMapping, Protocol, Role};
pub use server::ServerConfig;
use anyhow::{Context, Result};
use std::fs;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub enum Config {
Client(ClientConfig),
Server(ServerConfig),
}
impl Config {
pub fn role(&self) -> Role {
match self {
Config::Client(c) => c.role,
Config::Server(s) => s.role,
}
}
pub fn interface(&self) -> &str {
match self {
Config::Client(c) => &c.local_interface,
Config::Server(s) => &s.interface,
}
}
pub fn ports(&self) -> &[PortMapping] {
match self {
Config::Client(c) => &c.ports,
Config::Server(_) => &[],
}
}
pub fn ports_mut(&mut self) -> &mut Vec<PortMapping> {
match self {
Config::Client(c) => &mut c.ports,
Config::Server(_) => unreachable!("Server config has no ports"),
}
}
pub fn public_key(&self) -> &str {
match self {
Config::Client(c) => &c.public_key,
Config::Server(s) => &s.public_key,
}
}
pub fn save(&self) -> Result<()> {
match self {
Config::Client(c) => c.save(),
Config::Server(s) => s.save(),
}
}
pub fn server_address(&self) -> &str {
match self {
Config::Client(c) => &c.server_address,
Config::Server(_) => unreachable!("Server config has no server_address"),
}
}
pub fn server_port(&self) -> u16 {
match self {
Config::Client(c) => c.server_port,
Config::Server(_) => unreachable!("Server config has no server_port"),
}
}
pub fn listen_port(&self) -> u16 {
match self {
Config::Client(_) => unreachable!("Client config has no listen_port"),
Config::Server(s) => s.listen_port,
}
}
pub fn allowed_clients_count(&self) -> usize {
match self {
Config::Client(_) => 0,
Config::Server(s) => s.allowed_clients.len(),
}
}
}
pub fn load_config() -> Result<Config> {
let client_path = client_config_path();
if client_path.exists() {
let content = fs::read_to_string(&client_path)
.context(format!("Failed to read {}", client_path.display()))?;
let config: ClientConfig = toml::from_str(&content)
.context("Failed to parse client config")?;
return Ok(Config::Client(config));
}
let server_path = server_config_path();
if server_path.exists() {
let content = fs::read_to_string(&server_path)
.context(format!("Failed to read {}", server_path.display()))?;
let config: ServerConfig = toml::from_str(&content)
.context("Failed to parse server config")?;
return Ok(Config::Server(config));
}
Err(anyhow::anyhow!(
"No configuration found. Run 'porta setup' first.\n\
Searched:\n {}\n {}",
client_path.display(),
server_path.display()
))
}
pub fn client_config_path() -> PathBuf {
dirs::config_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join("porta")
.join("client.toml")
}
pub fn server_config_path() -> PathBuf {
PathBuf::from("/etc/porta/server.toml")
}
pub fn client_key_path() -> PathBuf {
dirs::config_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join("porta")
.join("client.key")
}
pub fn server_key_path() -> PathBuf {
PathBuf::from("/etc/porta/server.key")
}