diff --git a/crates/kitsune-activitypub/src/deliverer/mod.rs b/crates/kitsune-activitypub/src/deliverer/mod.rs index 7e26d6af0..663fdab24 100644 --- a/crates/kitsune-activitypub/src/deliverer/mod.rs +++ b/crates/kitsune-activitypub/src/deliverer/mod.rs @@ -1,6 +1,6 @@ use crate::{ error::{Error, Result}, - mapping::IntoActivity, + mapping::{self, IntoActivity}, InboxResolver, }; use diesel::{ @@ -16,6 +16,7 @@ use kitsune_db::{ schema::{accounts, posts, users}, PgPool, }; +use kitsune_service::{attachment::AttachmentService, url::UrlService}; use kitsune_type::ap::{ap_context, helper::StringOrObject, Activity, ActivityType, ObjectField}; use kitsune_util::try_join; use scoped_futures::ScopedFutureExt; @@ -26,15 +27,34 @@ pub mod core; const MAX_CONCURRENT_REQUESTS: usize = 10; +#[derive(TypedBuilder)] +pub struct Service { + attachment: AttachmentService, + url: UrlService, +} + #[derive(TypedBuilder)] #[builder(build_method(into = Arc))] pub struct Deliverer { core: core::Deliverer, db_pool: PgPool, inbox_resolver: InboxResolver, + service: Service, } impl Deliverer { + fn mapping_state(&self) -> mapping::State<'_> { + let service = mapping::Service::builder() + .attachment(&self.service.attachment) + .url(&self.service.url) + .build(); + + mapping::State::builder() + .db_pool(&self.db_pool) + .service(service) + .build() + } + async fn accept_follow(&self, follow: Follow) -> Result<()> { let (follower_inbox_url, (followed_account, followed_user)): (String, _) = self .db_pool @@ -57,7 +77,7 @@ impl Deliverer { }) .await?; - let followed_account_url = ctx.state.service.url.user_url(followed_account.id); + let followed_account_url = self.service.url.user_url(followed_account.id); // Constructing this here is against our idea of the `IntoActivity` and `IntoObject` traits // But I'm not sure how I could encode these into the form of these two traits @@ -105,7 +125,7 @@ impl Deliverer { .try_chunks(MAX_CONCURRENT_REQUESTS) .map_err(|err| err.1); - let activity = post.into_activity(&ctx.state).await?; + let activity = post.into_activity(self.mapping_state()).await?; // TODO: Should we deliver to the inboxes that are contained inside a `TryChunksError`? self.core @@ -143,7 +163,7 @@ impl Deliverer { .try_chunks(MAX_CONCURRENT_REQUESTS) .map_err(|err| err.1); - let delete_activity = post.into_negate_activity(&ctx.state).await?; + let delete_activity = post.into_negate_activity(self.mapping_state()).await?; // TODO: Should we deliver to the inboxes that are contained inside a `TryChunksError`? self.core @@ -177,7 +197,7 @@ impl Deliverer { .await?; if let Some(ref inbox_url) = inbox_url { - let activity = favourite.into_activity(&ctx.state).await?; + let activity = favourite.into_activity(self.mapping_state()).await?; self.core .deliver(inbox_url, &account, &user, &activity) @@ -210,7 +230,7 @@ impl Deliverer { .await?; if let Some(followed_inbox) = followed_inbox { - let follow_activity = follow.into_activity(&ctx.state).await?; + let follow_activity = follow.into_activity(self.mapping_state()).await?; self.core .deliver(&followed_inbox, &follower, &follower_user, &follow_activity) @@ -244,7 +264,7 @@ impl Deliverer { }) .await?; - let followed_account_url = ctx.state.service.url.user_url(followed_account.id); + let followed_account_url = self.service.url.user_url(followed_account.id); // Constructing this here is against our idea of the `IntoActivity` and `IntoObject` traits // But I'm not sure how I could encode these into the form of these two traits @@ -296,7 +316,7 @@ impl Deliverer { .await?; if let Some(ref inbox_url) = inbox_url { - let activity = favourite.into_negate_activity(&ctx.state).await?; + let activity = favourite.into_negate_activity(self.mapping_state()).await?; self.core .deliver(inbox_url, &account, &user, &activity) .await?; @@ -328,7 +348,7 @@ impl Deliverer { .await?; if let Some(ref followed_account_inbox_url) = followed_account_inbox_url { - let follow_activity = follow.into_negate_activity(&ctx.state).await?; + let follow_activity = follow.into_negate_activity(self.mapping_state()).await?; self.core .deliver( @@ -363,7 +383,7 @@ impl Deliverer { return Ok(()); }; - let activity = account.clone().into_activity(&ctx.state).await?; + let activity = account.clone().into_activity(self.mapping_state()).await?; let inbox_stream = self .inbox_resolver .resolve_followers(&account) @@ -407,7 +427,7 @@ impl Deliverer { .try_chunks(MAX_CONCURRENT_REQUESTS) .map_err(|err| err.1); - let mut activity = post.into_activity(&ctx.state).await?; + let mut activity = post.into_activity(self.mapping_state()).await?; // Patch in the update activity.r#type = ActivityType::Update; diff --git a/crates/kitsune-activitypub/src/error.rs b/crates/kitsune-activitypub/src/error.rs index d7cce8b6e..b9a7a865b 100644 --- a/crates/kitsune-activitypub/src/error.rs +++ b/crates/kitsune-activitypub/src/error.rs @@ -51,6 +51,9 @@ pub enum Error { #[error("Missing host")] MissingHost, + #[error("Not found")] + NotFound, + #[error(transparent)] Resolver(BoxError), @@ -63,6 +66,9 @@ pub enum Error { #[error(transparent)] SimdJson(#[from] simd_json::Error), + #[error("Unsupported media type")] + UnsupportedMediaType, + #[error(transparent)] UrlParse(#[from] url::ParseError), } diff --git a/crates/kitsune-activitypub/src/lib.rs b/crates/kitsune-activitypub/src/lib.rs index 7ece8f0de..b23f542a5 100644 --- a/crates/kitsune-activitypub/src/lib.rs +++ b/crates/kitsune-activitypub/src/lib.rs @@ -1,6 +1,6 @@ #![forbid(rust_2018_idioms)] #![warn(clippy::all, clippy::pedantic)] -#![allow(clippy::missing_errors_doc)] +#![allow(clippy::missing_errors_doc, clippy::module_name_repetitions)] #[macro_use] extern crate tracing; diff --git a/crates/kitsune-activitypub/src/mapping/activity.rs b/crates/kitsune-activitypub/src/mapping/activity.rs index 120faec70..a2dd31e3a 100644 --- a/crates/kitsune-activitypub/src/mapping/activity.rs +++ b/crates/kitsune-activitypub/src/mapping/activity.rs @@ -16,10 +16,10 @@ pub trait IntoActivity { type Output; type NegateOutput; - fn into_activity(self, state: &State) -> impl Future> + Send; + fn into_activity(self, state: State<'_>) -> impl Future> + Send; fn into_negate_activity( self, - state: &State, + state: State<'_>, ) -> impl Future> + Send; } @@ -27,7 +27,7 @@ impl IntoActivity for Account { type Output = Activity; type NegateOutput = Activity; - async fn into_activity(self, state: &State) -> Result { + async fn into_activity(self, state: State<'_>) -> Result { let account_url = state.service.url.user_url(self.id); Ok(Activity { @@ -40,7 +40,7 @@ impl IntoActivity for Account { }) } - async fn into_negate_activity(self, _state: &State) -> Result { + async fn into_negate_activity(self, _state: State<'_>) -> Result { todo!(); } } @@ -49,7 +49,7 @@ impl IntoActivity for Favourite { type Output = Activity; type NegateOutput = Activity; - async fn into_activity(self, state: &State) -> Result { + async fn into_activity(self, state: State<'_>) -> Result { let (account_url, post_url) = state .db_pool .with_connection(|db_conn| { @@ -80,7 +80,7 @@ impl IntoActivity for Favourite { }) } - async fn into_negate_activity(self, state: &State) -> Result { + async fn into_negate_activity(self, state: State<'_>) -> Result { let account_url = state .db_pool .with_connection(|db_conn| { @@ -107,7 +107,7 @@ impl IntoActivity for Follow { type Output = Activity; type NegateOutput = Activity; - async fn into_activity(self, state: &State) -> Result { + async fn into_activity(self, state: State<'_>) -> Result { let (attributed_to, object) = state .db_pool .with_connection(|db_conn| { @@ -138,7 +138,7 @@ impl IntoActivity for Follow { }) } - async fn into_negate_activity(self, state: &State) -> Result { + async fn into_negate_activity(self, state: State<'_>) -> Result { let attributed_to = state .db_pool .with_connection(|db_conn| { @@ -165,7 +165,7 @@ impl IntoActivity for Post { type Output = Activity; type NegateOutput = Activity; - async fn into_activity(self, state: &State) -> Result { + async fn into_activity(self, state: State<'_>) -> Result { let account_url = state.service.url.user_url(self.account_id); if let Some(reposted_post_id) = self.reposted_post_id { @@ -203,7 +203,7 @@ impl IntoActivity for Post { } } - async fn into_negate_activity(self, state: &State) -> Result { + async fn into_negate_activity(self, state: State<'_>) -> Result { let account_url = state.service.url.user_url(self.account_id); let activity = if self.reposted_post_id.is_some() { diff --git a/crates/kitsune-activitypub/src/mapping/mod.rs b/crates/kitsune-activitypub/src/mapping/mod.rs index 1b6f9ffde..1c4e90c37 100644 --- a/crates/kitsune-activitypub/src/mapping/mod.rs +++ b/crates/kitsune-activitypub/src/mapping/mod.rs @@ -10,14 +10,14 @@ mod util; pub use self::activity::IntoActivity; pub use self::object::IntoObject; -#[derive(TypedBuilder)] -pub struct Service { - attachment: AttachmentService, - url: UrlService, +#[derive(Clone, Copy, TypedBuilder)] +pub struct Service<'a> { + attachment: &'a AttachmentService, + url: &'a UrlService, } -#[derive(TypedBuilder)] -pub struct State { - db_pool: PgPool, - service: Service, +#[derive(Clone, Copy, TypedBuilder)] +pub struct State<'a> { + db_pool: &'a PgPool, + service: Service<'a>, } diff --git a/crates/kitsune-activitypub/src/mapping/object.rs b/crates/kitsune-activitypub/src/mapping/object.rs index 76041f779..969b583b7 100644 --- a/crates/kitsune-activitypub/src/mapping/object.rs +++ b/crates/kitsune-activitypub/src/mapping/object.rs @@ -28,20 +28,19 @@ use std::{future::Future, str::FromStr}; pub trait IntoObject { type Output; - fn into_object(self, state: &State) -> impl Future> + Send; + fn into_object(self, state: State<'_>) -> impl Future> + Send; } impl IntoObject for DbMediaAttachment { type Output = MediaAttachment; - async fn into_object(self, state: &State) -> Result { - let mime = - Mime::from_str(&self.content_type).map_err(|_| ApiError::UnsupportedMediaType)?; + async fn into_object(self, state: State<'_>) -> Result { + let mime = Mime::from_str(&self.content_type).map_err(|_| Error::UnsupportedMediaType)?; let r#type = match mime.type_() { mime::AUDIO => MediaAttachmentType::Audio, mime::IMAGE => MediaAttachmentType::Image, mime::VIDEO => MediaAttachmentType::Video, - _ => return Err(ApiError::UnsupportedMediaType.into()), + _ => return Err(Error::UnsupportedMediaType), }; let url = state.service.attachment.get_url(self.id).await?; @@ -94,12 +93,12 @@ fn build_post_tags( impl IntoObject for Post { type Output = Object; - async fn into_object(self, state: &State) -> Result { + async fn into_object(self, state: State<'_>) -> Result { // Right now a repost can't have content // Therefore it's also not an object // We just return en error here if self.reposted_post_id.is_some() { - return Err(ApiError::NotFound.into()); + return Err(Error::NotFound); } let (account, in_reply_to, mentions, emojis, attachment_stream) = state @@ -197,7 +196,7 @@ impl IntoObject for Post { impl IntoObject for Account { type Output = Actor; - async fn into_object(self, state: &State) -> Result { + async fn into_object(self, state: State<'_>) -> Result { let (icon, image) = state .db_pool .with_connection(|db_conn| { @@ -262,12 +261,12 @@ impl IntoObject for Account { impl IntoObject for CustomEmoji { type Output = Emoji; - async fn into_object(self, state: &State) -> Result { + async fn into_object(self, state: State<'_>) -> Result { // Officially we don't have any info about remote emojis as we're not the origin // Let's pretend we're not home and do not answer let name = match self.domain { None => Ok(format!(":{}:", self.shortcode)), - Some(_) => Err(ApiError::NotFound), + Some(_) => Err(Error::NotFound), }?; let icon = state diff --git a/crates/kitsune-activitypub/src/mapping/util.rs b/crates/kitsune-activitypub/src/mapping/util.rs index 56c8fe616..6a2a8cbef 100644 --- a/crates/kitsune-activitypub/src/mapping/util.rs +++ b/crates/kitsune-activitypub/src/mapping/util.rs @@ -3,12 +3,12 @@ use kitsune_db::model::{account::Account, post::Visibility}; use kitsune_type::ap::PUBLIC_IDENTIFIER; pub trait BaseToCc { - fn base_to_cc(&self, state: &State, account: &Account) -> (Vec, Vec); + fn base_to_cc(&self, state: State<'_>, account: &Account) -> (Vec, Vec); } impl BaseToCc for Visibility { #[inline] - fn base_to_cc(&self, state: &State, account: &Account) -> (Vec, Vec) { + fn base_to_cc(&self, state: State<'_>, account: &Account) -> (Vec, Vec) { let followers_url = state.service.url.followers_url(account.id); match self {