use std::convert::Infallible;
use std::future::Future;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::Arc;
use typeway_core::effects::{AllProvided, ECons, ENil, Effect};
use typeway_core::ApiSpec;
use crate::body::BoxBody;
use crate::router::{Router, RouterService};
use crate::server::LayeredServer;
use crate::serves::Serves;
pub struct EffectfulServer<A: ApiSpec, Provided = ENil> {
router: Arc<Router>,
_api: PhantomData<A>,
_provided: PhantomData<Provided>,
}
impl<A: ApiSpec> EffectfulServer<A, ENil> {
pub fn new<H: Serves<A>>(handlers: H) -> Self {
let mut router = Router::new();
handlers.register(&mut router);
EffectfulServer {
router: Arc::new(router),
_api: PhantomData,
_provided: PhantomData,
}
}
}
impl<A: ApiSpec, P> EffectfulServer<A, P> {
pub fn provide<E: Effect>(self) -> EffectfulServer<A, ECons<E, P>> {
EffectfulServer {
router: self.router,
_api: PhantomData,
_provided: PhantomData,
}
}
pub fn nest(self, prefix: &str) -> Self {
self.router.set_prefix(prefix);
self
}
pub fn max_body_size(self, max: usize) -> Self {
self.router.set_max_body_size(max);
self
}
pub fn with_state<T: Clone + Send + Sync + 'static>(self, state: T) -> Self {
self.router.set_state_injector(Arc::new(move |ext| {
ext.insert(state.clone());
}));
self
}
pub fn layer<L>(self, layer: L) -> EffectfulLayeredServer<A, P, L::Service>
where
L: tower_layer::Layer<RouterService>,
L::Service: tower_service::Service<
http::Request<hyper::body::Incoming>,
Response = http::Response<BoxBody>,
Error = Infallible,
> + Clone
+ Send
+ 'static,
<L::Service as tower_service::Service<http::Request<hyper::body::Incoming>>>::Future:
Send + 'static,
{
let router = self.router.clone();
let svc = RouterService::new(self.router);
let layered = layer.layer(svc);
EffectfulLayeredServer {
service: layered,
router,
_api: PhantomData,
_provided: PhantomData,
}
}
pub fn ready<Idx>(self) -> crate::server::Server<A>
where
A: AllProvided<P, Idx>,
{
crate::server::Server::from_router(self.router)
}
pub async fn serve<Idx>(
self,
addr: SocketAddr,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
where
A: AllProvided<P, Idx>,
{
self.ready::<Idx>().serve(addr).await
}
pub async fn serve_with_shutdown<Idx>(
self,
listener: tokio::net::TcpListener,
shutdown: impl Future<Output = ()> + Send,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
where
A: AllProvided<P, Idx>,
{
self.ready::<Idx>()
.serve_with_shutdown(listener, shutdown)
.await
}
}
pub struct EffectfulLayeredServer<A: ApiSpec, Provided, S> {
service: S,
router: Arc<Router>,
_api: PhantomData<A>,
_provided: PhantomData<Provided>,
}
impl<A: ApiSpec, P, S> EffectfulLayeredServer<A, P, S> {
pub fn provide<E: Effect>(self) -> EffectfulLayeredServer<A, ECons<E, P>, S> {
EffectfulLayeredServer {
service: self.service,
router: self.router,
_api: PhantomData,
_provided: PhantomData,
}
}
pub fn with_state<T: Clone + Send + Sync + 'static>(self, state: T) -> Self {
self.router.set_state_injector(Arc::new(move |ext| {
ext.insert(state.clone());
}));
self
}
pub fn max_body_size(self, max: usize) -> Self {
self.router.set_max_body_size(max);
self
}
pub fn nest(self, prefix: &str) -> Self {
self.router.set_prefix(prefix);
self
}
}
impl<A: ApiSpec, P, S> EffectfulLayeredServer<A, P, S>
where
S: tower_service::Service<
http::Request<hyper::body::Incoming>,
Response = http::Response<BoxBody>,
Error = Infallible,
> + Clone
+ Send
+ 'static,
S::Future: Send + 'static,
{
pub fn layer<L>(self, layer: L) -> EffectfulLayeredServer<A, P, L::Service>
where
L: tower_layer::Layer<S>,
L::Service: tower_service::Service<
http::Request<hyper::body::Incoming>,
Response = http::Response<BoxBody>,
Error = Infallible,
> + Clone
+ Send
+ 'static,
<L::Service as tower_service::Service<http::Request<hyper::body::Incoming>>>::Future:
Send + 'static,
{
EffectfulLayeredServer {
service: layer.layer(self.service),
router: self.router,
_api: PhantomData,
_provided: PhantomData,
}
}
}
impl<A: ApiSpec, P, S> EffectfulLayeredServer<A, P, S>
where
S: tower_service::Service<
http::Request<hyper::body::Incoming>,
Response = http::Response<BoxBody>,
Error = Infallible,
> + Clone
+ Send
+ 'static,
S::Future: Send + 'static,
{
pub fn ready<Idx>(self) -> LayeredServer<S>
where
A: AllProvided<P, Idx>,
{
LayeredServer {
service: self.service,
router: self.router,
}
}
pub async fn serve<Idx>(
self,
addr: SocketAddr,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
where
A: AllProvided<P, Idx>,
{
self.ready::<Idx>().serve(addr).await
}
pub async fn serve_with_shutdown<Idx>(
self,
listener: tokio::net::TcpListener,
shutdown: impl Future<Output = ()> + Send,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
where
A: AllProvided<P, Idx>,
{
self.ready::<Idx>()
.serve_with_shutdown(listener, shutdown)
.await
}
}