mirror of
https://git.alemi.dev/fedicharter.git
synced 2024-11-23 00:44:48 +01:00
chore: yanked nodeinfo because i need some changes
will eventually PR them in, here's the source https://codeberg.org/thefederationinfo/nodeinfo-rs
This commit is contained in:
parent
806ff114ba
commit
341a0a77aa
4 changed files with 200 additions and 0 deletions
|
@ -12,6 +12,7 @@ chrono = "0.4.31"
|
||||||
clap = { version = "4.4.6", features = ["derive"] }
|
clap = { version = "4.4.6", features = ["derive"] }
|
||||||
derive_more = "0.99.17"
|
derive_more = "0.99.17"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
# nodeinfo = { git = "https://codeberg.org/thefederationinfo/nodeinfo-rs.git" }
|
||||||
reqwest = { version = "0.11.20", features = ["json"] }
|
reqwest = { version = "0.11.20", features = ["json"] }
|
||||||
sea-orm = { version = "0.12.3", features = ["runtime-tokio-native-tls", "sqlx-sqlite", "sqlx-postgres"] }
|
sea-orm = { version = "0.12.3", features = ["runtime-tokio-native-tls", "sqlx-sqlite", "sqlx-postgres"] }
|
||||||
serde = { version = "1.0.188", features = ["derive"] }
|
serde = { version = "1.0.188", features = ["derive"] }
|
||||||
|
|
50
src/nodeinfo/fetcher.rs
Normal file
50
src/nodeinfo/fetcher.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::nodeinfo::model::NodeInfoOwned;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
struct WellKnownNodeInfo {
|
||||||
|
links: Vec<WellKnownNodeInfoRef>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
struct WellKnownNodeInfoRef {
|
||||||
|
rel: String,
|
||||||
|
href: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn node_info(domain: &str) -> Result<NodeInfoOwned, reqwest::Error> {
|
||||||
|
let client = reqwest::Client::builder()
|
||||||
|
.timeout(Duration::from_secs(5))
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
let well_known : WellKnownNodeInfo = client
|
||||||
|
.get(format!("https://{}/.well-known/nodeinfo", domain))
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.json()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let (_, best_version) = well_known.links.iter()
|
||||||
|
.filter_map(|x| Some((parse_nodeinfo_spec_version(&x.rel)?, x)))
|
||||||
|
.max_by(|a, b| a.0.cmp(&b.0))
|
||||||
|
.expect("no versions available");
|
||||||
|
|
||||||
|
client.get(&best_version.href)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_nodeinfo_spec_version(schema: &str) -> Option<i32> {
|
||||||
|
match schema { // TODO this silently filters out unsupported new versions
|
||||||
|
"http://nodeinfo.diaspora.software/ns/schema/1.0" => Some(1000),
|
||||||
|
"http://nodeinfo.diaspora.software/ns/schema/1.1" => Some(1010),
|
||||||
|
"http://nodeinfo.diaspora.software/ns/schema/2.0" => Some(2000),
|
||||||
|
"http://nodeinfo.diaspora.software/ns/schema/2.1" => Some(2010),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
2
src/nodeinfo/mod.rs
Normal file
2
src/nodeinfo/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod model;
|
||||||
|
pub mod fetcher;
|
147
src/nodeinfo/model.rs
Normal file
147
src/nodeinfo/model.rs
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
|
/// Node metadata for version detection only used for deserialization.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd, derive_more::Display)]
|
||||||
|
pub(crate) enum NodeVersion {
|
||||||
|
V1_0 = 1000,
|
||||||
|
V1_1 = 1001,
|
||||||
|
V2_0 = 2000,
|
||||||
|
V2_1 = 2001,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type NodeInfo<'a> = NodeInfoInternal<&'a str>;
|
||||||
|
pub type NodeInfoOwned = NodeInfoInternal<String>;
|
||||||
|
|
||||||
|
/// Node metadata about a server running in the fediverse.
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct NodeInfoInternal<T> {
|
||||||
|
pub version: NodeVersion,
|
||||||
|
pub software: Software<T>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub protocols: Vec<T>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub services: Services<T>,
|
||||||
|
#[serde(rename = "openRegistrations", default)]
|
||||||
|
pub open_registrations: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub usage: Usage,
|
||||||
|
#[serde(default)]
|
||||||
|
pub metadata: Map<String, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Node legacy metadata about a server running in the federation, only used for deserialization.
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
pub(crate) struct LegacyNodeInfo<'a> {
|
||||||
|
version: NodeVersion,
|
||||||
|
software: Software<&'a str>,
|
||||||
|
#[serde(default)]
|
||||||
|
services: Services<&'a str>,
|
||||||
|
#[serde(default)]
|
||||||
|
protocols: Services<&'a str>,
|
||||||
|
#[serde(rename = "openRegistrations", default)]
|
||||||
|
open_registrations: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
usage: Usage,
|
||||||
|
#[serde(default)]
|
||||||
|
metadata: Map<String, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Software contains infos about software running on the node.
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Software<T> {
|
||||||
|
pub name: T,
|
||||||
|
pub version: T,
|
||||||
|
pub repository: Option<T>,
|
||||||
|
pub homepage: Option<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Services tell about third party sites the node can connect to or interact with.
|
||||||
|
#[derive(Debug, PartialEq, Default, Serialize, Deserialize)]
|
||||||
|
pub struct Services<T> {
|
||||||
|
pub inbound: Vec<T>,
|
||||||
|
pub outbound: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Usage statistics for the node
|
||||||
|
#[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Usage {
|
||||||
|
pub users: Users,
|
||||||
|
pub local_posts: Option<i64>,
|
||||||
|
pub local_comments: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// UsersUsage are statistics about the users of the node.
|
||||||
|
#[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Users {
|
||||||
|
pub total: Option<i64>,
|
||||||
|
pub active_halfyear: Option<i64>,
|
||||||
|
pub active_month: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Software<&'a str> {
|
||||||
|
fn to_owned(&self) -> Software<String> {
|
||||||
|
Software {
|
||||||
|
name: self.name.to_string(),
|
||||||
|
version: self.version.to_string(),
|
||||||
|
repository: self.repository.map(ToString::to_string),
|
||||||
|
homepage: self.homepage.map(ToString::to_string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Services<&'a str> {
|
||||||
|
fn to_owned(&self) -> Services<String> {
|
||||||
|
Services {
|
||||||
|
inbound: self.inbound.iter().map(ToString::to_string).collect(),
|
||||||
|
outbound: self.outbound.iter().map(ToString::to_string).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeInfo<'_> {
|
||||||
|
/// Converts all internal `&str`s into `String`s.
|
||||||
|
pub fn to_owned(&self) -> NodeInfoOwned {
|
||||||
|
NodeInfoOwned {
|
||||||
|
version: self.version.to_string(),
|
||||||
|
software: self.software.to_owned(),
|
||||||
|
protocols: self.protocols.iter().map(ToString::to_string).collect(),
|
||||||
|
services: self.services.to_owned(),
|
||||||
|
open_registrations: self.open_registrations,
|
||||||
|
usage: self.usage.clone(),
|
||||||
|
metadata: self.metadata.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<LegacyNodeInfo<'a>> for NodeInfo<'a> {
|
||||||
|
fn from(other: LegacyNodeInfo<'a>) -> Self {
|
||||||
|
let mut combined_protocols: Vec<&'a str> = other
|
||||||
|
.protocols
|
||||||
|
.inbound
|
||||||
|
.into_iter()
|
||||||
|
.chain(other.protocols.outbound)
|
||||||
|
.collect();
|
||||||
|
combined_protocols.sort();
|
||||||
|
combined_protocols.dedup();
|
||||||
|
|
||||||
|
NodeInfo {
|
||||||
|
version: other.version,
|
||||||
|
software: other.software,
|
||||||
|
services: other.services,
|
||||||
|
protocols: combined_protocols,
|
||||||
|
open_registrations: other.open_registrations,
|
||||||
|
usage: other.usage,
|
||||||
|
metadata: other.metadata,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<LegacyNodeInfo<'a>> for NodeInfoOwned {
|
||||||
|
fn from(value: LegacyNodeInfo<'a>) -> Self {
|
||||||
|
NodeInfo::from(value).to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue