ロールでレートリミットを調整できるように

Resolve #9584
This commit is contained in:
syuilo 2023-01-15 16:52:12 +09:00
parent fb0f9711ba
commit 7fc8d2e6d5
7 changed files with 57 additions and 19 deletions

View file

@ -28,6 +28,7 @@ export type RoleOptions = {
noteEachClipsLimit: number;
userListLimit: number;
userEachUserListsLimit: number;
rateLimitFactor: number;
};
export const DEFAULT_ROLE: RoleOptions = {
@ -45,6 +46,7 @@ export const DEFAULT_ROLE: RoleOptions = {
noteEachClipsLimit: 200,
userListLimit: 10,
userEachUserListsLimit: 50,
rateLimitFactor: 1,
};
@Injectable()
@ -221,6 +223,7 @@ export class RoleService implements OnApplicationShutdown {
noteEachClipsLimit: Math.max(...getOptionValues('noteEachClipsLimit')),
userListLimit: Math.max(...getOptionValues('userListLimit')),
userEachUserListsLimit: Math.max(...getOptionValues('userEachUserListsLimit')),
rateLimitFactor: Math.max(...getOptionValues('rateLimitFactor')),
};
}

View file

@ -224,8 +224,11 @@ export class ApiCallService implements OnApplicationShutdown {
limit.key = ep.name;
}
// TODO: 毎リクエスト計算するのもあれだしキャッシュしたい
const factor = user ? (await this.roleService.getUserRoleOptions(user.id)).rateLimitFactor : 1;
// Rate limit
await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable<string> }, limitActor).catch(err => {
await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable<string> }, limitActor, factor).catch(err => {
throw new ApiError({
message: 'Rate limit exceeded. Please try again later.',
code: 'RATE_LIMIT_EXCEEDED',

View file

@ -26,7 +26,7 @@ export class RateLimiterService {
}
@bindThis
public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable<string> }, actor: string) {
public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable<string> }, actor: string, factor = 1) {
return new Promise<void>((ok, reject) => {
if (this.disabled) ok();
@ -34,7 +34,7 @@ export class RateLimiterService {
const min = (): void => {
const minIntervalLimiter = new Limiter({
id: `${actor}:${limitation.key}:min`,
duration: limitation.minInterval,
duration: limitation.minInterval * factor,
max: 1,
db: this.redisClient,
});
@ -62,8 +62,8 @@ export class RateLimiterService {
const max = (): void => {
const limiter = new Limiter({
id: `${actor}:${limitation.key}`,
duration: limitation.duration,
max: limitation.max,
duration: limitation.duration * factor,
max: limitation.max / factor,
db: this.redisClient,
});