use std::collections::HashMap;
use std::io::Write as _;
use std::sync::{Arc, Mutex, OnceLock};
const MIN_BYTES: usize = 4096;
const TIMEOUT_MS: u64 = 2_000;
const CACHE_CAP: usize = 64;
const WHITELIST: &[&str] = &["bash"];
fn env_cmd() -> Option<Vec<String>> {
let v = std::env::var("OCSERVE_SIFT").unwrap_or_default();
match v.trim() {
"" | "0" | "off" | "false" => None,
"auto" => Some(vec!["reliary".into(), "sift".into(), "--stdin".into()]),
path => Some(vec![path.into(), "sift".into(), "--stdin".into()]),
}
}
fn cmd_available(cmd: &[String]) -> bool {
static AVAIL: OnceLock<Mutex<HashMap<String, bool>>> = OnceLock::new();
let map = AVAIL.get_or_init(|| Mutex::new(HashMap::new()));
let key = cmd[0].clone();
if let Some(v) = map.lock().expect("sift avail").get(&key) {
return *v;
}
let ok = probe(cmd);
map.lock().expect("sift avail").entry(key).or_insert(ok);
ok
}
fn probe(cmd: &[String]) -> bool {
let mut c = std::process::Command::new(&cmd[0]);
c.args(&cmd[1..]);
if let Ok(home) = std::env::var("HOME") {
let old = std::env::var("PATH").unwrap_or_default();
c.env("PATH", format!("{home}/.local/bin:{old}"));
}
let _ = c.arg("--help");
match c
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn()
{
Ok(mut child) => {
for _ in 0..200 {
match child.try_wait() {
Ok(Some(_)) => return true,
Ok(None) => std::thread::sleep(std::time::Duration::from_millis(5)),
Err(_) => return false,
}
}
let _ = child.kill();
false
}
Err(_) => false,
}
}
fn cache() -> &'static Mutex<HashMap<u64, Option<Arc<str>>>> {
static C: OnceLock<Mutex<HashMap<u64, Option<Arc<str>>>>> = OnceLock::new();
C.get_or_init(|| Mutex::new(HashMap::new()))
}
fn run_sift(cmd: &[String], raw: &str) -> Option<String> {
let mut c = std::process::Command::new(&cmd[0]);
c.args(&cmd[1..])
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::null());
if let Ok(home) = std::env::var("HOME") {
let old = std::env::var("PATH").unwrap_or_default();
c.env("PATH", format!("{home}/.local/bin:{old}"));
}
let mut child = c.spawn().ok()?;
{
let mut stdin = child.stdin.take()?;
stdin.write_all(raw.as_bytes()).ok()?;
} let mut stdout = child.stdout.take()?;
let reader = std::thread::spawn(move || {
use std::io::Read as _;
let mut out = Vec::new();
let _ = stdout.read_to_end(&mut out);
out
});
let deadline = std::time::Instant::now() + std::time::Duration::from_millis(TIMEOUT_MS);
loop {
match child.try_wait() {
Ok(Some(status)) => {
let out = reader.join().ok()?;
if !status.success() {
return None;
}
return String::from_utf8(out).ok();
}
Ok(None) => {
if std::time::Instant::now() > deadline {
let _ = child.kill();
let _ = child.wait();
return None; }
std::thread::sleep(std::time::Duration::from_millis(5));
}
Err(_) => return None,
}
}
}
#[cfg(test)]
pub(crate) fn sift_env_lock() -> std::sync::MutexGuard<'static, ()> {
static L: std::sync::OnceLock<std::sync::Mutex<()>> = std::sync::OnceLock::new();
L.get_or_init(|| std::sync::Mutex::new(()))
.lock()
.unwrap_or_else(|e| e.into_inner())
}
pub fn maybe_sift(tool: &str, output: &str) -> Arc<str> {
let raw_len = output.len();
if raw_len < MIN_BYTES || !WHITELIST.contains(&tool) {
return Arc::from(output);
}
let Some(cmd) = env_cmd() else {
return Arc::from(output);
};
if !cmd_available(&cmd) {
return Arc::from(output);
}
let key = {
use std::hash::{Hash, Hasher};
let mut h = std::collections::hash_map::DefaultHasher::new();
tool.hash(&mut h);
output.hash(&mut h);
cmd[0].hash(&mut h);
h.finish()
};
if let Some(hit) = cache().lock().expect("sift cache").get(&key) {
return hit.clone().unwrap_or_else(|| Arc::from(output));
}
let result = match run_sift(&cmd, output) {
Some(new) if !new.is_empty() && new.len() < raw_len => {
let marker = format!("[compressed {raw_len} -> {} bytes]\n", new.len());
let combined: Arc<str> = if raw_len >= new.len() + marker.len() {
Arc::from(format!("{marker}{new}"))
} else {
Arc::from(new)
};
if combined.len() <= raw_len {
combined
} else {
Arc::from(output) }
}
_ => Arc::from(output),
};
let sent_sifted = result.as_ref() != output;
{
let mut m = cache().lock().expect("sift cache");
if m.len() >= CACHE_CAP {
m.clear(); }
m.insert(
key,
if sent_sifted {
Some(result.clone())
} else {
None
},
);
}
ocserve_metrics::labeled_counter(
"ocserve_sift_total",
if sent_sifted {
"outcome=\"compressed\""
} else {
"outcome=\"raw\""
},
1,
);
ocserve_metrics::labeled_counter(
"ocserve_sift_bytes_total",
"direction=\"in\"",
raw_len as u64,
);
ocserve_metrics::labeled_counter(
"ocserve_sift_bytes_total",
"direction=\"out\"",
result.len() as u64,
);
result
}
#[cfg(test)]
mod tests {
use super::*;
use std::os::unix::fs::PermissionsExt as _;
fn big_noise() -> String {
let mut s = String::new();
for i in 0..600 {
s.push_str(&format!("step {i}: compiling module m{i} ok\n"));
}
s
}
fn write_fake(name: &str, script: &str) -> std::path::PathBuf {
let dir = std::env::temp_dir().join(format!("ocserve-sift-fake-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let p = dir.join(name);
std::fs::write(&p, script).unwrap();
let mut perm = std::fs::metadata(&p).unwrap().permissions();
perm.set_mode(0o755);
std::fs::set_permissions(&p, perm).unwrap();
p
}
fn set_sift(v: &str) {
unsafe { std::env::set_var("OCSERVE_SIFT", v) }
}
fn env_lock() -> std::sync::MutexGuard<'static, ()> {
super::sift_env_lock()
}
#[test]
fn off_by_default_and_whitelist_and_threshold() {
let _g = env_lock();
unsafe { std::env::remove_var("OCSERVE_SIFT") };
let raw = big_noise();
assert_eq!(maybe_sift("bash", &raw).as_ref(), raw, "default off");
set_sift("auto");
assert_eq!(maybe_sift("read", &raw).as_ref(), raw, "whitelist fence");
assert_eq!(maybe_sift("bash", "short").as_ref(), "short");
unsafe { std::env::remove_var("OCSERVE_SIFT") };
}
#[test]
fn fake_compressor_shrinks_with_marker_never_inflating() {
let _g = env_lock();
let fake = write_fake(
"fake_shrink.sh",
"#!/bin/sh\ncat >/dev/null\necho 'FAIL test_x: assertion failed'\necho 'ok-summary [400 ok]'\n",
);
set_sift(fake.to_str().unwrap());
let raw = big_noise();
let out = maybe_sift("bash", &raw);
assert!(
out.len() < raw.len(),
"must shrink ({} < {})",
out.len(),
raw.len()
);
assert!(out.len() <= raw.len(), "never inflate");
assert!(out.contains("[compressed"), "marker present: {out}");
assert!(out.contains("assertion failed"), "signal preserved");
let out2 = maybe_sift("bash", &raw);
assert_eq!(out.as_ref(), out2.as_ref(), "cache must be byte-identical");
unsafe { std::env::remove_var("OCSERVE_SIFT") };
}
#[test]
fn empty_result_falls_back_to_raw() {
let _g = env_lock();
let fake = write_fake("fake_empty.sh", "#!/bin/sh\ncat >/dev/null\n");
set_sift(fake.to_str().unwrap());
let raw = big_noise();
let out = maybe_sift("bash", &raw);
assert_eq!(
out.as_ref(),
raw,
"empty compressed output must fall back to raw"
);
unsafe { std::env::remove_var("OCSERVE_SIFT") };
}
#[test]
fn missing_binary_falls_back_to_raw() {
let _g = env_lock();
set_sift("/nonexistent/reliary-binary-xyz");
let raw = big_noise();
let out = maybe_sift("bash", &raw);
assert_eq!(out.as_ref(), raw, "missing binary must fall back");
unsafe { std::env::remove_var("OCSERVE_SIFT") };
}
#[test]
fn inflation_falls_back_to_raw() {
let _g = env_lock();
let fake = write_fake(
"fake_inflate.sh",
"#!/bin/sh\ncat >/dev/null\nhead -c 999999 /dev/zero | tr '\\0' 'x'\n",
);
set_sift(fake.to_str().unwrap());
let raw = big_noise();
let out = maybe_sift("bash", &raw);
assert_eq!(out.as_ref(), raw, "inflated output must fall back to raw");
unsafe { std::env::remove_var("OCSERVE_SIFT") };
}
}