use actix_web::{error::ErrorBadRequest, web, Error, HttpResponse, Result}; use anyhow::anyhow; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::source::local_site::RegistrationMode; use lemmy_db_views::structs::SiteView; use lemmy_utils::{error::LemmyError, version}; use serde::{Deserialize, Serialize}; use url::Url; pub fn config(cfg: &mut web::ServiceConfig) { cfg .route("/nodeinfo/2.0.json", web::get().to(node_info)) .route("/.well-known/nodeinfo", web::get().to(node_info_well_known)); } async fn node_info_well_known( context: web::Data, ) -> Result { let node_info = NodeInfoWellKnown { links: vec![NodeInfoWellKnownLinks { rel: Url::parse("http://nodeinfo.diaspora.software/ns/schema/2.0")?, href: Url::parse(&format!( "{}/nodeinfo/2.0.json", &context.settings().get_protocol_and_hostname(), ))?, }], }; Ok(HttpResponse::Ok().json(node_info)) } async fn node_info(context: web::Data) -> Result { let site_view = SiteView::read_local(context.pool()) .await .map_err(|_| ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))?; let protocols = if site_view.local_site.federation_enabled { vec!["activitypub".to_string()] } else { vec![] }; let open_registrations = site_view.local_site.registration_mode == RegistrationMode::Open; let json = NodeInfo { version: "2.0".to_string(), software: NodeInfoSoftware { name: "lemmy".to_string(), version: version::VERSION.to_string(), }, protocols, usage: NodeInfoUsage { users: NodeInfoUsers { total: site_view.counts.users, active_halfyear: site_view.counts.users_active_half_year, active_month: site_view.counts.users_active_month, }, local_posts: site_view.counts.posts, local_comments: site_view.counts.comments, }, open_registrations, }; Ok(HttpResponse::Ok().json(json)) } #[derive(Serialize, Deserialize, Debug)] struct NodeInfoWellKnown { pub links: Vec, } #[derive(Serialize, Deserialize, Debug)] struct NodeInfoWellKnownLinks { pub rel: Url, pub href: Url, } #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct NodeInfo { pub version: String, pub software: NodeInfoSoftware, pub protocols: Vec, pub usage: NodeInfoUsage, pub open_registrations: bool, } #[derive(Serialize, Deserialize, Debug)] struct NodeInfoSoftware { pub name: String, pub version: String, } #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct NodeInfoUsage { pub users: NodeInfoUsers, pub local_posts: i64, pub local_comments: i64, } #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct NodeInfoUsers { pub total: i64, pub active_halfyear: i64, pub active_month: i64, }