use std::fs;
use std::io::BufReader;
use std::net::TcpListener;
use std::sync::Arc;
use rustls::ServerConfig as TlsServerConfig;
use rustls::pki_types::CertificateDer;
use crate::auth::RateLimiter;
use crate::config::ServerConfig;
use crate::handler::{self, HandlerContext};
use crate::storage::ProjectStorage;
fn build_tls_config(config: &ServerConfig) -> Result<TlsServerConfig, String> {
let cert_file = fs::File::open(&config.tls_cert_path)
.map_err(|e| format!("Cannot open TLS cert {}: {}", config.tls_cert_path.display(), e))?;
let mut cert_reader = BufReader::new(cert_file);
let certs: Vec<CertificateDer> = rustls_pemfile::certs(&mut cert_reader)
.collect::<Result<Vec<_>, _>>()
.map_err(|e| format!("Cannot parse TLS cert: {}", e))?;
if certs.is_empty() {
return Err("No certificates found in cert file".into());
}
let key_file = fs::File::open(&config.tls_key_path)
.map_err(|e| format!("Cannot open TLS key {}: {}", config.tls_key_path.display(), e))?;
let mut key_reader = BufReader::new(key_file);
let key = rustls_pemfile::private_key(&mut key_reader)
.map_err(|e| format!("Cannot parse TLS key: {}", e))?
.ok_or_else(|| "No private key found in key file".to_string())?;
let tls_config = TlsServerConfig::builder()
.with_no_client_auth()
.with_single_cert(certs, key)
.map_err(|e| format!("Cannot build TLS config: {}", e))?;
Ok(tls_config)
}
pub fn run(config: ServerConfig) -> Result<(), String> {
let psk = pwr_core::crypto::psk_from_hex(&config.auth_token)
.map_err(|e| format!("Invalid auth token: {}", e))?;
let storage = ProjectStorage::new(config.clone())?;
let storage = Arc::new(std::sync::RwLock::new(storage));
let rate_limiter = Arc::new(std::sync::Mutex::new(RateLimiter::new()));
let tls_config = Arc::new(build_tls_config(&config)?);
let bind_addr = config.bind_addr();
let listener = TcpListener::bind(&bind_addr)
.map_err(|e| format!("Cannot bind to {}: {}", bind_addr, e))?;
log::info!("pwr-server listening on {} (TLS 1.3)", bind_addr);
log::info!("Storage: {}", config.storage_base_path.display());
for stream_result in listener.incoming() {
let stream = stream_result.map_err(|e| format!("Accept error: {}", e))?;
let peer_addr = stream
.peer_addr()
.unwrap_or_else(|_| "unknown".parse().unwrap());
let psk = psk;
let storage = storage.clone();
let rate_limiter = rate_limiter.clone();
let tls_config = tls_config.clone();
std::thread::spawn(move || {
log::debug!("Connection from {}", peer_addr);
let conn = match rustls::ServerConnection::new(tls_config.clone()) {
Ok(c) => c,
Err(e) => {
log::error!("Cannot create TLS connection: {}", e);
return;
}
};
let mut tls_stream = rustls::StreamOwned::new(conn, stream);
let ctx = HandlerContext {
storage: storage.clone(),
rate_limiter: rate_limiter.clone(),
psk,
peer_addr,
connected_at: std::time::Instant::now(),
};
if let Err(e) = handler::handle_connection(&mut tls_stream, ctx) {
log::error!("Handler error for {}: {}", peer_addr, e);
}
});
}
Ok(())
}