#![allow(dead_code)]
use std::io;
use std::sync::mpsc;
use std::time::Duration;
use interprocess::local_socket::ListenerOptions;
use running_process::broker::server::local_socket_name;
pub fn unique_socket_name(label: &str) -> String {
#[cfg(windows)]
{
format!("rpb-v1-{label}-{}-{}", std::process::id(), unique_suffix())
}
#[cfg(unix)]
{
use std::hash::{Hash, Hasher};
use std::os::unix::fs::DirBuilderExt as _;
use std::sync::OnceLock;
static PRIVATE_SOCKET_DIR: OnceLock<std::path::PathBuf> = OnceLock::new();
let private_socket_dir = PRIVATE_SOCKET_DIR.get_or_init(|| {
let path = std::env::temp_dir().join(format!(
"rp-{}-{}",
std::process::id(),
unique_suffix() % 1_000_000
));
let mut builder = std::fs::DirBuilder::new();
builder
.mode(0o700)
.create(&path)
.expect("create owner-private broker test socket directory");
path
});
let mut hasher = std::collections::hash_map::DefaultHasher::new();
label.hash(&mut hasher);
let label_hash = hasher.finish() as u32;
let short_suffix = unique_suffix() % 1_000_000;
private_socket_dir
.join(format!("s-{label_hash:08x}-{short_suffix}.sock"))
.to_string_lossy()
.into_owned()
}
}
pub fn bind_test_socket(socket_name: &str) -> io::Result<interprocess::local_socket::Listener> {
prepare_test_socket(socket_name)?;
let name = local_socket_name(socket_name)?;
ListenerOptions::new().name(name).create_sync()
}
pub fn bind_ready_test_socket(
socket_name: &str,
ready_tx: &mpsc::Sender<Result<(), String>>,
) -> io::Result<interprocess::local_socket::Listener> {
match bind_test_socket(socket_name) {
Ok(listener) => {
ready_tx.send(Ok(())).unwrap();
Ok(listener)
}
Err(err) => {
let _ = ready_tx.send(Err(err.to_string()));
Err(err)
}
}
}
pub fn await_test_socket_ready(ready_rx: &mpsc::Receiver<Result<(), String>>, display_path: &str) {
match ready_rx.recv_timeout(Duration::from_secs(3)) {
Ok(Ok(())) => {}
Ok(Err(err)) => panic!("failed to bind test socket {display_path}: {err}"),
Err(err) => panic!("timed out waiting for test socket {display_path}: {err}"),
}
}
pub fn prepare_test_socket(socket_name: &str) -> io::Result<()> {
#[cfg(unix)]
{
let path = std::path::Path::new(socket_name);
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let _ = std::fs::remove_file(path);
}
#[cfg(windows)]
let _ = socket_name;
Ok(())
}
pub fn cleanup_test_socket(socket_name: &str) {
#[cfg(unix)]
{
let _ = std::fs::remove_file(socket_name);
}
#[cfg(windows)]
let _ = socket_name;
}
fn unique_suffix() -> u128 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
}