feat: fetch instance info when fetching other stuff

This commit is contained in:
əlemi 2024-05-28 03:10:10 +02:00
parent 1b08321d34
commit e0273d5155
Signed by: alemi
GPG key ID: A4895B84D311642C

View file

@ -3,7 +3,7 @@ use std::collections::BTreeMap;
use apb::{target::Addressed, Activity, Actor, ActorMut, Base, Collection, Object};
use base64::Engine;
use reqwest::{header::{ACCEPT, CONTENT_TYPE, USER_AGENT}, Method, Response};
use sea_orm::EntityTrait;
use sea_orm::{EntityTrait, IntoActiveModel, NotSet};
use crate::{errors::UpubError, model, VERSION};
@ -13,6 +13,8 @@ use super::{httpsign::HttpSignature, normalizer::Normalizer, Context};
pub trait Fetcher {
async fn webfinger(&self, user: &str, host: &str) -> crate::Result<String>;
async fn fetch_domain(&self, domain: &str) -> crate::Result<model::instance::Model>;
async fn fetch_user(&self, id: &str) -> crate::Result<model::actor::Model>;
async fn pull_user(&self, id: &str) -> crate::Result<serde_json::Value>;
@ -114,12 +116,62 @@ impl Fetcher for Context {
Err(UpubError::not_found())
}
async fn fetch_domain(&self, domain: &str) -> crate::Result<model::instance::Model> {
if let Some(x) = model::instance::Entity::find_by_domain(domain).one(self.db()).await? {
return Ok(x); // already in db, easy
}
let mut instance_model = model::instance::Model {
internal: 0,
domain: domain.to_string(),
name: None,
software: None,
down_since: None,
icon: None,
version: None,
users: None,
posts: None,
published: chrono::Utc::now(),
updated: chrono::Utc::now(),
};
if let Ok(res) = Self::request(
Method::GET, &format!("https://{domain}"), None, &format!("https://{}", self.domain()), self.pkey(), self.domain(),
).await {
if let Ok(actor) = res.json::<serde_json::Value>().await {
if let Some(name) = actor.name() {
instance_model.name = Some(name.to_string());
}
if let Some(icon) = actor.icon().id() {
instance_model.icon = Some(icon);
}
}
}
if let Ok(nodeinfo) = model::instance::Entity::nodeinfo(domain).await {
instance_model.software = Some(nodeinfo.software.name);
instance_model.version = nodeinfo.software.version;
instance_model.users = nodeinfo.usage.users.and_then(|x| x.total);
instance_model.posts = nodeinfo.usage.local_posts;
}
let mut active_model = instance_model.clone().into_active_model();
active_model.internal = NotSet;
model::instance::Entity::insert(active_model).exec(self.db()).await?;
let internal = model::instance::Entity::domain_to_internal(domain, self.db()).await?;
instance_model.internal = internal;
Ok(instance_model)
}
async fn fetch_user(&self, id: &str) -> crate::Result<model::actor::Model> {
if let Some(x) = model::actor::Entity::find_by_ap_id(id).one(self.db()).await? {
return Ok(x); // already in db, easy
}
let _domain = self.fetch_domain(&Context::server(id)).await?;
let user_document = self.pull_user(id).await?;
let user_model = model::actor::ActiveModel::new(&user_document)?;
@ -179,6 +231,8 @@ impl Fetcher for Context {
return Ok(x); // already in db, easy
}
let _domain = self.fetch_domain(&Context::server(id)).await?;
let activity_document = self.pull_activity(id).await?;
let activity_model = self.insert_activity(activity_document, Some(Context::server(id))).await?;
@ -236,6 +290,8 @@ async fn fetch_object_inner(ctx: &Context, id: &str, depth: usize) -> crate::Res
return Ok(x); // already in db, easy
}
let _domain = ctx.fetch_domain(&Context::server(id)).await?;
let object = ctx.pull_object(id).await?;
if let Some(oid) = object.id() {