Changed config & data structure

This commit is contained in:
Filip Znachor 2023-06-15 18:09:58 +02:00
parent d2efbe92ca
commit cf94b742e4
5 changed files with 80 additions and 65 deletions

23
conf.rs
View file

@ -1,4 +1,6 @@
use std::collections::HashMap;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::{Arc, Mutex};
use std::{fs::File, process::exit}; use std::{fs::File, process::exit};
use std::io::prelude::*; use std::io::prelude::*;
use serde::Deserialize; use serde::Deserialize;
@ -6,16 +8,16 @@ use lazy_static::lazy_static;
use serde_yaml::from_str; use serde_yaml::from_str;
lazy_static! { lazy_static! {
pub static ref CONFIG: RootConf = load_config(); pub static ref CONFIG: Arc<Mutex<RootConf>> = Arc::new(Mutex::new(load()));
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize, Clone)]
pub struct RootConf { pub struct RootConf {
pub listen: SocketAddr, pub listen: SocketAddr,
pub proxy: Vec<ProxyConf> pub proxy: HashMap<String, ProxyConf>
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize, Clone)]
pub struct ProxyConf { pub struct ProxyConf {
pub hosts: Vec<String>, pub hosts: Vec<String>,
pub target: String, pub target: String,
@ -24,14 +26,14 @@ pub struct ProxyConf {
pub timeout: Option<u64> pub timeout: Option<u64>
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize, Clone)]
pub struct SpawnConf { pub struct SpawnConf {
pub command: String, pub command: String,
pub args: Option<Vec<String>>, pub args: Option<Vec<String>>,
pub envs: Option<Vec<(String, String)>> pub envs: Option<Vec<(String, String)>>
} }
fn load_config() -> RootConf { fn load() -> RootConf {
let file = File::open("config.yml"); let file = File::open("config.yml");
if file.is_err() { if file.is_err() {
println!("[!] Config file was not found!"); exit(-1); println!("[!] Config file was not found!"); exit(-1);
@ -44,4 +46,13 @@ fn load_config() -> RootConf {
Ok(conf) => conf, Ok(conf) => conf,
Err(_) => {println!("[!] Unable to parse config!"); exit(0);} 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();
} }

View file

@ -2,14 +2,16 @@ listen: "[::]:3000"
proxy: proxy:
- hosts: [ "website.local.gd", "website-alt.local.gd" ] web:
socket: true hosts: [ "website.local.gd", "website-alt.local.gd" ]
target: "./www.sock" socket: true
spawn: target: "./www.sock"
command: "/usr/bin/node" spawn:
args: [ "./webserver/index.mjs" ] command: "/usr/bin/node"
envs: [ ["PORT", "www.sock"] ] args: [ "./webserver/index.mjs" ]
timeout: 10 envs: [ ["PORT", "www.sock"] ]
timeout: 10
- hosts: [ "git.local.gd" ] git:
target: "http://192.168.0.3:80" hosts: [ "git.local.gd" ]
target: "http://192.168.0.3:80"

25
data.rs
View file

@ -1,15 +1,15 @@
use std::{sync::{Arc, Mutex}}; use std::{sync::{Arc, Mutex}, vec};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use tokio::process::Child; use tokio::process::Child;
use std::collections::HashMap; use std::collections::HashMap;
use hyper::http::HeaderValue; use hyper::http::HeaderValue;
use crate::conf::{CONFIG, ProxyConf}; use crate::conf::{ProxyConf, self};
lazy_static! { lazy_static! {
pub static ref HOST_MAP: HashMap<String, usize> = generate_host_map(); pub static ref HOST_MAP: HashMap<String, String> = generate_host_map();
pub static ref SERVICES: Arc<Mutex<Vec<ServiceData>>> = Arc::new(Mutex::new(vec![])); pub static ref SERVICES: Arc<Mutex<HashMap<String, ServiceData>>> = Arc::new(Mutex::new(HashMap::from_iter(vec![])));
} }
pub struct ServiceData { pub struct ServiceData {
@ -28,14 +28,15 @@ impl ServiceData {
} }
} }
pub fn get_proxy(host_index: Option<&usize>) -> Option<&ProxyConf> { pub fn get_proxy(name: Option<&String>) -> Option<ProxyConf> {
match host_index { let c = conf::get();
Some(i) => CONFIG.proxy.get(i.clone()), match name {
Some(name) => c.proxy.get(name).cloned(),
None => None None => None
} }
} }
pub fn get_proxy_index(host: Option<&HeaderValue>) -> Option<&usize> { pub fn get_proxy_name(host: Option<&HeaderValue>) -> Option<&String> {
match host { match host {
Some(host) => { Some(host) => {
let host_parts: Vec<&str> = host.to_str().unwrap().split(":").collect(); 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<String, usize> { pub fn generate_host_map() -> HashMap<String, String> {
let mut hosts: Vec<(String, usize)> = vec![]; let mut hosts: Vec<(String, String)> = vec![];
for (i, proxy) in CONFIG.proxy.iter().enumerate() { for (name, proxy) in conf::get().proxy.iter() {
for host in proxy.hosts.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) HashMap::from_iter(hosts)

16
main.rs
View file

@ -10,17 +10,17 @@ use tower::make::Shared;
use hyper::{service::service_fn, Body, Client, Request, Response, Server}; 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<Body>) -> Result<Response<Body>, hyper::Error> { async fn run(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
let host = req.headers().get("host"); let host = req.headers().get("host");
let host_index = data::get_proxy_index(host); let name = data::get_proxy_name(host);
let proxy = data::get_proxy(host_index); let proxy = data::get_proxy(name);
match proxy { match proxy {
Some(p) => { Some(p) => {
check_service(host_index.unwrap().clone(), p).await; check_service(name.unwrap(), &p).await;
// Create new Request // Create new Request
let mut request_builder = Request::builder().method(req.method()); 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 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 host_count = HOST_MAP.len();
let service_count = CONFIG.proxy.len(); let service_count = conf::get().proxy.len();
println!("odproxy is listening on {} with {} hosts and {} services", CONFIG.listen, host_count, service_count); println!("odproxy is listening on {} with {} hosts and {} services", conf::get().listen, host_count, service_count);
if let Err(e) = server.await { if let Err(e) = server.await {
println!("error: {}", e); println!("error: {}", e);
} }
} }

View file

@ -1,60 +1,60 @@
use std::{process::Stdio, time::{Duration, SystemTime, UNIX_EPOCH}, path::Path, io::Error, thread}; use std::{process::Stdio, time::{Duration, SystemTime, UNIX_EPOCH}, path::Path, io::Error, thread};
use tokio::{process::{Command, Child}, time::sleep, fs}; 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<F>(index: usize, modify_fn: F) fn modify_service_data<F>(name: &String, modify_fn: F)
where F: FnOnce(&mut ServiceData) where F: FnOnce(&mut ServiceData)
{ {
let mut vec = SERVICES.lock().unwrap(); let mut hashmap = SERVICES.lock().unwrap();
if let Some(service_data) = vec.get_mut(index) { if let Some(service_data) = hashmap.get_mut(name) {
modify_fn(service_data); modify_fn(service_data);
} }
} }
fn set_service_running(index: usize) { fn set_service_running(name: &String) {
modify_service_data(index, |s| { modify_service_data(name, |s| {
s.running = true; s.running = true;
}); });
} }
fn set_service_last_active(index: usize) { fn set_service_last_active(name: &String) {
modify_service_data(index, |s| { modify_service_data(name, |s| {
s.last_active = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); s.last_active = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
}); });
} }
fn is_service_running(index: usize) -> bool { fn is_service_running(name: &String) -> bool {
if let Some(service_data) = SERVICES.lock().unwrap().get(index) { if let Some(service_data) = SERVICES.lock().unwrap().get(name) {
service_data.running service_data.running
} else { } else {
false 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.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); let path = Path::new(&proxy.target);
if path.exists() { if path.exists() {
fs::remove_file(path).await.unwrap(); fs::remove_file(path).await.unwrap();
} }
} }
start_service(index, proxy); start_service(name, &proxy);
if !is_service_running(index) { if !is_service_running(name) {
wait_for_service(proxy).await; wait_for_service(&proxy).await;
set_service_running(index); 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 mut status = false;
let spawn = proxy.spawn.as_ref().unwrap(); let spawn = proxy.spawn.as_ref().unwrap();
modify_service_data(index, |s| { modify_service_data(name, |s| {
if s.child.is_some() { if s.child.is_some() {
return; return;
} }
@ -73,8 +73,9 @@ fn start_service(index: usize, proxy: &ProxyConf) -> bool {
return status; return status;
} }
fn stop_service(index: usize) { fn stop_service(name: &String) {
modify_service_data(index, |s| { println!("Stopped");
modify_service_data(name, |s| {
match s.child.as_mut() { match s.child.as_mut() {
Some(c) => { Some(c) => {
c.start_kill().unwrap(); c.start_kill().unwrap();
@ -94,24 +95,24 @@ async fn wait_for_service(proxy: &ProxyConf) {
} }
pub async fn prepare_services() { pub async fn prepare_services() {
for i in 0..CONFIG.proxy.len() { let mut hashmap = SERVICES.lock().unwrap();
let mut vec = SERVICES.lock().unwrap(); for proxy in conf::get().proxy.into_iter() {
vec.insert(i, ServiceData::new()); hashmap.insert(proxy.0, ServiceData::new());
} }
let interval_duration = Duration::from_secs(10); let interval_duration = Duration::from_secs(10);
thread::spawn(move || { thread::spawn(move || {
loop { loop {
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); 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 { match proxy.timeout {
Some(t) => { Some(t) => {
{ {
let vec = SERVICES.lock().unwrap(); let hashmap = SERVICES.lock().unwrap();
let s = vec.get(i).unwrap(); let s = hashmap.get(name).unwrap();
if !s.running || s.last_active+t > now {continue;} if !s.running || s.last_active+t > now {continue;}
} }
stop_service(i); stop_service(name);
}, },
None => {} None => {}
} }