use chrono::{DateTime, Utc};
use headers::{HeaderValue, HeaderName, Header, HeaderMapExt};
use lazy_static::lazy_static;
use std::convert::TryFrom;
use std::fmt;
use std::ops::Deref;
use uuid::Uuid;
pub const X_SPAN_ID: &str = "x-span-id";
lazy_static! {
pub static ref X_SPAN_ID_HEADER: HeaderName = HeaderName::from_static(X_SPAN_ID);
}
#[derive(Debug, Clone)]
pub struct XSpanId(pub String);
impl XSpanId {
pub fn get_or_generate<T>(req: &hyper::Request<T>) -> Self {
let x_span_id = req.headers().typed_get::<XSpanId>();
match x_span_id {
Some(ref x) => x.clone(),
None => Self::default(),
}
}
}
impl Header for XSpanId {
fn name() -> &'static HeaderName {
&X_SPAN_ID_HEADER
}
fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
where
I: Iterator<Item = &'i HeaderValue>,
{
let value = values
.next()
.ok_or_else(headers::Error::invalid)?;
let value = value.to_str().map_err(|_| headers::Error::invalid())?;
Ok(XSpanId(value.to_owned()))
}
fn encode<E>(&self, values: &mut E)
where
E: Extend<HeaderValue>,
{
let value = HeaderValue::from_str(&self.0.to_string()).unwrap();
values.extend(std::iter::once(value));
}
}
impl Default for XSpanId {
fn default() -> Self {
XSpanId(Uuid::new_v4().to_string())
}
}
impl fmt::Display for XSpanId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone)]
pub struct IntoHeaderValue<T>(pub T);
impl<T> Deref for IntoHeaderValue<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
macro_rules! ihv_generate {
($t:ident) => {
impl std::convert::TryFrom<HeaderValue> for IntoHeaderValue<$t> {
type Error = headers::Error;
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
let value = hdr_value.to_str().map_err(|_| headers::Error::invalid())?;
let value = value.parse().map_err(|_| headers::Error::invalid())?;
Ok(IntoHeaderValue(value))
}
}
impl Into<HeaderValue> for IntoHeaderValue<$t> {
fn into(self) -> HeaderValue {
HeaderValue::from_str(&self.0.to_string()).unwrap()
}
}
};
}
ihv_generate!(u64);
ihv_generate!(i64);
ihv_generate!(i16);
ihv_generate!(u16);
ihv_generate!(u32);
ihv_generate!(usize);
ihv_generate!(isize);
ihv_generate!(i32);
impl TryFrom<HeaderValue> for IntoHeaderValue<Vec<String>> {
type Error = headers::Error;
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
Ok(IntoHeaderValue(
hdr_value
.to_str()
.map_err(|_| headers::Error::invalid())?
.split(',')
.filter_map(|x| match x.trim() {
"" => None,
y => Some(y.to_string()),
})
.collect(),
))
}
}
impl Into<HeaderValue> for IntoHeaderValue<Vec<String>> {
fn into(self) -> HeaderValue {
HeaderValue::from_str(&self.0.join(", ")).unwrap()
}
}
impl TryFrom<HeaderValue> for IntoHeaderValue<String> {
type Error = headers::Error;
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
let v = hdr_value
.to_str()
.map_err(|_| headers::Error::invalid())?
.to_string();
Ok(IntoHeaderValue(v))
}
}
impl Into<HeaderValue> for IntoHeaderValue<String> {
fn into(self) -> HeaderValue {
HeaderValue::from_str(&self.0).unwrap()
}
}
impl TryFrom<HeaderValue> for IntoHeaderValue<DateTime<Utc>> {
type Error = headers::Error;
fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
let v = hdr_value.to_str().map_err(|_| headers::Error::invalid())?;
Ok(IntoHeaderValue(
DateTime::parse_from_rfc3339(v)
.map_err(|_| headers::Error::invalid())?
.with_timezone(&Utc)
))
}
}
impl Into<HeaderValue> for IntoHeaderValue<DateTime<Utc>> {
fn into(self) -> HeaderValue {
HeaderValue::from_str(self.0.to_rfc3339().as_str()).unwrap()
}
}