use std::sync::Arc;
use super::root_presence::{LysRoot, RootPresence};
use crate::ServerError;
use crate::config::types::LysConfig;
#[derive(Debug)]
pub enum RootSlot {
Asked(Arc<RootPresence>),
Unasked {
cause: &'static str,
},
}
impl RootSlot {
#[must_use]
pub fn health(&self) -> (&'static str, Option<&'static str>) {
match self {
Self::Asked(root) => {
let answer = root.answer();
(answer.health(), answer.cause())
}
Self::Unasked { cause } => (LysRoot::NotAsked.health(), Some(cause)),
}
}
}
#[derive(Debug)]
pub enum RootQuestion {
Owner,
AtStart(Arc<RootPresence>),
Unasked(&'static str),
}
pub fn root_question(
lys: &LysConfig,
handle: Option<tokio::runtime::Handle>,
) -> Result<RootQuestion, ServerError> {
if lys.membership.is_some() || lys.grant_stream.is_some() {
return Ok(RootQuestion::Owner);
}
let Some(path) = lys.app_credential_path.as_ref() else {
return Ok(RootQuestion::Unasked("no_asking_credential"));
};
let Some(handle) = handle else {
return Ok(RootQuestion::Unasked("no_ask_runtime"));
};
let refused = |message: String| ServerError::ConfigValidation { message };
let credential = std::fs::read_to_string(path).map_err(|error| {
refused(format!(
"auth.lys.app_credential_path '{}' cannot be read: {}",
path.display(),
error.kind()
))
})?;
let api = lys.api_url.as_deref().unwrap_or(&lys.issuer);
let root = RootPresence::new(&lys.network_id, api, credential.trim().to_owned(), handle)
.map_err(|_| refused("lys_root_question_invalid".to_owned()))?;
Ok(RootQuestion::AtStart(Arc::new(root)))
}
pub fn start(
lys: &LysConfig,
health: &crate::health::HealthServerHandle,
runtime: Option<&tokio::runtime::Runtime>,
) -> Result<(), ServerError> {
match root_question(lys, runtime.map(|runtime| runtime.handle().clone()))? {
RootQuestion::Owner => Ok(()),
RootQuestion::Unasked(cause) => health.install_lys_root(RootSlot::Unasked { cause }),
RootQuestion::AtStart(root) => {
health.install_lys_root(RootSlot::Asked(Arc::clone(&root)))?;
root.ask_in_background();
Ok(())
}
}
}