nodeinfo_upub/
types.rs

1use serde::{Deserialize, Serialize};
2use serde_json::{Map, Value};
3
4/// Node metadata for version detection only used for deserialization.
5#[derive(Debug, Deserialize)]
6pub(crate) struct NodeVersion<'a> {
7  pub(crate) version: &'a str,
8}
9
10pub type NodeInfo<'a> = NodeInfoInternal<&'a str>;
11pub type NodeInfoOwned = NodeInfoInternal<String>;
12
13/// Node metadata about a server running in the fediverse.
14#[derive(Debug, PartialEq, Serialize, Deserialize)]
15pub struct NodeInfoInternal<T> {
16  pub version: T,
17  pub software: Software<T>,
18  #[serde(default)]
19  pub protocols: Vec<T>,
20  #[serde(default)]
21  pub services: Services<T>,
22  #[serde(rename = "openRegistrations", default)]
23  pub open_registrations: bool,
24  #[serde(default)]
25  pub usage: Usage,
26  #[serde(default)]
27  pub metadata: Map<String, Value>,
28}
29
30/// Node legacy metadata about a server running in the federation, only used for deserialization.
31#[derive(Debug, PartialEq, Deserialize)]
32pub struct LegacyNodeInfo<'a> {
33  version: &'a str,
34  software: Software<&'a str>,
35  #[serde(default)]
36  services: Services<&'a str>,
37  #[serde(default)]
38  protocols: Services<&'a str>,
39  #[serde(rename = "openRegistrations", default)]
40  open_registrations: bool,
41  #[serde(default)]
42  usage: Usage,
43  #[serde(default)]
44  metadata: Map<String, Value>,
45}
46
47/// Software contains infos about software running on the node.
48#[derive(Debug, PartialEq, Serialize, Deserialize)]
49pub struct Software<T> {
50  pub name: T,
51  pub version: Option<T>,
52  pub repository: Option<T>,
53  pub homepage: Option<T>,
54}
55
56/// Services tell about third party sites the node can connect to or interact with.
57#[derive(Debug, PartialEq, Default, Serialize, Deserialize)]
58pub struct Services<T> {
59  pub inbound: Vec<T>,
60  pub outbound: Vec<T>,
61}
62
63/// Usage statistics for the node
64#[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize)]
65#[serde(rename_all = "camelCase")]
66pub struct Usage {
67  pub users: Option<Users>,
68  pub local_posts: Option<i64>,
69  pub local_comments: Option<i64>,
70}
71
72// UsersUsage are statistics about the users of the node.
73#[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize)]
74#[serde(rename_all = "camelCase")]
75pub struct Users {
76  pub total: Option<i64>,
77  pub active_halfyear: Option<i64>,
78  pub active_month: Option<i64>,
79}
80
81impl<'a> Software<&'a str> {
82  fn to_owned(&self) -> Software<String> {
83    Software {
84      name: self.name.to_string(),
85      version: self.version.map(ToString::to_string),
86      repository: self.repository.map(ToString::to_string),
87      homepage: self.homepage.map(ToString::to_string),
88    }
89  }
90}
91
92impl<'a> Services<&'a str> {
93  fn to_owned(&self) -> Services<String> {
94    Services {
95      inbound: self.inbound.iter().map(ToString::to_string).collect(),
96      outbound: self.outbound.iter().map(ToString::to_string).collect(),
97    }
98  }
99}
100
101impl NodeInfo<'_> {
102  /// Converts all internal `&str`s into `String`s.
103  pub fn to_owned(&self) -> NodeInfoOwned {
104    NodeInfoOwned {
105      version: self.version.to_string(),
106      software: self.software.to_owned(),
107      protocols: self.protocols.iter().map(ToString::to_string).collect(),
108      services: self.services.to_owned(),
109      open_registrations: self.open_registrations,
110      usage: self.usage.clone(),
111      metadata: self.metadata.clone(),
112    }
113  }
114}
115
116impl<'a> From<LegacyNodeInfo<'a>> for NodeInfo<'a> {
117  fn from(other: LegacyNodeInfo<'a>) -> Self {
118    let mut combined_protocols: Vec<&'a str> = other
119      .protocols
120      .inbound
121      .into_iter()
122      .chain(other.protocols.outbound)
123      .collect();
124    combined_protocols.sort();
125    combined_protocols.dedup();
126
127    NodeInfo {
128      version: other.version,
129      software: other.software,
130      services: other.services,
131      protocols: combined_protocols,
132      open_registrations: other.open_registrations,
133      usage: other.usage,
134      metadata: other.metadata,
135    }
136  }
137}
138
139impl<'a> From<LegacyNodeInfo<'a>> for NodeInfoOwned {
140  fn from(value: LegacyNodeInfo<'a>) -> Self {
141    NodeInfo::from(value).to_owned()
142  }
143}