use std::io;
use std::net::SocketAddr;
use dope::launcher::Ctx;
use dope::manifold::env::Bundle;
use dope::manifold::listener::Listener;
use dope::manifold::listener::config::Config;
use dope::runtime::profile::Throughput;
use dope::transport::Tcp;
use dope::wire::Identity;
use dope::{DriverConfig, Executor};
use dope_extra::Trigger;
use dope_tls::{Endpoint, Tls};
pub type Env = Bundle<Tcp, Identity, Throughput>;
pub type TlsEnv = Bundle<Tcp, Tls, Throughput>;
mod app;
pub use app::{App, ConnState, Handler, Request, Response};
#[derive(Clone, Debug)]
pub struct Cfg {
pub bind: SocketAddr,
pub max_conn: usize,
pub backlog: i32,
}
#[pin_project::pin_project]
#[derive(dope_gen::Dispatcher)]
struct Dispatcher<'h, H: Handler> {
#[pin]
#[manifold]
listener: Listener<0, App<'h, H>, Env>,
}
pub fn serve<H: Handler>(
handler: H,
cfg: Cfg,
ctx: Ctx,
shutdown: Option<&Trigger>,
) -> io::Result<()> {
let listener_cfg = Config::<Tcp> {
max_conn: cfg.max_conn,
bind: cfg.bind,
backlog: cfg.backlog,
stream_opts: Default::default(),
listener_opts: dope::transport::config::tcp::ListenerOpts {
reuseport: dope::transport::config::SocketToggle::Enabled,
per_ip_cap: Some((cfg.max_conn / 2) as u32),
..Default::default()
},
};
let driver_cfg = <dope::DriverCfg as DriverConfig>::for_tcp_profile::<Throughput>(cfg.max_conn)
.with_cpu_id(Some(ctx.cpu));
let mut exec = Executor::new(driver_cfg)?;
let drv = exec.driver_mut();
if let Some(trigger) = shutdown {
trigger.register(drv);
}
let listener = Listener::<0, App<H>, Env>::open_in(App::new(&handler), listener_cfg, drv)?;
let mut app = core::pin::pin!(Dispatcher { listener });
exec.run(app.as_mut())
}
#[pin_project::pin_project]
#[derive(dope_gen::Dispatcher)]
struct TlsDispatcher<'h, H: Handler> {
#[pin]
#[manifold]
listener: Listener<0, App<'h, H, Tls>, TlsEnv>,
}
pub fn serve_tls<H: Handler>(
handler: H,
cfg: Cfg,
tls_cfg: shin::server::Config,
ctx: Ctx,
shutdown: Option<&Trigger>,
) -> io::Result<()> {
let listener_cfg = Config::<Tcp> {
max_conn: cfg.max_conn,
bind: cfg.bind,
backlog: cfg.backlog,
stream_opts: Default::default(),
listener_opts: dope::transport::config::tcp::ListenerOpts {
reuseport: dope::transport::config::SocketToggle::Enabled,
per_ip_cap: Some((cfg.max_conn / 2) as u32),
..Default::default()
},
};
let driver_cfg = <dope::DriverCfg as DriverConfig>::for_tcp_profile::<Throughput>(cfg.max_conn)
.with_cpu_id(Some(ctx.cpu));
let mut exec = Executor::new(driver_cfg)?;
let drv = exec.driver_mut();
if let Some(trigger) = shutdown {
trigger.register(drv);
}
let mut listener =
Listener::<0, App<H, Tls>, TlsEnv>::open_in(App::new(&handler), listener_cfg, drv)?;
listener.set_cfg(Endpoint::Server(Box::new(tls_cfg)));
let mut app = core::pin::pin!(TlsDispatcher { listener });
exec.run(app.as_mut())
}
#[cfg(feature = "rustls")]
pub type RustlsTlsEnv = Bundle<Tcp, dope_tls::RustTls, Throughput>;
#[cfg(feature = "rustls")]
#[pin_project::pin_project]
#[derive(dope_gen::Dispatcher)]
struct RustlsTlsDispatcher<'h, H: Handler> {
#[pin]
#[manifold]
listener: Listener<0, App<'h, H, dope_tls::RustTls>, RustlsTlsEnv>,
}
#[cfg(feature = "rustls")]
pub fn serve_tls_rustls<H: Handler>(
handler: H,
cfg: Cfg,
tls_cfg: std::sync::Arc<rustls::ServerConfig>,
ctx: Ctx,
shutdown: Option<&Trigger>,
) -> io::Result<()> {
let listener_cfg = Config::<Tcp> {
max_conn: cfg.max_conn,
bind: cfg.bind,
backlog: cfg.backlog,
stream_opts: Default::default(),
listener_opts: dope::transport::config::tcp::ListenerOpts {
reuseport: dope::transport::config::SocketToggle::Enabled,
per_ip_cap: Some((cfg.max_conn / 2) as u32),
..Default::default()
},
};
let driver_cfg = <dope::DriverCfg as DriverConfig>::for_tcp_profile::<Throughput>(cfg.max_conn)
.with_cpu_id(Some(ctx.cpu));
let mut exec = Executor::new(driver_cfg)?;
let drv = exec.driver_mut();
if let Some(trigger) = shutdown {
trigger.register(drv);
}
let mut listener = Listener::<0, App<H, dope_tls::RustTls>, RustlsTlsEnv>::open_in(
App::new(&handler),
listener_cfg,
drv,
)?;
listener.set_cfg(dope_tls::RustTlsEndpoint::Server(tls_cfg));
let mut app = core::pin::pin!(RustlsTlsDispatcher { listener });
exec.run(app.as_mut())
}