feat: replace instance actor decorator with real DB row
All checks were successful
lint / lint (push) Successful in 14m31s
test / unit (push) Successful in 15m58s

Migration inserts a service actor with a well-known UUID. Removes the
InstanceActorUserRepo wrapper — the real ApUserRepository finds it.
This commit is contained in:
2026-05-30 03:16:01 +02:00
parent 0c8fa01ab9
commit 90d13c883b
3 changed files with 15 additions and 64 deletions

View File

@@ -1,57 +0,0 @@
use std::sync::Arc;
use async_trait::async_trait;
use k_ap::{ApActorType, ApUser, ApUserRepository};
pub const INSTANCE_ACTOR_ID: uuid::Uuid =
uuid::Uuid::from_bytes([0, 0, 0, 0, 0, 0, 0x40, 0, 0x80, 0, 0, 0, 0, 0, 0, 0]);
pub struct InstanceActorUserRepo {
inner: Arc<dyn ApUserRepository>,
base_url: String,
}
impl InstanceActorUserRepo {
pub fn new(inner: Arc<dyn ApUserRepository>, base_url: String) -> Self {
Self { inner, base_url }
}
}
fn instance_ap_user(base_url: &str) -> ApUser {
ApUser {
id: INSTANCE_ACTOR_ID,
username: "instance".to_string(),
display_name: None,
bio: None,
avatar_url: None,
banner_url: None,
also_known_as: vec![],
profile_url: url::Url::parse(base_url).ok(),
attachment: vec![],
manually_approves_followers: false,
discoverable: false,
actor_type: ApActorType::Service,
featured_url: None,
}
}
#[async_trait]
impl ApUserRepository for InstanceActorUserRepo {
async fn find_by_id(&self, id: uuid::Uuid) -> anyhow::Result<Option<ApUser>> {
if id == INSTANCE_ACTOR_ID {
return Ok(Some(instance_ap_user(&self.base_url)));
}
self.inner.find_by_id(id).await
}
async fn find_by_username(&self, username: &str) -> anyhow::Result<Option<ApUser>> {
if username == "instance" {
return Ok(Some(instance_ap_user(&self.base_url)));
}
self.inner.find_by_username(username).await
}
async fn count_users(&self) -> anyhow::Result<usize> {
self.inner.count_users().await
}
}

View File

@@ -1,10 +1,12 @@
pub mod handler; pub mod handler;
pub mod instance_actor;
pub mod note; pub mod note;
pub mod port; pub mod port;
pub mod service; pub mod service;
pub mod urls; pub mod urls;
pub const INSTANCE_ACTOR_ID: uuid::Uuid =
uuid::Uuid::from_bytes([0, 0, 0, 0, 0, 0, 0x40, 0, 0x80, 0, 0, 0, 0, 0, 0, 0]);
pub use handler::ThoughtsObjectHandler; pub use handler::ThoughtsObjectHandler;
pub use note::ThoughtNote; pub use note::ThoughtNote;
pub use port::{ pub use port::{
@@ -34,22 +36,18 @@ pub struct ApServiceConfig {
pub async fn build_ap_service( pub async fn build_ap_service(
cfg: ApServiceConfig, cfg: ApServiceConfig,
) -> (Arc<ActivityPubService>, Arc<ApFederationAdapter>) { ) -> (Arc<ActivityPubService>, Arc<ApFederationAdapter>) {
let user_repo = Arc::new(instance_actor::InstanceActorUserRepo::new(
cfg.user_repo,
cfg.base_url.clone(),
));
let mut builder = ActivityPubService::builder(cfg.base_url) let mut builder = ActivityPubService::builder(cfg.base_url)
.activity_repo(cfg.activity_repo) .activity_repo(cfg.activity_repo)
.follow_repo(cfg.follow_repo) .follow_repo(cfg.follow_repo)
.actor_repo(cfg.actor_repo) .actor_repo(cfg.actor_repo)
.blocklist_repo(cfg.blocklist_repo) .blocklist_repo(cfg.blocklist_repo)
.user_repo(user_repo) .user_repo(cfg.user_repo)
.content_reader(cfg.ap_handler.clone()) .content_reader(cfg.ap_handler.clone())
.object_handler(cfg.ap_handler) .object_handler(cfg.ap_handler)
.allow_registration(cfg.allow_registration) .allow_registration(cfg.allow_registration)
.software_name("thoughts") .software_name("thoughts")
.debug(cfg.debug) .debug(cfg.debug)
.signed_fetch_actor_id(instance_actor::INSTANCE_ACTOR_ID); .signed_fetch_actor_id(INSTANCE_ACTOR_ID);
if let Some(publisher) = cfg.event_publisher { if let Some(publisher) = cfg.event_publisher {
builder = builder.event_publisher(publisher); builder = builder.event_publisher(publisher);
} }

View File

@@ -0,0 +1,10 @@
INSERT INTO users (id, username, email, password_hash, display_name, bio)
VALUES (
'00000000-0000-4000-8000-000000000000',
'instance',
'noreply@instance.invalid',
'!service-actor-no-login',
NULL,
NULL
)
ON CONFLICT (id) DO NOTHING;