fabaccess-bffh/bffhd/actors/process.rs

95 lines
3.2 KiB
Rust
Raw Normal View History

2022-05-05 15:50:44 +02:00
use futures_util::future::BoxFuture;
2022-03-13 21:54:48 +01:00
use std::collections::HashMap;
use std::process::{Command, Stdio};
2023-01-18 16:26:09 +01:00
use base64::Engine;
2022-04-26 23:21:43 +02:00
2022-03-13 21:54:48 +01:00
use crate::actors::Actor;
2022-03-16 18:10:59 +01:00
use crate::db::ArchivedValue;
use crate::resources::modules::fabaccess::ArchivedStatus;
2022-03-13 21:54:48 +01:00
use crate::resources::state::State;
pub struct Process {
name: String,
cmd: String,
args: Vec<String>,
}
impl Process {
pub fn new(name: String, params: &HashMap<String, String>) -> Option<Self> {
let cmd = params.get("cmd").map(|s| s.to_string())?;
2022-05-05 15:50:44 +02:00
let args = params
.get("args")
.map(|argv| argv.split_whitespace().map(|s| s.to_string()).collect())
.unwrap_or_else(Vec::new);
2022-03-13 21:54:48 +01:00
Some(Self { name, cmd, args })
}
pub fn into_boxed_actuator(self) -> Box<dyn Actor + Sync + Send> {
Box::new(self)
}
}
impl Actor for Process {
2022-03-16 18:10:59 +01:00
fn apply(&mut self, state: ArchivedValue<State>) -> BoxFuture<'static, ()> {
2022-03-13 21:54:48 +01:00
tracing::debug!(name=%self.name, cmd=%self.cmd, ?state,
"Process actor updating state");
let mut command = Command::new(&self.cmd);
command
.stdin(Stdio::null())
.args(self.args.iter())
.arg(&self.name);
2023-01-18 16:26:09 +01:00
if state.as_ref().raw.is_empty() {
match &state.as_ref().inner.state {
ArchivedStatus::Free => {
command.arg("free");
}
ArchivedStatus::InUse(by) => {
command.arg("inuse").arg(by.id.as_str());
}
ArchivedStatus::ToCheck(by) => {
command.arg("tocheck").arg(by.id.as_str());
}
ArchivedStatus::Blocked(by) => {
command.arg("blocked").arg(by.id.as_str());
}
ArchivedStatus::Disabled => {
command.arg("disabled");
}
ArchivedStatus::Reserved(by) => {
command.arg("reserved").arg(by.id.as_str());
}
2022-03-13 21:54:48 +01:00
}
2023-01-18 16:26:09 +01:00
} else {
let b64 = base64::prelude::BASE64_STANDARD_NO_PAD.encode(&state.as_ref().raw);
command.arg("raw").arg(b64);
2022-03-13 21:54:48 +01:00
}
let name = self.name.clone();
2022-05-05 15:50:44 +02:00
Box::pin(async move {
match command.output() {
Ok(retv) if retv.status.success() => {
tracing::trace!("Actor was successful");
let outstr = String::from_utf8_lossy(&retv.stdout);
for line in outstr.lines() {
tracing::debug!(%name, %line, "actor stdout");
}
2022-03-13 21:54:48 +01:00
}
2022-05-05 15:50:44 +02:00
Ok(retv) => {
tracing::warn!(%name, ?state, code=?retv.status,
"Actor returned nonzero exitcode"
);
if !retv.stderr.is_empty() {
let errstr = String::from_utf8_lossy(&retv.stderr);
for line in errstr.lines() {
tracing::warn!(%name, %line, "actor stderr");
}
2022-03-13 21:54:48 +01:00
}
}
2022-05-05 15:50:44 +02:00
Err(error) => tracing::warn!(%name, ?error, "process actor failed to run cmd"),
2022-03-13 21:54:48 +01:00
}
2022-05-05 15:50:44 +02:00
})
2022-03-13 21:54:48 +01:00
}
}