#[global_allocator] static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; mod backend; mod config; mod constants; mod error; mod globals; mod log; mod proxy; use crate::{ backend::{Backend, Backends}, config::parse_opts, constants::*, error::*, globals::*, log::*, proxy::Proxy, }; use futures::future::select_all; use hyper::Client; use hyper_trust_dns::TrustDnsResolver; use std::{collections::HashMap, io::Write, sync::Arc}; use tokio::time::Duration; fn main() { // env::set_var("RUST_LOG", "info"); env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")) .format(|buf, record| { let ts = buf.timestamp(); writeln!( buf, "{} [{}] {}", ts, record.level(), // record.target(), record.args(), // record.file().unwrap_or("unknown"), // record.line().unwrap_or(0), ) }) .init(); info!("Start http (reverse) proxy"); let mut runtime_builder = tokio::runtime::Builder::new_multi_thread(); runtime_builder.enable_all(); runtime_builder.thread_name("rpxy"); let runtime = runtime_builder.build().unwrap(); runtime.block_on(async { let mut globals = Globals { listen_sockets: Vec::new(), http_port: None, https_port: None, timeout: Duration::from_secs(TIMEOUT_SEC), max_clients: MAX_CLIENTS, clients_count: Default::default(), max_concurrent_streams: MAX_CONCURRENT_STREAMS, keepalive: true, runtime_handle: runtime.handle().clone(), }; let mut backends = Backends { default_app: None, apps: HashMap::::new(), }; let _ = parse_opts(&mut globals, &mut backends).expect("Invalid configuration"); entrypoint(Arc::new(globals), Arc::new(backends)) .await .unwrap() }); warn!("Exit the program"); } // entrypoint creates and spawns tasks of proxy services async fn entrypoint(globals: Arc, backends: Arc) -> Result<()> { let connector = TrustDnsResolver::default().into_rustls_webpki_https_connector(); let forwarder = Arc::new(Client::builder().build::<_, hyper::Body>(connector)); let addresses = globals.listen_sockets.clone(); let futures = select_all(addresses.into_iter().map(|addr| { let mut tls_enabled = false; if let Some(https_port) = globals.https_port { tls_enabled = https_port == (addr.port() as u16) } let proxy = Proxy { globals: globals.clone(), listening_on: addr, tls_enabled, backends: backends.clone(), forwarder: forwarder.clone(), }; globals.runtime_handle.spawn(proxy.start()) })); // wait for all future if let (Ok(_), _, _) = futures.await { error!("Some proxy services are down"); }; Ok(()) }