use std::sync::Arc;
use async_trait::async_trait;
use serde_json::Value;
use crate::libs::peer::{Extensions, PeerIdentity};
use crate::libs::toolbox::{CustomError, RequestContext};
use crate::model::EndpointSchema;
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum RequestOutcome {
Ok,
PublicErr {
code: u32,
},
InternalErr,
}
#[async_trait(?Send)]
pub trait BeforeRequest: Send + Sync {
async fn before(
&self,
ctx: &mut RequestContext,
endpoint: &EndpointSchema,
params: &Value,
) -> Result<(), CustomError>;
}
#[async_trait(?Send)]
pub trait AfterRequest: Send + Sync {
async fn after(
&self,
ctx: &RequestContext,
endpoint: &EndpointSchema,
outcome: &RequestOutcome,
);
}
#[async_trait(?Send)]
pub trait OnConnect: Send + Sync {
async fn on_connect(
&self,
peer: &PeerIdentity,
ext: &mut Extensions,
) -> Result<(), CustomError>;
}
#[derive(Clone, Default)]
pub struct Hooks {
pub(crate) before: Vec<Arc<dyn BeforeRequest>>,
pub(crate) after: Vec<Arc<dyn AfterRequest>>,
pub(crate) on_connect: Vec<Arc<dyn OnConnect>>,
}
impl Hooks {
pub fn is_empty(&self) -> bool {
self.before.is_empty() && self.after.is_empty() && self.on_connect.is_empty()
}
pub(crate) async fn run_before(
&self,
ctx: &mut RequestContext,
endpoint: &EndpointSchema,
params: &Value,
) -> Result<(), CustomError> {
for hook in &self.before {
hook.before(ctx, endpoint, params).await?;
}
Ok(())
}
pub(crate) async fn run_after(
&self,
ctx: &RequestContext,
endpoint: &EndpointSchema,
outcome: &RequestOutcome,
) {
for hook in &self.after {
hook.after(ctx, endpoint, outcome).await;
}
}
pub(crate) async fn run_on_connect(
&self,
peer: &PeerIdentity,
ext: &mut Extensions,
) -> Result<(), CustomError> {
for hook in &self.on_connect {
hook.on_connect(peer, ext).await?;
}
Ok(())
}
}
impl std::fmt::Debug for Hooks {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Hooks")
.field("before", &self.before.len())
.field("after", &self.after.len())
.field("on_connect", &self.on_connect.len())
.finish()
}
}