diff --git a/web/src/actors/header.rs b/web/src/actors/header.rs index ecb739f..86d3c64 100644 --- a/web/src/actors/header.rs +++ b/web/src/actors/header.rs @@ -13,18 +13,13 @@ pub fn ActorHeader() -> impl IntoView { move |id| { async move { match cache::OBJECTS.get(&Uri::full(U::Actor, &id)) { - Some(x) => Ok::<_, String>(x.clone()), + Some(x) => Some(x.clone()), None => { - let user : serde_json::Value = Http::fetch(&Uri::api(U::Actor, &id, true), auth) - .await - .map_err(|e| e.to_string())?; - let user = std::sync::Arc::new(user); - let uid = Uri::full(U::Actor, &id); - cache::OBJECTS.store(&uid, user.clone()); + let user = cache::OBJECTS.resolve(&id, U::Actor, auth).await?; if let Some(url) = user.url().id().str() { - cache::WEBFINGER.store(&url, uid); + cache::WEBFINGER.store(&url, user.id().unwrap_or_default().to_string()); } - Ok(user) + Some(user) }, } } @@ -32,8 +27,8 @@ pub fn ActorHeader() -> impl IntoView { ); move || match actor.get() { None => view! { }.into_view(), - Some(Err(e)) => view! { "could not resolve user: "{e} }.into_view(), - Some(Ok(actor)) => { + Some(None) => view! { "could not resolve user" }.into_view(), + Some(Some(actor)) => { let avatar_url = actor.icon().get().map(|x| x.url().id().str().unwrap_or(FALLBACK_IMAGE_URL.into())).unwrap_or(FALLBACK_IMAGE_URL.into()); let background_url = actor.image().get().map(|x| x.url().id().str().unwrap_or(FALLBACK_IMAGE_URL.into())).unwrap_or(FALLBACK_IMAGE_URL.into()); let username = actor.preferred_username().unwrap_or_default().to_string(); diff --git a/web/src/lib.rs b/web/src/lib.rs index 36c0f34..0dfdea4 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -41,7 +41,7 @@ pub mod cache { #[derive(Debug)] pub enum LookupStatus { - Resolving, + Resolving, // TODO use this to avoid fetching twice! Found(T), NotFound, } @@ -90,6 +90,26 @@ impl Cache for DashmapCache { } } +impl DashmapCache { + pub async fn resolve(&self, key: &str, kind: UriClass, auth: Auth) -> Option { + let full_key = Uri::full(kind, key); + match self.get(&full_key) { + Some(x) => Some(x), + None => { + let obj = match Http::fetch::(&Uri::api(kind, key, true), auth).await { + Ok(obj) => Arc::new(obj), + Err(e) => { + tracing::error!("failed loading object from backend: {e}"); + return None; + }, + }; + cache::OBJECTS.store(&full_key, obj.clone()); + Some(obj) + }, + } + } +} + // TODO would be cool unifying a bit the fetch code too impl DashmapCache { diff --git a/web/src/objects/view.rs b/web/src/objects/view.rs index 662c126..ee646fb 100644 --- a/web/src/objects/view.rs +++ b/web/src/objects/view.rs @@ -1,48 +1,28 @@ -use std::sync::Arc; - use leptos::*; use leptos_router::*; use crate::prelude::*; -use apb::{Base, Object}; +use apb::{Object}; #[component] pub fn ObjectView() -> impl IntoView { let params = use_params_map(); let auth = use_context::().expect("missing auth context"); - let feeds = use_context::().expect("missing feeds context"); let object = create_local_resource( move || params.get().get("id").cloned().unwrap_or_default(), move |oid| async move { - let obj = match cache::OBJECTS.get(&Uri::full(U::Object, &oid)) { - Some(x) => x.clone(), - None => { - let obj = match Http::fetch::(&Uri::api(U::Object, &oid, true), auth).await { - Ok(obj) => Arc::new(obj), - Err(e) => { - tracing::error!("failed loading object from backend: {e}"); - return None; - }, - }; - if let Ok(author) = obj.attributed_to().id() { - if let Ok(user) = Http::fetch::( - &Uri::api(U::Actor, author, true), auth - ).await { - cache::OBJECTS.store(&Uri::full(U::Actor, author), Arc::new(user)); - } - } - cache::OBJECTS.store(&Uri::full(U::Object, &oid), obj.clone()); - obj - } - }; - if let Ok(ctx) = obj.context().id() { - let tl_url = format!("{}/context/page", Uri::api(U::Object, ctx, false)); - if !feeds.context.next.get_untracked().starts_with(&tl_url) { - feeds.context.reset(Some(tl_url)); - } + let obj = cache::OBJECTS.resolve(&oid, U::Object, auth).await?; + if let Ok(author) = obj.attributed_to().id() { + cache::OBJECTS.resolve(&author, U::Actor, auth).await; } - Some(obj) + + // if let Ok(ctx) = obj.context().id() { + // let tl_url = format!("{}/context/page", Uri::api(U::Object, ctx, false)); + // if !feeds.context.next.get_untracked().starts_with(&tl_url) { + // feeds.context.reset(Some(tl_url)); + // } + // } } );