Changed config & data structure
This commit is contained in:
parent
d2efbe92ca
commit
cf94b742e4
23
conf.rs
23
conf.rs
|
@ -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();
|
||||||
}
|
}
|
22
config.yml
22
config.yml
|
@ -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
25
data.rs
|
@ -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
16
main.rs
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
59
services.rs
59
services.rs
|
@ -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 => {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue