pub mod balancer;
mod builder;
pub mod health;
pub mod proxy;
pub mod router;
pub mod tcp;
pub mod types;
pub mod udp;
pub use builder::RefractiumBuilder;
use crate::core::types::ProtocolRoute;
use crate::errors::Result;
use router::Router;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use tcp::TcpServer;
use tokio_util::sync::CancellationToken;
use udp::UdpServer;
use self::health::HealthMonitor;
pub struct Refractium {
pub(crate) router_tcp: Arc<Router>,
pub(crate) router_udp: Arc<Router>,
pub(crate) health: Arc<HealthMonitor>,
pub(crate) peek_buffer_size: usize,
pub(crate) peek_timeout_ms: u64,
pub(crate) max_connections: usize,
pub(crate) max_connections_per_ip: usize,
pub(crate) cancel_token: CancellationToken,
}
impl Refractium {
#[must_use]
pub const fn builder() -> RefractiumBuilder {
RefractiumBuilder::new()
}
pub async fn reload_routes(&self, tcp: Vec<ProtocolRoute>, udp: Vec<ProtocolRoute>) {
let mut targets = tcp
.iter()
.flat_map(|r| r.forward_to.to_vec())
.collect::<Vec<_>>();
targets.extend(udp.iter().flat_map(|r| r.forward_to.to_vec()));
self.router_tcp
.update_balancer(tcp, Arc::clone(&self.health))
.await;
self.router_udp
.update_balancer(udp, Arc::clone(&self.health))
.await;
self.health.start_monitoring(targets);
}
#[must_use]
pub fn cancel_token(&self) -> CancellationToken {
self.cancel_token.clone()
}
pub async fn run_tcp(&self, addr: SocketAddr) -> Result<()> {
TcpServer::new(
addr,
Arc::clone(&self.router_tcp),
Arc::clone(&self.health),
self.peek_buffer_size,
self.peek_timeout_ms,
self.max_connections,
self.max_connections_per_ip,
self.cancel_token.clone(),
)
.start()
.await
}
pub async fn run_udp(&self, addr: SocketAddr) -> Result<()> {
UdpServer::new(
addr,
Arc::clone(&self.router_udp),
Arc::clone(&self.health),
self.cancel_token.clone(),
)
.start()
.await
}
pub async fn run_both(&self, addr: SocketAddr) -> Result<()> {
tokio::try_join!(self.run_tcp(addr), self.run_udp(addr))?;
Ok(())
}
pub async fn report_health(&self) {
let tcp_status = self.router_tcp.get_health_status().await;
let udp_status = self.router_udp.get_health_status().await;
if !tcp_status.is_empty() {
println!("\n[TCP Backends]");
Self::print_status_map(tcp_status);
}
if !udp_status.is_empty() {
println!("\n[UDP Backends]");
Self::print_status_map(udp_status);
}
println!();
}
fn print_status_map(status: HashMap<String, Vec<(String, bool)>>) {
for (proto, backends) in status {
print!(" {proto} -> ");
for (idx, (addr, alive)) in backends.iter().enumerate() {
if idx > 0 {
print!(", ");
}
let s = if *alive {
"\x1b[32mUP\x1b[0m"
} else {
"\x1b[31mDOWN\x1b[0m"
};
print!("{addr} [{s}]");
}
println!();
}
}
}