Resurrect Service Worker (#7108)
* Resolve #7106 * fix lint * fix lint * save lang in idb * fix lint * fix * cache locale file * fix lint * ✌️ * wip * fix [wip] * fix [wip] Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
44
src/client/scripts/i18n.ts
Normal file
44
src/client/scripts/i18n.ts
Normal file
@ -0,0 +1,44 @@
|
||||
// Notice: Service Workerでも使用します
|
||||
export class I18n<T extends Record<string, any>> {
|
||||
public locale: T;
|
||||
|
||||
constructor(locale: T) {
|
||||
this.locale = locale;
|
||||
|
||||
if (_DEV_) {
|
||||
console.log('i18n', this.locale);
|
||||
}
|
||||
|
||||
//#region BIND
|
||||
this.t = this.t.bind(this);
|
||||
//#endregion
|
||||
}
|
||||
|
||||
// string にしているのは、ドット区切りでのパス指定を許可するため
|
||||
// なるべくこのメソッド使うよりもlocale直接参照の方がvueのキャッシュ効いてパフォーマンスが良いかも
|
||||
public t(key: string, args?: Record<string, any>): string {
|
||||
try {
|
||||
let str = key.split('.').reduce((o, i) => o[i], this.locale) as string;
|
||||
|
||||
if (_DEV_) {
|
||||
if (!str.includes('{')) {
|
||||
console.warn(`i18n: '${key}' has no any arg. so ref prop directly instead of call this method.`);
|
||||
}
|
||||
}
|
||||
|
||||
if (args) {
|
||||
for (const [k, v] of Object.entries(args)) {
|
||||
str = str.replace(`{${k}}`, v);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
} catch (e) {
|
||||
if (_DEV_) {
|
||||
console.warn(`missing localization '${key}'`);
|
||||
return `⚠'${key}'⚠`;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
68
src/client/scripts/initialize-sw.ts
Normal file
68
src/client/scripts/initialize-sw.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { instance } from '@/instance';
|
||||
import { $i } from '@/account';
|
||||
import { api } from '@/os';
|
||||
import { lang } from '@/config';
|
||||
|
||||
export async function initializeSw() {
|
||||
if (instance.swPublickey &&
|
||||
('serviceWorker' in navigator) &&
|
||||
('PushManager' in window) &&
|
||||
$i && $i.token) {
|
||||
navigator.serviceWorker.register(`/sw.js`);
|
||||
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.active?.postMessage({
|
||||
msg: 'initialize',
|
||||
lang,
|
||||
});
|
||||
// SEE: https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#Parameters
|
||||
registration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: urlBase64ToUint8Array(instance.swPublickey)
|
||||
}).then(subscription => {
|
||||
function encode(buffer: ArrayBuffer | null) {
|
||||
return btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)));
|
||||
}
|
||||
|
||||
// Register
|
||||
api('sw/register', {
|
||||
endpoint: subscription.endpoint,
|
||||
auth: encode(subscription.getKey('auth')),
|
||||
publickey: encode(subscription.getKey('p256dh'))
|
||||
});
|
||||
})
|
||||
// When subscribe failed
|
||||
.catch(async (err: Error) => {
|
||||
// 通知が許可されていなかったとき
|
||||
if (err.name === 'NotAllowedError') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 違うapplicationServerKey (または gcm_sender_id)のサブスクリプションが
|
||||
// 既に存在していることが原因でエラーになった可能性があるので、
|
||||
// そのサブスクリプションを解除しておく
|
||||
const subscription = await registration.pushManager.getSubscription();
|
||||
if (subscription) subscription.unsubscribe();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the URL safe base64 string to a Uint8Array
|
||||
* @param base64String base64 string
|
||||
*/
|
||||
function urlBase64ToUint8Array(base64String: string): Uint8Array {
|
||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||
const base64 = (base64String + padding)
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
const rawData = window.atob(base64);
|
||||
const outputArray = new Uint8Array(rawData.length);
|
||||
|
||||
for (let i = 0; i < rawData.length; ++i) {
|
||||
outputArray[i] = rawData.charCodeAt(i);
|
||||
}
|
||||
return outputArray;
|
||||
}
|
Reference in New Issue
Block a user