Clone fewer Arcs by using statics to distribute references to the server
This commit is contained in:
parent
285768f509
commit
597bc6aa6b
31
src/lib.rs
31
src/lib.rs
|
@ -192,7 +192,6 @@ compile_error!("Please enable only one of either the `gemini_srv` or `scgi_srv`
|
|||
compile_error!("Please enable at least one of either the `gemini_srv` or `scgi_srv` features on the kochab crate");
|
||||
|
||||
use std::{
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
future::Future,
|
||||
};
|
||||
|
@ -260,32 +259,32 @@ pub const REQUEST_URI_MAX_LEN: usize = 1024;
|
|||
/// The default port for the gemini protocol
|
||||
pub const GEMINI_PORT: u16 = 1965;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ServerInner {
|
||||
#[cfg(feature = "gemini_srv")]
|
||||
tls_acceptor: TlsAcceptor,
|
||||
routes: Arc<RoutingNode<Handler>>,
|
||||
routes: RoutingNode<Handler>,
|
||||
timeout: Duration,
|
||||
complex_timeout: Option<Duration>,
|
||||
autorewrite: bool,
|
||||
#[cfg(feature="ratelimiting")]
|
||||
rate_limits: Arc<RoutingNode<RateLimiter<IpAddr>>>,
|
||||
rate_limits: RoutingNode<RateLimiter<IpAddr>>,
|
||||
#[cfg(feature="user_management")]
|
||||
manager: UserManager,
|
||||
}
|
||||
|
||||
impl ServerInner {
|
||||
async fn serve_ip(self, listener: TcpListener) -> Result<()> {
|
||||
let static_self: &'static Self = Box::leak(Box::new(self));
|
||||
|
||||
#[cfg(feature = "ratelimiting")]
|
||||
tokio::spawn(prune_ratelimit_log(self.rate_limits.clone()));
|
||||
tokio::spawn(prune_ratelimit_log(&static_self.rate_limits));
|
||||
|
||||
loop {
|
||||
let (stream, _addr) = listener.accept().await
|
||||
.context("Failed to accept client")?;
|
||||
let this = self.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Err(err) = this.serve_client(stream).await {
|
||||
if let Err(err) = static_self.serve_client(stream).await {
|
||||
error!("{:?}", err);
|
||||
}
|
||||
});
|
||||
|
@ -296,16 +295,17 @@ impl ServerInner {
|
|||
// Yeah it's code duplication, but I can't find a way around it, so this is what we're
|
||||
// getting for now
|
||||
async fn serve_unix(self, listener: UnixListener) -> Result<()> {
|
||||
let static_self: &'static Self = Box::leak(Box::new(self));
|
||||
|
||||
#[cfg(feature = "ratelimiting")]
|
||||
tokio::spawn(prune_ratelimit_log(self.rate_limits.clone()));
|
||||
tokio::spawn(prune_ratelimit_log(&static_self.rate_limits));
|
||||
|
||||
loop {
|
||||
let (stream, _addr) = listener.accept().await
|
||||
.context("Failed to accept client")?;
|
||||
let this = self.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Err(err) = this.serve_client(stream).await {
|
||||
if let Err(err) = static_self.serve_client(stream).await {
|
||||
error!("{:?}", err);
|
||||
}
|
||||
});
|
||||
|
@ -962,14 +962,14 @@ impl Server {
|
|||
let data_dir = self.data_dir;
|
||||
|
||||
Ok(ServerInner {
|
||||
routes: Arc::new(self.routes),
|
||||
routes: self.routes,
|
||||
timeout: self.timeout,
|
||||
complex_timeout: self.complex_body_timeout_override,
|
||||
autorewrite: self.autorewrite,
|
||||
#[cfg(feature = "gemini_srv")]
|
||||
tls_acceptor: TlsAcceptor::from(config),
|
||||
#[cfg(feature="ratelimiting")]
|
||||
rate_limits: Arc::new(self.rate_limits),
|
||||
rate_limits: self.rate_limits,
|
||||
#[cfg(feature="user_management")]
|
||||
manager: UserManager::new(
|
||||
self.database.unwrap_or_else(move|| sled::open(data_dir).unwrap())
|
||||
|
@ -981,6 +981,11 @@ impl Server {
|
|||
///
|
||||
/// `addr` can be anything `tokio` can parse, including just a string like
|
||||
/// "localhost:1965"
|
||||
///
|
||||
/// This will only ever exit with an error. It's important to note that even if the
|
||||
/// function exits, the server will NOT be deallocated, since references to it in
|
||||
/// concurrently running futures may still exist. As such, a loop that handles an
|
||||
/// error by re-serving a new server may trigger a memory leak.
|
||||
pub async fn serve_ip(self, addr: impl ToSocketAddrs + Send) -> Result<()> {
|
||||
let server = self.build()?;
|
||||
let socket = TcpListener::bind(addr).await?;
|
||||
|
@ -992,6 +997,8 @@ impl Server {
|
|||
///
|
||||
/// Requires an address in the form of a path to bind to. This is only available when
|
||||
/// in `scgi_srv` mode.
|
||||
///
|
||||
/// Please read the details and warnings of [`serve_ip()`] for more information
|
||||
pub async fn serve_unix(self, addr: impl AsRef<std::path::Path>) -> Result<()> {
|
||||
let server = self.build()?;
|
||||
let socket = UnixListener::bind(addr)?;
|
||||
|
|
Loading…
Reference in a new issue