use super::{FailureKind, FailurePhase, FailureReport};
use std::sync::Arc;
use tokio::sync::mpsc;
use tokio_util::sync::CancellationToken;
use tracing::Span;
#[derive(Clone, Debug)]
pub struct ReconnectHandle {
tx: mpsc::Sender<Arc<str>>,
}
impl ReconnectHandle {
#[inline]
pub(crate) fn new(tx: mpsc::Sender<Arc<str>>) -> Self {
Self { tx }
}
#[inline]
pub fn try_request_reconnect(&self, reason: impl Into<Arc<str>>) -> bool {
self.tx.try_send(reason.into()).is_ok()
}
}
#[derive(Debug)]
pub enum RunOutcome {
Disconnected,
ReconnectRequested(Arc<str>),
Fatal(FailureReport),
}
#[derive(Clone)]
pub struct SessionContext {
pub cancel: CancellationToken,
pub reconnect: ReconnectHandle,
pub span: Span,
pub attempt: u64,
}
impl SessionContext {
#[inline]
pub fn fatal(
&self,
phase: FailurePhase,
summary: impl Into<Arc<str>>,
code: Option<Arc<str>>,
) -> FailureReport {
FailureReport {
phase,
kind: FailureKind::Fatal,
summary: summary.into(),
code,
}
}
}
#[async_trait::async_trait]
pub trait Connector: Send + Sync + 'static {
type InitContext: Send + 'static;
type Handle: Send + Sync + 'static;
type Session: Session<Handle = Self::Handle>;
fn new(ctx: Self::InitContext) -> Result<Self, <Self::Session as Session>::Error>
where
Self: Sized;
async fn connect(
&self,
ctx: SessionContext,
) -> Result<Self::Session, <Self::Session as Session>::Error>;
fn classify_error(
&self,
phase: FailurePhase,
err: &<Self::Session as Session>::Error,
) -> FailureKind;
#[inline]
fn error_summary(&self, err: &<Self::Session as Session>::Error) -> Arc<str> {
Arc::<str>::from(err.to_string())
}
#[inline]
fn error_code(&self, _err: &<Self::Session as Session>::Error) -> Option<Arc<str>> {
None
}
}
#[async_trait::async_trait]
pub trait Session: Send + 'static {
type Handle: Send + Sync + 'static;
type Error: std::error::Error + Send + Sync + 'static;
fn handle(&self) -> &Arc<Self::Handle>;
async fn init(&mut self, ctx: &SessionContext) -> Result<(), Self::Error>;
async fn run(self, ctx: SessionContext) -> Result<RunOutcome, Self::Error>;
}