From 40bfa3ef0407f83484031bfe74dcecb149c202a0 Mon Sep 17 00:00:00 2001 From: tamaina Date: Sat, 6 Feb 2021 18:55:53 +0900 Subject: Resurrect Service Worker (#7108) * Resolve #7106 * fix lint * fix lint * save lang in idb * fix lint * fix * cache locale file * fix lint * :v: * wip * fix [wip] * fix [wip] Co-authored-by: syuilo --- src/client/sw/compose-notification.ts | 13 ++++- src/client/sw/i18n.ts | 5 -- src/client/sw/sw.ts | 89 ++++++++++++++++++++++++++++++++--- 3 files changed, 93 insertions(+), 14 deletions(-) delete mode 100644 src/client/sw/i18n.ts (limited to 'src/client/sw') diff --git a/src/client/sw/compose-notification.ts b/src/client/sw/compose-notification.ts index 17421db5c8..e9586dd574 100644 --- a/src/client/sw/compose-notification.ts +++ b/src/client/sw/compose-notification.ts @@ -1,8 +1,17 @@ +/** + * Notification composer of Service Worker + */ +declare var self: ServiceWorkerGlobalScope; + import { getNoteSummary } from '../../misc/get-note-summary'; import getUserName from '../../misc/get-user-name'; -import { i18n } from '@/sw/i18n'; -export default async function(type, data): Promise<[string, NotificationOptions]> { +export default async function(type, data, i18n): Promise<[string, NotificationOptions] | null | undefined> { + if (!i18n) { + console.log('no i18n'); + return; + } + switch (type) { case 'driveFileCreated': // TODO (Server Side) return [i18n.t('_notification.fileUploaded'), { diff --git a/src/client/sw/i18n.ts b/src/client/sw/i18n.ts deleted file mode 100644 index 9b3e3b2f4d..0000000000 --- a/src/client/sw/i18n.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { I18n } from '@/i18n'; - -export const i18n = new I18n({ - // TODO -}); diff --git a/src/client/sw/sw.ts b/src/client/sw/sw.ts index 91d668c27b..c92cae1292 100644 --- a/src/client/sw/sw.ts +++ b/src/client/sw/sw.ts @@ -3,17 +3,30 @@ */ declare var self: ServiceWorkerGlobalScope; +import { get, set } from 'idb-keyval'; import composeNotification from '@/sw/compose-notification'; +import { I18n } from '@/scripts/i18n'; +//#region Variables const version = _VERSION_; const cacheName = `mk-cache-${version}`; - const apiUrl = `${location.origin}/api/`; -// インストールされたとき -self.addEventListener('install', ev => { - console.info('installed'); +let lang: string; +let i18n: I18n; +let pushesPool: any[] = []; +//#endregion + +//#region Startup +get('lang').then(async prelang => { + if (!prelang) return; + lang = prelang; + return fetchLocale(); +}); +//#endregion +//#region Lifecycle: Install +self.addEventListener('install', ev => { ev.waitUntil( caches.open(cacheName) .then(cache => { @@ -24,7 +37,9 @@ self.addEventListener('install', ev => { .then(() => self.skipWaiting()) ); }); +//#endregion +//#region Lifecycle: Activate self.addEventListener('activate', ev => { ev.waitUntil( caches.keys() @@ -36,7 +51,9 @@ self.addEventListener('activate', ev => { .then(() => self.clients.claim()) ); }); +//#endregion +//#region When: Fetching self.addEventListener('fetch', ev => { if (ev.request.method !== 'GET' || ev.request.url.startsWith(apiUrl)) return; ev.respondWith( @@ -49,8 +66,9 @@ self.addEventListener('fetch', ev => { }) ); }); +//#endregion -// プッシュ通知を受け取ったとき +//#region When: Caught Notification self.addEventListener('push', ev => { // クライアント取得 ev.waitUntil(self.clients.matchAll({ @@ -59,8 +77,65 @@ self.addEventListener('push', ev => { // クライアントがあったらストリームに接続しているということなので通知しない if (clients.length != 0) return; - const { type, body } = ev.data.json(); + const { type, body } = ev.data?.json(); + + // localeを読み込めておらずi18nがundefinedだった場合はpushesPoolにためておく + if (!i18n) return pushesPool.push({ type, body }); - return self.registration.showNotification(...(await composeNotification(type, body))); + const n = await composeNotification(type, body, i18n); + if (n) return self.registration.showNotification(...n); })); }); +//#endregion + +//#region When: Caught a message from the client +self.addEventListener('message', ev => { + switch(ev.data) { + case 'clear': + return; // TODO + default: + break; + } + + if (typeof ev.data === 'object') { + // E.g. '[object Array]' → 'array' + const otype = Object.prototype.toString.call(ev.data).slice(8, -1).toLowerCase(); + + if (otype === 'object') { + if (ev.data.msg === 'initialize') { + lang = ev.data.lang; + set('lang', lang); + fetchLocale(); + } + } + } +}); +//#endregion + +//#region Function: (Re)Load i18n instance +async function fetchLocale() { + //#region localeファイルの読み込み + // Service Workerは何度も起動しそのたびにlocaleを読み込むので、CacheStorageを使う + const localeUrl = `/assets/locales/${lang}.${version}.json`; + let localeRes = await caches.match(localeUrl); + + if (!localeRes) { + localeRes = await fetch(localeUrl); + const clone = localeRes?.clone(); + if (!clone?.clone().ok) return; + + caches.open(cacheName).then(cache => cache.put(localeUrl, clone)); + } + + i18n = new I18n(await localeRes.json()); + //#endregion + + //#region i18nをきちんと読み込んだ後にやりたい処理 + for (const { type, body } of pushesPool) { + const n = await composeNotification(type, body, i18n); + if (n) self.registration.showNotification(...n); + } + pushesPool = []; + //#endregion +} +//#endregion -- cgit v1.2.3-freya