FeDirect/src/known_software.rs

100 lines
3.2 KiB
Rust

use rocket::request::FromParam;
use serde::Deserialize;
use std::{
collections::{HashMap, HashSet},
sync::LazyLock,
};
pub static KNOWN_SOFTWARE: LazyLock<KnownSoftware> =
LazyLock::new(|| serde_json::from_str(include_str!("../known-software.json")).unwrap());
pub static KNOWN_SOFTWARE_NAMES: LazyLock<HashMap<String, String>> =
LazyLock::new(|| KNOWN_SOFTWARE.get_name_map());
pub static KNOWN_SOFTWARE_NODEINFO_NAMES: LazyLock<
HashMap<String, (String, HashMap<String, String>)>,
> = LazyLock::new(|| KNOWN_SOFTWARE.get_nodeinfo_name_map());
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Software {
name: String,
nodeinfo_name: String,
build_metadata: Option<String>,
aliases: HashSet<String>,
groups: HashSet<String>,
fork_of: Option<String>,
}
#[derive(Deserialize)]
pub struct Group {
name: String,
aliases: HashSet<String>,
}
#[derive(Deserialize)]
pub struct KnownSoftware {
software: HashMap<String, Software>,
groups: HashMap<String, Group>,
}
impl KnownSoftware {
fn get_name_map(&self) -> HashMap<String, String> {
let mut map = HashMap::new();
self.software.iter().for_each(|(name, software)| {
software.aliases.iter().for_each(|alias| {
assert_eq!(map.insert(alias.to_owned(), name.to_owned()), None);
});
});
self.groups.iter().for_each(|(name, group)| {
group.aliases.iter().for_each(|alias: &String| {
assert_eq!(map.insert(alias.to_owned(), name.to_owned()), None);
});
});
map
}
fn get_nodeinfo_name_map(&self) -> HashMap<String, (String, HashMap<String, String>)> {
let mut map: HashMap<String, (String, HashMap<String, String>)> = HashMap::new();
self.software.iter().for_each(|(name, software)| {
if let Some((mut_name, mut_map)) = map.get_mut(&software.nodeinfo_name) {
if let Some(build_metadata) = &software.build_metadata {
assert_eq!(
mut_map.insert(build_metadata.to_owned(), name.to_owned()),
None
);
} else {
*mut_name = name.to_owned();
}
} else {
let mut build_metadata_map = HashMap::new();
if let Some(build_metadata) = &software.build_metadata {
build_metadata_map.insert(build_metadata.to_owned(), name.to_owned());
}
map.insert(
software.nodeinfo_name.to_owned(),
(name.to_owned(), build_metadata_map),
);
}
});
map
}
}
pub struct KnownInstanceSoftware<'r> {
pub requested: &'r str,
pub resolved: &'static String,
}
impl<'r> FromParam<'r> for KnownInstanceSoftware<'r> {
type Error = &'r str;
fn from_param(param: &'r str) -> Result<Self, Self::Error> {
if let Some(resolved) = KNOWN_SOFTWARE_NAMES.get(param) {
Ok(KnownInstanceSoftware {
requested: param,
resolved,
})
} else {
Err(param)
}
}
}