about summary refs log tree commit diff stats
path: root/src/smd
diff options
context:
space:
mode:
Diffstat (limited to 'src/smd')
-rw-r--r--src/smd/context.rs27
-rw-r--r--src/smd/endpoints.rs36
-rw-r--r--src/smd/main.rs71
3 files changed, 110 insertions, 24 deletions
diff --git a/src/smd/context.rs b/src/smd/context.rs
new file mode 100644
index 0000000..d8194c5
--- /dev/null
+++ b/src/smd/context.rs
@@ -0,0 +1,27 @@
+use super::Config;
+use salaryman::service::Service;
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
+use std::sync::Arc;
+use tokio::sync::Mutex;
+
+pub struct SalarymanDContext {
+    pub config: Config,
+    pub service: Vec<Arc<Mutex<Service>>>,
+}
+impl SalarymanDContext {
+    pub fn new() -> Self {
+        Self {
+            config: Config::new(),
+            service: Vec::new(),
+        }
+    }
+    pub fn from_parts(config: Config, service: Vec<Arc<Mutex<Service>>>) -> Self {
+        Self { config, service }
+    }
+}
+
+#[derive(Serialize, Deserialize, JsonSchema, Debug)]
+pub struct StdinBuffer {
+    pub string: String,
+}
diff --git a/src/smd/endpoints.rs b/src/smd/endpoints.rs
index 8b13789..48c9720 100644
--- a/src/smd/endpoints.rs
+++ b/src/smd/endpoints.rs
@@ -1 +1,37 @@
+use super::{
+    Config,
+    context::{SalarymanDContext, StdinBuffer},
+};
+use dropshot::{HttpError, HttpResponseOk, RequestContext, TypedBody, endpoint};
+use std::sync::Arc;
 
+#[endpoint {
+    method = GET,
+    path = "/config",
+}]
+pub async fn endpoint_get_config(
+    rqctx: RequestContext<Arc<SalarymanDContext>>,
+) -> Result<HttpResponseOk<Config>, HttpError> {
+    Ok(HttpResponseOk(rqctx.context().config.clone()))
+}
+
+#[endpoint {
+    method = PUT,
+    path = "/services/write"
+}]
+pub async fn endpoint_post_stdin(
+    rqctx: RequestContext<Arc<SalarymanDContext>>,
+    update: TypedBody<StdinBuffer>,
+) -> Result<HttpResponseOk<()>, HttpError> {
+    let ctx = rqctx.context();
+    let stdin_str = update.into_inner();
+    for i in 0..ctx.service.len() {
+        let mut lock = ctx.service[i].lock().await;
+        if lock.started().await {
+            lock.writeln_stdin(stdin_str.string.clone()).await.unwrap(); //TODO: PROPERLY HANDLE ERROR!
+        }
+        drop(lock);
+    }
+
+    Ok(HttpResponseOk(()))
+}
diff --git a/src/smd/main.rs b/src/smd/main.rs
index fee2d9e..628785a 100644
--- a/src/smd/main.rs
+++ b/src/smd/main.rs
@@ -1,11 +1,17 @@
+mod context;
 mod endpoints;
 
 use clap::Parser;
+use dropshot::{ApiDescription, ConfigLogging, ConfigLoggingLevel, ServerBuilder};
 use salaryman::service::{Service, ServiceConf};
+use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use tokio::fs::read_to_string;
+use tokio::{fs::read_to_string, sync::Mutex};
 
-use std::{net::IpAddr, path::PathBuf};
+use std::{net::IpAddr, path::PathBuf, sync::Arc};
+
+use crate::context::SalarymanDContext;
+use crate::endpoints::{endpoint_get_config, endpoint_post_stdin};
 
 #[derive(Parser, Debug)]
 #[command(version, about, long_about = None)]
@@ -36,11 +42,28 @@ struct Args {
     port: u16,
 }
 
-#[derive(Serialize, Deserialize, Debug)]
-struct Config {
-    address: Option<IpAddr>,
-    port: Option<u16>,
-    service: Vec<ServiceConf>,
+#[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<IpAddr>,
+    pub port: Option<u16>,
+    pub user: Vec<User>,
+    pub service: Vec<ServiceConf>,
+}
+impl Config {
+    pub fn new() -> Self {
+        Self {
+            address: None,
+            port: None,
+            user: Vec::new(),
+            service: Vec::new(),
+        }
+    }
 }
 
 async fn load_config(file: &PathBuf) -> Result<Config, Box<dyn std::error::Error>> {
@@ -66,26 +89,26 @@ async fn load_config(file: &PathBuf) -> Result<Config, Box<dyn std::error::Error
 async fn main() -> Result<(), Box<dyn std::error::Error>> {
     let args = Args::parse();
     let conf: Config = load_config(&args.config).await?;
-    let mut services: Vec<Service> = Vec::new();
+    let mut services: Vec<Arc<Mutex<Service>>> = Vec::new();
     for i in 0..conf.service.len() {
-        services.push(Service::from_conf(&conf.service[i]));
+        services.push(Arc::new(Mutex::new(Service::from_conf(&conf.service[i]))));
         if conf.service[i].autostart {
-            services[i].start().await?;
-            services[i].scan_stdout().await?;
-            services[i].scan_stderr().await?;
-        }
-    }
-    tokio::time::sleep(std::time::Duration::from_secs(60)).await;
-    println!("trying to write to stdin!");
-    for i in 0..services.len() {
-        services[i].write_stdin("stop\n".into()).await?;
-    }
-    tokio::time::sleep(std::time::Duration::from_secs(30)).await;
-    for mut service in services {
-        match service.stop().await {
-            Ok(_) => println!("lol it was killed"),
-            Err(_) => println!("it either didn't exist, or failed to kill"),
+            let mut lock = services[i].lock().await;
+            lock.start().await?;
+            lock.scan_stdout().await?;
+            lock.scan_stderr().await?;
+            drop(lock);
         }
     }
+    let log_conf = ConfigLogging::StderrTerminal {
+        level: ConfigLoggingLevel::Info,
+    };
+    let log = log_conf.to_logger("smd")?;
+    let ctx = Arc::new(SalarymanDContext::from_parts(conf, services));
+    let mut api = ApiDescription::new();
+    api.register(endpoint_get_config).unwrap();
+    api.register(endpoint_post_stdin).unwrap();
+    let server = ServerBuilder::new(api, ctx.clone(), log).start()?;
+    server.await?;
     Ok(())
 }