use super::{Node, NodeContext, NodeKind, NodeRequest, NodeResponse}; use crate::{config::DynNode, error::ServiceError}; use anyhow::Result; use http::Request; use http_body_util::{combinators::BoxBody, BodyExt, Full}; use serde::Deserialize; use serde_yml::Value; use std::{future::Future, pin::Pin, sync::Arc}; pub struct FallbackKind; #[derive(Deserialize)] struct Fallback(Vec); impl NodeKind for FallbackKind { fn name(&self) -> &'static str { "fallback" } fn instanciate(&self, config: Value) -> Result> { Ok(Arc::new(serde_yml::from_value::(config)?)) } } impl Node for Fallback { fn handle<'a>( &'a self, context: &'a mut NodeContext, request: NodeRequest, ) -> Pin> + Send + Sync + 'a>> { Box::pin(async move { let (parts, body) = request.into_parts(); let body = body .collect() .await .map_err(|_| ServiceError::Other)? .to_bytes(); for (i, h) in self.0.iter().enumerate() { let last = i == self.0.len() - 1; let res = h .handle( context, Request::from_parts( parts.clone(), BoxBody::new(Full::new(body.clone()).map_err(|x| match x {})), ), ) .await; if last { return res; } if let Ok(resp) = res { if resp.status().is_success() || resp.status().is_redirection() || resp.status().is_informational() { return Ok(resp); } } } Err(ServiceError::CustomStatic( "fallback module without any handlers", )) }) } }