use crate::{ objects::{person::DbUser, post::DbPost}, Error, }; use activitypub_federation::config::{FederationConfig, UrlVerifier}; use anyhow::anyhow; use async_trait::async_trait; use std::{ str::FromStr, sync::{Arc, Mutex}, }; use url::Url; pub async fn new_instance( hostname: &str, name: String, ) -> Result, Error> { let mut system_user = DbUser::new(hostname, "system".into())?; system_user.ap_id = Url::parse(&format!("http://{}/", hostname))?.into(); let local_user = DbUser::new(hostname, name)?; let database = Arc::new(Database { system_user: system_user.clone(), users: Mutex::new(vec![local_user]), posts: Mutex::new(vec![]), }); let config = FederationConfig::builder() .domain(hostname) .signed_fetch_actor(&system_user) .app_data(database) .url_verifier(Box::new(MyUrlVerifier())) .debug(true) .build() .await?; Ok(config) } pub type DatabaseHandle = Arc; /// Our "database" which contains all known posts and users (local and federated) pub struct Database { pub system_user: DbUser, pub users: Mutex>, pub posts: Mutex>, } /// Use this to store your federation blocklist, or a database connection needed to retrieve it. #[derive(Clone)] struct MyUrlVerifier(); #[async_trait] impl UrlVerifier for MyUrlVerifier { async fn verify(&self, url: &Url) -> Result<(), activitypub_federation::error::Error> { if url.domain() == Some("malicious.com") { Err(activitypub_federation::error::Error::Other( "malicious domain".into(), )) } else { Ok(()) } } } pub enum Webserver { Axum, ActixWeb, } impl FromStr for Webserver { type Err = (); fn from_str(s: &str) -> Result { Ok(match s { "axum" => Webserver::Axum, "actix-web" => Webserver::ActixWeb, _ => panic!("Invalid webserver parameter, must be either `axum` or `actix-web`"), }) } } pub fn listen( config: &FederationConfig, webserver: &Webserver, ) -> Result<(), Error> { match webserver { Webserver::Axum => crate::axum::http::listen(config)?, Webserver::ActixWeb => crate::actix_web::http::listen(config)?, } Ok(()) } impl Database { pub fn local_user(&self) -> DbUser { let lock = self.users.lock().unwrap(); lock.first().unwrap().clone() } pub fn read_user(&self, name: &str) -> Result { let db_user = self.local_user(); if name == db_user.name { Ok(db_user) } else { Err(anyhow!("Invalid user {name}").into()) } } }