use std::any::TypeId;
use std::collections::HashSet;
use std::{cell::RefCell, convert::Infallible, rc::Rc};
use crate::host::clock::Clock;
use crate::host::grpc::GrpcHost;
use crate::host::shared_data::SharedData;
use crate::{
context,
event::{After, Exchange, Start},
host::Host,
reactor::{http::HttpReactor, root::RootReactor},
types::{HttpCid, RootCid},
BoxFuture,
};
use super::{extractability, AlreadyExtracted, Exclusive, FromContext, FromContextOnce};
pub struct ConfigureContext {
pub(crate) host: Rc<dyn Host>,
pub(crate) clock: Rc<dyn Clock>,
pub(crate) grpc_host: Rc<dyn GrpcHost>,
pub(crate) shared_data: Rc<dyn SharedData>,
#[cfg(feature = "experimental_metrics")]
pub(crate) metrics: Rc<dyn crate::host::metrics::MetricsHost>,
pub(crate) root_reactor: Rc<RootReactor>,
pub(crate) unique_extractions: RefCell<HashSet<TypeId>>,
}
context!(ConfigureContext);
impl ConfigureContext {
pub(crate) fn extract_unique<T: 'static>(
&self,
op: impl FnOnce() -> T,
) -> Result<T, AlreadyExtracted<T>> {
self.unique_extractions
.borrow_mut()
.insert(TypeId::of::<T>())
.then(op)
.ok_or_else(AlreadyExtracted::default)
}
}
impl FromContext<ConfigureContext, extractability::Transitive> for Rc<dyn Host> {
type Error = Infallible;
fn from_context(context: &ConfigureContext) -> Result<Self, Self::Error> {
Ok(context.host.clone())
}
}
impl FromContext<ConfigureContext, extractability::Transitive> for Rc<dyn Clock> {
type Error = Infallible;
fn from_context(context: &ConfigureContext) -> Result<Self, Self::Error> {
Ok(context.clock.clone())
}
}
impl FromContext<ConfigureContext, extractability::Transitive> for Rc<dyn SharedData> {
type Error = Infallible;
fn from_context(context: &ConfigureContext) -> Result<Self, Self::Error> {
Ok(context.shared_data.clone())
}
}
#[cfg(feature = "experimental_metrics")]
impl FromContext<ConfigureContext, extractability::Transitive>
for Rc<dyn crate::host::metrics::MetricsHost>
{
type Error = Infallible;
fn from_context(context: &ConfigureContext) -> Result<Self, Self::Error> {
Ok(context.metrics.clone())
}
}
impl FromContext<ConfigureContext, extractability::Transitive> for Rc<RootReactor> {
type Error = Infallible;
fn from_context(context: &ConfigureContext) -> Result<Self, Self::Error> {
Ok(context.root_reactor.clone())
}
}
impl FromContext<ConfigureContext, extractability::Transitive> for RootCid {
type Error = Infallible;
fn from_context(context: &ConfigureContext) -> Result<Self, Self::Error> {
Ok(context.root_reactor.context_id())
}
}
pub struct FilterContext {
parent: Rc<ConfigureContext>,
http_reactor: Rc<HttpReactor>,
}
impl FilterContext {
pub(crate) fn new(parent: Rc<ConfigureContext>, http_reactor: Rc<HttpReactor>) -> Self {
Self {
parent,
http_reactor,
}
}
fn parent(&self) -> &ConfigureContext {
&self.parent
}
}
context!(FilterContext => ConfigureContext {FilterContext::parent});
impl<E> FromContextOnce<FilterContext> for Exchange<E>
where
E: After<Start> + 'static,
{
type Error = AlreadyExtracted<Exchange<E>>;
type Future<'c> = BoxFuture<'c, Result<Self, Self::Error>>;
fn from_context_once(context: Exclusive<FilterContext>) -> Self::Future<'_> {
Box::pin(async move {
let exchange = Exchange::new(
context.http_reactor.clone(),
context.parent.host.clone(),
Some(Start {
_context_id: context.http_reactor.context_id(),
}),
);
Ok(exchange.wait_for_event::<E>().await)
})
}
}
impl FromContext<FilterContext> for Rc<HttpReactor> {
type Error = Infallible;
fn from_context(context: &FilterContext) -> Result<Self, Self::Error> {
Ok(context.http_reactor.clone())
}
}
impl FromContext<FilterContext> for HttpCid {
type Error = Infallible;
fn from_context(context: &FilterContext) -> Result<Self, Self::Error> {
Ok(context.http_reactor.context_id())
}
}