diff --git a/conf.rs b/conf.rs index adbceb7..216e898 100755 --- a/conf.rs +++ b/conf.rs @@ -1,4 +1,6 @@ +use std::collections::HashMap; use std::net::SocketAddr; +use std::sync::{Arc, Mutex}; use std::{fs::File, process::exit}; use std::io::prelude::*; use serde::Deserialize; @@ -6,16 +8,16 @@ use lazy_static::lazy_static; use serde_yaml::from_str; lazy_static! { - pub static ref CONFIG: RootConf = load_config(); + pub static ref CONFIG: Arc> = Arc::new(Mutex::new(load())); } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Clone)] pub struct RootConf { pub listen: SocketAddr, - pub proxy: Vec + pub proxy: HashMap } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Clone)] pub struct ProxyConf { pub hosts: Vec, pub target: String, @@ -24,14 +26,14 @@ pub struct ProxyConf { pub timeout: Option } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Clone)] pub struct SpawnConf { pub command: String, pub args: Option>, pub envs: Option> } -fn load_config() -> RootConf { +fn load() -> RootConf { let file = File::open("config.yml"); if file.is_err() { println!("[!] Config file was not found!"); exit(-1); @@ -44,4 +46,13 @@ fn load_config() -> RootConf { Ok(conf) => conf, Err(_) => {println!("[!] Unable to parse config!"); exit(0);} } +} + +pub fn reload() { + let conf: RootConf = load(); + *CONFIG.lock().unwrap() = conf; +} + +pub fn get() -> RootConf { + return CONFIG.lock().unwrap().clone(); } \ No newline at end of file diff --git a/config.yml b/config.yml index f20a503..62faf9f 100755 --- a/config.yml +++ b/config.yml @@ -2,14 +2,16 @@ listen: "[::]:3000" proxy: -- hosts: [ "website.local.gd", "website-alt.local.gd" ] - socket: true - target: "./www.sock" - spawn: - command: "/usr/bin/node" - args: [ "./webserver/index.mjs" ] - envs: [ ["PORT", "www.sock"] ] - timeout: 10 + web: + hosts: [ "website.local.gd", "website-alt.local.gd" ] + socket: true + target: "./www.sock" + spawn: + command: "/usr/bin/node" + args: [ "./webserver/index.mjs" ] + envs: [ ["PORT", "www.sock"] ] + timeout: 10 -- hosts: [ "git.local.gd" ] - target: "http://192.168.0.3:80" \ No newline at end of file + git: + hosts: [ "git.local.gd" ] + target: "http://192.168.0.3:80" \ No newline at end of file diff --git a/data.rs b/data.rs index a25739c..a51e914 100755 --- a/data.rs +++ b/data.rs @@ -1,15 +1,15 @@ -use std::{sync::{Arc, Mutex}}; +use std::{sync::{Arc, Mutex}, vec}; use lazy_static::lazy_static; use tokio::process::Child; use std::collections::HashMap; use hyper::http::HeaderValue; -use crate::conf::{CONFIG, ProxyConf}; +use crate::conf::{ProxyConf, self}; lazy_static! { - pub static ref HOST_MAP: HashMap = generate_host_map(); - pub static ref SERVICES: Arc>> = Arc::new(Mutex::new(vec![])); + pub static ref HOST_MAP: HashMap = generate_host_map(); + pub static ref SERVICES: Arc>> = Arc::new(Mutex::new(HashMap::from_iter(vec![]))); } pub struct ServiceData { @@ -28,14 +28,15 @@ impl ServiceData { } } -pub fn get_proxy(host_index: Option<&usize>) -> Option<&ProxyConf> { - match host_index { - Some(i) => CONFIG.proxy.get(i.clone()), +pub fn get_proxy(name: Option<&String>) -> Option { + let c = conf::get(); + match name { + Some(name) => c.proxy.get(name).cloned(), None => None } } -pub fn get_proxy_index(host: Option<&HeaderValue>) -> Option<&usize> { +pub fn get_proxy_name(host: Option<&HeaderValue>) -> Option<&String> { match host { Some(host) => { let host_parts: Vec<&str> = host.to_str().unwrap().split(":").collect(); @@ -49,11 +50,11 @@ pub fn get_proxy_index(host: Option<&HeaderValue>) -> Option<&usize> { } } -pub fn generate_host_map() -> HashMap { - let mut hosts: Vec<(String, usize)> = vec![]; - for (i, proxy) in CONFIG.proxy.iter().enumerate() { +pub fn generate_host_map() -> HashMap { + let mut hosts: Vec<(String, String)> = vec![]; + for (name, proxy) in conf::get().proxy.iter() { for host in proxy.hosts.iter() { - hosts.push((host.to_string(), i)); + hosts.push((host.to_string(), name.to_string())); }; } HashMap::from_iter(hosts) diff --git a/main.rs b/main.rs index d471611..ced89f3 100755 --- a/main.rs +++ b/main.rs @@ -10,17 +10,17 @@ use tower::make::Shared; use hyper::{service::service_fn, Body, Client, Request, Response, Server}; -use crate::{conf::CONFIG, services::prepare_services}; +use crate::services::prepare_services; async fn run(req: Request) -> Result, hyper::Error> { let host = req.headers().get("host"); - let host_index = data::get_proxy_index(host); - let proxy = data::get_proxy(host_index); + let name = data::get_proxy_name(host); + let proxy = data::get_proxy(name); match proxy { Some(p) => { - check_service(host_index.unwrap().clone(), p).await; + check_service(name.unwrap(), &p).await; // Create new Request let mut request_builder = Request::builder().method(req.method()); @@ -66,13 +66,13 @@ async fn main() { let make_service = Shared::new(service_fn(run)); - let server = Server::bind(&CONFIG.listen).serve(make_service); + let server = Server::bind(&conf::get().listen).serve(make_service); let host_count = HOST_MAP.len(); - let service_count = CONFIG.proxy.len(); - println!("odproxy is listening on {} with {} hosts and {} services", CONFIG.listen, host_count, service_count); + let service_count = conf::get().proxy.len(); + println!("odproxy is listening on {} with {} hosts and {} services", conf::get().listen, host_count, service_count); if let Err(e) = server.await { println!("error: {}", e); } -} +} \ No newline at end of file diff --git a/services.rs b/services.rs index 6f046ae..7c7b966 100755 --- a/services.rs +++ b/services.rs @@ -1,60 +1,60 @@ use std::{process::Stdio, time::{Duration, SystemTime, UNIX_EPOCH}, path::Path, io::Error, thread}; use tokio::{process::{Command, Child}, time::sleep, fs}; -use crate::{data::{SERVICES, ServiceData}, conf::{ProxyConf, CONFIG}}; +use crate::{data::{SERVICES, ServiceData}, conf::{ProxyConf, self}}; -fn modify_service_data(index: usize, modify_fn: F) +fn modify_service_data(name: &String, modify_fn: F) where F: FnOnce(&mut ServiceData) { - let mut vec = SERVICES.lock().unwrap(); - if let Some(service_data) = vec.get_mut(index) { + let mut hashmap = SERVICES.lock().unwrap(); + if let Some(service_data) = hashmap.get_mut(name) { modify_fn(service_data); } } -fn set_service_running(index: usize) { - modify_service_data(index, |s| { +fn set_service_running(name: &String) { + modify_service_data(name, |s| { s.running = true; }); } -fn set_service_last_active(index: usize) { - modify_service_data(index, |s| { +fn set_service_last_active(name: &String) { + modify_service_data(name, |s| { s.last_active = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); }); } -fn is_service_running(index: usize) -> bool { - if let Some(service_data) = SERVICES.lock().unwrap().get(index) { +fn is_service_running(name: &String) -> bool { + if let Some(service_data) = SERVICES.lock().unwrap().get(name) { service_data.running } else { false } } -pub async fn check_service(index: usize, proxy: &ProxyConf) { +pub async fn check_service(name: &String, proxy: &ProxyConf) { if proxy.spawn.is_some() { - if proxy.socket.unwrap_or(false) && SERVICES.lock().unwrap().get(index).unwrap().child.is_none() { + if proxy.socket.unwrap_or(false) && SERVICES.lock().unwrap().get(name).unwrap().child.is_none() { let path = Path::new(&proxy.target); if path.exists() { fs::remove_file(path).await.unwrap(); } } - start_service(index, proxy); - if !is_service_running(index) { - wait_for_service(proxy).await; - set_service_running(index); + start_service(name, &proxy); + if !is_service_running(name) { + wait_for_service(&proxy).await; + set_service_running(name); } - set_service_last_active(index); + set_service_last_active(name); } } -fn start_service(index: usize, proxy: &ProxyConf) -> bool { +fn start_service(name: &String, proxy: &ProxyConf) -> bool { let mut status = false; let spawn = proxy.spawn.as_ref().unwrap(); - modify_service_data(index, |s| { + modify_service_data(name, |s| { if s.child.is_some() { return; } @@ -73,8 +73,9 @@ fn start_service(index: usize, proxy: &ProxyConf) -> bool { return status; } -fn stop_service(index: usize) { - modify_service_data(index, |s| { +fn stop_service(name: &String) { + println!("Stopped"); + modify_service_data(name, |s| { match s.child.as_mut() { Some(c) => { c.start_kill().unwrap(); @@ -94,24 +95,24 @@ async fn wait_for_service(proxy: &ProxyConf) { } pub async fn prepare_services() { - for i in 0..CONFIG.proxy.len() { - let mut vec = SERVICES.lock().unwrap(); - vec.insert(i, ServiceData::new()); + let mut hashmap = SERVICES.lock().unwrap(); + for proxy in conf::get().proxy.into_iter() { + hashmap.insert(proxy.0, ServiceData::new()); } - + let interval_duration = Duration::from_secs(10); thread::spawn(move || { loop { let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); - for (i, proxy) in CONFIG.proxy.iter().enumerate() { + for (name, proxy) in conf::get().proxy.iter() { match proxy.timeout { Some(t) => { { - let vec = SERVICES.lock().unwrap(); - let s = vec.get(i).unwrap(); + let hashmap = SERVICES.lock().unwrap(); + let s = hashmap.get(name).unwrap(); if !s.running || s.last_active+t > now {continue;} } - stop_service(i); + stop_service(name); }, None => {} }