use core::marker::PhantomData;
use std::rc::Rc;
use tokio::task::JoinHandle;
use xitca_io::net::Stream;
use xitca_service::{Service, ready::ReadyService};
use crate::{
net::ListenerDyn,
worker::{self, ServiceAny},
};
pub type ServiceObj = Box<
dyn for<'a> xitca_service::object::ServiceObject<
(&'a str, &'a [(String, ListenerDyn)]),
Response = (Vec<JoinHandle<()>>, ServiceAny),
Error = (),
> + Send
+ Sync,
>;
struct Container<F, Req> {
inner: F,
_t: PhantomData<fn(Req)>,
}
impl<'a, F, Req> Service<(&'a str, &'a [(String, ListenerDyn)])> for Container<F, Req>
where
F: IntoServiceObj<Req>,
Req: TryFrom<Stream> + 'static,
{
type Response = (Vec<JoinHandle<()>>, ServiceAny);
type Error = ();
async fn call(
&self,
(name, listeners): (&'a str, &'a [(String, ListenerDyn)]),
) -> Result<Self::Response, Self::Error> {
let service = self.inner.call(()).await.map_err(|_| ())?;
let service = Rc::new(service);
let handles = listeners
.iter()
.filter(|(n, _)| n == name)
.map(|(_, listener)| worker::start(listener, &service))
.collect::<Vec<_>>();
Ok((handles, service as _))
}
}
pub trait IntoServiceObj<Req>: Send + Sync + 'static
where
Self: Service<Response = Self::Service> + Send + Sync + 'static,
Req: TryFrom<Stream> + 'static,
{
type Service: ReadyService + Service<Req>;
fn into_object(self) -> ServiceObj;
}
impl<T, Req> IntoServiceObj<Req> for T
where
T: Service + Send + Sync + 'static,
T::Response: ReadyService + Service<Req>,
Req: TryFrom<Stream> + 'static,
{
type Service = T::Response;
fn into_object(self) -> ServiceObj {
Box::new(Container {
inner: self,
_t: PhantomData,
})
}
}