Add the ability to detect software from semver build metadata

This commit is contained in:
CenTdemeern1 2025-01-13 07:31:48 +01:00
parent 8e6a2d20b4
commit 84639fa3b5
5 changed files with 64 additions and 10 deletions

7
Cargo.lock generated
View file

@ -281,6 +281,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"reqwest", "reqwest",
"rocket", "rocket",
"semver",
"serde", "serde",
"serde_json", "serde_json",
"url", "url",
@ -1537,6 +1538,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "semver"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.217" version = "1.0.217"

View file

@ -6,6 +6,7 @@ edition = "2021"
[dependencies] [dependencies]
reqwest = "0.12.12" reqwest = "0.12.12"
rocket = { version = "0.5.1", features = ["json"] } rocket = { version = "0.5.1", features = ["json"] }
semver = "1.0.24"
serde = { version = "1.0.217", features = ["derive"] } serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.135" serde_json = "1.0.135"
url = "2.5.4" url = "2.5.4"

View file

@ -88,6 +88,31 @@
], ],
"forkOf": "mastodon" "forkOf": "mastodon"
}, },
"glitch-soc": {
"name": "Mastodon Glitch Edition",
"nodeinfoName": "mastodon",
"buildMetadata": "glitch",
"aliases": [
"glitch"
],
"groups": [
"mastodon-compliant",
"mastodon-compliant-api"
],
"forkOf": "mastodon"
},
"chuckya": {
"name": "Chuckya",
"nodeinfoName": "mastodon",
"buildMetadata": "chuckya",
"aliases": [
"chuckya"
],
"groups": [
"mastodon-compliant"
],
"forkOf": "mastodon"
},
"misskey": { "misskey": {
"name": "Misskey", "name": "Misskey",
"nodeinfoName": "misskey", "nodeinfoName": "misskey",

View file

@ -53,6 +53,7 @@ struct NodeInfo {
#[derive(Deserialize)] #[derive(Deserialize)]
struct NodeInfoSoftware { struct NodeInfoSoftware {
name: String, name: String,
version: String,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -105,8 +106,11 @@ pub async fn instance_info(secure: bool, host: &str) -> Option<Json<InstanceInfo
.await .await
.ok()?; .ok()?;
let nodeinfo: NodeInfo = serde_json::from_str(&response).ok()?; let nodeinfo: NodeInfo = serde_json::from_str(&response).ok()?;
let software = KNOWN_SOFTWARE_NODEINFO_NAMES let (software_name, fork_map) = KNOWN_SOFTWARE_NODEINFO_NAMES.get(&nodeinfo.software.name)?;
.get(&nodeinfo.software.name)? let software = semver::Version::parse(&nodeinfo.software.version)
.ok()
.and_then(|v| fork_map.get(v.build.as_str()))
.unwrap_or(software_name)
.to_owned(); .to_owned();
Some(Json(InstanceInfo { Some(Json(InstanceInfo {
name: name name: name

View file

@ -9,14 +9,16 @@ pub static KNOWN_SOFTWARE: LazyLock<KnownSoftware> =
LazyLock::new(|| serde_json::from_str(include_str!("../known-software.json")).unwrap()); LazyLock::new(|| serde_json::from_str(include_str!("../known-software.json")).unwrap());
pub static KNOWN_SOFTWARE_NAMES: LazyLock<HashMap<String, String>> = pub static KNOWN_SOFTWARE_NAMES: LazyLock<HashMap<String, String>> =
LazyLock::new(|| KNOWN_SOFTWARE.get_name_map()); LazyLock::new(|| KNOWN_SOFTWARE.get_name_map());
pub static KNOWN_SOFTWARE_NODEINFO_NAMES: LazyLock<HashMap<String, String>> = pub static KNOWN_SOFTWARE_NODEINFO_NAMES: LazyLock<
LazyLock::new(|| KNOWN_SOFTWARE.get_nodeinfo_name_map()); HashMap<String, (String, HashMap<String, String>)>,
> = LazyLock::new(|| KNOWN_SOFTWARE.get_nodeinfo_name_map());
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Software { pub struct Software {
name: String, name: String,
nodeinfo_name: String, nodeinfo_name: String,
build_metadata: Option<String>,
aliases: HashSet<String>, aliases: HashSet<String>,
groups: HashSet<String>, groups: HashSet<String>,
fork_of: Option<String>, fork_of: Option<String>,
@ -50,13 +52,28 @@ impl KnownSoftware {
map map
} }
fn get_nodeinfo_name_map(&self) -> HashMap<String, String> { fn get_nodeinfo_name_map(&self) -> HashMap<String, (String, HashMap<String, String>)> {
let mut map = HashMap::new(); let mut map: HashMap<String, (String, HashMap<String, String>)> = HashMap::new();
self.software.iter().for_each(|(name, software)| { self.software.iter().for_each(|(name, software)| {
assert_eq!( if let Some((mut_name, mut_map)) = map.get_mut(&software.nodeinfo_name) {
map.insert(software.nodeinfo_name.to_owned(), name.to_owned()), if let Some(build_metadata) = &software.build_metadata {
None 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 map
} }