use std::sync::Arc;
use async_trait::async_trait;
use uuid::Uuid;
use crate::errors::{DialectError, ObservabilityError, RouteError, SignerError, UpstreamError};
use crate::types::{
ObserveEvent, PerCandidateReason, Principal, RequestContext, RetryDecision, RouteDecision,
ShapedRequest, ShapedRequestBuilder, SignedRequest, SigningCapability, SlotKey, Upstream,
UpstreamCandidate,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FilterOutput {
pub kept_upstream_ids: Vec<Uuid>,
pub reason: String,
pub per_candidate_reasons: Vec<PerCandidateReason>,
}
#[derive(Debug)]
pub enum FilterError {
Runtime {
reason: String,
},
Trap {
reason: String,
},
}
impl std::fmt::Display for FilterError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
FilterError::Runtime { reason } => write!(f, "filter runtime error: {}", reason),
FilterError::Trap { reason } => write!(f, "filter trap error: {}", reason),
}
}
}
impl std::error::Error for FilterError {}
pub trait FilterPlugin: Send + Sync {
fn filter(
&self,
ctx: &RequestContext,
principal: &Principal,
candidates: &[UpstreamCandidate],
) -> Result<FilterOutput, FilterError>;
fn plugin_id(&self) -> Uuid;
fn plugin_name(&self) -> &str;
fn slot_key(&self) -> SlotKey {
SlotKey::global(self.plugin_name())
}
}
pub trait RouterPlugin: Send + Sync {
fn route(
&self,
ctx: &RequestContext,
principal: &Principal,
candidates: &[UpstreamCandidate],
) -> Result<RouteDecision, RouteError>;
}
pub trait UpstreamDialect: Send + Sync {
fn shape(
&self,
ctx: &RequestContext,
upstream: &Upstream,
principal: &Principal,
builder: &mut ShapedRequestBuilder,
) -> Result<ShapedRequest, DialectError>;
}
#[async_trait]
pub trait Signer: Send + Sync {
async fn sign(
&self,
shaped: ShapedRequest,
capability: &mut SigningCapability,
) -> Result<SignedRequest, SignerError>;
async fn on_unauthorized(&self, err: &UpstreamError) -> RetryDecision;
}
#[async_trait]
pub trait SignerFactory: Send + Sync {
async fn build(&self, upstream: &Upstream) -> Result<Arc<dyn Signer>, SignerError>;
}
pub trait ApiKeyAwareSignerFactory: Send + Sync {
fn with_router_choice(
&self,
api_key: String,
router_chosen_upstream_name: String,
) -> Arc<dyn SignerFactory>;
}
pub trait ObservabilityHook: Send + Sync {
fn observe(&self, event: ObserveEvent) -> Result<(), ObservabilityError>;
}