Skip to main content

runtime_paths/
endpoint.rs

1use std::path::PathBuf;
2
3use sha2::{Digest, Sha256};
4
5/// Stable workdir identity for endpoint names (pipe / labels).
6///
7/// Uses SHA-256 of the canonical workdir path so the value does not change
8/// across Rust/std hasher versions. Returns the first 16 hex chars.
9pub fn workdir_identity_hash(workdir: &std::path::Path) -> String {
10    let normalized = normalize_workdir_for_hash(workdir);
11    let bytes = normalized.to_string_lossy();
12    let digest = Sha256::digest(bytes.as_bytes());
13    hex_encode_prefix(&digest, 16)
14}
15
16fn hex_encode_prefix(bytes: &[u8], chars: usize) -> String {
17    const HEX: &[u8; 16] = b"0123456789abcdef";
18    let nibble_count = chars.min(bytes.len() * 2);
19    let mut out = String::with_capacity(nibble_count);
20    for byte in bytes {
21        if out.len() >= nibble_count {
22            break;
23        }
24        out.push(HEX[(byte >> 4) as usize] as char);
25        if out.len() >= nibble_count {
26            break;
27        }
28        out.push(HEX[(byte & 0xf) as usize] as char);
29    }
30    out
31}
32
33fn normalize_workdir_for_hash(workdir: &std::path::Path) -> PathBuf {
34    workdir
35        .canonicalize()
36        .unwrap_or_else(|_| workdir.to_path_buf())
37}
38
39pub fn meowclient_named_pipe_name_for_workdir(workdir: &std::path::Path) -> String {
40    format!(
41        r"\\.\pipe\meowclient-meowd-{}",
42        workdir_identity_hash(workdir)
43    )
44}
45
46#[cfg(unix)]
47pub fn meowclient_endpoint_label_for_workdir(workdir: &std::path::Path) -> String {
48    crate::RuntimePaths::for_workdir(workdir)
49        .meowclient_socket_path()
50        .display()
51        .to_string()
52}
53
54#[cfg(windows)]
55pub fn meowclient_endpoint_label_for_workdir(workdir: &std::path::Path) -> String {
56    meowclient_named_pipe_name_for_workdir(workdir)
57}
58
59#[cfg(not(any(unix, windows)))]
60pub fn meowclient_endpoint_label_for_workdir(workdir: &std::path::Path) -> String {
61    crate::RuntimePaths::for_workdir(workdir)
62        .meowclient_socket_path()
63        .display()
64        .to_string()
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use std::path::Path;
71
72    #[test]
73    fn identity_hash_is_stable_hex() {
74        let hash = workdir_identity_hash(Path::new("/tmp/meow-workdir-test"));
75        assert_eq!(hash.len(), 16);
76        assert!(hash.chars().all(|c| c.is_ascii_hexdigit()));
77        assert_eq!(
78            hash,
79            workdir_identity_hash(Path::new("/tmp/meow-workdir-test"))
80        );
81    }
82}