#![doc(html_favicon_url = "https://sentry-brand.storage.googleapis.com/favicon.ico")]
#![doc(html_logo_url = "https://sentry-brand.storage.googleapis.com/sentry-glyph-black.png")]
#![warn(missing_docs)]
use std::marker::PhantomData;
use std::sync::Arc;
use std::task::{Context, Poll};
use sentry_core::{Hub, SentryFuture, SentryFutureExt};
use tower_layer::Layer;
use tower_service::Service;
#[cfg(feature = "http")]
mod http;
#[cfg(feature = "http")]
pub use crate::http::*;
pub trait HubProvider<H, Request>
where
H: Into<Arc<Hub>>,
{
fn hub(&self, request: &Request) -> H;
}
impl<H, F, Request> HubProvider<H, Request> for F
where
F: Fn(&Request) -> H,
H: Into<Arc<Hub>>,
{
fn hub(&self, request: &Request) -> H {
(self)(request)
}
}
impl<Request> HubProvider<Arc<Hub>, Request> for Arc<Hub> {
fn hub(&self, _request: &Request) -> Arc<Hub> {
self.clone()
}
}
#[derive(Clone, Copy)]
pub struct NewFromTopProvider;
impl<Request> HubProvider<Arc<Hub>, Request> for NewFromTopProvider {
fn hub(&self, _request: &Request) -> Arc<Hub> {
#[allow(clippy::redundant_closure)]
Hub::with(|hub| Hub::new_from_top(hub)).into()
}
}
pub struct SentryLayer<P, H, Request>
where
P: HubProvider<H, Request>,
H: Into<Arc<Hub>>,
{
provider: P,
_hub: PhantomData<(H, Request)>,
}
impl<S, P, H, Request> Layer<S> for SentryLayer<P, H, Request>
where
P: HubProvider<H, Request> + Clone,
H: Into<Arc<Hub>>,
{
type Service = SentryService<S, P, H, Request>;
fn layer(&self, service: S) -> Self::Service {
SentryService {
service,
provider: self.provider.clone(),
_hub: PhantomData,
}
}
}
impl<P, H, Request> Clone for SentryLayer<P, H, Request>
where
P: HubProvider<H, Request> + Clone,
H: Into<Arc<Hub>>,
{
fn clone(&self) -> Self {
Self {
provider: self.provider.clone(),
_hub: PhantomData,
}
}
}
impl<P, H, Request> SentryLayer<P, H, Request>
where
P: HubProvider<H, Request> + Clone,
H: Into<Arc<Hub>>,
{
pub fn new(provider: P) -> Self {
Self {
provider,
_hub: PhantomData,
}
}
}
pub struct SentryService<S, P, H, Request>
where
P: HubProvider<H, Request>,
H: Into<Arc<Hub>>,
{
service: S,
provider: P,
_hub: PhantomData<(H, Request)>,
}
impl<S, Request, P, H> Service<Request> for SentryService<S, P, H, Request>
where
S: Service<Request>,
P: HubProvider<H, Request>,
H: Into<Arc<Hub>>,
{
type Response = S::Response;
type Error = S::Error;
type Future = SentryFuture<S::Future>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, request: Request) -> Self::Future {
let hub = self.provider.hub(&request).into();
let fut = Hub::run(hub.clone(), || self.service.call(request));
fut.bind_hub(hub)
}
}
impl<S, P, H, Request> Clone for SentryService<S, P, H, Request>
where
S: Clone,
P: HubProvider<H, Request> + Clone,
H: Into<Arc<Hub>>,
{
fn clone(&self) -> Self {
Self {
service: self.service.clone(),
provider: self.provider.clone(),
_hub: PhantomData,
}
}
}
impl<S, P, H, Request> SentryService<S, P, H, Request>
where
P: HubProvider<H, Request> + Clone,
H: Into<Arc<Hub>>,
{
pub fn new(provider: P, service: S) -> Self {
SentryLayer::<P, H, Request>::new(provider).layer(service)
}
}
pub type NewSentryLayer<Request> = SentryLayer<NewFromTopProvider, Arc<Hub>, Request>;
impl<Request> NewSentryLayer<Request> {
pub fn new_from_top() -> Self {
Self {
provider: NewFromTopProvider,
_hub: PhantomData,
}
}
}
pub type NewSentryService<S, Request> = SentryService<S, NewFromTopProvider, Arc<Hub>, Request>;
impl<S, Request> NewSentryService<S, Request> {
pub fn new_from_top(service: S) -> Self {
Self {
provider: NewFromTopProvider,
service,
_hub: PhantomData,
}
}
}