chore (backend-rs): more documents on NodeInfo

This commit is contained in:
naskya 2024-06-01 11:25:20 +09:00
parent c1255ef965
commit 8293ed8e87
No known key found for this signature in database
GPG key ID: 712D413B3A9FED5C
4 changed files with 27 additions and 7 deletions

View file

@ -1,10 +1,13 @@
//! NodeInfo fetcher //! NodeInfo fetcher
//!
//! ref: <https://nodeinfo.diaspora.software/protocol.html>
use crate::federation::nodeinfo::schema::*; use crate::federation::nodeinfo::schema::*;
use crate::util::http_client; use crate::util::http_client;
use isahc::AsyncReadResponseExt; use isahc::AsyncReadResponseExt;
use serde::Deserialize; use serde::Deserialize;
/// Errors that can occur while fetching NodeInfo from a remote server
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum Error { pub enum Error {
#[error("HTTP client aquisition error: {0}")] #[error("HTTP client aquisition error: {0}")]
@ -21,25 +24,23 @@ pub enum Error {
MissingNodeinfo, MissingNodeinfo,
} }
/// Represents the schema of `/.well-known/nodeinfo`.
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct NodeinfoLinks { pub struct NodeinfoLinks {
links: Vec<NodeinfoLink>, links: Vec<NodeinfoLink>,
} }
/// Represents one entry of `/.well-known/nodeinfo`.
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct NodeinfoLink { pub struct NodeinfoLink {
rel: String, rel: String,
href: String, href: String,
} }
#[inline] /// Fetches `/.well-known/nodeinfo` and parses the result.
fn wellknown_nodeinfo_url(host: &str) -> String {
format!("https://{}/.well-known/nodeinfo", host)
}
async fn fetch_nodeinfo_links(host: &str) -> Result<NodeinfoLinks, Error> { async fn fetch_nodeinfo_links(host: &str) -> Result<NodeinfoLinks, Error> {
let client = http_client::client()?; let client = http_client::client()?;
let wellknown_url = wellknown_nodeinfo_url(host); let wellknown_url = format!("https://{}/.well-known/nodeinfo", host);
let mut wellknown_response = client.get_async(&wellknown_url).await?; let mut wellknown_response = client.get_async(&wellknown_url).await?;
if !wellknown_response.status().is_success() { if !wellknown_response.status().is_success() {
@ -54,6 +55,9 @@ async fn fetch_nodeinfo_links(host: &str) -> Result<NodeinfoLinks, Error> {
Ok(serde_json::from_str(&wellknown_response.text().await?)?) Ok(serde_json::from_str(&wellknown_response.text().await?)?)
} }
/// Check if any of the following relations is present in the given [NodeinfoLinks].
/// * <http://nodeinfo.diaspora.software/ns/schema/2.0>
/// * <http://nodeinfo.diaspora.software/ns/schema/2.1>
fn check_nodeinfo_link(links: NodeinfoLinks) -> Result<String, Error> { fn check_nodeinfo_link(links: NodeinfoLinks) -> Result<String, Error> {
for link in links.links { for link in links.links {
if link.rel == "http://nodeinfo.diaspora.software/ns/schema/2.1" if link.rel == "http://nodeinfo.diaspora.software/ns/schema/2.1"
@ -66,6 +70,7 @@ fn check_nodeinfo_link(links: NodeinfoLinks) -> Result<String, Error> {
Err(Error::MissingNodeinfo) Err(Error::MissingNodeinfo)
} }
/// Fetches the nodeinfo from the given URL and parses the result.
async fn fetch_nodeinfo_impl(nodeinfo_link: &str) -> Result<Nodeinfo20, Error> { async fn fetch_nodeinfo_impl(nodeinfo_link: &str) -> Result<Nodeinfo20, Error> {
let client = http_client::client()?; let client = http_client::client()?;
let mut response = client.get_async(nodeinfo_link).await?; let mut response = client.get_async(nodeinfo_link).await?;
@ -85,7 +90,7 @@ async fn fetch_nodeinfo_impl(nodeinfo_link: &str) -> Result<Nodeinfo20, Error> {
// for napi export // for napi export
type Nodeinfo = Nodeinfo20; type Nodeinfo = Nodeinfo20;
/// Fetches and returns the NodeInfo of a remote server. /// Fetches and returns the NodeInfo (version 2.0) of a remote server.
#[crate::export] #[crate::export]
pub async fn fetch_nodeinfo(host: &str) -> Result<Nodeinfo, Error> { pub async fn fetch_nodeinfo(host: &str) -> Result<Nodeinfo, Error> {
tracing::info!("fetching from {}", host); tracing::info!("fetching from {}", host);

View file

@ -9,6 +9,7 @@ use sea_orm::{ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter};
use serde_json::json; use serde_json::json;
use std::collections::HashMap; use std::collections::HashMap;
/// Errors that can occur while generating NodeInfo of the local server
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum Error { pub enum Error {
#[error("Database error: {0}")] #[error("Database error: {0}")]
@ -19,6 +20,14 @@ pub enum Error {
Json(#[from] serde_json::Error), Json(#[from] serde_json::Error),
} }
/// Fetches the number of total/active local users and local posts.
///
/// # Return value
/// A tuple containing the following information in this order:
/// * the total number of local users
/// * the total number of local users active in the last 6 months
/// * the total number of local users active in the last month (MAU)
/// * the total number of posts from local users
async fn statistics() -> Result<(u64, u64, u64, u64), DbErr> { async fn statistics() -> Result<(u64, u64, u64, u64), DbErr> {
let db = db_conn().await?; let db = db_conn().await?;
@ -49,6 +58,8 @@ async fn statistics() -> Result<(u64, u64, u64, u64), DbErr> {
) )
} }
/// Generates NodeInfo (version 2.1) of the local server.
/// This function doesn't use caches and returns the latest information.
async fn generate_nodeinfo_2_1() -> Result<Nodeinfo21, Error> { async fn generate_nodeinfo_2_1() -> Result<Nodeinfo21, Error> {
let (local_users, local_active_halfyear, local_active_month, local_posts) = let (local_users, local_active_halfyear, local_active_month, local_posts) =
statistics().await?; statistics().await?;

View file

@ -1,4 +1,6 @@
//! NodeInfo handler //! NodeInfo handler
//!
//! ref: <https://nodeinfo.diaspora.software/>
pub mod fetch; pub mod fetch;
pub mod generate; pub mod generate;

View file

@ -1,4 +1,6 @@
//! Schema definitions of NodeInfo version 2.0 and 2.1 //! Schema definitions of NodeInfo version 2.0 and 2.1
//!
//! ref: <https://nodeinfo.diaspora.software/schema.html>
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;