ap types and nodeinfo

This commit is contained in:
2026-05-04 13:24:57 +03:00
parent 944dadb7ed
commit bcf83ae3e1
2 changed files with 153 additions and 0 deletions
@@ -0,0 +1,56 @@
use std::sync::Arc;
use axum::Json;
use axum::extract::State;
use axum::response::Response;
use crate::state::AppState;
pub async fn well_known(
State(state): State<Arc<AppState>>,
) -> Result<Json<serde_json::Value>, Response> {
let ap = state.ap.as_ref().ok_or_else(|| {
(axum::http::StatusCode::NOT_FOUND, "not found").into_response()
})?;
Ok(Json(serde_json::json!({
"links": [{
"rel": "http://nodeinfo/2.1",
"href": format!("https://{}/nodeinfo/2.1", ap.domain),
}]
})))
}
use axum::response::IntoResponse;
pub async fn nodeinfo(
State(state): State<Arc<AppState>>,
) -> Result<Json<serde_json::Value>, Response> {
let ap = state.ap.as_ref().ok_or_else(|| {
(axum::http::StatusCode::NOT_FOUND, "not found").into_response()
})?;
let dbi = state.db.lock().await;
let users: i64 = dbi.db.query_row("SELECT COUNT(*) FROM sessions", [], |r| r.get(0)).unwrap_or(0);
let puzzles: i64 = dbi.db.query_row("SELECT COUNT(*) FROM puzzles", [], |r| r.get(0)).unwrap_or(0);
Ok(Json(serde_json::json!({
"version": "2.1",
"software": {
"name": "cruciverb",
"version": env!("CARGO_PKG_VERSION"),
"repository": "https://git.lashman.live/lashman/cruciverb",
},
"protocols": ["activitypub"],
"services": { "inbound": [], "outbound": ["atom1.0", "rss2.0"] },
"openRegistrations": true,
"usage": {
"users": { "total": users },
"localPosts": puzzles,
},
"metadata": {
"nodeName": format!("cruciverb @ {}", ap.domain),
"nodeDescription": "self-hosted crossword puzzles",
"features": ["daily_puzzles", "community_clues", "puzzle_editor", "cryptic_mode"],
},
})))
}
+97
View File
@@ -0,0 +1,97 @@
use serde::{Deserialize, Serialize};
pub const PUBLIC: &str = "https://www.w3.org/ns/activitystreams#Public";
pub const CONTEXT: &str = "https://www.w3.org/ns/activitystreams";
pub const SECURITY_CONTEXT: &str = "https://w3id.org/security/v1";
#[derive(Debug, Serialize, Deserialize)]
pub struct Actor {
#[serde(rename = "@context")]
pub context: serde_json::Value,
pub id: String,
#[serde(rename = "type")]
pub actor_type: String,
#[serde(rename = "preferredUsername")]
pub preferred_username: String,
pub name: String,
pub summary: String,
pub inbox: String,
pub outbox: String,
pub followers: String,
#[serde(rename = "publicKey")]
pub public_key: ActorPublicKey,
#[serde(skip_serializing_if = "Option::is_none")]
pub endpoints: Option<serde_json::Value>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ActorPublicKey {
pub id: String,
pub owner: String,
#[serde(rename = "publicKeyPem")]
pub public_key_pem: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Activity {
#[serde(rename = "@context", skip_serializing_if = "Option::is_none")]
pub context: Option<serde_json::Value>,
pub id: String,
#[serde(rename = "type")]
pub activity_type: String,
pub actor: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub published: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cc: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub object: Option<serde_json::Value>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Note {
#[serde(rename = "type")]
pub note_type: String,
pub id: String,
#[serde(rename = "attributedTo")]
pub attributed_to: String,
pub content: String,
pub published: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
pub to: Vec<String>,
pub cc: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tag: Option<Vec<serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attachment: Option<Vec<serde_json::Value>>,
}
#[derive(Debug, Serialize)]
pub struct OrderedCollection {
#[serde(rename = "@context")]
pub context: String,
pub id: String,
#[serde(rename = "type")]
pub collection_type: String,
#[serde(rename = "totalItems")]
pub total_items: usize,
#[serde(rename = "orderedItems")]
pub ordered_items: Vec<serde_json::Value>,
}
#[derive(Debug, Serialize)]
pub struct WebFingerResponse {
pub subject: String,
pub links: Vec<WebFingerLink>,
}
#[derive(Debug, Serialize)]
pub struct WebFingerLink {
pub rel: String,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub link_type: Option<String>,
pub href: String,
}