Skip to content

Commit

Permalink
Merge branch 'develop' into fix-not-responding-since-null
Browse files Browse the repository at this point in the history
  • Loading branch information
syuilo authored Jun 22, 2024
2 parents afd88c7 + 8a9de08 commit 6d2b1d5
Show file tree
Hide file tree
Showing 12 changed files with 50 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Feat: レートリミット制限に引っかかったときに`Retry-After`ヘッダーを返すように (#13949)
- Fix: アンテナ・クリップ・リスト・ウェブフックがロールポリシーの上限より一つ多く作れてしまうのを修正 (#14036)
- Fix: notRespondingSinceが実装される前に不通になったインスタンスが自動的に配信停止にならない (#14059)
- Fix: FTT有効時、タイムライン用エンドポイントで`sinceId`にキャッシュ内最古のものより古いものを指定した場合に正しく結果が返ってこない問題を修正

## 2024.5.0

Expand Down
12 changes: 4 additions & 8 deletions packages/backend/src/core/FanoutTimelineEndpointService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@ export class FanoutTimelineEndpointService {

@bindThis
private async getMiNotes(ps: TimelineOptions): Promise<MiNote[]> {
let noteIds: string[];
let shouldFallbackToDb = false;

// 呼び出し元と以下の処理をシンプルにするためにdbFallbackを置き換える
if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]);

Expand All @@ -67,12 +64,11 @@ export class FanoutTimelineEndpointService {
const redisResult = await this.fanoutTimelineService.getMulti(ps.redisTimelines, ps.untilId, ps.sinceId);

// TODO: いい感じにgetMulti内でソート済だからuniqするときにredisResultが全てソート済なのを利用して再ソートを避けたい
const redisResultIds = Array.from(new Set(redisResult.flat(1)));

redisResultIds.sort(idCompare);
noteIds = redisResultIds.slice(0, ps.limit);
const redisResultIds = Array.from(new Set(redisResult.flat(1))).sort(idCompare);

shouldFallbackToDb = shouldFallbackToDb || (noteIds.length === 0);
let noteIds = redisResultIds.slice(0, ps.limit);
const oldestNoteId = ascending ? redisResultIds[0] : redisResultIds[redisResultIds.length - 1];
const shouldFallbackToDb = noteIds.length === 0 || ps.sinceId != null && ps.sinceId < oldestNoteId;

if (!shouldFallbackToDb) {
let filter = ps.noteFilter ?? (_note => true);
Expand Down
35 changes: 35 additions & 0 deletions packages/backend/test/e2e/timelines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// pnpm jest -- e2e/timelines.ts

import * as assert from 'assert';
import { Redis } from 'ioredis';
import { loadConfig } from '@/config.js';
import { api, post, randomString, sendEnvUpdateRequest, signup, sleep, uploadUrl } from '../utils.js';

function genHost() {
Expand All @@ -17,7 +19,13 @@ function waitForPushToTl() {
return sleep(500);
}

let redisForTimelines: Redis;

describe('Timelines', () => {
beforeAll(() => {
redisForTimelines = new Redis(loadConfig().redisForTimelines);
});

describe('Home TL', () => {
test.concurrent('自分の visibility: followers なノートが含まれる', async () => {
const [alice] = await Promise.all([signup()]);
Expand Down Expand Up @@ -1272,6 +1280,33 @@ describe('Timelines', () => {

assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});

/** @see https://github.com/misskey-dev/misskey/issues/14000 */
test.concurrent('FTT: sinceId にキャッシュより古いノートを指定しても、sinceId による絞り込みが正しく動作する', async () => {
const alice = await signup();
const noteSince = await post(alice, { text: 'Note where id will be `sinceId`.' });
const note1 = await post(alice, { text: '1' });
const note2 = await post(alice, { text: '2' });
await redisForTimelines.del('list:userTimeline:' + alice.id);
const note3 = await post(alice, { text: '3' });

const res = await api('users/notes', { userId: alice.id, sinceId: noteSince.id });
assert.deepStrictEqual(res.body, [note1, note2, note3]);
});

test.concurrent('FTT: sinceId にキャッシュより古いノートを指定しても、sinceId と untilId による絞り込みが正しく動作する', async () => {
const alice = await signup();
const noteSince = await post(alice, { text: 'Note where id will be `sinceId`.' });
const note1 = await post(alice, { text: '1' });
const note2 = await post(alice, { text: '2' });
await redisForTimelines.del('list:userTimeline:' + alice.id);
const note3 = await post(alice, { text: '3' });
const noteUntil = await post(alice, { text: 'Note where id will be `untilId`.' });
await post(alice, { text: '4' });

const res = await api('users/notes', { userId: alice.id, sinceId: noteSince.id, untilId: noteUntil.id });
assert.deepStrictEqual(res.body, [note3, note2, note1]);
});
});

// TODO: リノートミュート済みユーザーのテスト
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ module.exports = {
'vue/no-dupe-keys': 'warn',
'vue/valid-v-for': 'warn',
'vue/return-in-computed-property': 'warn',
'vue/no-setup-props-destructure': 'warn',
'vue/no-setup-props-reactivity-loss': 'warn',
'vue/max-attributes-per-line': 'off',
'vue/html-self-closing': 'off',
'vue/singleline-html-element-content-newline': 'off',
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ const getColor = (i) => {
return colorSets[i % colorSets.length];
};

// eslint-disable-next-line vue/no-setup-props-destructure
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const now = props.nowForChromatic != null ? new Date(props.nowForChromatic) : new Date();
let chartInstance: Chart | null = null;
let chartData: {
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkDateSeparatedList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export default defineComponent({
el.style.left = '';
}

// eslint-disable-next-line vue/no-setup-props-destructure
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const classes = {
[$style['date-separated-list']]: true,
[$style['date-separated-list-nogap']]: props.noGap,
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkMediaAudio.vue
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ function hasFocus() {
const playerEl = shallowRef<HTMLDivElement>();
const audioEl = shallowRef<HTMLAudioElement>();

// eslint-disable-next-line vue/no-setup-props-destructure
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.audio.isSensitive && defaultStore.state.nsfw !== 'ignore'));

// Menu
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkMediaVideo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ function hasFocus() {
return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement);
}

// eslint-disable-next-line vue/no-setup-props-destructure
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore'));

// Menu
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkTutorialDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ const emit = defineEmits<{

const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();

// eslint-disable-next-line vue/no-setup-props-destructure
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const page = ref(props.initialPage ?? 0);

watch(page, (to) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkUserSetupDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ const emit = defineEmits<{

const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();

// eslint-disable-next-line vue/no-setup-props-destructure
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const page = ref(defaultStore.state.accountSetupWizard);

watch(page, () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/frontend/src/components/global/MkTime.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ function getDateSafe(n: Date | string | number) {
}
}

// eslint-disable-next-line vue/no-setup-props-destructure
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const _time = props.time == null ? NaN : getDateSafe(props.time).getTime();
const invalid = Number.isNaN(_time);
const absolute = !invalid ? dateTimeFormat.format(_time) : i18n.ts._ago.invalid;

// eslint-disable-next-line vue/no-setup-props-destructure
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const now = ref(props.origin?.getTime() ?? Date.now());
const ago = computed(() => (now.value - _time) / 1000/*ms*/);

Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/pages/reversi/game.board.vue
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ const props = defineProps<{
const showBoardLabels = ref<boolean>(false);
const useAvatarAsStone = ref<boolean>(true);
const autoplaying = ref<boolean>(false);
// eslint-disable-next-line vue/no-setup-props-destructure
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const game = ref<Misskey.entities.ReversiGameDetailed & { logs: Reversi.Serializer.SerializedLog[] }>(deepClone(props.game));
const logPos = ref<number>(game.value.logs.length);
const engine = shallowRef<Reversi.Game>(Reversi.Serializer.restoreGame({
Expand Down

0 comments on commit 6d2b1d5

Please sign in to comment.