You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
multihook/src/server/action/mod.rs

65 lines
1.9 KiB
Rust

use crate::utils::error::{MultihookError, MultihookResult};
use self::template::ActionTemplate;
use std::{collections::HashMap, sync::Arc};
use tokio::{process::Command, sync::Semaphore};
mod template;
static MAX_CONCURRENCY: usize = 256;
#[derive(Clone)]
pub struct Action {
template: ActionTemplate,
semaphore: Arc<Semaphore>,
}
impl Action {
/// Creates a new command that also checks for parallel runs
pub fn new<S: Into<String>>(command: S, allow_parallel: bool) -> Self {
let semaphore = if allow_parallel {
Semaphore::new(MAX_CONCURRENCY)
} else {
Semaphore::new(1)
};
Self {
template: ActionTemplate::new(command.into()),
semaphore: Arc::new(semaphore),
}
}
/// Executes the action
pub async fn run(
&self,
body: &serde_json::Value,
env: &HashMap<&str, String>,
) -> MultihookResult<()> {
let command = self.template.evaluate(&body);
log::debug!("Acquiring lock for parallel runs...");
let permit = self.semaphore.acquire().await.unwrap();
log::debug!("Lock acquired. Running command...");
std::mem::drop(permit);
let output = Command::new("sh")
.envs(env)
.arg("-c")
.arg(command)
.kill_on_drop(true)
.output()
.await?;
log::debug!("Command finished. Releasing parallel lock...");
let stderr = String::from_utf8_lossy(&output.stderr[..]);
let stdout = String::from_utf8_lossy(&output.stdout[..]);
log::debug!("Command output is: {}", stdout);
if output.status.success() {
Ok(())
} else {
log::error!("Errors occurred during command execution: {}", stderr);
Err(MultihookError::ActionError(stderr.into_owned()))
}
}
}