diff --git a/packages/frontend-shared/js/retry-on-throttled.ts b/packages/frontend-shared/js/retry-on-throttled.ts new file mode 100644 index 0000000000..f73e19b5c7 --- /dev/null +++ b/packages/frontend-shared/js/retry-on-throttled.ts @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: outvi and other Sharkey contributors + * SPDX-License-Identifier: AGPL-3.0-only +*/ + +async function sleep(ms: number): Promise { + return new Promise((resolve) => { + window.setTimeout(() => { + resolve(); + }, ms); + }); +} + +export async function retryOnThrottled(f: () => Promise, retryCount = 5): Promise { + let lastError; + for (let i = 0; i < Math.min(retryCount, 1); i++) { + try { + return await f(); + } catch (err: any) { + // RATE_LIMIT_EXCEEDED + if (typeof err === 'object' && err?.id === 'd5826d14-3982-4d2e-8011-b9e9f02499ef') { + lastError = err; + await sleep(err?.info?.fullResetMs ?? 1000); + } else { + throw err; + } + } + } + + throw lastError; +} diff --git a/packages/frontend/src/components/page/page.note.vue b/packages/frontend/src/components/page/page.note.vue index df26874c17..543e9afdaf 100644 --- a/packages/frontend/src/components/page/page.note.vue +++ b/packages/frontend/src/components/page/page.note.vue @@ -11,8 +11,9 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/page/page.vue b/packages/frontend/src/components/page/page.vue index a31c5eff28..9f9feeed49 100644 --- a/packages/frontend/src/components/page/page.vue +++ b/packages/frontend/src/components/page/page.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/page-editor/els/page-editor.el.note.vue b/packages/frontend/src/pages/page-editor/els/page-editor.el.note.vue index f275ec9517..7d56743967 100644 --- a/packages/frontend/src/pages/page-editor/els/page-editor.el.note.vue +++ b/packages/frontend/src/pages/page-editor/els/page-editor.el.note.vue @@ -25,6 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only /* eslint-disable vue/no-mutating-props */ import { watch, ref } from 'vue'; import * as Misskey from 'misskey-js'; +import { retryOnThrottled } from '@@/js/retry-on-throttled.js'; import XContainer from '../page-editor.container.vue'; import MkInput from '@/components/MkInput.vue'; import MkSwitch from '@/components/MkSwitch.vue'; @@ -35,6 +36,7 @@ import { i18n } from '@/i18n.js'; const props = defineProps<{ modelValue: Misskey.entities.PageBlock & { type: 'note' }; + index: number; }>(); const emit = defineEmits<{ @@ -58,7 +60,13 @@ watch(id, async () => { ...props.modelValue, note: id.value, }); - note.value = await misskeyApi('notes/show', { noteId: id.value }); + const timeoutId = window.setTimeout(async () => { + note.value = await retryOnThrottled(() => misskeyApi('notes/show', { noteId: id.value })); + }, 500 * props.index); // rate limit is 2 reqs per sec + + return () => { + window.clearTimeout(timeoutId); + }; }, { immediate: true, }); diff --git a/packages/frontend/src/pages/page-editor/page-editor.blocks.vue b/packages/frontend/src/pages/page-editor/page-editor.blocks.vue index f191320180..8d7ba1a3ab 100644 --- a/packages/frontend/src/pages/page-editor/page-editor.blocks.vue +++ b/packages/frontend/src/pages/page-editor/page-editor.blocks.vue @@ -5,10 +5,16 @@ SPDX-License-Identifier: AGPL-3.0-only