From e33f9a59f875edf1240ca80c1014235296ff3cbf Mon Sep 17 00:00:00 2001 From: yuzu Date: Sat, 12 Jul 2025 22:17:26 +0000 Subject: add additional endpoints; change out mutexes for rwlocks git-svn-id: svn+ssh://diminuette.aengel.lesbianunix.dev/salaryman/trunk@15 b9215c17-b818-4693-b096-d1e41a411fef --- src/server/main.rs | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 src/server/main.rs (limited to 'src/server/main.rs') diff --git a/src/server/main.rs b/src/server/main.rs new file mode 100644 index 0000000..7557145 --- /dev/null +++ b/src/server/main.rs @@ -0,0 +1,162 @@ +mod context; +mod endpoints; + +use clap::Parser; +use dropshot::{ApiDescription, ConfigDropshot, ConfigLogging, ConfigLoggingLevel, ServerBuilder}; +use salaryman::service::{Service, ServiceConf}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use tokio::{fs::read_to_string, sync::RwLock}; + +use std::{ + net::{IpAddr, SocketAddr}, + path::PathBuf, + sync::Arc, +}; + +use crate::context::{SalarymanDContext, SalarymanService}; +use crate::endpoints::{ + endpoint_get_config, endpoint_get_config_save, endpoint_get_service, endpoint_get_services, + endpoint_post_service, endpoint_post_stdin, endpoint_put_config, endpoint_restart_service, + endpoint_start_service, endpoint_stop_service, +}; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + #[arg( + short, + long, + value_name = "FILE", + help = "config file override", + default_value = "salaryman.toml" + )] + config: PathBuf, + #[arg( + short, + long, + value_name = "ADDR", + help = "IP address to bind API to", + default_value = "127.0.0.1" + )] + address: IpAddr, + #[arg( + short, + long, + value_name = "PORT", + help = "TCP Port to bind API to", + default_value = "3080" + )] + port: u16, +} + +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)] +pub struct User { + pub username: String, + pub token: String, +} + +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)] +pub struct Config { + pub address: Option, + pub port: Option, + pub user: Vec, + pub service: Vec, +} +impl Config { + pub fn new() -> Self { + Self { + address: None, + port: None, + user: Vec::new(), + service: Vec::new(), + } + } +} + +async fn load_config(file: &PathBuf) -> Result> { + let s: String = match read_to_string(file).await { + Ok(s) => s, + Err(_) => { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::NotFound, + "cannot find config file", + ))); + } + }; + match toml::from_str(s.as_str()) { + Ok(c) => Ok(c), + Err(_) => Err(Box::new(std::io::Error::new( + std::io::ErrorKind::Other, + "unable to parse config file", + ))), + } +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let args = Args::parse(); + let conf: Config = load_config(&args.config).await?; + let addr = if let Some(addr) = conf.address { + addr + } else { + args.address + }; + let port = if let Some(port) = conf.port { + port + } else { + args.port + }; + let bind = SocketAddr::new(addr, port); + let services: RwLock>> = RwLock::new(Vec::new()); + for i in 0..conf.service.len() { + let mut lock = services.write().await; + lock.push(Arc::new(SalarymanService::from_parts( + conf.service[i].clone(), + Arc::new(RwLock::new(Service::from_conf(&conf.service[i]))), + ))); + drop(lock); + } + let lock = services.write().await; + for i in 0..lock.len() { + if lock[i].config.autostart { + let mut l = lock[i].service.write().await; + l.start().await?; + l.scan_stdout().await?; + l.scan_stderr().await?; + drop(l); + } + } + drop(lock); + let log_conf = ConfigLogging::StderrTerminal { + level: ConfigLoggingLevel::Info, + }; + let log = log_conf.to_logger("smd")?; + let ctx = Arc::new(SalarymanDContext::from_parts( + services, + args.config, + Arc::new(RwLock::new(conf)), + )); + let config = ConfigDropshot { + bind_address: bind, + ..Default::default() + }; + let mut api = ApiDescription::new(); + api.register(endpoint_get_services)?; + api.register(endpoint_get_service)?; + api.register(endpoint_start_service)?; + api.register(endpoint_stop_service)?; + api.register(endpoint_restart_service)?; + api.register(endpoint_post_stdin)?; + api.register(endpoint_post_service)?; + api.register(endpoint_get_config)?; + api.register(endpoint_put_config)?; + api.register(endpoint_get_config_save)?; + api.openapi("Salaryman", semver::Version::new(1, 0, 0)) + .write(&mut std::io::stdout())?; + let server = ServerBuilder::new(api, ctx.clone(), log) + .config(config) + .start()?; + server.await?; + Ok(()) +} -- cgit 1.4.1-2-gfad0