mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-19 05:55:34 +09:00
refactor(api): drop Bunny for pluggable cache purge adapters (#2742)
This commit is contained in:
1 parent
84dcf6b8a8
commit
ca7ddd9272
45 files changed
+929
-977
No files matched your search
@@ -21,7 +21,7 @@ import {
|
||||
} from '@app/api/channel/services/message/MessageHelpers';
|
||||
import {applyUploadRelayDecision, resolveUploadRelayDecision} from '@app/api/channel/services/UploadRelay';
|
||||
import {SYSTEM_USER_ID} from '@app/api/constants/Core';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/BunnyPurgeQueue';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/CachePurgeQueue';
|
||||
import type {IGatewayService} from '@app/api/infrastructure/IGatewayService';
|
||||
import type {IStorageService} from '@app/api/infrastructure/IStorageService';
|
||||
import type {LimitConfigService} from '@app/api/limits/LimitConfigService';
|
||||
@@ -387,10 +387,8 @@ export class AttachmentUploadService {
|
||||
}
|
||||
const cdnKey = makeAttachmentCdnKey(message.channelId, attachment.id, attachment.filename);
|
||||
await this.storageService.deleteObject(Config.s3.buckets.cdn, cdnKey);
|
||||
if (Config.bunny.purgeEnabled) {
|
||||
const cdnUrl = makeAttachmentCdnUrl(message.channelId, attachment.id, attachment.filename);
|
||||
await this.purgeQueue.addUrls([cdnUrl]);
|
||||
}
|
||||
const cdnUrl = makeAttachmentCdnUrl(message.channelId, attachment.id, attachment.filename);
|
||||
await this.purgeQueue.addUrls([cdnUrl]);
|
||||
const updatedAttachments = message.attachments.filter((a: Attachment) => a.id !== attachmentId);
|
||||
const updatedRowData = {
|
||||
...message.toRow(),
|
||||
|
||||
@@ -12,7 +12,7 @@ import type {MessagePersistenceService} from '@app/api/channel/services/message/
|
||||
import type {GuildAuditLogService} from '@app/api/guild/GuildAuditLogService';
|
||||
import type {IGuildRepositoryAggregate} from '@app/api/guild/repositories/IGuildRepositoryAggregate';
|
||||
import type {AvatarService} from '@app/api/infrastructure/AvatarService';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/BunnyPurgeQueue';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/CachePurgeQueue';
|
||||
import type {IGatewayService} from '@app/api/infrastructure/IGatewayService';
|
||||
import type {ILiveKitService} from '@app/api/infrastructure/ILiveKitService';
|
||||
import type {ISnowflakeService} from '@app/api/infrastructure/ISnowflakeService';
|
||||
|
||||
@@ -16,7 +16,7 @@ import type {IFavoriteMemeRepository} from '@app/api/favorite_meme/IFavoriteMeme
|
||||
import type {GuildAuditLogService} from '@app/api/guild/GuildAuditLogService';
|
||||
import type {IGuildRepositoryAggregate} from '@app/api/guild/repositories/IGuildRepositoryAggregate';
|
||||
import type {AvatarService} from '@app/api/infrastructure/AvatarService';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/BunnyPurgeQueue';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/CachePurgeQueue';
|
||||
import type {EmbedService} from '@app/api/infrastructure/EmbedService';
|
||||
import type {ILiveKitService} from '@app/api/infrastructure/ILiveKitService';
|
||||
import type {IStorageService} from '@app/api/infrastructure/IStorageService';
|
||||
|
||||
@@ -20,7 +20,7 @@ import {MessageValidationService} from '@app/api/channel/services/message/Messag
|
||||
import type {IFavoriteMemeRepository} from '@app/api/favorite_meme/IFavoriteMemeRepository';
|
||||
import type {GuildAuditLogService} from '@app/api/guild/GuildAuditLogService';
|
||||
import type {IGuildRepositoryAggregate} from '@app/api/guild/repositories/IGuildRepositoryAggregate';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/BunnyPurgeQueue';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/CachePurgeQueue';
|
||||
import type {IGatewayService} from '@app/api/infrastructure/IGatewayService';
|
||||
import type {IMediaService} from '@app/api/infrastructure/IMediaService';
|
||||
import type {ISnowflakeService} from '@app/api/infrastructure/ISnowflakeService';
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {IChannelRepositoryAggregate} from '@app/api/channel/repositories/IC
|
||||
import {dispatchChannelEvent} from '@app/api/channel/services/ChannelGatewayDispatch';
|
||||
import {dispatchMessageCreateBroadcast} from '@app/api/channel/services/message/MessageGatewayDispatch';
|
||||
import {purgeMessageAttachments} from '@app/api/channel/services/message/MessageHelpers';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/BunnyPurgeQueue';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/CachePurgeQueue';
|
||||
import type {IGatewayService} from '@app/api/infrastructure/IGatewayService';
|
||||
import type {IStorageService} from '@app/api/infrastructure/IStorageService';
|
||||
import type {UserCacheService} from '@app/api/infrastructure/UserCacheService';
|
||||
|
||||
@@ -9,7 +9,7 @@ import {isOperationDisabled, purgeMessageAttachments} from '@app/api/channel/ser
|
||||
import type {MessageSearchService} from '@app/api/channel/services/message/MessageSearchService';
|
||||
import type {MessageValidationService} from '@app/api/channel/services/message/MessageValidationService';
|
||||
import type {GuildAuditLogService} from '@app/api/guild/GuildAuditLogService';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/BunnyPurgeQueue';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/CachePurgeQueue';
|
||||
import type {IGatewayService} from '@app/api/infrastructure/IGatewayService';
|
||||
import type {IStorageService} from '@app/api/infrastructure/IStorageService';
|
||||
import type {RequestCache} from '@app/api/middleware/RequestCacheMiddleware';
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {createAttachmentID, createChannelID, createMessageID, createUserID} from '@app/api/BrandedTypes';
|
||||
import {Config} from '@app/api/Config';
|
||||
import {purgeMessageAttachments} from '@app/api/channel/services/message/MessageHelpers';
|
||||
import type {MessageEmbed} from '@app/api/database/types/MessageTypes';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/CachePurgeQueue';
|
||||
import type {IStorageService} from '@app/api/infrastructure/IStorageService';
|
||||
import {Message} from '@app/api/models/Message';
|
||||
import {MessageTypes} from '@fluxer/constants/src/ChannelConstants';
|
||||
import {describe, expect, it} from 'vitest';
|
||||
|
||||
const CHANNEL_ID = createChannelID(10n);
|
||||
const ATTACHMENT_KEY = 'attachments/10/200/ação.png';
|
||||
const OTHER_MESSAGE_ATTACHMENT_KEY = 'attachments/11/300/photo.jpg';
|
||||
|
||||
function imageEmbed(key: string): MessageEmbed {
|
||||
return {
|
||||
type: 'image',
|
||||
title: null,
|
||||
description: null,
|
||||
url: null,
|
||||
timestamp: null,
|
||||
color: null,
|
||||
author: null,
|
||||
provider: null,
|
||||
thumbnail: null,
|
||||
image: {
|
||||
url: `${Config.endpoints.media}/${key}`,
|
||||
width: 16,
|
||||
height: 16,
|
||||
description: null,
|
||||
content_type: 'image/png',
|
||||
content_hash: null,
|
||||
placeholder: null,
|
||||
flags: 0,
|
||||
duration: null,
|
||||
},
|
||||
video: null,
|
||||
footer: null,
|
||||
fields: null,
|
||||
nsfw: null,
|
||||
};
|
||||
}
|
||||
|
||||
function makeMessageWithMedia(): Message {
|
||||
return new Message({
|
||||
channel_id: CHANNEL_ID,
|
||||
bucket: 0,
|
||||
message_id: createMessageID(100n),
|
||||
author_id: createUserID(3n),
|
||||
type: MessageTypes.DEFAULT,
|
||||
webhook_id: null,
|
||||
webhook_name: null,
|
||||
webhook_avatar_hash: null,
|
||||
content: '',
|
||||
edited_timestamp: null,
|
||||
pinned_timestamp: null,
|
||||
flags: 0,
|
||||
mention_everyone: false,
|
||||
mention_users: null,
|
||||
mention_roles: null,
|
||||
mention_channels: null,
|
||||
attachments: [
|
||||
{
|
||||
attachment_id: createAttachmentID(200n),
|
||||
filename: 'ação.png',
|
||||
size: 1024n,
|
||||
title: null,
|
||||
description: null,
|
||||
width: 16,
|
||||
height: 16,
|
||||
content_type: 'image/png',
|
||||
content_hash: null,
|
||||
placeholder: null,
|
||||
flags: 0,
|
||||
duration: null,
|
||||
nsfw: null,
|
||||
waveform: null,
|
||||
},
|
||||
],
|
||||
embeds: [imageEmbed(ATTACHMENT_KEY), imageEmbed(OTHER_MESSAGE_ATTACHMENT_KEY)],
|
||||
sticker_items: null,
|
||||
message_reference: null,
|
||||
message_snapshots: null,
|
||||
call: null,
|
||||
has_reaction: null,
|
||||
version: 1,
|
||||
});
|
||||
}
|
||||
|
||||
describe('purgeMessageAttachments', () => {
|
||||
it('queues each stored media URL of a deleted message once and leaves media of other messages alone', async () => {
|
||||
const deletedObjects: Array<string> = [];
|
||||
const queuedUrls: Array<string> = [];
|
||||
const storageService = {
|
||||
deleteObject: async (bucket: string, key: string) => {
|
||||
deletedObjects.push(`${bucket}/${key}`);
|
||||
},
|
||||
} as unknown as IStorageService;
|
||||
const purgeQueue: IPurgeQueue = {
|
||||
addUrls: async (urls) => {
|
||||
queuedUrls.push(...urls);
|
||||
},
|
||||
};
|
||||
|
||||
await purgeMessageAttachments(makeMessageWithMedia(), storageService, purgeQueue);
|
||||
|
||||
expect(deletedObjects).toEqual([`${Config.s3.buckets.cdn}/${ATTACHMENT_KEY}`]);
|
||||
expect(queuedUrls).toEqual([`${Config.endpoints.media}/${ATTACHMENT_KEY}`]);
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
MessageSnapshot as CassandraMessageSnapshot,
|
||||
MessageAttachment,
|
||||
} from '@app/api/database/types/MessageTypes';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/BunnyPurgeQueue';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/CachePurgeQueue';
|
||||
import type {ISnowflakeService} from '@app/api/infrastructure/ISnowflakeService';
|
||||
import type {IStorageService} from '@app/api/infrastructure/IStorageService';
|
||||
import {Logger} from '@app/api/Logger';
|
||||
@@ -353,21 +353,17 @@ export async function purgeMessageAttachments(
|
||||
continue;
|
||||
}
|
||||
cdnKeys.add(cdnKey);
|
||||
if (Config.bunny.purgeEnabled) {
|
||||
cdnUrls.push(makeAttachmentCdnUrl(message.channelId, attachment.id, attachment.filename));
|
||||
}
|
||||
cdnUrls.push(makeAttachmentCdnUrl(message.channelId, attachment.id, attachment.filename));
|
||||
}
|
||||
for (const embedKey of collectEmbedReferencedAttachmentCdnKeys(message, ownedCdnKeys)) {
|
||||
if (cdnKeys.has(embedKey)) {
|
||||
continue;
|
||||
}
|
||||
cdnKeys.add(embedKey);
|
||||
if (Config.bunny.purgeEnabled) {
|
||||
cdnUrls.push(`${Config.endpoints.media}/${embedKey}`);
|
||||
}
|
||||
cdnUrls.push(`${Config.endpoints.media}/${embedKey}`);
|
||||
}
|
||||
await Promise.all([...cdnKeys].map((cdnKey) => storageService.deleteObject(Config.s3.buckets.cdn, cdnKey)));
|
||||
if (Config.bunny.purgeEnabled && cdnUrls.length > 0) {
|
||||
if (cdnUrls.length > 0) {
|
||||
await purgeQueue.addUrls(cdnUrls);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
type SelfMessageFilter,
|
||||
} from '@app/api/channel/services/message/SelfMessageFilter';
|
||||
import {assertMutableUserId} from '@app/api/constants/Core';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/BunnyPurgeQueue';
|
||||
import type {IPurgeQueue} from '@app/api/infrastructure/CachePurgeQueue';
|
||||
import type {IGatewayService} from '@app/api/infrastructure/IGatewayService';
|
||||
import type {IStorageService} from '@app/api/infrastructure/IStorageService';
|
||||
import {Logger} from '@app/api/Logger';
|
||||
|
||||
Reference in new issue
Block a user