ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/salaryman/trunk/src/smd/main.rs
Revision: 14
Committed: Sat Jul 12 06:17:38 2025 UTC (2 months, 4 weeks ago) by yuzu
File size: 4110 byte(s)
Log Message:
add start, stop, restart endpoints

File Contents

# Content
1 mod context;
2 mod endpoints;
3
4 use clap::Parser;
5 use dropshot::{ApiDescription, ConfigDropshot, ConfigLogging, ConfigLoggingLevel, ServerBuilder};
6 use salaryman::service::{Service, ServiceConf};
7 use schemars::JsonSchema;
8 use serde::{Deserialize, Serialize};
9 use tokio::{fs::read_to_string, sync::Mutex};
10
11 use std::{
12 net::{IpAddr, SocketAddr},
13 path::PathBuf,
14 sync::Arc,
15 };
16
17 use crate::context::{SalarymanDContext, SalarymanService};
18 use crate::endpoints::{
19 endpoint_get_service, endpoint_get_services, endpoint_post_stdin, endpoint_restart_service,
20 endpoint_start_service, endpoint_stop_service,
21 };
22
23 #[derive(Parser, Debug)]
24 #[command(version, about, long_about = None)]
25 struct Args {
26 #[arg(
27 short,
28 long,
29 value_name = "FILE",
30 help = "config file override",
31 default_value = "salaryman.toml"
32 )]
33 config: PathBuf,
34 #[arg(
35 short,
36 long,
37 value_name = "ADDR",
38 help = "IP address to bind API to",
39 default_value = "127.0.0.1"
40 )]
41 address: IpAddr,
42 #[arg(
43 short,
44 long,
45 value_name = "PORT",
46 help = "TCP Port to bind API to",
47 default_value = "3080"
48 )]
49 port: u16,
50 }
51
52 #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)]
53 pub struct User {
54 pub username: String,
55 pub token: String,
56 }
57
58 #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)]
59 pub struct Config {
60 pub address: Option<IpAddr>,
61 pub port: Option<u16>,
62 pub user: Vec<User>,
63 pub service: Vec<ServiceConf>,
64 }
65 impl Config {
66 pub fn new() -> Self {
67 Self {
68 address: None,
69 port: None,
70 user: Vec::new(),
71 service: Vec::new(),
72 }
73 }
74 }
75
76 async fn load_config(file: &PathBuf) -> Result<Config, Box<dyn std::error::Error>> {
77 let s: String = match read_to_string(file).await {
78 Ok(s) => s,
79 Err(_) => {
80 return Err(Box::new(std::io::Error::new(
81 std::io::ErrorKind::NotFound,
82 "cannot find config file",
83 )));
84 }
85 };
86 match toml::from_str(s.as_str()) {
87 Ok(c) => Ok(c),
88 Err(_) => Err(Box::new(std::io::Error::new(
89 std::io::ErrorKind::Other,
90 "unable to parse config file",
91 ))),
92 }
93 }
94
95 #[tokio::main]
96 async fn main() -> Result<(), Box<dyn std::error::Error>> {
97 let args = Args::parse();
98 let conf: Config = load_config(&args.config).await?;
99 let addr = if let Some(addr) = conf.address {
100 addr
101 } else {
102 args.address
103 };
104 let port = if let Some(port) = conf.port {
105 port
106 } else {
107 args.port
108 };
109 let bind = SocketAddr::new(addr, port);
110 let mut services: Vec<Arc<SalarymanService>> = Vec::new();
111 for i in 0..conf.service.len() {
112 services.push(Arc::new(SalarymanService::from_parts(
113 conf.service[i].clone(),
114 Arc::new(Mutex::new(Service::from_conf(&conf.service[i]))),
115 )));
116 }
117 for i in 0..services.len() {
118 if services[i].config.autostart {
119 let mut lock = services[i].service.lock().await;
120 lock.start().await?;
121 lock.scan_stdout().await?;
122 lock.scan_stderr().await?;
123 }
124 }
125 let log_conf = ConfigLogging::StderrTerminal {
126 level: ConfigLoggingLevel::Info,
127 };
128 let log = log_conf.to_logger("smd")?;
129 let ctx = Arc::new(SalarymanDContext::from_vec(services));
130 let config = ConfigDropshot {
131 bind_address: bind,
132 ..Default::default()
133 };
134 let mut api = ApiDescription::new();
135 api.register(endpoint_get_services)?;
136 api.register(endpoint_get_service)?;
137 api.register(endpoint_start_service)?;
138 api.register(endpoint_stop_service)?;
139 api.register(endpoint_restart_service)?;
140 api.register(endpoint_post_stdin)?;
141 api.openapi("Salaryman", semver::Version::new(1, 0, 0))
142 .write(&mut std::io::stdout())?;
143 let server = ServerBuilder::new(api, ctx.clone(), log)
144 .config(config)
145 .start()?;
146 server.await?;
147 Ok(())
148 }