Skip to content

Commit

Permalink
Merge branch 'develop' into fix-chart-instance-card-mini-is-no-longer…
Browse files Browse the repository at this point in the history
…-displayed
  • Loading branch information
syuilo authored Jun 15, 2024
2 parents be0af2d + 1a82a41 commit 8e7dd4d
Show file tree
Hide file tree
Showing 15 changed files with 123 additions and 118 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"ghcr.io/devcontainers-contrib/features/corepack:1": {}
},
"forwardPorts": [3000],
"postCreateCommand": "sudo chmod 755 .devcontainer/init.sh && .devcontainer/init.sh",
"postCreateCommand": "/bin/bash .devcontainer/init.sh",
"customizations": {
"vscode": {
"extensions": [
Expand Down
2 changes: 2 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ services:

volumes:
- ../:/workspace:cached
- node_modules:/workspace/node_modules

command: sleep infinity

Expand Down Expand Up @@ -46,6 +47,7 @@ services:
volumes:
postgres-data:
redis-data:
node_modules:

networks:
internal_network:
Expand Down
3 changes: 2 additions & 1 deletion .devcontainer/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

set -xe

sudo chown -R node /workspace
sudo chown node node_modules
git config --global --add safe.directory /workspace
git submodule update --init
corepack install
corepack enable
Expand Down
4 changes: 4 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ contact_links:
- name: 💬 Misskey official Discord
url: https://discord.gg/Wp8gVStHW3
about: Chat freely about Misskey
#
- name: 💬 Start discussion
url: https://github.com/misskey-dev/misskey/discussions
about: The official forum to join conversation and ask question
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

### Client
- `/about#federation` ページなどで各インスタンスのチャートが表示されなくなっていた問題を修正
- Fix: ユーザーページの追加情報のラベルを投稿者のサーバーの絵文字で表示する (#13968)

### Server
- チャート生成時にinstance.suspentionStateに置き換えられたinstance.isSuspendedが参照されてしまう問題を修正

- Feat: レートリミット制限に引っかかったときに`Retry-After`ヘッダーを返すように (#13949)

## 2024.5.0

Expand Down
4 changes: 2 additions & 2 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"type": "module",
"engines": {
"node": "^20.10.0"
"node": "^20.10.0 || ^22.0.0"
},
"scripts": {
"start": "node ./built/boot/entry.js",
Expand Down Expand Up @@ -159,7 +159,7 @@
"qrcode": "1.5.3",
"random-seed": "0.3.0",
"ratelimiter": "3.4.1",
"re2": "1.20.10",
"re2": "1.21.2",
"redis-lock": "0.1.4",
"reflect-metadata": "0.2.2",
"rename": "1.0.4",
Expand Down
30 changes: 5 additions & 25 deletions packages/backend/src/models/_.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,42 +82,22 @@ import { MiReversiGame } from '@/models/ReversiGame.js';
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';

export interface MiRepository<T extends ObjectLiteral> {
createTableColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[];
createTableColumnNamesWithPrimaryKey(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[];
createTableColumnNames(this: Repository<T> & MiRepository<T>): string[];
insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>;
selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void;
}

export const miRepository = {
createTableColumnNames(queryBuilder) {
// @ts-expect-error -- protected
const insertedColumns = queryBuilder.getInsertedColumns();
if (insertedColumns.length) {
return insertedColumns.map(column => column.databaseName);
}
if (!queryBuilder.expressionMap.mainAlias?.hasMetadata && !queryBuilder.expressionMap.insertColumns.length) {
// @ts-expect-error -- protected
const valueSets = queryBuilder.getValueSets();
if (valueSets.length === 1) {
return Object.keys(valueSets[0]);
}
}
return queryBuilder.expressionMap.insertColumns;
},
createTableColumnNamesWithPrimaryKey(queryBuilder) {
const columnNames = this.createTableColumnNames(queryBuilder);
if (!columnNames.includes('id')) {
columnNames.unshift('id');
}
return columnNames;
createTableColumnNames() {
return this.metadata.columns.filter(column => column.isSelect && !column.isVirtual).map(column => column.databaseName);
},
async insertOne(entity, findOptions?) {
const queryBuilder = this.createQueryBuilder().insert().values(entity);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const mainAlias = queryBuilder.expressionMap.mainAlias!;
const name = mainAlias.name;
mainAlias.name = 't';
const columnNames = this.createTableColumnNamesWithPrimaryKey(queryBuilder);
const columnNames = this.createTableColumnNames();
queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames });
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Expand All @@ -138,7 +118,7 @@ export const miRepository = {
selectOrAddSelect = (selection, selectionAliasName) => builder.addSelect(selection, selectionAliasName);
return builder.select(selection, selectionAliasName);
};
for (const columnName of this.createTableColumnNamesWithPrimaryKey(queryBuilder)) {
for (const columnName of this.createTableColumnNames()) {
selectOrAddSelect(`${builder.alias}.${columnName}`, `${builder.alias}_${columnName}`);
}
},
Expand Down
27 changes: 21 additions & 6 deletions packages/backend/src/server/api/ApiCallService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ export class ApiCallService implements OnApplicationShutdown {
reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="insufficient_scope", error_description="${err.message}"`);
}
statusCode = statusCode ?? 403;
} else if (err.code === 'RATE_LIMIT_EXCEEDED') {
const info: unknown = err.info;
const unixEpochInSeconds = Date.now();
if (typeof(info) === 'object' && info && 'resetMs' in info && typeof(info.resetMs) === 'number') {
const cooldownInSeconds = Math.ceil((info.resetMs - unixEpochInSeconds) / 1000);
// もしかするとマイナスになる可能性がなくはないのでマイナスだったら0にしておく
reply.header('Retry-After', Math.max(cooldownInSeconds, 0).toString(10));
} else {
this.logger.warn(`rate limit information has unexpected type ${typeof(err.info?.reset)}`);
}
} else if (!statusCode) {
statusCode = 500;
}
Expand Down Expand Up @@ -308,12 +318,17 @@ export class ApiCallService implements OnApplicationShutdown {
if (factor > 0) {
// Rate limit
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',
id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef',
httpStatusCode: 429,
});
if ('info' in err) {
// errはLimiter.LimiterInfoであることが期待される
throw new ApiError({
message: 'Rate limit exceeded. Please try again later.',
code: 'RATE_LIMIT_EXCEEDED',
id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef',
httpStatusCode: 429,
}, err.info);
} else {
throw new TypeError('information must be a rate-limiter information.');
}
});
}
}
Expand Down
36 changes: 19 additions & 17 deletions packages/backend/src/server/api/RateLimiterService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ export class RateLimiterService {

@bindThis
public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable<string> }, actor: string, factor = 1) {
return new Promise<void>((ok, reject) => {
if (this.disabled) ok();
{
if (this.disabled) {
return Promise.resolve();
}

// Short-term limit
const min = (): void => {
const min = new Promise<void>((ok, reject) => {
const minIntervalLimiter = new Limiter({
id: `${actor}:${limitation.key}:min`,
duration: limitation.minInterval! * factor,
Expand All @@ -46,25 +48,25 @@ export class RateLimiterService {

minIntervalLimiter.get((err, info) => {
if (err) {
return reject('ERR');
return reject({ code: 'ERR', info });
}

this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`);

if (info.remaining === 0) {
reject('BRIEF_REQUEST_INTERVAL');
return reject({ code: 'BRIEF_REQUEST_INTERVAL', info });
} else {
if (hasLongTermLimit) {
max();
return max.then(ok, reject);
} else {
ok();
return ok();
}
}
});
};
});

// Long term limit
const max = (): void => {
const max = new Promise<void>((ok, reject) => {
const limiter = new Limiter({
id: `${actor}:${limitation.key}`,
duration: limitation.duration! * factor,
Expand All @@ -74,18 +76,18 @@ export class RateLimiterService {

limiter.get((err, info) => {
if (err) {
return reject('ERR');
return reject({ code: 'ERR', info });
}

this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`);

if (info.remaining === 0) {
reject('RATE_LIMIT_EXCEEDED');
return reject({ code: 'RATE_LIMIT_EXCEEDED', info });
} else {
ok();
return ok();
}
});
};
});

const hasShortTermLimit = typeof limitation.minInterval === 'number';

Expand All @@ -94,12 +96,12 @@ export class RateLimiterService {
typeof limitation.max === 'number';

if (hasShortTermLimit) {
min();
return min;
} else if (hasLongTermLimit) {
max();
return max;
} else {
ok();
return Promise.resolve();
}
});
}
}
}
2 changes: 1 addition & 1 deletion packages/frontend/src/pages/user/home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="user.fields.length > 0" class="fields">
<dl v-for="(field, i) in user.fields" :key="i" class="field">
<dt class="name">
<Mfm :text="field.name" :plain="true" :colored="false"/>
<Mfm :text="field.name" :author="user" :plain="true" :colored="false"/>
</dt>
<dd class="value">
<Mfm :text="field.value" :author="user" :colored="false"/>
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { type UserConfig, defineConfig } from 'vite';

import locales from '../../locales/index.js';
import meta from '../../package.json';
import packageInfo from './package.json' assert { type: 'json' };
import packageInfo from './package.json' with { type: 'json' };
import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js';
import pluginJson5 from './vite.json5.js';

Expand Down
2 changes: 1 addition & 1 deletion packages/sw/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { fileURLToPath } from 'node:url';
import * as esbuild from 'esbuild';
import locales from '../../locales/index.js';
import meta from '../../package.json' assert { type: "json" };
import meta from '../../package.json' with { type: "json" };
const watch = process.argv[2]?.includes('watch');

const __dirname = fileURLToPath(new URL('.', import.meta.url))
Expand Down
Loading

0 comments on commit 8e7dd4d

Please sign in to comment.