mirror of
https://git.alemi.dev/fedicharter.git
synced 2024-11-12 20:09:21 +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"] }
|
||||
derive_more = "0.99.17"
|
||||
lazy_static = "1.4.0"
|
||||
# nodeinfo = { git = "https://codeberg.org/thefederationinfo/nodeinfo-rs.git" }
|
||||
reqwest = { version = "0.11.20", features = ["json"] }
|
||||
sea-orm = { version = "0.12.3", features = ["runtime-tokio-native-tls", "sqlx-sqlite", "sqlx-postgres"] }
|
||||
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