diff --git a/packages/backend/src/remote/activitypub/deliver-manager.ts b/packages/backend/src/remote/activitypub/deliver-manager.ts index e0af5b8f9..1f5702ae7 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') + // 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') + .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" みたいな問い合わせにすればよりパフォーマンス向上できそう diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts index 02df9e97f..572fc8251 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'].includes(note.visibility)) { + manager.addFollowersRecipe(); + } + + if (['public', 'home'].includes(note.visibility)) { + manager.addEveryone(); + } + + await manager.execute(); + + deliverToRelays(user, content); }