use std::collections::BTreeMap;
use axum::response::IntoResponse;
use axum::Json;
use serde::Serialize;
use super::version::{SUPPORTED, VERSION};
#[derive(Debug, Clone, Serialize)]
pub struct Capabilities(BTreeMap<&'static str, bool>);
const CORE: [&str; 3] = ["streaming", "sessions", "cancellation"];
const EXTENDED: [&str; 3] = ["files_input", "files_output", "session_listing"];
const FULL: [&str; 1] = ["harness_management"];
const ALL: [&str; 9] = [
"streaming",
"sessions",
"cancellation",
"files_input",
"files_output",
"session_listing",
"harness_management",
"session_sharing",
"idempotency",
];
impl Capabilities {
pub fn current() -> Self {
let implemented = [
"streaming",
"sessions",
"cancellation",
"session_listing",
"harness_management",
"session_sharing",
"files_input",
"files_output",
];
Self(
ALL.iter()
.map(|&name| (name, implemented.contains(&name)))
.collect(),
)
}
fn all_of(&self, names: &[&str]) -> bool {
names
.iter()
.all(|n| self.0.get(n).copied().unwrap_or(false))
}
pub fn class(&self) -> &'static str {
if !self.all_of(&CORE) {
return "core";
}
if !self.all_of(&EXTENDED) {
return "core";
}
if self.all_of(&FULL) {
"full"
} else {
"extended"
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct Discovery {
pub object: &'static str,
pub protocol: &'static str,
pub versions: Vec<&'static str>,
pub default_version: &'static str,
pub conformance_class: &'static str,
pub capabilities: Capabilities,
pub implementation: Implementation,
}
#[derive(Debug, Clone, Serialize)]
pub struct Implementation {
pub name: &'static str,
pub version: &'static str,
}
pub async fn handle() -> impl IntoResponse {
let capabilities = Capabilities::current();
let conformance_class = capabilities.class();
Json(Discovery {
object: "uhp.discovery",
protocol: "uhp",
versions: SUPPORTED.to_vec(),
default_version: VERSION,
conformance_class,
capabilities,
implementation: Implementation {
name: "embacle-server",
version: env!("CARGO_PKG_VERSION"),
},
})
}