use std::net::{Ipv6Addr, SocketAddr};
use sonic_client::SonicMultiplexer;
pub const PASS: &str = "SecretPassword";
#[must_use]
pub fn start_sonic() -> (SpawnGuard, SocketAddr) {
use std::process::Command;
use std::sync::atomic::{AtomicU16, Ordering};
use std::time::Duration;
static COUNTER: AtomicU16 = AtomicU16::new(0);
let counter = COUNTER.fetch_add(1, Ordering::SeqCst);
let addr = SocketAddr::from((Ipv6Addr::LOCALHOST, 1550 + counter));
let sonic_bin_path = concat!(env!("CARGO_TARGET_TMPDIR"), "/../debug/sonic");
let sonic_data_path = std::path::Path::new(concat!(env!("CARGO_TARGET_TMPDIR"), "/data"));
if sonic_data_path.exists() {
std::fs::remove_dir_all(sonic_data_path).unwrap();
}
let sonic = Command::new(sonic_bin_path)
.env("SONIC_CHANNEL__INET", addr.to_string())
.env("SONIC_SERVER__LOG_LEVEL", "WARN")
.env("SONIC_STORE__KV__PATH", sonic_data_path.join("kv"))
.env("SONIC_STORE__FST__PATH", sonic_data_path.join("fst"))
.spawn()
.unwrap();
let sonic = SpawnGuard(sonic);
let start = std::time::Instant::now();
let multiplexer = SonicMultiplexer::new().unwrap();
let mut error: Option<std::io::Error> = None;
while start.elapsed() < Duration::from_secs(1) {
use sonic_client::control::SonicChannelControlBlocking;
match SonicChannelControlBlocking::connect(addr, PASS, &multiplexer) {
Ok(channel) => match channel.ping() {
Ok(()) => {
error = None;
break;
}
Err(err) => {
error = Some(err);
std::thread::sleep(Duration::from_millis(50));
continue;
}
},
Err(err) => {
error = Some(err);
std::thread::sleep(Duration::from_millis(50));
continue;
}
}
}
if let Some(error) = error {
panic!("{error}");
}
(sonic, addr)
}
pub struct SpawnGuard(pub std::process::Child);
impl std::ops::Deref for SpawnGuard {
type Target = std::process::Child;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for SpawnGuard {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Drop for SpawnGuard {
fn drop(&mut self) {
self.0.kill().unwrap();
self.0.wait().unwrap();
}
}