diff --git a/src/activities/create_post.rs b/src/activities/create_post.rs deleted file mode 100644 index 6f85e2d..0000000 --- a/src/activities/create_post.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::{ - instance::DatabaseHandle, - objects::{person::DbUser, post::Note}, - DbPost, -}; -use activitypub_federation::{ - config::Data, - fetch::object_id::ObjectId, - kinds::activity::CreateType, - protocol::helpers::deserialize_one_or_many, - traits::{ActivityHandler, Object}, -}; -use serde::{Deserialize, Serialize}; -use url::Url; - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct CreatePost { - pub(crate) actor: ObjectId, - #[serde(deserialize_with = "deserialize_one_or_many")] - pub(crate) to: Vec, - pub(crate) object: Note, - #[serde(rename = "type")] - pub(crate) kind: CreateType, - pub(crate) id: Url, -} - -impl CreatePost { - pub fn new(note: Note, id: Url) -> CreatePost { - CreatePost { - actor: note.attributed_to.clone(), - to: note.to.clone(), - object: note, - kind: CreateType::Create, - id, - } - } -} - -#[async_trait::async_trait] -impl ActivityHandler for CreatePost { - type DataType = DatabaseHandle; - type Error = crate::error::Error; - - fn id(&self) -> &Url { - &self.id - } - - fn actor(&self) -> &Url { - self.actor.inner() - } - - async fn verify(&self, data: &Data) -> Result<(), Self::Error> { - DbPost::verify(&self.object, &self.id, data).await?; - Ok(()) - } - - async fn receive(self, data: &Data) -> Result<(), Self::Error> { - DbPost::from_json(self.object, data).await?; - Ok(()) - } -} diff --git a/src/axum/http.rs b/src/axum/http.rs deleted file mode 100644 index 447bcec..0000000 --- a/src/axum/http.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::error::Error; -use crate::{ - instance::DatabaseHandle, - objects::person::{DbUser, Person, PersonAcceptedActivities}, -}; -use activitypub_federation::{ - axum::{ - inbox::{receive_activity, ActivityData}, - json::FederationJson, - }, - config::{Data, FederationConfig, FederationMiddleware}, - fetch::webfinger::{build_webfinger_response, extract_webfinger_name, Webfinger}, - protocol::context::WithContext, - traits::Object, -}; -use axum::{ - extract::{Path, Query}, - response::IntoResponse, - routing::{get, post}, - Json, Router, -}; -use axum_macros::debug_handler; -use serde::Deserialize; -use std::net::ToSocketAddrs; -use tracing::info; - -pub fn listen(config: &FederationConfig) -> Result<(), Error> { - let hostname = config.domain(); - info!("Listening with axum on {hostname}"); - let config = config.clone(); - let app = Router::new() - .route("/:user/inbox", post(http_post_user_inbox)) - .route("/:user", get(http_get_user)) - .route("/.well-known/webfinger", get(webfinger)) - .layer(FederationMiddleware::new(config)); - - let addr = hostname - .to_socket_addrs()? - .next() - .expect("Failed to lookup domain name"); - let server = axum::Server::bind(&addr).serve(app.into_make_service()); - - tokio::spawn(server); - Ok(()) -} - -#[debug_handler] -async fn http_get_user( - Path(name): Path, - data: Data, -) -> Result>, Error> { - let db_user = data.read_user(&name)?; - let json_user = db_user.into_json(&data).await?; - Ok(FederationJson(WithContext::new_default(json_user))) -} - -#[debug_handler] -async fn http_post_user_inbox( - data: Data, - activity_data: ActivityData, -) -> impl IntoResponse { - receive_activity::, DbUser, DatabaseHandle>( - activity_data, - &data, - ) - .await -} - -#[derive(Deserialize)] -struct WebfingerQuery { - resource: String, -} - -#[debug_handler] -async fn webfinger( - Query(query): Query, - data: Data, -) -> Result, Error> { - let name = extract_webfinger_name(&query.resource, &data)?; - let db_user = data.read_user(&name)?; - Ok(Json(build_webfinger_response( - query.resource, - db_user.ap_id.into_inner(), - ))) -} diff --git a/src/axum/mod.rs b/src/axum/mod.rs deleted file mode 100644 index 1e089da..0000000 --- a/src/axum/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::error::Error; -use axum::http::StatusCode; -use axum::response::{IntoResponse, Response}; - -#[allow(clippy::diverging_sub_expression, clippy::items_after_statements)] -pub mod http; - -impl IntoResponse for Error { - fn into_response(self) -> Response { - (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", self.0)).into_response() - } -} diff --git a/src/error.rs b/src/error.rs index 48e7713..52be184 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,5 @@ +use axum::http::StatusCode; +use axum::response::{IntoResponse, Response}; use std::fmt::{Display, Formatter}; #[derive(Debug)] @@ -17,3 +19,9 @@ where Error(t.into()) } } + +impl IntoResponse for Error { + fn into_response(self) -> Response { + (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", self.0)).into_response() + } +} diff --git a/src/activities/accept.rs b/src/federation/activities/accept.rs similarity index 89% rename from src/activities/accept.rs rename to src/federation/activities/accept.rs index 9305213..c073967 100644 --- a/src/activities/accept.rs +++ b/src/federation/activities/accept.rs @@ -1,4 +1,7 @@ -use crate::{activities::follow::Follow, instance::DatabaseHandle, objects::person::DbUser}; +use crate::{ + federation::activities::follow::Follow, federation::objects::person::DbUser, + instance::DatabaseHandle, +}; use activitypub_federation::{ config::Data, fetch::object_id::ObjectId, kinds::activity::AcceptType, traits::ActivityHandler, }; diff --git a/src/activities/follow.rs b/src/federation/activities/follow.rs similarity index 93% rename from src/activities/follow.rs rename to src/federation/activities/follow.rs index 51e8ee1..6f5de8d 100644 --- a/src/activities/follow.rs +++ b/src/federation/activities/follow.rs @@ -1,6 +1,6 @@ use crate::{ - activities::accept::Accept, generate_object_id, instance::DatabaseHandle, - objects::person::DbUser, + federation::activities::accept::Accept, federation::objects::person::DbUser, + generate_object_id, instance::DatabaseHandle, }; use activitypub_federation::{ config::Data, diff --git a/src/activities/mod.rs b/src/federation/activities/mod.rs similarity index 60% rename from src/activities/mod.rs rename to src/federation/activities/mod.rs index 73f5dd6..5e2ad4b 100644 --- a/src/activities/mod.rs +++ b/src/federation/activities/mod.rs @@ -1,3 +1,2 @@ pub mod accept; -pub mod create_post; pub mod follow; diff --git a/src/federation/mod.rs b/src/federation/mod.rs new file mode 100644 index 0000000..67e6c0f --- /dev/null +++ b/src/federation/mod.rs @@ -0,0 +1,3 @@ +pub mod activities; +pub mod objects; +pub mod routes; diff --git a/src/objects/mod.rs b/src/federation/objects/mod.rs similarity index 100% rename from src/objects/mod.rs rename to src/federation/objects/mod.rs diff --git a/src/objects/person.rs b/src/federation/objects/person.rs similarity index 89% rename from src/objects/person.rs rename to src/federation/objects/person.rs index 0424c77..cabb5b4 100644 --- a/src/objects/person.rs +++ b/src/federation/objects/person.rs @@ -1,8 +1,7 @@ use crate::error::Error; use crate::{ - activities::{accept::Accept, create_post::CreatePost, follow::Follow}, + federation::activities::{accept::Accept, follow::Follow}, instance::DatabaseHandle, - objects::post::DbPost, utils::generate_object_id, }; use activitypub_federation::{ @@ -40,7 +39,6 @@ pub struct DbUser { pub enum PersonAcceptedActivities { Follow(Follow), Accept(Accept), - CreateNote(CreatePost), } impl DbUser { @@ -90,18 +88,6 @@ impl DbUser { Ok(()) } - pub async fn post(&self, post: DbPost, data: &Data) -> Result<(), Error> { - let id = generate_object_id(data.domain())?; - let create = CreatePost::new(post.into_json(data).await?, id.clone()); - let mut inboxes = vec![]; - for f in self.followers.clone() { - let user: DbUser = ObjectId::from(f).dereference(data).await?; - inboxes.push(user.shared_inbox_or_inbox()); - } - self.send(create, inboxes, data).await?; - Ok(()) - } - pub(crate) async fn send( &self, activity: Activity, diff --git a/src/objects/post.rs b/src/federation/objects/post.rs similarity index 95% rename from src/objects/post.rs rename to src/federation/objects/post.rs index cbdf8e8..857e4f4 100644 --- a/src/objects/post.rs +++ b/src/federation/objects/post.rs @@ -1,4 +1,6 @@ -use crate::{error::Error, generate_object_id, instance::DatabaseHandle, objects::person::DbUser}; +use crate::{ + error::Error, federation::objects::person::DbUser, generate_object_id, instance::DatabaseHandle, +}; use activitypub_federation::{ config::Data, fetch::object_id::ObjectId, diff --git a/src/federation/routes.rs b/src/federation/routes.rs new file mode 100644 index 0000000..74c8abd --- /dev/null +++ b/src/federation/routes.rs @@ -0,0 +1,33 @@ +use crate::error::Error; +use crate::federation::objects::person::{DbUser, Person, PersonAcceptedActivities}; +use crate::instance::DatabaseHandle; +use activitypub_federation::axum::inbox::{receive_activity, ActivityData}; +use activitypub_federation::axum::json::FederationJson; +use activitypub_federation::config::Data; +use activitypub_federation::protocol::context::WithContext; +use activitypub_federation::traits::Object; +use axum::extract::path::Path; +use axum::response::IntoResponse; +use axum_macros::debug_handler; + +#[debug_handler] +pub async fn http_get_user( + Path(name): Path, + data: Data, +) -> Result>, Error> { + let db_user = data.read_user(&name)?; + let json_user = db_user.into_json(&data).await?; + Ok(FederationJson(WithContext::new_default(json_user))) +} + +#[debug_handler] +pub async fn http_post_user_inbox( + data: Data, + activity_data: ActivityData, +) -> impl IntoResponse { + receive_activity::, DbUser, DatabaseHandle>( + activity_data, + &data, + ) + .await +} diff --git a/src/instance.rs b/src/instance.rs index daf97e2..4add418 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,12 +1,12 @@ use crate::error::Error; -use crate::objects::{person::DbUser, post::DbPost}; +use crate::federation::objects::{person::DbUser, post::DbPost}; use activitypub_federation::config::{FederationConfig, UrlVerifier}; use anyhow::anyhow; use async_trait::async_trait; use std::sync::{Arc, Mutex}; use url::Url; -pub async fn new_instance( +pub async fn federation_config( hostname: &str, name: String, ) -> Result, Error> { diff --git a/src/main.rs b/src/main.rs index c47d642..be66f90 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,21 @@ -use crate::axum::http::listen; -use crate::{instance::new_instance, objects::post::DbPost, utils::generate_object_id}; +use crate::{instance::federation_config, utils::generate_object_id}; use error::Error; use tracing::log::LevelFilter; -mod activities; -mod axum; +use activitypub_federation::config::FederationMiddleware; +use axum::{ + routing::{get, post}, + Router, Server, +}; + +use crate::federation::routes::http_get_user; +use crate::federation::routes::http_post_user_inbox; +use std::net::ToSocketAddrs; +use tracing::info; + mod error; +mod federation; mod instance; -mod objects; mod utils; #[tokio::main] @@ -18,8 +26,22 @@ async fn main() -> Result<(), Error> { .filter_module("fediwiki", LevelFilter::Info) .init(); - let alpha = new_instance("localhost:8001", "alpha".to_string()).await?; - listen(&alpha)?; + let config = federation_config("localhost:8001", "alpha".to_string()).await?; + let hostname = config.domain(); + info!("Listening with axum on {hostname}"); + let config = config.clone(); + let app = Router::new() + .route("/:user/inbox", post(http_post_user_inbox)) + .route("/:user", get(http_get_user)) + .layer(FederationMiddleware::new(config)); + + let addr = hostname + .to_socket_addrs()? + .next() + .expect("Failed to lookup domain name"); + let server = Server::bind(&addr).serve(app.into_make_service()); + + tokio::spawn(server); Ok(()) }