use core::{fmt, marker::PhantomData};
use crate::user::UserId;
use rama_core::{
Layer, Service,
extensions::{Extensions, ExtensionsRef},
telemetry::tracing,
username::{UsernameLabelParser, parse_username},
};
#[derive(Default)]
pub struct UsernameLabelParserLayer<P> {
_parser: PhantomData<fn() -> P>,
}
impl<P> UsernameLabelParserLayer<P> {
#[inline(always)]
#[must_use]
pub fn new() -> Self {
Self {
_parser: PhantomData,
}
}
}
impl<P> fmt::Debug for UsernameLabelParserLayer<P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("UsernameLabelParserLayer")
.field("parser", &core::any::type_name::<P>())
.finish()
}
}
impl<P> Clone for UsernameLabelParserLayer<P> {
fn clone(&self) -> Self {
Self {
_parser: PhantomData,
}
}
}
impl<S, P> Layer<S> for UsernameLabelParserLayer<P> {
type Service = UsernameLabelParserService<S, P>;
fn layer(&self, inner: S) -> Self::Service {
Self::Service {
inner,
_parser: PhantomData,
}
}
}
pub struct UsernameLabelParserService<S, P> {
inner: S,
_parser: PhantomData<fn() -> P>,
}
impl<S: fmt::Debug, P> fmt::Debug for UsernameLabelParserService<S, P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("UsernameLabelParserService")
.field("inner", &self.inner)
.field("parser", &core::any::type_name::<P>())
.finish()
}
}
impl<S: Clone, P> Clone for UsernameLabelParserService<S, P> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
_parser: PhantomData,
}
}
}
impl<S, P, Input> Service<Input> for UsernameLabelParserService<S, P>
where
S: Service<Input>,
P: UsernameLabelParser,
Input: ExtensionsRef,
{
type Output = S::Output;
type Error = S::Error;
fn serve(
&self,
input: Input,
) -> impl Future<Output = Result<Self::Output, Self::Error>> + Send + '_ {
let extensions = input.extensions();
match extensions.get_ref() {
Some(UserId::Username(username)) => {
let label_extensions = Extensions::new();
match parse_username(&label_extensions, P::default(), username) {
Ok(new_username) => {
tracing::debug!(
"username label parser: success: overwrite id username '{username}' with '{new_username}'"
);
extensions.insert(UserId::Username(new_username));
extensions.extend(&label_extensions);
}
Err(err) => {
tracing::debug!(
"failed to parse username labels, keep existing username: '{username}'; err = {err}"
);
}
}
}
Some(UserId::Token(_)) => {
tracing::debug!("no parsing to do, incompatible user id in input: token");
}
None | Some(UserId::Anonymous) => {
tracing::debug!("no parsing to do, incompatible user id in input: none/anonymous");
}
}
self.inner.serve(input)
}
}