use std::sync::Arc;
use crate::error::Error;
#[cfg(feature = "capture-v1")]
use std::collections::HashMap;
#[cfg(feature = "capture-v1")]
use uuid::Uuid;
#[cfg(feature = "capture-v1")]
use crate::event_v1::{EventResult, V1ErrorResponse};
type OnErrorFn = dyn Fn(&PostHogError<'_>) + Send + Sync + 'static;
type SharedOnErrorHook = Arc<OnErrorFn>;
#[derive(Clone)]
pub(crate) struct OnErrorHook(SharedOnErrorHook);
impl OnErrorHook {
pub(crate) fn new<F>(hook: F) -> Self
where
F: Fn(&PostHogError<'_>) + Send + Sync + 'static,
{
Self(Arc::new(hook))
}
pub(crate) fn apply(&self, failure: &PostHogError<'_>) {
(self.0)(failure)
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum PostHogError<'a> {
Capture(CaptureFailure<'a>),
FeatureFlags(FlagsFailure<'a>),
LocalEvaluation(LocalEvaluationFailure<'a>),
}
#[derive(Debug)]
#[non_exhaustive]
pub struct CaptureFailure<'a> {
pub(crate) error: Option<&'a Error>,
pub(crate) status: Option<u16>,
pub(crate) attempt: u32,
pub(crate) event_count: usize,
pub(crate) historical_migration: bool,
#[cfg(feature = "capture-v1")]
pub(crate) request_id: Option<&'a Uuid>,
#[cfg(feature = "capture-v1")]
pub(crate) results: &'a HashMap<Uuid, EventResult>,
#[cfg(feature = "capture-v1")]
pub(crate) error_response: Option<&'a V1ErrorResponse>,
}
impl<'a> CaptureFailure<'a> {
#[cfg_attr(
not(feature = "capture-v1"),
doc = "\nAlways present: every capture failure surfaced to the hook carries a cause."
)]
#[cfg_attr(
feature = "capture-v1",
doc = "\n`None` only when the request itself succeeded (`2xx`) but some events were not\npersisted after the retry budget — inspect [`event_results`](Self::event_results)."
)]
pub fn error(&self) -> Option<&Error> {
self.error
}
pub fn status(&self) -> Option<u16> {
self.status
}
pub fn attempt(&self) -> u32 {
self.attempt
}
#[cfg_attr(
feature = "capture-v1",
doc = "\nCounts only undelivered events (`retry`/`drop`), including any finalized on\nearlier attempts. This can be smaller than [`event_results`](Self::event_results)`.len()`,\nwhich also reports persisted `ok`/`warning` verdicts — filter by status before\ntreating an entry as lost."
)]
pub fn event_count(&self) -> usize {
self.event_count
}
pub fn historical_migration(&self) -> bool {
self.historical_migration
}
#[cfg(feature = "capture-v1")]
pub fn request_id(&self) -> Option<&Uuid> {
self.request_id
}
#[cfg(feature = "capture-v1")]
pub fn event_results(&self) -> &HashMap<Uuid, EventResult> {
self.results
}
#[cfg(feature = "capture-v1")]
pub fn error_response(&self) -> Option<&V1ErrorResponse> {
self.error_response
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct FlagsFailure<'a> {
pub(crate) error: &'a Error,
pub(crate) endpoint: &'a str,
pub(crate) distinct_id: Option<&'a str>,
pub(crate) status: Option<u16>,
pub(crate) body: Option<&'a str>,
}
impl<'a> FlagsFailure<'a> {
pub fn error(&self) -> &Error {
self.error
}
pub fn endpoint(&self) -> &str {
self.endpoint
}
pub fn distinct_id(&self) -> Option<&str> {
self.distinct_id
}
pub fn status(&self) -> Option<u16> {
self.status
}
pub fn body(&self) -> Option<&str> {
self.body
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct LocalEvaluationFailure<'a> {
pub(crate) error: &'a Error,
pub(crate) status: Option<u16>,
}
impl<'a> LocalEvaluationFailure<'a> {
pub fn error(&self) -> &Error {
self.error
}
pub fn status(&self) -> Option<u16> {
self.status
}
}