diff options
author | metamuffin <metamuffin@disroot.org> | 2024-06-22 12:54:39 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-06-22 12:54:39 +0200 |
commit | 4da8fe84c07e3f9e83f9b769f1670f4d52466001 (patch) | |
tree | bf4384034771001b136207c4df386daf99dac7fa /src/modules/switch.rs | |
parent | 1451273fa59d14070e525562ec466a21128fa671 (diff) | |
download | gnix-4da8fe84c07e3f9e83f9b769f1670f4d52466001.tar gnix-4da8fe84c07e3f9e83f9b769f1670f4d52466001.tar.bz2 gnix-4da8fe84c07e3f9e83f9b769f1670f4d52466001.tar.zst |
add switch module
Diffstat (limited to 'src/modules/switch.rs')
-rw-r--r-- | src/modules/switch.rs | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/src/modules/switch.rs b/src/modules/switch.rs new file mode 100644 index 0000000..bbb9e98 --- /dev/null +++ b/src/modules/switch.rs @@ -0,0 +1,71 @@ +use super::{Node, NodeContext, NodeKind, NodeRequest, NodeResponse}; +use crate::{config::DynNode, error::ServiceError}; +use anyhow::Result; +use futures::Future; +use headers::{HeaderMapExt, Upgrade}; +use hyper::Method; +use serde::Deserialize; +use std::{pin::Pin, sync::Arc}; + +pub struct SwitchKind; + +#[derive(Deserialize)] +pub struct Switch { + condition: Condition, + case_true: DynNode, + case_false: DynNode, +} + +impl NodeKind for SwitchKind { + fn name(&self) -> &'static str { + "switch" + } + fn instanciate(&self, config: serde_yaml::Value) -> Result<Arc<dyn Node>> { + Ok(Arc::new(serde_yaml::from_value::<Switch>(config)?)) + } +} + +impl Node for Switch { + fn handle<'a>( + &'a self, + context: &'a mut NodeContext, + request: NodeRequest, + ) -> Pin<Box<dyn Future<Output = Result<NodeResponse, ServiceError>> + Send + Sync + 'a>> { + Box::pin(async move { + let cond = self.condition.test(&request); + if cond { + &self.case_true + } else { + &self.case_false + } + .handle(context, request) + .await + }) + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "snake_case")] +enum Condition { + IsWebsocketUpgrade, + IsPost, + IsGet, + HasHeader(String), + PathStartsWith(String), + PathIs(String), +} + +impl Condition { + pub fn test(&self, req: &NodeRequest) -> bool { + match self { + Condition::IsWebsocketUpgrade => { + req.headers().typed_get::<Upgrade>() == Some(Upgrade::websocket()) + } + Condition::HasHeader(name) => req.headers().contains_key(name), + Condition::PathStartsWith(path_prefix) => req.uri().path().starts_with(path_prefix), + Condition::PathIs(path) => req.uri().path() == path, + Condition::IsPost => req.method() == Method::POST, + Condition::IsGet => req.method() == Method::GET, + } + } +} |