From be065b57899ca3e8f787f6adf33c780c8e58f39f Mon Sep 17 00:00:00 2001 From: cp-20 Date: Fri, 6 Dec 2024 00:52:00 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20ogp=20cache=20=E3=82=92=20message=20?= =?UTF-8?q?=E3=81=94=E3=81=A8=E3=81=AB=E5=88=86=E5=89=B2=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=83=96=E3=83=A9=E3=82=A6=E3=82=B6=E3=81=AB=E3=82=AD=E3=83=A3?= =?UTF-8?q?=E3=83=83=E3=82=B7=E3=83=A5=E3=81=95=E3=81=9B=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/domain/messagesView.ts | 3 ++- src/store/entities/messages.ts | 22 +++++++++++++--------- src/views/Settings/ThemeTab.vue | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/store/domain/messagesView.ts b/src/store/domain/messagesView.ts index 6c86f38517..61c557fba7 100644 --- a/src/store/domain/messagesView.ts +++ b/src/store/domain/messagesView.ts @@ -66,7 +66,8 @@ const useMessagesViewPinia = defineStore('domain/messagesView', () => { .map(async e => { try { await messagesStore.fetchOgpData({ - url: e.url + url: e.url, + messageId }) } catch { // TODO: エラー処理、無効な埋め込みの扱いを考える必要あり diff --git a/src/store/entities/messages.ts b/src/store/entities/messages.ts index 3a7c761d90..54601455a7 100644 --- a/src/store/entities/messages.ts +++ b/src/store/entities/messages.ts @@ -1,13 +1,14 @@ import type { FileInfo, Message, MessageStamp, Ogp } from '@traptitech/traq' import type { AxiosError } from 'axios' import mitt from 'mitt' -import { defineStore, acceptHMRUpdate } from 'pinia' +import { acceptHMRUpdate, defineStore } from 'pinia' import { ref } from 'vue' import apis from '/@/lib/apis' import { createSingleflight } from '/@/lib/basic/async' import { wsListener } from '/@/lib/websocket' import { convertToRefsStore } from '/@/store/utils/convertToRefsStore' import type { ExternalUrl, FileId, MessageId } from '/@/types/entity-ids' +import axios from 'axios' type MessageEventMap = { reconnect: void @@ -21,7 +22,14 @@ export const messageMitt = mitt() const getMessage = createSingleflight(apis.getMessage.bind(apis)) const getFileMeta = createSingleflight(apis.getFileMeta.bind(apis)) -const getOgp = createSingleflight(apis.getOgp.bind(apis)) +// メッセージごとにネットワーク上 (ブラウザ上) のキャッシュを分けるために message=encodeURIComponent(messageId) を apis.getOgp に追加している +// (クエリパラメータを追加で渡せないので fetch で回避している) +const getOgp = createSingleflight((url: string, messageId: string) => { + const base = '/api/v3/ogp' + const urlEncoded = encodeURIComponent(url) + const messageIdEncoded = encodeURIComponent(messageId) + return axios.get(`${base}?url=${urlEncoded}&message=${messageIdEncoded}`) +}) const useMessagesStorePinia = defineStore('entities/messages', () => { /** @@ -101,18 +109,14 @@ const useMessagesStorePinia = defineStore('entities/messages', () => { const ogpDataMap = ref(new Map()) const fetchOgpData = async ({ url, - ignoreCache = false + messageId }: { url: ExternalUrl + messageId: MessageId ignoreCache?: boolean }) => { - if (!ignoreCache && ogpDataMap.value.has(url)) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return ogpDataMap.value.get(url)! - } - try { - const [{ data: ogpData }, shared] = await getOgp(url) + const [{ data: ogpData }, shared] = await getOgp(url, messageId) // ページにOGPが存在しない場合、undefinedを返す if (ogpData.type === 'empty') { if (!shared) ogpDataMap.value.set(url, undefined) diff --git a/src/views/Settings/ThemeTab.vue b/src/views/Settings/ThemeTab.vue index 32e2dd6fb3..29b20a26dd 100644 --- a/src/views/Settings/ThemeTab.vue +++ b/src/views/Settings/ThemeTab.vue @@ -61,7 +61,7 @@