use anyhow::{Context, Result};
use std::path::Path;
use std::time::Duration;
pub fn start_in_current_runtime(data_dir: &Path, grpc: &str, http: &str) -> Result<()> {
std::fs::create_dir_all(data_dir)
.with_context(|| format!("create holger data dir {}", data_dir.display()))?;
let cfg_path = data_dir.join("holger-dev-pair.ron");
std::fs::write(&cfg_path, holger_server_lib::dev_pair_ron(data_dir, grpc, http))
.with_context(|| format!("write holger config {}", cfg_path.display()))?;
let mut holger = holger_server_lib::read_ron_config(&cfg_path)
.with_context(|| format!("read holger config {}", cfg_path.display()))?;
holger.instantiate_backends().context("holger: instantiate backends")?;
holger_server_lib::wire_holger(&mut holger).context("holger: wire routes")?;
holger.start().context("holger: start servers")?;
Ok(())
}
pub struct EmbeddedHolger {
_rt: tokio::runtime::Runtime,
pub grpc: String,
pub http: String,
}
impl EmbeddedHolger {
pub fn start(data_dir: &Path, grpc: &str, http: &str) -> Result<Self> {
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.worker_threads(2)
.thread_name("holger-embed")
.build()
.context("build holger tokio runtime")?;
{
let _guard = rt.enter();
start_in_current_runtime(data_dir, grpc, http)?;
}
Ok(Self { _rt: rt, grpc: grpc.to_string(), http: http.to_string() })
}
pub fn wait_ready(&self, timeout: Duration) -> Result<()> {
wait_ready(&self.http, timeout)
}
}
pub fn wait_ready(http_addr: &str, timeout: Duration) -> Result<()> {
let url = format!("http://{http_addr}/cache/index/config.json");
let deadline = std::time::Instant::now() + timeout;
loop {
if ureq::get(&url)
.timeout(Duration::from_millis(500))
.call()
.is_ok()
{
return Ok(());
}
if std::time::Instant::now() >= deadline {
anyhow::bail!("holger HTTP gateway never became ready at {url} (waited {timeout:?})");
}
std::thread::sleep(Duration::from_millis(150));
}
}