1use serde::{Deserialize, Serialize};
2use serde_json::{Map, Value};
3
4#[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#[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#[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#[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#[derive(Debug, PartialEq, Default, Serialize, Deserialize)]
58pub struct Services<T> {
59 pub inbound: Vec<T>,
60 pub outbound: Vec<T>,
61}
62
63#[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#[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 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}