From 8920eeb86af5c29e576b6a10784696edb02731f7 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Tue, 11 Oct 2022 00:27:43 +0200 Subject: [PATCH 1/4] ActivityPub: allow all known shared inboxes to be addressed This is oriented on this paragraph from the AP spec: > Additionally, if an object is addressed to the Public special collection, > a server MAY deliver that object to all known sharedInbox endpoints > on the network. --- .../src/remote/activitypub/deliver-manager.ts | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/remote/activitypub/deliver-manager.ts b/packages/backend/src/remote/activitypub/deliver-manager.ts index e0af5b8f9..5fd0d5f60 100644 --- a/packages/backend/src/remote/activitypub/deliver-manager.ts +++ b/packages/backend/src/remote/activitypub/deliver-manager.ts @@ -8,6 +8,10 @@ interface IRecipe { type: string; } +interface IEveryoneRecipe extends IRecipe { + type: 'Everyone'; +} + interface IFollowersRecipe extends IRecipe { type: 'Followers'; } @@ -17,6 +21,9 @@ interface IDirectRecipe extends IRecipe { to: IRemoteUser; } +const isEveryone = (recipe: any): recipe is IEveryoneRecipe => + recipe.type === 'Everyone'; + const isFollowers = (recipe: any): recipe is IFollowersRecipe => recipe.type === 'Followers'; @@ -63,6 +70,13 @@ export default class DeliverManager { this.addRecipe(recipe); } + /** + * Add recipe to send this activity to all known sharedInboxes + */ + public addEveryone() { + this.addRecipe({ type: 'Everyone' } as IEveryoneRecipe); + } + /** * Add recipe * @param recipe Recipe @@ -82,9 +96,26 @@ export default class DeliverManager { /* build inbox list - Process follower recipes first to avoid duplication when processing - direct recipes later. + Processing order matters to avoid duplication. */ + + if (this.recipes.some(r => isEveryone(r))) { + // deliver to all of known network + const sharedInboxes = await Users.createQueryBuilder('users') + .select('users.sharedInbox', 'sharedInbox') + // can't deliver to unknown shared inbox + .where('users.sharedInbox IS NOT NULL') + // don't deliver to ourselves + .andWhere('users.host IS NOT NULL') + // so we don't have to make our inboxes Set work as hard + .groupBy('users.sharedInbox') + .getRawMany(); + + for (const inbox of sharedInboxes) { + inboxes.add(inbox.sharedInbox); + } + } + if (this.recipes.some(r => isFollowers(r))) { // followers deliver // TODO: SELECT DISTINCT ON ("followerSharedInbox") "followerSharedInbox" みたいな問い合わせにすればよりパフォーマンス向上できそう From 421b42d07da18ad6fdc50434596801a7d2157a93 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Tue, 11 Oct 2022 00:30:32 +0200 Subject: [PATCH 2/4] backend: send delete activity to all known instances closes https://akkoma.dev/FoundKeyGang/FoundKey/issues/190 Changelog: Added --- packages/backend/src/services/note/delete.ts | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts index 61b75c963..f23ec2616 100644 --- a/packages/backend/src/services/note/delete.ts +++ b/packages/backend/src/services/note/delete.ts @@ -10,7 +10,7 @@ import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; import { Note } from '@/models/entities/note.js'; import { Notes, Users, Instances } from '@/models/index.js'; import { notesChart, perUserNotesChart, instanceChart } from '@/services/chart/index.js'; -import { deliverToFollowers, deliverToUser } from '@/remote/activitypub/deliver-manager.js'; +import DeliverManager from '@/remote/activitypub/deliver-manager.js'; import { countSameRenotes } from '@/misc/count-same-renotes.js'; import { isPureRenote } from '@/misc/renote.js'; import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; @@ -132,10 +132,22 @@ async function getMentionedRemoteUsers(note: Note): Promise { } async function deliverToConcerned(user: { id: ILocalUser['id']; host: null; }, note: Note, content: any) { - deliverToFollowers(user, content); - deliverToRelays(user, content); + const manager = new DeliverManager(user, content); + const remoteUsers = await getMentionedRemoteUsers(note); for (const remoteUser of remoteUsers) { - deliverToUser(user, content, remoteUser); + manager.addDirectRecipe(remoteUser); } + + if (['public', 'home', 'followers'].contains(note.visibility)) { + manager.addFollowersRecipe(); + } + + if (['public', 'home'].contains(note.visibility)) { + manager.addEveryone(); + } + + await manager.execute(); + + deliverToRelays(user, content); } From 0b8fa2665cc7f7fd4ca1b5a5694e1d6e4ee5dbcc Mon Sep 17 00:00:00 2001 From: Johann150 Date: Tue, 11 Oct 2022 20:15:59 +0200 Subject: [PATCH 3/4] use DISTINCT instead of GROUP BY This should have better performance for large recordsets. Ref: https://akkoma.dev/FoundKeyGang/FoundKey/pulls/198#issuecomment-4032 --- packages/backend/src/remote/activitypub/deliver-manager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/remote/activitypub/deliver-manager.ts b/packages/backend/src/remote/activitypub/deliver-manager.ts index 5fd0d5f60..1f5702ae7 100644 --- a/packages/backend/src/remote/activitypub/deliver-manager.ts +++ b/packages/backend/src/remote/activitypub/deliver-manager.ts @@ -103,12 +103,12 @@ export default class DeliverManager { // deliver to all of known network const sharedInboxes = await Users.createQueryBuilder('users') .select('users.sharedInbox', 'sharedInbox') + // so we don't have to make our inboxes Set work as hard + .distinct(true) // can't deliver to unknown shared inbox .where('users.sharedInbox IS NOT NULL') // don't deliver to ourselves .andWhere('users.host IS NOT NULL') - // so we don't have to make our inboxes Set work as hard - .groupBy('users.sharedInbox') .getRawMany(); for (const inbox of sharedInboxes) { From 7cd11e7afd51cd8f6ede64a4bc9fae220d084200 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Tue, 11 Oct 2022 21:26:20 +0200 Subject: [PATCH 4/4] fix function name --- packages/backend/src/services/note/delete.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts index f23ec2616..8076f1daa 100644 --- a/packages/backend/src/services/note/delete.ts +++ b/packages/backend/src/services/note/delete.ts @@ -139,11 +139,11 @@ async function deliverToConcerned(user: { id: ILocalUser['id']; host: null; }, n manager.addDirectRecipe(remoteUser); } - if (['public', 'home', 'followers'].contains(note.visibility)) { + if (['public', 'home', 'followers'].includes(note.visibility)) { manager.addFollowersRecipe(); } - if (['public', 'home'].contains(note.visibility)) { + if (['public', 'home'].includes(note.visibility)) { manager.addEveryone(); }