]> Untitled Git - lemmy.git/blob - server/src/routes/nodeinfo.rs
Merge branch 'dev' into federation
[lemmy.git] / server / src / routes / nodeinfo.rs
1 use crate::apub::get_apub_protocol_string;
2 use crate::db::site_view::SiteView;
3 use crate::version;
4 use crate::Settings;
5 use actix_web::body::Body;
6 use actix_web::web;
7 use actix_web::HttpResponse;
8 use diesel::r2d2::{ConnectionManager, Pool};
9 use diesel::PgConnection;
10 use failure::Error;
11 use serde::{Deserialize, Serialize};
12 use std::fmt::Debug;
13 use url::Url;
14
15 pub fn config(cfg: &mut web::ServiceConfig) {
16   cfg
17     .route("/nodeinfo/2.0.json", web::get().to(node_info))
18     .route("/.well-known/nodeinfo", web::get().to(node_info_well_known));
19 }
20
21 async fn node_info_well_known() -> Result<HttpResponse<Body>, Error> {
22   let node_info = NodeInfoWellKnown {
23     links: NodeInfoWellKnownLinks {
24       rel: Url::parse("http://nodeinfo.diaspora.software/ns/schema/2.0")?,
25       href: Url::parse(&format!(
26         "{}://{}/nodeinfo/2.0.json",
27         get_apub_protocol_string(),
28         Settings::get().hostname
29       ))?,
30     },
31   };
32   Ok(HttpResponse::Ok().json(node_info))
33 }
34
35 async fn node_info(
36   db: web::Data<Pool<ConnectionManager<PgConnection>>>,
37 ) -> Result<HttpResponse, actix_web::Error> {
38   let res = web::block(move || {
39     let conn = db.get()?;
40     let site_view = match SiteView::read(&conn) {
41       Ok(site_view) => site_view,
42       Err(_) => return Err(format_err!("not_found")),
43     };
44     let protocols = if Settings::get().federation.enabled {
45       vec!["activitypub".to_string()]
46     } else {
47       vec![]
48     };
49     Ok(NodeInfo {
50       version: "2.0".to_string(),
51       software: NodeInfoSoftware {
52         name: "lemmy".to_string(),
53         version: version::VERSION.to_string(),
54       },
55       protocols,
56       usage: NodeInfoUsage {
57         users: NodeInfoUsers {
58           total: site_view.number_of_users,
59         },
60         local_posts: site_view.number_of_posts,
61         local_comments: site_view.number_of_comments,
62         open_registrations: site_view.open_registration,
63       },
64       metadata: NodeInfoMetadata {
65         community_list_url: Some(Url::parse(&format!(
66           "{}://{}/federation/communities",
67           get_apub_protocol_string(),
68           Settings::get().hostname
69         ))?),
70       },
71     })
72   })
73   .await
74   .map(|json| HttpResponse::Ok().json(json))
75   .map_err(|_| HttpResponse::InternalServerError())?;
76   Ok(res)
77 }
78
79 #[derive(Serialize, Deserialize, Debug)]
80 pub struct NodeInfoWellKnown {
81   pub links: NodeInfoWellKnownLinks,
82 }
83
84 #[derive(Serialize, Deserialize, Debug)]
85 pub struct NodeInfoWellKnownLinks {
86   pub rel: Url,
87   pub href: Url,
88 }
89
90 #[derive(Serialize, Deserialize, Debug)]
91 pub struct NodeInfo {
92   pub version: String,
93   pub software: NodeInfoSoftware,
94   pub protocols: Vec<String>,
95   pub usage: NodeInfoUsage,
96   pub metadata: NodeInfoMetadata,
97 }
98
99 #[derive(Serialize, Deserialize, Debug)]
100 pub struct NodeInfoSoftware {
101   pub name: String,
102   pub version: String,
103 }
104
105 #[derive(Serialize, Deserialize, Debug)]
106 #[serde(rename_all = "camelCase")]
107 pub struct NodeInfoUsage {
108   pub users: NodeInfoUsers,
109   pub local_posts: i64,
110   pub local_comments: i64,
111   pub open_registrations: bool,
112 }
113
114 #[derive(Serialize, Deserialize, Debug)]
115 pub struct NodeInfoUsers {
116   pub total: i64,
117 }
118
119 #[derive(Serialize, Deserialize, Debug)]
120 pub struct NodeInfoMetadata {
121   pub community_list_url: Option<Url>,
122 }