diff options
author | metamuffin <metamuffin@disroot.org> | 2025-04-10 20:27:38 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-04-10 20:27:38 +0200 |
commit | 518cbf0c2658bb43ba2297df973a3c2b1b3dca61 (patch) | |
tree | 8c25591114f341050f6eb1425221872e89e1b2cd | |
parent | 8123a63fa9ec0e1736784cdb08d93a6ea72a904d (diff) | |
download | gnix-518cbf0c2658bb43ba2297df973a3c2b1b3dca61.tar gnix-518cbf0c2658bb43ba2297df973a3c2b1b3dca61.tar.bz2 gnix-518cbf0c2658bb43ba2297df973a3c2b1b3dca61.tar.zst |
add semaphore module
-rw-r--r-- | src/modules/mod.rs | 2 | ||||
-rw-r--r-- | src/modules/semaphore.rs | 56 |
2 files changed, 58 insertions, 0 deletions
diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 65e9666..71f60c9 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -34,6 +34,7 @@ mod ratelimit; mod redirect; mod switch; mod upgrade_insecure; +mod semaphore; pub type NodeRequest = Request<BoxBody<Bytes, ServiceError>>; pub type NodeResponse = Response<BoxBody<Bytes, ServiceError>>; @@ -63,6 +64,7 @@ pub static MODULES: &[&dyn NodeKind] = &[ &delay::DelayKind, &ratelimit::RatelimitKind, &log::LogKind, + &semaphore::SemaphoreKind, ]; pub struct NodeContext { diff --git a/src/modules/semaphore.rs b/src/modules/semaphore.rs new file mode 100644 index 0000000..b4f50b2 --- /dev/null +++ b/src/modules/semaphore.rs @@ -0,0 +1,56 @@ +/* + This file is part of gnix (https://codeberg.org/metamuffin/gnix) + which is licensed under the GNU Affero General Public License (version 3); see /COPYING. + Copyright (C) 2025 metamuffin <metamuffin.org> +*/ +use super::{Node, NodeContext, NodeKind, NodeRequest, NodeResponse}; +use crate::{config::DynNode, error::ServiceError}; +use anyhow::Result; +use serde::Deserialize; +use serde_yml::Value; +use std::{ + future::Future, + pin::Pin, + sync::Arc, +}; +use tokio::sync::Semaphore; + +pub struct SemaphoreKind; + +#[derive(Deserialize)] +struct SemaphoreConfig { + permits: usize, + next: DynNode, +} + +struct SemaphoreState { + config: SemaphoreConfig, + semaphore: Semaphore, +} + +impl NodeKind for SemaphoreKind { + fn name(&self) -> &'static str { + "semaphore" + } + fn instanciate(&self, config: Value) -> Result<Arc<dyn Node>> { + let config = serde_yml::from_value::<SemaphoreConfig>(config)?; + Ok(Arc::new(SemaphoreState { + semaphore: Semaphore::new(config.permits), + config, + })) + } +} +impl Node for SemaphoreState { + 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 _permit = self.semaphore.acquire().await; + let resp = self.config.next.handle(context, request).await?; + drop(_permit); + Ok(resp) + }) + } +} |