use crate::middleware::Context;
use async_graphql::{Request, Response};
use async_trait::async_trait;
use std::sync::Arc;
#[async_trait]
pub trait Plugin: Send + Sync + 'static {
type Error: std::fmt::Display + Send + Sync + 'static;
fn name(&self) -> &str;
async fn on_request(&self, _ctx: &Context, _req: &Request) -> Result<(), Self::Error> {
Ok(())
}
async fn on_response(&self, _ctx: &Context, _res: &Response) -> Result<(), Self::Error> {
Ok(())
}
async fn on_schema_build(
&self,
_builder: &mut crate::schema::SchemaBuilder,
) -> Result<(), Self::Error> {
Ok(())
}
async fn on_subgraph_request(
&self,
_service_name: &str,
_headers: &mut tonic::metadata::MetadataMap,
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Default, Clone)]
pub struct PluginRegistry {
plugins: Vec<Arc<dyn Plugin<Error = Box<dyn std::error::Error + Send + Sync>>>>,
}
impl PluginRegistry {
pub fn new() -> Self {
Self {
plugins: Vec::new(),
}
}
pub fn register<P>(&mut self, plugin: P)
where
P: Plugin + 'static,
P::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
{
struct ErasurePlugin<T>(T);
#[async_trait]
impl<T> Plugin for ErasurePlugin<T>
where
T: Plugin + Send + Sync,
T::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
{
type Error = Box<dyn std::error::Error + Send + Sync>;
fn name(&self) -> &str {
self.0.name()
}
async fn on_request(&self, ctx: &Context, req: &Request) -> Result<(), Self::Error> {
self.0.on_request(ctx, req).await.map_err(Into::into)
}
async fn on_response(&self, ctx: &Context, res: &Response) -> Result<(), Self::Error> {
self.0.on_response(ctx, res).await.map_err(Into::into)
}
async fn on_schema_build(
&self,
builder: &mut crate::schema::SchemaBuilder,
) -> Result<(), Self::Error> {
self.0.on_schema_build(builder).await.map_err(Into::into)
}
async fn on_subgraph_request(
&self,
service_name: &str,
headers: &mut tonic::metadata::MetadataMap,
) -> Result<(), Self::Error> {
self.0
.on_subgraph_request(service_name, headers)
.await
.map_err(Into::into)
}
}
self.plugins.push(Arc::new(ErasurePlugin(plugin)));
}
pub async fn on_request(&self, ctx: &Context, req: &Request) -> crate::error::Result<()> {
for plugin in &self.plugins {
plugin
.on_request(ctx, req)
.await
.map_err(|e| crate::error::Error::Plugin(e.to_string()))?;
}
Ok(())
}
pub async fn on_response(&self, ctx: &Context, res: &Response) -> crate::error::Result<()> {
for plugin in &self.plugins {
plugin
.on_response(ctx, res)
.await
.map_err(|e| crate::error::Error::Plugin(e.to_string()))?;
}
Ok(())
}
pub async fn on_schema_build(
&self,
builder: &mut crate::schema::SchemaBuilder,
) -> crate::error::Result<()> {
for plugin in &self.plugins {
plugin
.on_schema_build(builder)
.await
.map_err(|e| crate::error::Error::Plugin(e.to_string()))?;
}
Ok(())
}
pub async fn on_subgraph_request(
&self,
service_name: &str,
headers: &mut tonic::metadata::MetadataMap,
) -> crate::error::Result<()> {
for plugin in &self.plugins {
plugin
.on_subgraph_request(service_name, headers)
.await
.map_err(|e| crate::error::Error::Plugin(e.to_string()))?;
}
Ok(())
}
}