use std::future::Future;
use std::sync::Arc;
use nasaga_backend::{SagaBackend, SagaBackendFactory};
use nasaga_core::ServiceIdentity;
use natelemetry::TraceContext;
use crate::{
HandleOutcome, Orchestrator, ParticipantHandled, ParticipantRuntime, SagaCommandEnvelope,
SagaCommandService, SagaResultEnvelope,
};
pub trait SagaCommandHandler: Send + Sync + 'static {
fn handle_authenticated_command(
&self,
envelope: &SagaCommandEnvelope,
producer: &ServiceIdentity,
) -> impl Future<Output = anyhow::Result<ParticipantHandled>> + Send;
fn handle_authenticated_command_traced(
&self,
envelope: &SagaCommandEnvelope,
producer: &ServiceIdentity,
receipt_trace: Option<&TraceContext>,
) -> impl Future<Output = anyhow::Result<ParticipantHandled>> + Send {
let _ = receipt_trace;
self.handle_authenticated_command(envelope, producer)
}
}
pub struct ParticipantCommandHandler<B: SagaBackend, S> {
runtime: Arc<ParticipantRuntime<B>>,
service: Arc<S>,
}
impl<B: SagaBackend, S> ParticipantCommandHandler<B, S> {
pub fn new(runtime: Arc<ParticipantRuntime<B>>, service: Arc<S>) -> Self {
Self {
runtime,
service,
}
}
}
impl<B, S> SagaCommandHandler for ParticipantCommandHandler<B, S>
where
B: SagaBackend + 'static,
S: SagaCommandService<B>,
{
async fn handle_authenticated_command(
&self,
envelope: &SagaCommandEnvelope,
producer: &ServiceIdentity,
) -> anyhow::Result<ParticipantHandled> {
self.service
.handle_saga_command(&self.runtime, envelope, producer)
.await
}
async fn handle_authenticated_command_traced(
&self,
envelope: &SagaCommandEnvelope,
producer: &ServiceIdentity,
receipt_trace: Option<&TraceContext>,
) -> anyhow::Result<ParticipantHandled> {
self.service
.handle_saga_command_traced(&self.runtime, envelope, producer, receipt_trace)
.await
}
}
pub trait SagaResultHandler: Send + Sync + 'static {
fn handle_authenticated_result(
&self,
envelope: &SagaResultEnvelope,
producer: &ServiceIdentity,
now_ms: i64,
) -> impl Future<Output = anyhow::Result<HandleOutcome>> + Send;
fn handle_authenticated_result_traced(
&self,
envelope: &SagaResultEnvelope,
producer: &ServiceIdentity,
receipt_trace: Option<&TraceContext>,
now_ms: i64,
) -> impl Future<Output = anyhow::Result<HandleOutcome>> + Send {
let _ = receipt_trace;
self.handle_authenticated_result(envelope, producer, now_ms)
}
}
impl<B: SagaBackend + SagaBackendFactory + 'static> SagaResultHandler for Orchestrator<B> {
async fn handle_authenticated_result(
&self,
envelope: &SagaResultEnvelope,
producer: &ServiceIdentity,
now_ms: i64,
) -> anyhow::Result<HandleOutcome> {
Orchestrator::<B>::handle_authenticated_result(self, envelope, producer, now_ms).await
}
async fn handle_authenticated_result_traced(
&self,
envelope: &SagaResultEnvelope,
producer: &ServiceIdentity,
receipt_trace: Option<&TraceContext>,
now_ms: i64,
) -> anyhow::Result<HandleOutcome> {
Orchestrator::<B>::handle_authenticated_result_traced(
self,
envelope,
producer,
receipt_trace,
now_ms,
)
.await
}
}