1 use actix_web::{error::ErrorBadRequest, web, Error, HttpResponse, Result};
3 use lemmy_api_common::context::LemmyContext;
4 use lemmy_db_schema::RegistrationMode;
5 use lemmy_db_views::structs::SiteView;
7 cache_header::{cache_1hour, cache_3days},
11 use serde::{Deserialize, Serialize};
14 pub fn config(cfg: &mut web::ServiceConfig) {
18 web::get().to(node_info).wrap(cache_1hour()),
21 "/.well-known/nodeinfo",
22 web::get().to(node_info_well_known).wrap(cache_3days()),
26 async fn node_info_well_known(
27 context: web::Data<LemmyContext>,
28 ) -> Result<HttpResponse, LemmyError> {
29 let node_info = NodeInfoWellKnown {
30 links: vec![NodeInfoWellKnownLinks {
31 rel: Url::parse("http://nodeinfo.diaspora.software/ns/schema/2.0")?,
32 href: Url::parse(&format!(
33 "{}/nodeinfo/2.0.json",
34 &context.settings().get_protocol_and_hostname(),
38 Ok(HttpResponse::Ok().json(node_info))
41 async fn node_info(context: web::Data<LemmyContext>) -> Result<HttpResponse, Error> {
42 let site_view = SiteView::read_local(&mut context.pool())
44 .map_err(|_| ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))?;
46 let protocols = if site_view.local_site.federation_enabled {
47 Some(vec!["activitypub".to_string()])
51 // Since there are 3 registration options,
52 // we need to set open_registrations as true if RegistrationMode is not Closed.
53 let open_registrations = Some(site_view.local_site.registration_mode != RegistrationMode::Closed);
55 version: Some("2.0".to_string()),
56 software: Some(NodeInfoSoftware {
57 name: Some("lemmy".to_string()),
58 version: Some(version::VERSION.to_string()),
61 usage: Some(NodeInfoUsage {
62 users: Some(NodeInfoUsers {
63 total: Some(site_view.counts.users),
64 active_halfyear: Some(site_view.counts.users_active_half_year),
65 active_month: Some(site_view.counts.users_active_month),
67 local_posts: Some(site_view.counts.posts),
68 local_comments: Some(site_view.counts.comments),
73 Ok(HttpResponse::Ok().json(json))
76 #[derive(Serialize, Deserialize, Debug)]
77 struct NodeInfoWellKnown {
78 pub links: Vec<NodeInfoWellKnownLinks>,
81 #[derive(Serialize, Deserialize, Debug)]
82 struct NodeInfoWellKnownLinks {
87 #[derive(Serialize, Deserialize, Debug, Default)]
88 #[serde(rename_all = "camelCase", default)]
90 pub version: Option<String>,
91 pub software: Option<NodeInfoSoftware>,
92 pub protocols: Option<Vec<String>>,
93 pub usage: Option<NodeInfoUsage>,
94 pub open_registrations: Option<bool>,
97 #[derive(Serialize, Deserialize, Debug, Default)]
99 pub struct NodeInfoSoftware {
100 pub name: Option<String>,
101 pub version: Option<String>,
104 #[derive(Serialize, Deserialize, Debug, Default)]
105 #[serde(rename_all = "camelCase", default)]
106 pub struct NodeInfoUsage {
107 pub users: Option<NodeInfoUsers>,
108 pub local_posts: Option<i64>,
109 pub local_comments: Option<i64>,
112 #[derive(Serialize, Deserialize, Debug, Default)]
113 #[serde(rename_all = "camelCase", default)]
114 pub struct NodeInfoUsers {
115 pub total: Option<i64>,
116 pub active_halfyear: Option<i64>,
117 pub active_month: Option<i64>,