use crate::endpoint::WitchcraftEndpoint;
use crate::health::endpoint_500s::EndpointHealth;
use crate::server::RawBody;
use crate::service::endpoint_metrics::EndpointMetrics;
use crate::service::handler::BodyWriteAborted;
use bytes::Bytes;
use conjure_http::server::{EndpointMetadata, PathSegment};
use futures_util::future::BoxFuture;
use http::{Method, Request, Response};
use http_body::combinators::BoxBody;
use std::borrow::Cow;
use std::sync::Arc;
pub struct ExtendedPathEndpoint<T> {
inner: T,
path: Vec<PathSegment>,
template: String,
}
impl<T> ExtendedPathEndpoint<T>
where
T: EndpointMetadata,
{
pub fn new(inner: T, path_prefix: &str) -> Self {
debug_assert!(path_prefix.starts_with('/') && !path_prefix.ends_with('/'));
let path = path_prefix
.strip_prefix('/')
.unwrap()
.split('/')
.map(|s| PathSegment::Literal(Cow::Owned(s.to_string())))
.chain(inner.path().iter().cloned())
.collect();
let template = format!("{path_prefix}{}", inner.template());
ExtendedPathEndpoint {
inner,
path,
template,
}
}
}
impl<T> EndpointMetadata for ExtendedPathEndpoint<T>
where
T: EndpointMetadata,
{
fn method(&self) -> Method {
self.inner.method()
}
fn path(&self) -> &[PathSegment] {
&self.path
}
fn template(&self) -> &str {
&self.template
}
fn service_name(&self) -> &str {
self.inner.service_name()
}
fn name(&self) -> &str {
self.inner.name()
}
fn deprecated(&self) -> Option<&str> {
self.inner.deprecated()
}
}
impl<T> WitchcraftEndpoint for ExtendedPathEndpoint<T>
where
T: WitchcraftEndpoint,
{
fn metrics(&self) -> Option<&EndpointMetrics> {
self.inner.metrics()
}
fn health(&self) -> Option<&Arc<EndpointHealth>> {
self.inner.health()
}
fn handle<'life0, 'async_trait>(
&'life0 self,
req: Request<RawBody>,
) -> BoxFuture<Response<BoxBody<Bytes, BodyWriteAborted>>>
where
'life0: 'async_trait,
Self: 'async_trait,
{
self.inner.handle(req)
}
}