[backend] Rework media proxying for better performance

This commit is contained in:
Laura Hausmann 2023-11-22 18:47:32 +01:00
parent c00e28712e
commit 4e6e22633e
No known key found for this signature in database
GPG Key ID: D044E84C5BE01605
4 changed files with 36 additions and 14 deletions

View File

@ -31,6 +31,11 @@ export function metaToPugArgs(meta: Meta): object {
}; };
} }
export function fetchMetaSync(): Meta | null {
return cache;
}
export async function fetchMeta(noCache = false): Promise<Meta> { export async function fetchMeta(noCache = false): Promise<Meta> {
if (!noCache && cache) return cache; if (!noCache && cache) return cache;

View File

@ -8,6 +8,7 @@ import config from "@/config/index.js";
import { appendQuery, query } from "@/prelude/url.js"; import { appendQuery, query } from "@/prelude/url.js";
import { DriveFolders, Users } from "../index.js"; import { DriveFolders, Users } from "../index.js";
import { deepClone } from "@/misc/clone.js"; import { deepClone } from "@/misc/clone.js";
import { fetchMetaSync } from "@/misc/fetch-meta.js";
type PackOptions = { type PackOptions = {
detail?: boolean; detail?: boolean;
@ -71,14 +72,9 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({
); );
} }
// リモートかつ期限切れはローカルプロキシを試みる if (file.isLink && config.proxyRemoteFiles) {
if (file.uri != null && file.isLink && config.proxyRemoteFiles) { const url = this.getDatabasePrefetchUrl(file, thumbnail);
const key = thumbnail ? file.thumbnailAccessKey : file.webpublicAccessKey; if (url != null) return `${config.url}/proxy/${encodeURIComponent(new URL(url).pathname)}?${query({ url: url })}`;
if (key && !key.match("/")) {
// 古いものはここにオブジェクトストレージキーが入ってるので除外
return `${config.url}/files/${key}`;
}
} }
return thumbnail return thumbnail
@ -92,6 +88,25 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({
: file.webpublicUrl ?? file.url; : file.webpublicUrl ?? file.url;
}, },
getFinalUrl(url: string): string {
if (!config.proxyRemoteFiles) return url;
if (url.startsWith(`${config.url}/files`)) return url;
if (url.startsWith(`${config.url}/static-assets`)) return url;
if (url.startsWith(`${config.url}/identicon`)) return url;
if (url.startsWith(`${config.url}/avatar`)) return url;
const meta = fetchMetaSync();
const baseUrl = meta ? meta.objectStorageBaseUrl ?? `${meta.objectStorageUseSSL ? "https" : "http"}://${meta.objectStorageEndpoint}${meta.objectStoragePort ? `:${meta.objectStoragePort}` : ""}/${meta.objectStorageBucket}` : null;
if (baseUrl !== null && url.startsWith(baseUrl)) return url;
return `${config.url}/proxy/${encodeURIComponent(new URL(url).pathname)}?${query({ url: url })}`;
},
getFinalUrlMaybe(url?: string | null): string | null {
if (url == null) return null;
return this.getFinalUrl(url);
},
async calcDriveUsageOf( async calcDriveUsageOf(
user: User["id"] | { id: User["id"] }, user: User["id"] | { id: User["id"] },
): Promise<number> { ): Promise<number> {

View File

@ -339,7 +339,7 @@ export const UserRepository = db.getRepository(User).extend({
this.getIdenticonUrl(user.id) this.getIdenticonUrl(user.id)
); );
} else if (user.avatarId) { } else if (user.avatarId) {
if (user.avatarUrl) return user.avatarUrl; if (user.avatarUrl) return DriveFiles.getFinalUrl(user.avatarUrl);
const avatar = await DriveFiles.findOneByOrFail({ id: user.avatarId }); const avatar = await DriveFiles.findOneByOrFail({ id: user.avatarId });
return ( return (
DriveFiles.getPublicUrl(avatar, true) || this.getIdenticonUrl(user.id) DriveFiles.getPublicUrl(avatar, true) || this.getIdenticonUrl(user.id)
@ -351,7 +351,7 @@ export const UserRepository = db.getRepository(User).extend({
getAvatarUrlSync(user: User): string { getAvatarUrlSync(user: User): string {
if (user.avatarId && user.avatarUrl) { if (user.avatarId && user.avatarUrl) {
return user.avatarUrl; return DriveFiles.getFinalUrl(user.avatarUrl);
} else if (user.avatar) { } else if (user.avatar) {
return ( return (
DriveFiles.getPublicUrl(user.avatar, true) || DriveFiles.getPublicUrl(user.avatar, true) ||
@ -514,7 +514,7 @@ export const UserRepository = db.getRepository(User).extend({
lastFetchedAt: user.lastFetchedAt lastFetchedAt: user.lastFetchedAt
? user.lastFetchedAt.toISOString() ? user.lastFetchedAt.toISOString()
: null, : null,
bannerUrl: user.bannerId ? (user.bannerUrl ?? (user.banner bannerUrl: user.bannerId ? (DriveFiles.getFinalUrlMaybe(user.bannerUrl) ?? (user.banner
? DriveFiles.getPublicUrl(user.banner, false) ? DriveFiles.getPublicUrl(user.banner, false)
: null)) : null, : null)) : null,
bannerBlurhash: user.bannerId ? (user.bannerBlurhash ?? user.banner?.blurhash ?? null) : null, bannerBlurhash: user.bannerId ? (user.bannerBlurhash ?? user.banner?.blurhash ?? null) : null,

View File

@ -35,12 +35,14 @@ export class UserConverter {
const profile = UserProfiles.findOneBy({ userId: u.id }); const profile = UserProfiles.findOneBy({ userId: u.id });
const bio = profile.then(profile => MfmHelpers.toHtml(mfm.parse(profile?.description ?? ""), profile?.mentions, u.host).then(p => p ?? escapeMFM(profile?.description ?? ""))); const bio = profile.then(profile => MfmHelpers.toHtml(mfm.parse(profile?.description ?? ""), profile?.mentions, u.host).then(p => p ?? escapeMFM(profile?.description ?? "")));
const avatar = u.avatarId const avatar = u.avatarId
? u.avatarUrl ?? (DriveFiles.findOneBy({ id: u.avatarId })) ? DriveFiles.getFinalUrlMaybe(u.avatarUrl) ?? (DriveFiles.findOneBy({ id: u.avatarId }))
.then(p => p?.url ?? Users.getIdenticonUrl(u.id)) .then(p => p?.url ?? Users.getIdenticonUrl(u.id))
.then(p => DriveFiles.getFinalUrl(p))
: Users.getIdenticonUrl(u.id); : Users.getIdenticonUrl(u.id);
const banner = u.bannerId const banner = u.bannerId
? u.bannerUrl ?? (DriveFiles.findOneBy({ id: u.bannerId })) ? DriveFiles.getFinalUrlMaybe(u.bannerUrl) ?? (DriveFiles.findOneBy({ id: u.bannerId }))
.then(p => p?.url ?? `${config.url}/static-assets/transparent.png`) .then(p => p?.url ?? `${config.url}/static-assets/transparent.png`)
.then(p => DriveFiles.getFinalUrl(p))
: `${config.url}/static-assets/transparent.png`; : `${config.url}/static-assets/transparent.png`;
const isFollowedOrSelf = !!localUser && const isFollowedOrSelf = !!localUser &&