From 75ef8bba7c2adae9f26bf2afd0c373befb80a32a Mon Sep 17 00:00:00 2001 From: silverpill Date: Mon, 2 May 2022 17:31:31 +0000 Subject: [PATCH] Move import_post to fetcher::helpers module --- src/activitypub/fetcher/helpers.rs | 100 ++++++++++++++++++++++++++++- src/activitypub/mod.rs | 2 +- src/activitypub/receiver.rs | 99 +--------------------------- src/mastodon_api/search/helpers.rs | 6 +- 4 files changed, 106 insertions(+), 101 deletions(-) diff --git a/src/activitypub/fetcher/helpers.rs b/src/activitypub/fetcher/helpers.rs index 6cec1d6..4f6f46b 100644 --- a/src/activitypub/fetcher/helpers.rs +++ b/src/activitypub/fetcher/helpers.rs @@ -1,10 +1,16 @@ +use std::collections::HashMap; use std::path::Path; use tokio_postgres::GenericClient; +use crate::activitypub::activity::Object; use crate::activitypub::actor::ActorAddress; -use crate::config::Instance; +use crate::activitypub::inbox::create_note::handle_note; +use crate::activitypub::receiver::parse_object_id; +use crate::config::{Config, Instance}; use crate::errors::{DatabaseError, HttpError, ValidationError}; +use crate::models::posts::queries::get_post_by_object_id; +use crate::models::posts::types::Post; use crate::models::profiles::queries::{ get_profile_by_actor_id, get_profile_by_acct, @@ -12,6 +18,7 @@ use crate::models::profiles::queries::{ }; use crate::models::profiles::types::DbActorProfile; use super::fetchers::{ + fetch_object, fetch_profile, fetch_profile_by_actor_id, FetchError, @@ -104,3 +111,94 @@ pub async fn import_profile_by_actor_address( let profile = create_profile(db_client, profile_data).await?; Ok(profile) } + +pub async fn import_post( + config: &Config, + db_client: &mut impl GenericClient, + object_id: String, + object_received: Option, +) -> Result { + let instance = config.instance(); + let media_dir = config.media_dir(); + let mut maybe_object_id_to_fetch = Some(object_id); + let mut maybe_object = object_received; + let mut objects = vec![]; + let mut redirects: HashMap = HashMap::new(); + let mut posts = vec![]; + + // Fetch ancestors by going through inReplyTo references + // TODO: fetch replies too + #[allow(clippy::while_let_loop)] + loop { + let object_id = match maybe_object_id_to_fetch { + Some(object_id) => { + if parse_object_id(&instance.url(), &object_id).is_ok() { + // Object is a local post + assert!(objects.len() > 0); + break; + } + match get_post_by_object_id(db_client, &object_id).await { + Ok(post) => { + // Object already fetched + if objects.len() == 0 { + // Return post corresponding to initial object ID + return Ok(post); + }; + break; + }, + Err(DatabaseError::NotFound(_)) => (), + Err(other_error) => return Err(other_error.into()), + }; + object_id + }, + None => { + // No object to fetch + break; + }, + }; + let object = match maybe_object { + Some(object) => object, + None => { + let object = fetch_object(&instance, &object_id).await + .map_err(|err| { + log::warn!("{}", err); + ValidationError("failed to fetch object") + })?; + log::info!("fetched object {}", object.id); + object + }, + }; + if object.id != object_id { + // ID of fetched object doesn't match requested ID + // Add IDs to the map of redirects + redirects.insert(object_id, object.id.clone()); + maybe_object_id_to_fetch = Some(object.id.clone()); + // Don't re-fetch object on the next iteration + maybe_object = Some(object); + } else { + maybe_object_id_to_fetch = object.in_reply_to.clone(); + maybe_object = None; + objects.push(object); + }; + } + let initial_object_id = objects[0].id.clone(); + + // Objects are ordered according to their place in reply tree, + // starting with the root + objects.reverse(); + for object in objects { + let post = handle_note( + db_client, + &instance, + &media_dir, + object, + &redirects, + ).await?; + posts.push(post); + } + + let initial_post = posts.into_iter() + .find(|post| post.object_id.as_ref() == Some(&initial_object_id)) + .unwrap(); + Ok(initial_post) +} diff --git a/src/activitypub/mod.rs b/src/activitypub/mod.rs index 4b2442d..07dc895 100644 --- a/src/activitypub/mod.rs +++ b/src/activitypub/mod.rs @@ -5,6 +5,6 @@ pub mod constants; pub mod deliverer; pub mod fetcher; mod inbox; -pub mod receiver; +mod receiver; pub mod views; mod vocabulary; diff --git a/src/activitypub/receiver.rs b/src/activitypub/receiver.rs index 53aaeae..0571d1a 100644 --- a/src/activitypub/receiver.rs +++ b/src/activitypub/receiver.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use actix_web::HttpRequest; use regex::Regex; use serde::de::DeserializeOwned; @@ -15,7 +13,7 @@ use crate::models::posts::queries::{ get_post_by_object_id, delete_post, }; -use crate::models::posts::types::{Post, PostCreateData}; +use crate::models::posts::types::PostCreateData; use crate::models::profiles::queries::{ get_profile_by_actor_id, get_profile_by_acct, @@ -39,12 +37,10 @@ use super::activity::{ create_activity_accept_follow, }; use super::deliverer::deliver_activity; -use super::fetcher::fetchers::fetch_object; use super::fetcher::helpers::{ get_or_import_profile_by_actor_id, - ImportError, + import_post, }; -use super::inbox::create_note::handle_note; use super::inbox::update_person::handle_update_person; use super::vocabulary::*; @@ -145,97 +141,6 @@ fn get_object_id(object: Value) -> Result { Ok(object_id) } -pub async fn import_post( - config: &Config, - db_client: &mut impl GenericClient, - object_id: String, - object_received: Option, -) -> Result { - let instance = config.instance(); - let media_dir = config.media_dir(); - let mut maybe_object_id_to_fetch = Some(object_id); - let mut maybe_object = object_received; - let mut objects = vec![]; - let mut redirects: HashMap = HashMap::new(); - let mut posts = vec![]; - - // Fetch ancestors by going through inReplyTo references - // TODO: fetch replies too - #[allow(clippy::while_let_loop)] - loop { - let object_id = match maybe_object_id_to_fetch { - Some(object_id) => { - if parse_object_id(&instance.url(), &object_id).is_ok() { - // Object is a local post - assert!(objects.len() > 0); - break; - } - match get_post_by_object_id(db_client, &object_id).await { - Ok(post) => { - // Object already fetched - if objects.len() == 0 { - // Return post corresponding to initial object ID - return Ok(post); - }; - break; - }, - Err(DatabaseError::NotFound(_)) => (), - Err(other_error) => return Err(other_error.into()), - }; - object_id - }, - None => { - // No object to fetch - break; - }, - }; - let object = match maybe_object { - Some(object) => object, - None => { - let object = fetch_object(&instance, &object_id).await - .map_err(|err| { - log::warn!("{}", err); - ValidationError("failed to fetch object") - })?; - log::info!("fetched object {}", object.id); - object - }, - }; - if object.id != object_id { - // ID of fetched object doesn't match requested ID - // Add IDs to the map of redirects - redirects.insert(object_id, object.id.clone()); - maybe_object_id_to_fetch = Some(object.id.clone()); - // Don't re-fetch object on the next iteration - maybe_object = Some(object); - } else { - maybe_object_id_to_fetch = object.in_reply_to.clone(); - maybe_object = None; - objects.push(object); - }; - } - let initial_object_id = objects[0].id.clone(); - - // Objects are ordered according to their place in reply tree, - // starting with the root - objects.reverse(); - for object in objects { - let post = handle_note( - db_client, - &instance, - &media_dir, - object, - &redirects, - ).await?; - posts.push(post); - } - - let initial_post = posts.into_iter() - .find(|post| post.object_id.as_ref() == Some(&initial_object_id)) - .unwrap(); - Ok(initial_post) -} - fn require_actor_signature(actor_id: &str, signer_id: &str) -> Result<(), HttpError> { diff --git a/src/mastodon_api/search/helpers.rs b/src/mastodon_api/search/helpers.rs index 391add1..81a9c7b 100644 --- a/src/mastodon_api/search/helpers.rs +++ b/src/mastodon_api/search/helpers.rs @@ -3,8 +3,10 @@ use tokio_postgres::GenericClient; use url::Url; use crate::activitypub::actor::ActorAddress; -use crate::activitypub::receiver::import_post; -use crate::activitypub::fetcher::helpers::import_profile_by_actor_address; +use crate::activitypub::fetcher::helpers::{ + import_post, + import_profile_by_actor_address, +}; use crate::config::Config; use crate::errors::{ValidationError, HttpError}; use crate::mastodon_api::accounts::types::Account;