use crate::broker::lifecycle::names::{validate_service_name, PipePathError};
const PIPE_PREFIX_V2: &str = "rpb-v2";
pub fn v2_program_pipe(
program: &str,
sid_hash: &str,
pipe_idx: u32,
) -> Result<String, PipePathError> {
validate_service_name(program)?;
validate_sid_hash(sid_hash)?;
Ok(format!("{PIPE_PREFIX_V2}-{program}-{sid_hash}-{pipe_idx}"))
}
fn validate_sid_hash(sid_hash: &str) -> Result<(), PipePathError> {
if sid_hash.is_empty() {
return Err(PipePathError::InvalidName {
name: sid_hash.into(),
reason: "sid_hash must be at least 1 character",
});
}
if sid_hash.len() != 16 {
return Err(PipePathError::InvalidName {
name: sid_hash.into(),
reason: "sid_hash must be exactly 16 hex characters",
});
}
for c in sid_hash.chars() {
if !c.is_ascii_hexdigit() || c.is_ascii_uppercase() {
return Err(PipePathError::InvalidName {
name: sid_hash.into(),
reason: "sid_hash must be lowercase hex digits",
});
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
const VALID_SID: &str = "deadbeefcafef00d";
#[test]
fn v2_program_pipe_happy_path() {
let name = v2_program_pipe("zccache", VALID_SID, 0)
.expect("valid inputs produce a v2 pipe name");
assert_eq!(name, "rpb-v2-zccache-deadbeefcafef00d-0");
}
#[test]
fn v2_program_pipe_distinct_pipe_idx_distinct_names() {
let name_0 = v2_program_pipe("zccache", VALID_SID, 0).expect("idx=0 valid");
let name_7 = v2_program_pipe("zccache", VALID_SID, 7).expect("idx=7 valid");
assert_ne!(name_0, name_7);
assert!(name_7.ends_with("-7"));
}
#[test]
fn v2_program_pipe_rejects_invalid_program() {
assert!(matches!(
v2_program_pipe("", VALID_SID, 0),
Err(PipePathError::InvalidName { .. })
));
assert!(matches!(
v2_program_pipe("Zccache", VALID_SID, 0),
Err(PipePathError::InvalidName { .. })
));
let too_long = "a".repeat(65);
assert!(matches!(
v2_program_pipe(&too_long, VALID_SID, 0),
Err(PipePathError::InvalidName { .. })
));
}
#[test]
fn v2_program_pipe_rejects_invalid_sid_hash() {
assert!(matches!(
v2_program_pipe("zccache", "", 0),
Err(PipePathError::InvalidName { .. })
));
assert!(matches!(
v2_program_pipe("zccache", "deadbeefcafef00", 0),
Err(PipePathError::InvalidName { .. })
));
assert!(matches!(
v2_program_pipe("zccache", "deadbeefcafef00g", 0),
Err(PipePathError::InvalidName { .. })
));
assert!(matches!(
v2_program_pipe("zccache", "DEADBEEFCAFEF00D", 0),
Err(PipePathError::InvalidName { .. })
));
}
}