use std::sync::Arc;
use anyhow::{Context, Result};
use aviso::state::{JsonFileStore, MemoryStore, StateStore};
use aviso::{AvisoClient, AvisoClientBuilder};
use crate::config::Resolved;
use crate::exit::usage_error;
use crate::paths;
pub(crate) fn build(
resolved: &Resolved,
state_store: Option<Arc<dyn StateStore>>,
flush_cursor_on_exit: bool,
) -> Result<AvisoClient> {
let base_url = resolved
.base_url
.as_ref()
.ok_or_else(|| {
usage_error(
"base_url is required; set base_url in the config file, --base-url on the command line, or the AVISO_BASE_URL environment variable",
)
})?
.value
.clone();
let mut builder: AvisoClientBuilder = AvisoClient::builder().base_url(base_url);
if let Some(t) = resolved.timeout.as_ref() {
builder = builder.timeout(t.value);
}
if let Some(h) = resolved.heartbeat_interval.as_ref() {
builder = builder.heartbeat_interval(h.value);
}
if let Some(provider) = resolved.auth_provider.as_ref() {
builder = builder.auth(Arc::clone(provider));
}
for path in &resolved.tls_ca_bundle_paths.value {
let bytes = std::fs::read(path).map_err(|e| {
usage_error(format!(
"could not read --ca-bundle PEM file `{}`: {e}",
path.display()
))
})?;
let cert = reqwest::Certificate::from_pem(&bytes).map_err(|e| {
usage_error(format!(
"--ca-bundle PEM file `{}` did not parse as an X.509 certificate: {e}",
path.display()
))
})?;
builder = builder.ca_bundle(cert);
}
if resolved.tls_danger_accept_invalid_certs.value {
builder = builder.danger_accept_invalid_certs(true);
}
if let Some(store) = state_store {
builder = builder.state_store(store);
}
if flush_cursor_on_exit {
builder = builder.flush_cursor_on_exit(true);
}
builder.build().context("build aviso client")
}
pub(crate) async fn build_state_store(
resolved: &Resolved,
no_state_store: bool,
) -> Result<Arc<dyn StateStore>> {
if no_state_store {
return Ok(Arc::new(MemoryStore::new()) as Arc<dyn StateStore>);
}
let path = &resolved.state_path.value;
if let Some(parent) = path.parent() {
paths::ensure_secure_dir(parent).with_context(|| {
format!(
"create parent directory for state file: {}",
parent.display()
)
})?;
}
let store = JsonFileStore::open(path.clone())
.await
.with_context(|| format!("open JsonFileStore at {}", path.display()))?;
Ok(Arc::new(store) as Arc<dyn StateStore>)
}