#![cfg_attr(docsrs, feature(doc_cfg))]
mod config;
mod listener;
mod shutdown;
mod worker;
#[cfg(feature = "compio")]
mod worker_compio;
use std::io;
use std::net::SocketAddr;
use std::str::FromStr;
use tako_rs_core::router::Router;
pub use crate::config::PerThreadConfig;
pub use crate::shutdown::PerThreadShutdown;
use crate::worker::worker_main;
#[cfg(feature = "compio")]
use crate::worker_compio::worker_main_compio;
pub fn serve_per_thread(addr: &str, router: Router, cfg: PerThreadConfig) -> io::Result<()> {
let workers = cfg.workers;
let (handle, shutdown) = spawn_per_thread(addr, router, cfg)?;
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.map_err(|e| io::Error::other(format!("ctrl-c runtime: {e}")))?;
let result: io::Result<()> = rt.block_on(async {
shutdown.wait_for_bind_outcome(workers).await?;
let _ = tokio::signal::ctrl_c().await;
Ok(())
});
shutdown.trigger();
for h in handle {
let _ = h.join();
}
result
}
pub fn spawn_per_thread(
addr: &str,
router: Router,
cfg: PerThreadConfig,
) -> io::Result<(Vec<std::thread::JoinHandle<()>>, PerThreadShutdown)> {
let socket_addr =
SocketAddr::from_str(addr).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
let router: &'static Router = Box::leak(Box::new(router));
let shutdown = PerThreadShutdown::new();
let mut handles = Vec::with_capacity(cfg.workers);
for worker_id in 0..cfg.workers {
let cfg = cfg.clone();
let shutdown = shutdown.clone();
let h = std::thread::Builder::new()
.name(format!("tako-pt-{worker_id}"))
.spawn(move || worker_main(worker_id, socket_addr, router, cfg, shutdown))
.expect("spawn tako-pt worker");
handles.push(h);
}
Ok((handles, shutdown))
}
#[cfg(feature = "compio")]
#[cfg_attr(docsrs, doc(cfg(feature = "compio")))]
pub fn serve_per_thread_compio(addr: &str, router: Router, cfg: PerThreadConfig) -> io::Result<()> {
let socket_addr =
SocketAddr::from_str(addr).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
let router: &'static Router = Box::leak(Box::new(router));
let workers = cfg.workers;
let shutdown = PerThreadShutdown::new();
let mut handles = Vec::with_capacity(cfg.workers);
for worker_id in 0..cfg.workers {
let cfg = cfg.clone();
let shutdown = shutdown.clone();
let h = std::thread::Builder::new()
.name(format!("tako-pt-compio-{worker_id}"))
.spawn(move || worker_main_compio(worker_id, socket_addr, router, cfg, shutdown))
.expect("spawn tako-pt-compio worker");
handles.push(h);
}
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.map_err(|e| io::Error::other(format!("ctrl-c runtime: {e}")))?;
let result: io::Result<()> = rt.block_on(async {
shutdown.wait_for_bind_outcome(workers).await?;
let _ = tokio::signal::ctrl_c().await;
Ok(())
});
shutdown.trigger();
for h in handles {
let _ = h.join();
}
result
}