From e045aa2661f3968184069237ef5deeba6d1474dd Mon Sep 17 00:00:00 2001 From: Chocolate Pie <106949016+chocolate-pie@users.noreply.github.com> Date: Sun, 11 Jun 2023 15:50:38 +0900 Subject: [PATCH] Merge remote-tracking branch 'upstream/develop' into flash-request-token --- CHANGELOG.md | 14 ++-- locales/de-DE.yml | 11 +-- locales/en-US.yml | 11 +-- locales/ja-JP.yml | 8 +-- locales/tr-TR.yml | 71 +++++++++++++++++++ locales/zh-CN.yml | 1 + locales/zh-TW.yml | 1 + package.json | 2 +- packages/backend/src/core/CacheService.ts | 11 +++ .../backend/src/core/CustomEmojiService.ts | 14 +++- .../src/core/FederatedInstanceService.ts | 14 +++- .../src/core/PushNotificationService.ts | 14 +++- packages/backend/src/core/RoleService.ts | 1 + .../backend/src/core/UserKeypairService.ts | 14 +++- .../core/activitypub/ApDbResolverService.ts | 15 +++- packages/backend/src/misc/cache.ts | 32 ++++++++- .../src/server/api/AuthenticateService.ts | 14 +++- .../src/server/api/endpoints/roles/list.ts | 1 + .../src/server/api/endpoints/roles/users.ts | 1 + .../src/components/global/MkError.vue | 4 +- packages/frontend/src/ui/deck/column.vue | 1 + packages/misskey-js/etc/misskey-js.api.md | 4 +- 22 files changed, 223 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a054d33da..b4c24b0edc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,20 +11,24 @@ - --> - -## 13.13.2 (unreleased) +## 13.13.2 ### General +- エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるように +- ロールが付与されているユーザーリストを非公開にできるように - プレイにAPI Tokenを要求できる関数を追加 +### Client +- Fix: タブがバックグラウンドでもstreamが切断されないように + +### Server +- Fix: キャッシュが溜まり続けないように + ## 13.13.1 ### Client - Fix: タブがアクティブな間はstreamが切断されないように -### General -- エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるようになりました - ### Server - Fix: api/metaで`TypeError: JSON5.parse is not a function`エラーが発生する問題を修正 diff --git a/locales/de-DE.yml b/locales/de-DE.yml index c4c12cb1aa..9b52a50697 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -991,7 +991,7 @@ postToTheChannel: "In Kanal senden" cannotBeChangedLater: "Kann später nicht mehr geändert werden." reactionAcceptance: "Reaktionsannahme" likeOnly: "Nur \"Gefällt mir\"" -likeOnlyForRemote: "Nur \"Gefällt mir\" für fremde Instanzen" +likeOnlyForRemote: "Alle (Nur \"Gefällt mir\" für fremde Instanzen)" nonSensitiveOnly: "Keine Sensitiven" nonSensitiveOnlyForLocalLikeOnlyForRemote: "Keine Sensitiven (Nur \"Gefällt mir\" von fremden Instanzen)" rolesAssignedToMe: "Mir zugewiesene Rollen" @@ -1062,6 +1062,7 @@ later: "Später" goToMisskey: "Zu Misskey" additionalEmojiDictionary: "Zusätzliche Emoji-Wörterbücher" installed: "Installiert" +branding: "Branding" _initialAccountSetting: accountCreated: "Dein Konto wurde erfolgreich erstellt!" letsStartAccountSetup: "Lass uns nun dein Konto einrichten." @@ -1093,7 +1094,7 @@ _accountMigration: migrationConfirm: "Dieses Konto wirklich zu {account} umziehen? Sobald der Umzug beginnt, kann er nicht rückgängig gemacht werden, und dieses Konto nicht wieder im ursprünglichen Zustand verwendet werden." movedAndCannotBeUndone: "\nDieses Konto wurde migriert.\nDiese Aktion ist unwiderruflich." postMigrationNote: "Dieses Konto wird 24 Stunden nach Abschluss der Migration allen Konten, denen es derzeit folgt, nicht mehr folgen.\n\nSowohl die Anzahl der Follower als auch die der Konten, denen dieses Konto folgt, wird dann auf Null gesetzt. Um zu vermeiden, dass Follower dieses Kontos dessen Beiträge, welche nur für Follower bestimmt sind, nicht mehr sehen können, werden sie diesem Konto jedoch weiterhin folgen." - movedTo: "Umzugsziel:" + movedTo: "Neues Konto:" _achievements: earnedAt: "Freigeschaltet am" _types: @@ -1347,7 +1348,7 @@ _role: condition: "Bedingung" isConditionalRole: "Dies ist eine konditionale Rolle." isPublic: "Öffentliche Rolle" - descriptionOfIsPublic: "Ist dies aktiviert, so kann jeder die Liste der Benutzer, die dieser Rolle zugewiesen sind, einsehen. Zusätzlich wird diese Rolle im Profil zugewiesener Benutzer angezeigt." + descriptionOfIsPublic: "Diese Rolle wird im Profil zugewiesener Benutzer angezeigt." options: "Optionen" policies: "Richtlinien" baseRole: "Rollenvorlage" @@ -1356,8 +1357,8 @@ _role: iconUrl: "Icon-URL" asBadge: "Als Abzeichen anzeigen" descriptionOfAsBadge: "Ist dies aktiviert, so wird das Icon dieser Rolle an der Seite der Namen von Benutzern mit dieser Rolle angezeigt." - isExplorable: "Rollenchronik veröffentlichen" - descriptionOfIsExplorable: "Ist dies aktiviert, so ist die Rollenchronik dieser Rolle frei zugänglich. Die Chronik von Rollen, welche nicht öffentlich sind, wird auch bei Aktivierung nicht veröffentlicht." + isExplorable: "Benutzerliste veröffentlichen" + descriptionOfIsExplorable: "Ist dies aktiviert, so ist die Chronik dieser Rolle, sowie eine Liste der Benutzer mit dieser Rolle, frei zugänglich." displayOrder: "Position" descriptionOfDisplayOrder: "Je höher die Nummer, desto höher die UI-Position." canEditMembersByModerator: "Moderatoren können Benutzern diese Rolle zuweisen" diff --git a/locales/en-US.yml b/locales/en-US.yml index 0f1c7c89fe..8938208574 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -991,7 +991,7 @@ postToTheChannel: "Post to channel" cannotBeChangedLater: "This cannot be changed later." reactionAcceptance: "Reaction Acceptance" likeOnly: "Only likes" -likeOnlyForRemote: "Only likes for remote instances" +likeOnlyForRemote: "All (Only likes for remote instances)" nonSensitiveOnly: "Non-sensitive only" nonSensitiveOnlyForLocalLikeOnlyForRemote: "Non-sensitive only (Only likes from remote)" rolesAssignedToMe: "Roles assigned to me" @@ -1062,6 +1062,7 @@ later: "Later" goToMisskey: "To Misskey" additionalEmojiDictionary: "Additional emoji dictionaries" installed: "Installed" +branding: "Branding" _initialAccountSetting: accountCreated: "Your account was successfully created!" letsStartAccountSetup: "For starters, let's set up your profile." @@ -1093,7 +1094,7 @@ _accountMigration: migrationConfirm: "Really migrate this account to {account}? Once started, this process cannot be stopped or taken back, and you will not be able to use this account in its original state anymore." movedAndCannotBeUndone: "\nThis account has been migrated.\nMigration cannot be reversed." postMigrationNote: "This account will unfollow all accounts it is currently following 24 hours after migration finishes.\nBoth the number of follows and followers will then become zero. To avoid your followers from being unable to see followers only posts of this account, they will however continue following this account." - movedTo: "Account to move to:" + movedTo: "New account:" _achievements: earnedAt: "Unlocked at" _types: @@ -1347,7 +1348,7 @@ _role: condition: "Condition" isConditionalRole: "This is a conditional role." isPublic: "Public role" - descriptionOfIsPublic: "Anyone will be able to view a list of users assigned to this role. In addition, this role will be displayed in the profiles of assigned users." + descriptionOfIsPublic: "This role will be displayed in the profiles of assigned users." options: "Options" policies: "Policies" baseRole: "Role template" @@ -1356,8 +1357,8 @@ _role: iconUrl: "Icon URL" asBadge: "Show as badge" descriptionOfAsBadge: "This role's icon will be displayed next to the username of users with this role if turned on." - isExplorable: "Role timeline is public" - descriptionOfIsExplorable: "This role's timeline will become publicly accessible if enabled. Timelines of non-public roles will not be made public even if set." + isExplorable: "Make role explorable" + descriptionOfIsExplorable: "This role's timeline and the list of users with this will be made public if enabled." displayOrder: "Position" descriptionOfDisplayOrder: "The higher the number, the higher its UI position." canEditMembersByModerator: "Allow moderators to edit the list of members for this role" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 16f90c4d03..efdb95fafc 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1355,8 +1355,8 @@ _role: conditional: "コンディショナル" condition: "条件" isConditionalRole: "これはコンディショナルロールです。" - isPublic: "ロールを公開" - descriptionOfIsPublic: "ロールにアサインされたユーザーを誰でも見ることができます。また、ユーザーのプロフィールでこのロールが表示されます。" + isPublic: "公開ロール" + descriptionOfIsPublic: "ユーザーのプロフィールでこのロールが表示されます。" options: "オプション" policies: "ポリシー" baseRole: "ベースロール" @@ -1365,8 +1365,8 @@ _role: iconUrl: "アイコン画像のURL" asBadge: "バッジとして表示" descriptionOfAsBadge: "オンにすると、ユーザー名の横にロールのアイコンが表示されます。" - isExplorable: "ロールタイムラインを公開" - descriptionOfIsExplorable: "オンにすると、ロールのタイムラインを公開します。ロールの公開がオフの場合、タイムラインの公開はされません。" + isExplorable: "ユーザーを見つけやすくする" + descriptionOfIsExplorable: "オンにすると、「みつける」でメンバー一覧が公開されるほか、ロールのタイムラインが利用可能になります。" displayOrder: "表示順" descriptionOfDisplayOrder: "数値が大きいほどUI上で先頭に表示されます。" canEditMembersByModerator: "モデレーターのメンバー編集を許可" diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml index 7bd8188a48..cc402eec48 100644 --- a/locales/tr-TR.yml +++ b/locales/tr-TR.yml @@ -1,6 +1,7 @@ --- _lang_: "Türkçe" introMisskey: "Açık kaynaklı bir dağıtılmış mikroblog hizmeti olan Misskey'e hoş geldiniz.\nMisskey, neler olup bittiğini paylaşmak ve herkese sizden bahsetmek için \"notlar\" oluşturmanıza olanak tanıyan, açık kaynaklı, dağıtılmış bir mikroblog hizmetidir.\nHerkesin notlarına kendi tepkilerinizi hızlıca eklemek için \"Tepkiler\" özelliğini de kullanabilirsiniz👍.\nYeni bir dünyayı keşfedin🚀." +poweredByMisskeyDescription: "name}Açık kaynak bir platform\nMisskeyDünya'nın en sunucularında biri。" monthAndDay: "{month}Ay {day}Gün" search: "Arama" notifications: "Bildirim" @@ -13,7 +14,9 @@ cancel: "İptal" enterUsername: "Kullanıcı adınızı giriniz" noNotes: "Notlar mevcut değil." noNotifications: "Bildirim bulunmuyor" +instance: "Sunucu" settings: "Ayarlar" +notificationSettings: "Bildirim Ayarları" basicSettings: "Temel Ayarlar" otherSettings: "Diğer Ayarlar" openInWindow: "Bir pencere ile aç" @@ -21,9 +24,11 @@ profile: "Profil" timeline: "Zaman çizelgesi" noAccountDescription: "Bu kullanıcı henüz biyografisini yazmadı" login: "Giriş Yap " +loggingIn: "Oturum aç" logout: "Çıkış Yap" signup: "Kayıt Ol" uploading: "Yükleniyor" +save: "Kaydet" users: "Kullanıcı" addUser: "Kullanıcı Ekle" favorite: "Favoriler" @@ -31,6 +36,7 @@ favorites: "Favoriler" unfavorite: "Favorilerden Kaldır" favorited: "Favorilerime eklendi." alreadyFavorited: "Zaten favorilerinizde kayıtlı." +cantFavorite: "Favorilere kayıt yapılamadı" pin: "Sabitlenmiş" unpin: "Sabitlemeyi kaldır" copyContent: "İçeriği kopyala" @@ -40,23 +46,88 @@ deleteAndEdit: "Sil ve yeniden düzenle" deleteAndEditConfirm: "Bu notu silip yeniden düzenlemek istiyor musunuz? Bu nota ilişkin tüm Tepkiler, Yeniden Notlar ve Yanıtlar da silinecektir." addToList: "Listeye ekle" sendMessage: "Mesaj Gönder" +copyRSS: "RSSKopyala" copyUsername: "Kullanıcı Adını Kopyala" +copyUserId: "KullanıcıyıKopyala" +copyNoteId: "Kimlik notunu kopyala" searchUser: "Kullanıcıları ara" +reply: "yanıt" +loadMore: "Devamını yükle" +showMore: "Devamını yükle" +lists: "Listeler" +noLists: "Liste yok" +note: "not" +notes: "notlar" +following: "takipçi" +followers: "takipçi" +followsYou: "seni takip ediyor" +createList: "Liste oluştur" +manageLists: "Yönetici Listeleri" +error: "hata" +follow: "takipçi" +followRequest: "Takip isteği" +followRequests: "Takip istekleri" +unfollow: "takip etmeyi bırak" +followRequestPending: "Bekleyen Takip Etme Talebi" +enterEmoji: "Emoji Giriniz" +renote: "vazgeçme" +unrenote: "not alma" +renoted: "yeniden adlandırılmış" +cantRenote: "Ayrılamama" +cantReRenote: "not alabilirmiyim" +quote: "alıntı" +pinnedNote: "Sabitlenen" pinned: "Sabitlenmiş" +you: "sen" +unmute: "sesi aç" +renoteMute: "sesi kapat" +renoteUnmute: "sesi açmayı iptal et" +block: "engelle" +unblock: "engellemeyi kaldır" +suspend: "askıya al" +unsuspend: "askıya alma" +blockConfirm: "Onayı engelle" +unblockConfirm: "engellemeyi kaldır onayla" +selectChannel: "Kanal seç" +flagAsBot: "Bot olarak işaretle" +instances: "Sunucu" remove: "Sil" +pinnedNotes: "Sabitlenen" +userList: "Listeler" smtpUser: "Kullanıcı Adı" smtpPass: "Şifre" user: "Kullanıcı" searchByGoogle: "Arama" +_theme: + keys: + renote: "vazgeçme" _sfx: + note: "notlar" notification: "Bildirim" _widgets: profile: "Profil" notifications: "Bildirim" timeline: "Zaman çizelgesi" +_cw: + show: "Devamını yükle" +_visibility: + followers: "takipçi" _profile: username: "Kullanıcı Adı" +_exportOrImport: + followingList: "takipçi" + blockingList: "engelle" + userLists: "Listeler" +_notification: + _types: + follow: "takipçi" + renote: "vazgeçme" + quote: "alıntı" + _actions: + reply: "yanıt" + renote: "vazgeçme" _deck: _columns: notifications: "Bildirim" tl: "Zaman çizelgesi" + list: "Listeler" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 9c278ea751..313c254c79 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1060,6 +1060,7 @@ cancelReactionConfirm: "要取消回应吗?" changeReactionConfirm: "要更改回应吗?" later: "一会再说" goToMisskey: "去往Misskey" +additionalEmojiDictionary: "表情符号追加字典" installed: "已安装" _initialAccountSetting: accountCreated: "账户创建完成了!" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index ef0baeef50..8017018507 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1062,6 +1062,7 @@ later: "稍後再說" goToMisskey: "往Misskey" additionalEmojiDictionary: "表情符號的附加辭典" installed: "已安裝" +branding: "品牌宣傳" _initialAccountSetting: accountCreated: "帳戶已建立完成!" letsStartAccountSetup: "來進行帳戶的初始設定吧。" diff --git a/package.json b/package.json index eff0bf2dc2..dd0c1d57e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.13.1", + "version": "13.13.2", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/backend/src/core/CacheService.ts b/packages/backend/src/core/CacheService.ts index 3d78015a53..1a66c19715 100644 --- a/packages/backend/src/core/CacheService.ts +++ b/packages/backend/src/core/CacheService.ts @@ -177,6 +177,17 @@ export class CacheService implements OnApplicationShutdown { @bindThis public dispose(): void { this.redisForSub.off('message', this.onMessage); + this.userByIdCache.dispose(); + this.localUserByNativeTokenCache.dispose(); + this.localUserByIdCache.dispose(); + this.uriPersonCache.dispose(); + this.userProfileCache.dispose(); + this.userMutingsCache.dispose(); + this.userBlockingCache.dispose(); + this.userBlockedCache.dispose(); + this.renoteMutingsCache.dispose(); + this.userFollowingsCache.dispose(); + this.userFollowingChannelsCache.dispose(); } @bindThis diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts index 3499df38b7..5f2ced77eb 100644 --- a/packages/backend/src/core/CustomEmojiService.ts +++ b/packages/backend/src/core/CustomEmojiService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { DataSource, In, IsNull } from 'typeorm'; import * as Redis from 'ioredis'; import { DI } from '@/di-symbols.js'; @@ -18,7 +18,7 @@ import type { Serialized } from '@/server/api/stream/types.js'; const parseEmojiStrRegexp = /^(\w+)(?:@([\w.-]+))?$/; @Injectable() -export class CustomEmojiService { +export class CustomEmojiService implements OnApplicationShutdown { private cache: MemoryKVCache; public localEmojisCache: RedisSingleCache>; @@ -349,4 +349,14 @@ export class CustomEmojiService { this.cache.set(`${emoji.name} ${emoji.host}`, emoji); } } + + @bindThis + public dispose(): void { + this.cache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts index 8b9a87a380..3603d59dcc 100644 --- a/packages/backend/src/core/FederatedInstanceService.ts +++ b/packages/backend/src/core/FederatedInstanceService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import * as Redis from 'ioredis'; import type { InstancesRepository } from '@/models/index.js'; import type { Instance } from '@/models/entities/Instance.js'; @@ -9,7 +9,7 @@ import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; @Injectable() -export class FederatedInstanceService { +export class FederatedInstanceService implements OnApplicationShutdown { public federatedInstanceCache: RedisKVCache; constructor( @@ -77,4 +77,14 @@ export class FederatedInstanceService { this.federatedInstanceCache.set(result.host, result); } + + @bindThis + public dispose(): void { + this.federatedInstanceCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts index a4c569bdec..15a1d74878 100644 --- a/packages/backend/src/core/PushNotificationService.ts +++ b/packages/backend/src/core/PushNotificationService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import push from 'web-push'; import * as Redis from 'ioredis'; import { DI } from '@/di-symbols.js'; @@ -42,7 +42,7 @@ function truncateBody(type: T, body: Pus } @Injectable() -export class PushNotificationService { +export class PushNotificationService implements OnApplicationShutdown { private subscriptionsCache: RedisKVCache; constructor( @@ -115,4 +115,14 @@ export class PushNotificationService { }); } } + + @bindThis + public dispose(): void { + this.subscriptionsCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 40ae106662..79922d0a87 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -435,6 +435,7 @@ export class RoleService implements OnApplicationShutdown { @bindThis public dispose(): void { this.redisForSub.off('message', this.onMessage); + this.roleAssignmentByUserIdCache.dispose(); } @bindThis diff --git a/packages/backend/src/core/UserKeypairService.ts b/packages/backend/src/core/UserKeypairService.ts index 72c35c529c..d768f08650 100644 --- a/packages/backend/src/core/UserKeypairService.ts +++ b/packages/backend/src/core/UserKeypairService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import * as Redis from 'ioredis'; import type { User } from '@/models/entities/User.js'; import type { UserKeypairsRepository } from '@/models/index.js'; @@ -8,7 +8,7 @@ import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; @Injectable() -export class UserKeypairService { +export class UserKeypairService implements OnApplicationShutdown { private cache: RedisKVCache; constructor( @@ -31,4 +31,14 @@ export class UserKeypairService { public async getUserKeypair(userId: User['id']): Promise { return await this.cache.fetch(userId); } + + @bindThis + public dispose(): void { + this.cache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index 2b404ebeca..2d9e7a14ee 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import escapeRegexp from 'escape-regexp'; import { DI } from '@/di-symbols.js'; import type { NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js'; @@ -30,7 +30,7 @@ export type UriParseResult = { }; @Injectable() -export class ApDbResolverService { +export class ApDbResolverService implements OnApplicationShutdown { private publicKeyCache: MemoryKVCache; private publicKeyByUserIdCache: MemoryKVCache; @@ -162,4 +162,15 @@ export class ApDbResolverService { key, }; } + + @bindThis + public dispose(): void { + this.publicKeyCache.dispose(); + this.publicKeyByUserIdCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index 5610929648..f130a7db8b 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -83,6 +83,16 @@ export class RedisKVCache { // TODO: イベント発行して他プロセスのメモリキャッシュも更新できるようにする } + + @bindThis + public gc() { + this.memoryCache.gc(); + } + + @bindThis + public dispose() { + this.memoryCache.dispose(); + } } export class RedisSingleCache { @@ -174,10 +184,15 @@ export class RedisSingleCache { export class MemoryKVCache { public cache: Map; private lifetime: number; + private gcIntervalHandle: NodeJS.Timer; constructor(lifetime: MemoryKVCache['lifetime']) { this.cache = new Map(); this.lifetime = lifetime; + + this.gcIntervalHandle = setInterval(() => { + this.gc(); + }, 1000 * 60 * 3); } @bindThis @@ -200,7 +215,7 @@ export class MemoryKVCache { } @bindThis - public delete(key: string) { + public delete(key: string): void { this.cache.delete(key); } @@ -255,6 +270,21 @@ export class MemoryKVCache { } return value; } + + @bindThis + public gc(): void { + const now = Date.now(); + for (const [key, { date }] of this.cache.entries()) { + if ((now - date) > this.lifetime) { + this.cache.delete(key); + } + } + } + + @bindThis + public dispose(): void { + clearInterval(this.gcIntervalHandle); + } } export class MemorySingleCache { diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts index e7a31477e2..89283a4b52 100644 --- a/packages/backend/src/server/api/AuthenticateService.ts +++ b/packages/backend/src/server/api/AuthenticateService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import type { AccessTokensRepository, AppsRepository, UsersRepository } from '@/models/index.js'; import type { LocalUser } from '@/models/entities/User.js'; @@ -18,7 +18,7 @@ export class AuthenticationError extends Error { } @Injectable() -export class AuthenticateService { +export class AuthenticateService implements OnApplicationShutdown { private appCache: MemoryKVCache; constructor( @@ -91,4 +91,14 @@ export class AuthenticateService { } } } + + @bindThis + public dispose(): void { + this.appCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/server/api/endpoints/roles/list.ts b/packages/backend/src/server/api/endpoints/roles/list.ts index d61c6b8dc6..5ad29839c2 100644 --- a/packages/backend/src/server/api/endpoints/roles/list.ts +++ b/packages/backend/src/server/api/endpoints/roles/list.ts @@ -30,6 +30,7 @@ export default class extends Endpoint { super(meta, paramDef, async (ps, me) => { const roles = await this.rolesRepository.findBy({ isPublic: true, + isExplorable: true, }); return await this.roleEntityService.packMany(roles, me); }); diff --git a/packages/backend/src/server/api/endpoints/roles/users.ts b/packages/backend/src/server/api/endpoints/roles/users.ts index 607dc24206..b2cb8b42a8 100644 --- a/packages/backend/src/server/api/endpoints/roles/users.ts +++ b/packages/backend/src/server/api/endpoints/roles/users.ts @@ -49,6 +49,7 @@ export default class extends Endpoint { const role = await this.rolesRepository.findOneBy({ id: ps.roleId, isPublic: true, + isExplorable: true, }); if (role == null) { diff --git a/packages/frontend/src/components/global/MkError.vue b/packages/frontend/src/components/global/MkError.vue index 24b0835135..503e00387c 100644 --- a/packages/frontend/src/components/global/MkError.vue +++ b/packages/frontend/src/components/global/MkError.vue @@ -1,7 +1,7 @@