feat(web): webfinger cache

This commit is contained in:
əlemi 2024-05-23 16:16:27 +02:00
parent 06413322a3
commit b700e06d10
Signed by: alemi
GPG key ID: A4895B84D311642C
2 changed files with 66 additions and 1 deletions

View file

@ -34,3 +34,4 @@ lazy_static = "1.4"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
web-sys = { version = "0.3", features = ["Screen"] } web-sys = { version = "0.3", features = ["Screen"] }
mdhtml = { path = "../mdhtml/" } mdhtml = { path = "../mdhtml/" }
jrd = "0.1.0"

View file

@ -24,12 +24,13 @@ use uriproxy::UriClass;
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref CACHE: ObjectCache = ObjectCache::default(); pub static ref CACHE: ObjectCache = ObjectCache::default();
pub static ref WEBFINGER: WebfingerCache = WebfingerCache::default();
} }
pub type Object = Arc<serde_json::Value>; pub type Object = Arc<serde_json::Value>;
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct ObjectCache(pub Arc<dashmap::DashMap<String, Object>>); pub struct ObjectCache(Arc<dashmap::DashMap<String, Object>>);
impl ObjectCache { impl ObjectCache {
pub fn get(&self, k: &str) -> Option<Object> { pub fn get(&self, k: &str) -> Option<Object> {
@ -59,6 +60,69 @@ impl ObjectCache {
} }
} }
#[derive(Debug, Clone)]
enum LookupStatus {
Resolving,
Found(String),
NotFound,
}
#[derive(Debug, Clone, Default)]
pub struct WebfingerCache(Arc<dashmap::DashMap<String, LookupStatus>>);
impl WebfingerCache {
pub async fn blocking_resolve(&self, user: &str, domain: &str) -> Option<String> {
if let Some(x) = self.get(user, domain) { return Some(x); }
self.fetch(user, domain).await;
self.get(user, domain)
}
pub fn resolve(&self, user: &str, domain: &str) -> Option<String> {
if let Some(x) = self.get(user, domain) { return Some(x); }
let (_self, user, domain) = (self.clone(), user.to_string(), domain.to_string());
leptos::spawn_local(async move { _self.fetch(&user, &domain).await });
None
}
fn get(&self, user: &str, domain: &str) -> Option<String> {
let query = format!("{user}@{domain}");
match self.0.get(&query).map(|x| (*x).clone())? {
LookupStatus::Resolving | LookupStatus::NotFound => None,
LookupStatus::Found(x) => Some(x),
}
}
async fn fetch(&self, user: &str, domain: &str) {
let query = format!("{user}@{domain}");
self.0.insert(query.to_string(), LookupStatus::Resolving);
match reqwest::get(format!("{URL_BASE}/.well-known/webfinger?resource=acct:{query}")).await {
Ok(res) => match res.error_for_status() {
Ok(res) => match res.json::<jrd::JsonResourceDescriptor>().await {
Ok(doc) => {
if let Some(uid) = doc.links.into_iter().find(|x| x.rel == "self").map(|x| x.href).flatten() {
self.0.insert(query, LookupStatus::Found(uid));
} else {
self.0.insert(query, LookupStatus::NotFound);
}
},
Err(e) => {
tracing::error!("invalid webfinger response: {e:?}");
self.0.remove(&query);
},
},
Err(e) => {
tracing::error!("could not resolve webfinbger: {e:?}");
self.0.insert(query, LookupStatus::NotFound);
},
},
Err(e) => {
tracing::error!("failed accessing webfinger server: {e:?}");
self.0.remove(&query);
},
}
}
}
pub struct Http; pub struct Http;