WIP: alternative way to handle non-local object parsing

This commit is contained in:
Felix Ableitner 2020-12-01 13:00:18 +01:00
parent 2bdb15b06d
commit 9cbb80ca8e
20 changed files with 156 additions and 57 deletions

View file

@ -2,7 +2,6 @@ use crate::{
activities::receive::get_actor_as_user, activities::receive::get_actor_as_user,
fetcher::get_or_fetch_and_insert_comment, fetcher::get_or_fetch_and_insert_comment,
ActorType, ActorType,
FromApub,
NoteExt, NoteExt,
}; };
use activitystreams::{ use activitystreams::{
@ -20,6 +19,7 @@ use lemmy_db::{
use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs}; use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs};
use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError}; use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation}; use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation};
use crate::objects::FromApub;
pub(crate) async fn receive_create_comment( pub(crate) async fn receive_create_comment(
create: Create, create: Create,

View file

@ -1,9 +1,9 @@
use crate::{ use crate::{
activities::receive::get_actor_as_user, activities::receive::get_actor_as_user,
fetcher::get_or_fetch_and_insert_comment, fetcher::get_or_fetch_and_insert_comment,
FromApub,
NoteExt, NoteExt,
}; };
use crate::objects::FromApub;
use activitystreams::{activity::*, prelude::*}; use activitystreams::{activity::*, prelude::*};
use anyhow::Context; use anyhow::Context;
use lemmy_db::{ use lemmy_db::{

View file

@ -2,9 +2,9 @@ use crate::{
activities::receive::get_actor_as_user, activities::receive::get_actor_as_user,
fetcher::get_or_fetch_and_insert_post, fetcher::get_or_fetch_and_insert_post,
ActorType, ActorType,
FromApub,
PageExt, PageExt,
}; };
use crate::objects::FromApub;
use activitystreams::{ use activitystreams::{
activity::{Create, Dislike, Like, Remove, Update}, activity::{Create, Dislike, Like, Remove, Update},
prelude::*, prelude::*,

View file

@ -1,9 +1,9 @@
use crate::{ use crate::{
activities::receive::get_actor_as_user, activities::receive::get_actor_as_user,
fetcher::get_or_fetch_and_insert_post, fetcher::get_or_fetch_and_insert_post,
FromApub,
PageExt, PageExt,
}; };
use crate::objects::FromApub;
use activitystreams::{activity::*, prelude::*}; use activitystreams::{activity::*, prelude::*};
use anyhow::Context; use anyhow::Context;
use lemmy_db::{ use lemmy_db::{

View file

@ -3,9 +3,9 @@ use crate::{
check_is_apub_id_valid, check_is_apub_id_valid,
fetcher::get_or_fetch_and_upsert_user, fetcher::get_or_fetch_and_upsert_user,
inbox::get_activity_to_and_cc, inbox::get_activity_to_and_cc,
FromApub,
NoteExt, NoteExt,
}; };
use crate::objects::FromApub;
use activitystreams::{ use activitystreams::{
activity::{ActorAndObjectRefExt, Create, Delete, Undo, Update}, activity::{ActorAndObjectRefExt, Create, Delete, Undo, Update},
base::{AsBase, ExtendsExt}, base::{AsBase, ExtendsExt},

View file

@ -6,7 +6,6 @@ use crate::{
ActorType, ActorType,
ApubLikeableType, ApubLikeableType,
ApubObjectType, ApubObjectType,
ToApub,
}; };
use activitystreams::{ use activitystreams::{
activity::{ activity::{
@ -39,6 +38,7 @@ use log::debug;
use reqwest::Client; use reqwest::Client;
use serde_json::Error; use serde_json::Error;
use url::Url; use url::Url;
use crate::objects::ToApub;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ApubObjectType for Comment { impl ApubObjectType for Comment {

View file

@ -5,8 +5,8 @@ use crate::{
ActorType, ActorType,
ApubLikeableType, ApubLikeableType,
ApubObjectType, ApubObjectType,
ToApub,
}; };
use crate::objects::ToApub;
use activitystreams::{ use activitystreams::{
activity::{ activity::{
kind::{CreateType, DeleteType, DislikeType, LikeType, RemoveType, UndoType, UpdateType}, kind::{CreateType, DeleteType, DislikeType, LikeType, RemoveType, UndoType, UpdateType},

View file

@ -4,8 +4,8 @@ use crate::{
extensions::context::lemmy_context, extensions::context::lemmy_context,
ActorType, ActorType,
ApubObjectType, ApubObjectType,
ToApub,
}; };
use crate::objects::ToApub;
use activitystreams::{ use activitystreams::{
activity::{ activity::{
kind::{CreateType, DeleteType, UndoType, UpdateType}, kind::{CreateType, DeleteType, UndoType, UpdateType},

View file

@ -1,7 +1,6 @@
use crate::{ use crate::{
check_is_apub_id_valid, check_is_apub_id_valid,
ActorType, ActorType,
FromApub,
GroupExt, GroupExt,
NoteExt, NoteExt,
PageExt, PageExt,
@ -39,6 +38,7 @@ use reqwest::Client;
use serde::Deserialize; use serde::Deserialize;
use std::{fmt::Debug, time::Duration}; use std::{fmt::Debug, time::Duration};
use url::Url; use url::Url;
use crate::objects::FromApub;
static ACTOR_REFETCH_INTERVAL_SECONDS: i64 = 24 * 60 * 60; static ACTOR_REFETCH_INTERVAL_SECONDS: i64 = 24 * 60 * 60;
static ACTOR_REFETCH_INTERVAL_SECONDS_DEBUG: i64 = 10; static ACTOR_REFETCH_INTERVAL_SECONDS_DEBUG: i64 = 10;

View file

@ -1,6 +1,5 @@
use crate::{ use crate::{
http::{create_apub_response, create_apub_tombstone_response}, http::{create_apub_response, create_apub_tombstone_response},
ToApub,
}; };
use actix_web::{body::Body, web, web::Path, HttpResponse}; use actix_web::{body::Body, web, web::Path, HttpResponse};
use diesel::result::Error::NotFound; use diesel::result::Error::NotFound;
@ -9,6 +8,7 @@ use lemmy_structs::blocking;
use lemmy_utils::LemmyError; use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use serde::Deserialize; use serde::Deserialize;
use crate::objects::ToApub;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct CommentQuery { pub struct CommentQuery {

View file

@ -2,7 +2,6 @@ use crate::{
extensions::context::lemmy_context, extensions::context::lemmy_context,
http::{create_apub_response, create_apub_tombstone_response}, http::{create_apub_response, create_apub_tombstone_response},
ActorType, ActorType,
ToApub,
}; };
use activitystreams::{ use activitystreams::{
base::{AnyBase, BaseExt, ExtendsExt}, base::{AnyBase, BaseExt, ExtendsExt},
@ -14,6 +13,7 @@ use lemmy_structs::blocking;
use lemmy_utils::LemmyError; use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use serde::Deserialize; use serde::Deserialize;
use crate::objects::ToApub;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct CommunityQuery { pub struct CommunityQuery {

View file

@ -1,6 +1,5 @@
use crate::{ use crate::{
http::{create_apub_response, create_apub_tombstone_response}, http::{create_apub_response, create_apub_tombstone_response},
ToApub,
}; };
use actix_web::{body::Body, web, HttpResponse}; use actix_web::{body::Body, web, HttpResponse};
use diesel::result::Error::NotFound; use diesel::result::Error::NotFound;
@ -9,6 +8,7 @@ use lemmy_structs::blocking;
use lemmy_utils::LemmyError; use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use serde::Deserialize; use serde::Deserialize;
use crate::objects::ToApub;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct PostQuery { pub struct PostQuery {

View file

@ -1,8 +1,9 @@
use crate::{extensions::context::lemmy_context, http::create_apub_response, ActorType, ToApub}; use crate::{extensions::context::lemmy_context, http::create_apub_response, ActorType};
use activitystreams::{ use activitystreams::{
base::BaseExt, base::BaseExt,
collection::{CollectionExt, OrderedCollection}, collection::{CollectionExt, OrderedCollection},
}; };
use crate::objects::ToApub;
use actix_web::{body::Body, web, HttpResponse}; use actix_web::{body::Body, web, HttpResponse};
use lemmy_db::user::User_; use lemmy_db::user::User_;
use lemmy_structs::blocking; use lemmy_structs::blocking;

View file

@ -18,7 +18,7 @@ use activitystreams::{
activity::Follow, activity::Follow,
actor::{ApActor, Group, Person}, actor::{ApActor, Group, Person},
base::AnyBase, base::AnyBase,
object::{ApObject, Note, Page, Tombstone}, object::{ApObject, Note, Page},
}; };
use activitystreams_ext::{Ext1, Ext2}; use activitystreams_ext::{Ext1, Ext2};
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
@ -109,33 +109,6 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
} }
} }
/// Trait for converting an object or actor into the respective ActivityPub type.
#[async_trait::async_trait(?Send)]
pub(crate) trait ToApub {
type ApubType;
async fn to_apub(&self, pool: &DbPool) -> Result<Self::ApubType, LemmyError>;
fn to_tombstone(&self) -> Result<Tombstone, LemmyError>;
}
#[async_trait::async_trait(?Send)]
pub(crate) trait FromApub {
type ApubType;
/// Converts an object from ActivityPub type to Lemmy internal type.
///
/// * `apub` The object to read from
/// * `context` LemmyContext which holds DB pool, HTTP client etc
/// * `expected_domain` If present, ensure that the domains of this and of the apub object ID are
/// identical
async fn from_apub(
apub: &Self::ApubType,
context: &LemmyContext,
expected_domain: Option<Url>,
request_counter: &mut i32,
) -> Result<Self, LemmyError>
where
Self: Sized;
}
/// Common functions for ActivityPub objects, which are implemented by most (but not all) objects /// Common functions for ActivityPub objects, which are implemented by most (but not all) objects
/// and actors in Lemmy. /// and actors in Lemmy.
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]

View file

@ -11,9 +11,7 @@ use crate::{
get_source_markdown_value, get_source_markdown_value,
set_content_and_source, set_content_and_source,
}, },
FromApub,
NoteExt, NoteExt,
ToApub,
}; };
use activitystreams::{ use activitystreams::{
object::{kind::NoteType, ApObject, Note, Tombstone}, object::{kind::NoteType, ApObject, Note, Tombstone},
@ -36,6 +34,8 @@ use lemmy_utils::{
}; };
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use url::Url; use url::Url;
use crate::objects::{FromApub, ToApub, FromApubToForm};
use lemmy_utils::settings::Settings;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ToApub for Comment { impl ToApub for Comment {
@ -87,12 +87,41 @@ impl ToApub for Comment {
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl FromApub for CommentForm { impl FromApub for Comment {
type ApubType = NoteExt; type ApubType = NoteExt;
/// Converts a `Note` to `CommentForm`. /// Converts a `Note` to `Comment`.
/// ///
/// If the parent community, post and comment(s) are not known locally, these are also fetched. /// If the parent community, post and comment(s) are not known locally, these are also fetched.
async fn from_apub(
note: &NoteExt,
context: &LemmyContext,
expected_domain: Option<Url>,
request_counter: &mut i32,
) -> Result<Comment, LemmyError> {
let comment_id = note.id_unchecked().context(location_info!())?;
let domain = comment_id.domain().context(location_info!())?;
if domain == Settings::get().hostname {
let comment = blocking(context.pool(), move |conn| {
Comment::read_from_apub_id(conn, comment_id.as_str())
})
.await??;
Ok(comment)
} else {
let comment_form = CommentForm::from_apub(note, context, expected_domain, request_counter)?;
let comment = blocking(context.pool(), move |conn| {
Comment::upsert(conn, comment_form)
})
.await??;
Ok(comment)
}
}
}
#[async_trait::async_trait(?Send)]
impl FromApubToForm for CommentForm {
type ApubType = NoteExt;
async fn from_apub( async fn from_apub(
note: &NoteExt, note: &NoteExt,
context: &LemmyContext, context: &LemmyContext,

View file

@ -8,9 +8,7 @@ use crate::{
set_content_and_source, set_content_and_source,
}, },
ActorType, ActorType,
FromApub,
GroupExt, GroupExt,
ToApub,
}; };
use activitystreams::{ use activitystreams::{
actor::{kind::GroupType, ApActor, Endpoints, Group}, actor::{kind::GroupType, ApActor, Endpoints, Group},
@ -32,6 +30,7 @@ use lemmy_utils::{
utils::{check_slurs, check_slurs_opt, convert_datetime}, utils::{check_slurs, check_slurs_opt, convert_datetime},
LemmyError, LemmyError,
}; };
use crate::objects::{FromApub, ToApub, FromApubToForm};
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use url::Url; use url::Url;
@ -106,8 +105,24 @@ impl ToApub for Community {
create_tombstone(self.deleted, &self.actor_id, self.updated, GroupType::Group) create_tombstone(self.deleted, &self.actor_id, self.updated, GroupType::Group)
} }
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl FromApub for CommunityForm { impl FromApub for Community {
type ApubType = GroupExt;
/// Converts a `Group` to `Community`.
async fn from_apub(
group: &GroupExt,
context: &LemmyContext,
expected_domain: Option<Url>,
request_counter: &mut i32,
) -> Result<Community, LemmyError> {
todo!()
}
}
#[async_trait::async_trait(?Send)]
impl FromApubToForm for CommunityForm {
type ApubType = GroupExt; type ApubType = GroupExt;
async fn from_apub( async fn from_apub(

View file

@ -9,6 +9,8 @@ use anyhow::{anyhow, Context};
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use lemmy_utils::{location_info, utils::convert_datetime, LemmyError}; use lemmy_utils::{location_info, utils::convert_datetime, LemmyError};
use url::Url; use url::Url;
use lemmy_websocket::LemmyContext;
use lemmy_db::DbPool;
pub(crate) mod comment; pub(crate) mod comment;
pub(crate) mod community; pub(crate) mod community;
@ -16,6 +18,46 @@ pub(crate) mod post;
pub(crate) mod private_message; pub(crate) mod private_message;
pub(crate) mod user; pub(crate) mod user;
/// Trait for converting an object or actor into the respective ActivityPub type.
#[async_trait::async_trait(?Send)]
pub(crate) trait ToApub {
type ApubType;
async fn to_apub(&self, pool: &DbPool) -> Result<Self::ApubType, LemmyError>;
fn to_tombstone(&self) -> Result<Tombstone, LemmyError>;
}
#[async_trait::async_trait(?Send)]
pub(crate) trait FromApub {
type ApubType;
/// Converts an object from ActivityPub type to Lemmy internal type.
///
/// * `apub` The object to read from
/// * `context` LemmyContext which holds DB pool, HTTP client etc
/// * `expected_domain` If present, ensure that the domains of this and of the apub object ID are
/// identical
async fn from_apub(
apub: &Self::ApubType,
context: &LemmyContext,
expected_domain: Option<Url>,
request_counter: &mut i32,
) -> Result<Self, LemmyError>
where
Self: Sized;
}
#[async_trait::async_trait(?Send)]
pub(in crate::objects) trait FromApubToForm {
type ApubType;
async fn from_apub(
apub: &Self::ApubType,
context: &LemmyContext,
expected_domain: Option<Url>,
request_counter: &mut i32,
) -> Result<Self, LemmyError>
where
Self: Sized;
}
/// Updated is actually the deletion time /// Updated is actually the deletion time
fn create_tombstone<T>( fn create_tombstone<T>(
deleted: bool, deleted: bool,

View file

@ -7,9 +7,7 @@ use crate::{
get_source_markdown_value, get_source_markdown_value,
set_content_and_source, set_content_and_source,
}, },
FromApub,
PageExt, PageExt,
ToApub,
}; };
use activitystreams::{ use activitystreams::{
object::{kind::PageType, ApObject, Image, Page, Tombstone}, object::{kind::PageType, ApObject, Image, Page, Tombstone},
@ -35,6 +33,7 @@ use lemmy_utils::{
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use log::error; use log::error;
use url::Url; use url::Url;
use crate::objects::{FromApubToForm, ToApub, FromApub};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ToApub for Post { impl ToApub for Post {
@ -98,12 +97,26 @@ impl ToApub for Post {
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl FromApub for PostForm { impl FromApub for Post {
type ApubType = PageExt; type ApubType = PageExt;
/// Converts a `PageExt` to `PostForm`. /// Converts a `PageExt` to `PostForm`.
/// ///
/// If the post's community or creator are not known locally, these are also fetched. /// If the post's community or creator are not known locally, these are also fetched.
async fn from_apub(
note: &PageExt,
context: &LemmyContext,
expected_domain: Option<Url>,
request_counter: &mut i32,
) -> Result<Post, LemmyError> {
todo!()
}
}
#[async_trait::async_trait(?Send)]
impl FromApubToForm for PostForm {
type ApubType = PageExt;
async fn from_apub( async fn from_apub(
page: &PageExt, page: &PageExt,
context: &LemmyContext, context: &LemmyContext,

View file

@ -8,10 +8,9 @@ use crate::{
get_source_markdown_value, get_source_markdown_value,
set_content_and_source, set_content_and_source,
}, },
FromApub,
NoteExt, NoteExt,
ToApub,
}; };
use crate::objects::{FromApubToForm, ToApub, FromApub};
use activitystreams::{ use activitystreams::{
object::{kind::NoteType, ApObject, Note, Tombstone}, object::{kind::NoteType, ApObject, Note, Tombstone},
prelude::*, prelude::*,
@ -63,7 +62,21 @@ impl ToApub for PrivateMessage {
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl FromApub for PrivateMessageForm { impl FromApub for PrivateMessage {
type ApubType = NoteExt;
async fn from_apub(
note: &NoteExt,
context: &LemmyContext,
expected_domain: Option<Url>,
request_counter: &mut i32,
) -> Result<PrivateMessage, LemmyError> {
todo!()
}
}
#[async_trait::async_trait(?Send)]
impl FromApubToForm for PrivateMessageForm {
type ApubType = NoteExt; type ApubType = NoteExt;
async fn from_apub( async fn from_apub(

View file

@ -2,10 +2,9 @@ use crate::{
extensions::context::lemmy_context, extensions::context::lemmy_context,
objects::{check_object_domain, get_source_markdown_value, set_content_and_source}, objects::{check_object_domain, get_source_markdown_value, set_content_and_source},
ActorType, ActorType,
FromApub,
PersonExt, PersonExt,
ToApub,
}; };
use crate::objects::{FromApubToForm, ToApub, FromApub};
use activitystreams::{ use activitystreams::{
actor::{ApActor, Endpoints, Person}, actor::{ApActor, Endpoints, Person},
object::{ApObject, Image, Tombstone}, object::{ApObject, Image, Tombstone},
@ -81,7 +80,21 @@ impl ToApub for User_ {
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl FromApub for UserForm { impl FromApub for User_ {
type ApubType = PersonExt;
async fn from_apub(
note: &PersonExt,
context: &LemmyContext,
expected_domain: Option<Url>,
request_counter: &mut i32,
) -> Result<User_, LemmyError> {
todo!()
}
}
#[async_trait::async_trait(?Send)]
impl FromApubToForm for UserForm {
type ApubType = PersonExt; type ApubType = PersonExt;
async fn from_apub( async fn from_apub(