From 74b3c19c3f851d6d91ce762de94c96fdc8c4c5c8 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 26 Jun 2025 12:47:23 +0900 Subject: [PATCH 1/4] wip --- packages/backend/src/core/ChatService.ts | 16 +++++++++ .../src/core/activitypub/ApRendererService.ts | 33 ++++++++++++++++++- packages/backend/src/models/ChatMessage.ts | 20 +++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/core/ChatService.ts b/packages/backend/src/core/ChatService.ts index 5cd336a097..565141ea9c 100644 --- a/packages/backend/src/core/ChatService.ts +++ b/packages/backend/src/core/ChatService.ts @@ -28,6 +28,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { emojiRegex } from '@/misc/emoji-regex.js'; import { NotificationService } from '@/core/NotificationService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js'; +import { trackPromise } from '@/misc/promise-tracker.js'; const MAX_ROOM_MEMBERS = 50; const MAX_REACTIONS_PER_MESSAGE = 100; @@ -81,6 +83,7 @@ export class ChatService { private chatEntityService: ChatEntityService, private idService: IdService, private globalEventService: GlobalEventService, + private apDeliverManagerService: ApDeliverManagerService, private apRendererService: ApRendererService, private queueService: QueueService, private pushNotificationService: PushNotificationService, @@ -236,6 +239,19 @@ export class ChatService { }, 3000); } + //#region AP deliver + if (this.userEntityService.isLocalUser(fromUser) && this.userEntityService.isRemoteUser(toUser)) { + (async () => { + const content = await this.apRendererService.renderChatMessage(inserted, false); + const activity = this.apRendererService.addContext(content); + + const dm = this.apDeliverManagerService.createDeliverManager(fromUser, activity); + dm.addDirectRecipe(toUser); + trackPromise(dm.execute()); + })(); + } + //#endregion + return packedMessage; } diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 55521d6e3a..9a84d77e0b 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -23,7 +23,7 @@ import { MfmService, type Appender } from '@/core/MfmService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import type { MiUserKeypair } from '@/models/UserKeypair.js'; -import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository, MiMeta } from '@/models/_.js'; +import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository, MiMeta, MiChatMessage } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { IdService } from '@/core/IdService.js'; @@ -502,6 +502,37 @@ export class ApRendererService { }; } + @bindThis + public async renderChatMessage(message: MiChatMessage, dive = true): Promise { + const getPromisedFiles = async (ids: string[]): Promise => { + if (ids.length === 0) return []; + const items = await this.driveFilesRepository.findBy({ id: In(ids) }); + return ids.map(id => items.find(item => item.id === id)).filter(x => x != null); + }; + + const attributedTo = this.userEntityService.genLocalUserUri(message.fromUserId); + + const files = await getPromisedFiles([message.fileId]); + + const emojis = await this.getEmojis(message.emojis); + const apemojis = emojis.filter(emoji => !emoji.localOnly).map(emoji => this.renderEmoji(emoji)); + + const tag = [ + ...apemojis, + ]; + + return { + id: `${this.config.url}/chat-messages/${message.id}`, + type: 'Misskey:ChatMessage', + attributedTo, + text: message.text, + published: this.idService.parse(note.id).date.toISOString(), + to: message.toUserId, + attachment: files.map(x => this.renderDocument(x)), + tag, + }; + } + @bindThis public async renderPerson(user: MiLocalUser) { const id = this.userEntityService.genLocalUserUri(user.id); diff --git a/packages/backend/src/models/ChatMessage.ts b/packages/backend/src/models/ChatMessage.ts index 3d2b64268e..ca647efee9 100644 --- a/packages/backend/src/models/ChatMessage.ts +++ b/packages/backend/src/models/ChatMessage.ts @@ -55,6 +55,8 @@ export class MiChatMessage { }) public text: string | null; + // 連合用 + // ローカルはnull @Column('varchar', { length: 512, nullable: true, }) @@ -82,4 +84,22 @@ export class MiChatMessage { length: 1024, array: true, default: '{}', }) public reactions: string[]; + + // 連合用 + @Column('varchar', { + length: 128, array: true, default: '{}', + }) + public emojis: string[]; + + // 連合用 + @Column('boolean', { + default: false, + }) + public isDelivering: boolean; + + // 連合用 + @Column('boolean', { + default: false, + }) + public isDeliverFailed: boolean; } From a1da2135ebfce1cb5be2d23fbf403454052f2eba Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:22:21 +0900 Subject: [PATCH 2/4] Update ApRendererService.ts --- .../src/core/activitypub/ApRendererService.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 9a84d77e0b..0bf6627491 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -504,15 +504,9 @@ export class ApRendererService { @bindThis public async renderChatMessage(message: MiChatMessage, dive = true): Promise { - const getPromisedFiles = async (ids: string[]): Promise => { - if (ids.length === 0) return []; - const items = await this.driveFilesRepository.findBy({ id: In(ids) }); - return ids.map(id => items.find(item => item.id === id)).filter(x => x != null); - }; - const attributedTo = this.userEntityService.genLocalUserUri(message.fromUserId); - const files = await getPromisedFiles([message.fileId]); + const file = message.fileId ? await this.driveFilesRepository.findOneBy({ id: message.fileId }) : null; const emojis = await this.getEmojis(message.emojis); const apemojis = emojis.filter(emoji => !emoji.localOnly).map(emoji => this.renderEmoji(emoji)); @@ -526,9 +520,9 @@ export class ApRendererService { type: 'Misskey:ChatMessage', attributedTo, text: message.text, - published: this.idService.parse(note.id).date.toISOString(), + published: this.idService.parse(message.id).date.toISOString(), to: message.toUserId, - attachment: files.map(x => this.renderDocument(x)), + attachment: file ? [this.renderDocument(file)] : [], tag, }; } From b5f284aae310c6f49f853d7dc89746f8850ad152 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:25:11 +0900 Subject: [PATCH 3/4] Update ApInboxService.ts --- packages/backend/src/core/activitypub/ApInboxService.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index e88f60b806..bd7edf4c44 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -457,6 +457,11 @@ export class ApInboxService { } } + @bindThis + private async chatMessage(actor: MiRemoteUser, activity: IChatMessage): Promise { + const targetUri = getApId(activity.object); + } + @bindThis private async delete(actor: MiRemoteUser, activity: IDelete): Promise { if (actor.uri !== activity.actor) { From d287d43c9841049f48cda99e84c35f9730f956a8 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:33:20 +0900 Subject: [PATCH 4/4] Update ApInboxService.ts --- .../src/core/activitypub/ApInboxService.ts | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index bd7edf4c44..786f2078d5 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -458,8 +458,33 @@ export class ApInboxService { } @bindThis - private async chatMessage(actor: MiRemoteUser, activity: IChatMessage): Promise { - const targetUri = getApId(activity.object); + private async chatMessage(resolver: Resolver, actor: MiRemoteUser, message: IObject): Promise { + const uri = getApId(message); + + if (typeof message === 'object') { + if (actor.uri !== message.attributedTo) { + return 'skip: actor.uri !== message.attributedTo'; + } + + if (typeof message.id === 'string') { + if (this.utilityService.extractDbHost(actor.uri) !== this.utilityService.extractDbHost(message.id)) { + return 'skip: host in actor.uri !== message.id'; + } + } else { + return 'skip: message.id is not a string'; + } + } + + try { + await this.chatService.createMessageViaAp(message, actor, resolver); + return 'ok'; + } catch (err) { + if (err instanceof StatusError && !err.isRetryable) { + return `skip ${err.statusCode}`; + } else { + throw err; + } + } } @bindThis