]> Untitled Git - lemmy.git/blob - crates/apub/src/fetcher/mod.rs
If viewed actor isnt in db, fetch it from other instance (#2145)
[lemmy.git] / crates / apub / src / fetcher / mod.rs
1 use crate::fetcher::webfinger::webfinger_resolve_actor;
2 use itertools::Itertools;
3 use lemmy_api_common::blocking;
4 use lemmy_apub_lib::traits::{ActorType, ApubObject};
5 use lemmy_db_schema::traits::ApubActor;
6 use lemmy_utils::{settings::structs::Settings, LemmyError};
7 use lemmy_websocket::LemmyContext;
8
9 pub mod post_or_comment;
10 pub mod search;
11 pub mod user_or_community;
12 pub mod webfinger;
13
14 /// Resolve actor identifier (eg `!news@example.com`) from local database to avoid network requests.
15 /// This only works for local actors, and remote actors which were previously fetched (so it doesnt
16 /// trigger any new fetch).
17 #[tracing::instrument(skip_all)]
18 pub async fn resolve_actor_identifier<Actor, DbActor>(
19   identifier: &str,
20   context: &LemmyContext,
21 ) -> Result<DbActor, LemmyError>
22 where
23   Actor:
24     ApubObject<DataType = LemmyContext> + ApubObject<DbType = DbActor> + ActorType + Send + 'static,
25   for<'de2> <Actor as ApubObject>::ApubType: serde::Deserialize<'de2>,
26   DbActor: ApubActor + Send + 'static,
27 {
28   // remote actor
29   if identifier.contains('@') {
30     let (name, domain) = identifier
31       .splitn(2, '@')
32       .collect_tuple()
33       .expect("invalid query");
34     let name = name.to_string();
35     let domain = format!("{}://{}", Settings::get().get_protocol_string(), domain);
36     let actor = blocking(context.pool(), move |conn| {
37       DbActor::read_from_name_and_domain(conn, &name, &domain)
38     })
39     .await?;
40     if actor.is_ok() {
41       Ok(actor?)
42     } else {
43       // Fetch the actor from its home instance using webfinger
44       let id = webfinger_resolve_actor::<Actor>(identifier, context, &mut 0).await?;
45       let actor: DbActor = blocking(context.pool(), move |conn| {
46         DbActor::read_from_apub_id(conn, &id)
47       })
48       .await??
49       .expect("actor exists as we fetched just before");
50       Ok(actor)
51     }
52   }
53   // local actor
54   else {
55     let identifier = identifier.to_string();
56     Ok(
57       blocking(context.pool(), move |conn| {
58         DbActor::read_from_name(conn, &identifier)
59       })
60       .await??,
61     )
62   }
63 }