summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortamaina <tamaina@hotmail.co.jp>2021-08-20 19:38:16 +0900
committerGitHub <noreply@github.com>2021-08-20 19:38:16 +0900
commitfc56b1269084f4556e2a03f6dd3ffd893a5e0063 (patch)
treea12164680b0517457550595816862eeeabf6ec84 /src
parentCreate dependabot.yml (diff)
downloadsharkey-fc56b1269084f4556e2a03f6dd3ffd893a5e0063.tar.gz
sharkey-fc56b1269084f4556e2a03f6dd3ffd893a5e0063.tar.bz2
sharkey-fc56b1269084f4556e2a03f6dd3ffd893a5e0063.zip
refactor: localStorageのaccountsはindexedDBで保持するように (#7609)
* accountsストアはindexedDBで保持するように * fix lint * fix indexeddb available detection * remove debugging code * fix lint * resolve https://github.com/misskey-dev/misskey/pull/7609/files/ba756204b77ce6e1189b8443e9641f2d02119621#diff-f565878e8202f0037b830c780b7c0932dc1bb5fd3d05ede14d72d10efbc3740c Firefoxでの動作を改善 * fix lint * fix lint * add changelog
Diffstat (limited to 'src')
-rw-r--r--src/client/account.ts57
-rw-r--r--src/client/init.ts9
-rw-r--r--src/client/pages/settings/accounts.vue10
-rw-r--r--src/client/scripts/get-account-from-id.ts7
-rw-r--r--src/client/scripts/idb-proxy.ts38
-rw-r--r--src/client/ui/_common_/sidebar.vue6
-rw-r--r--src/client/ui/default.header.vue6
-rw-r--r--src/client/ui/default.sidebar.vue6
8 files changed, 111 insertions, 28 deletions
diff --git a/src/client/account.ts b/src/client/account.ts
index 2b860b3ddf..cf52c4d828 100644
--- a/src/client/account.ts
+++ b/src/client/account.ts
@@ -1,7 +1,8 @@
+import { get, set } from '@client/scripts/idb-proxy';
import { reactive } from 'vue';
import { apiUrl } from '@client/config';
import { waiting } from '@client/os';
-import { unisonReload } from '@client/scripts/unison-reload';
+import { unisonReload, reloadChannel } from '@client/scripts/unison-reload';
// TODO: 他のタブと永続化されたstateを同期
@@ -17,22 +18,43 @@ const data = localStorage.getItem('account');
// TODO: 外部からはreadonlyに
export const $i = data ? reactive(JSON.parse(data) as Account) : null;
-export function signout() {
+export async function signout() {
+ waiting();
localStorage.removeItem('account');
+
+ //#region Remove account
+ const accounts = await getAccounts();
+ accounts.splice(accounts.findIndex(x => x.id === $i.id), 1);
+ set('accounts', accounts);
+ //#endregion
+
+ //#region Remove push notification registration
+ const registration = await navigator.serviceWorker.ready;
+ const push = await registration.pushManager.getSubscription();
+ if (!push) return;
+ await fetch(`${apiUrl}/sw/unregister`, {
+ method: 'POST',
+ body: JSON.stringify({
+ i: $i.token,
+ endpoint: push.endpoint,
+ }),
+ });
+ //#endregion
+
document.cookie = `igi=; path=/`;
- location.href = '/';
+
+ if (accounts.length > 0) login(accounts[0].token);
+ else unisonReload();
}
-export function getAccounts() {
- const accountsData = localStorage.getItem('accounts');
- const accounts: { id: Account['id'], token: Account['token'] }[] = accountsData ? JSON.parse(accountsData) : [];
- return accounts;
+export async function getAccounts(): Promise<{ id: Account['id'], token: Account['token'] }[]> {
+ return (await get('accounts')) || [];
}
-export function addAccount(id: Account['id'], token: Account['token']) {
- const accounts = getAccounts();
+export async function addAccount(id: Account['id'], token: Account['token']) {
+ const accounts = await getAccounts();
if (!accounts.some(x => x.id === id)) {
- localStorage.setItem('accounts', JSON.stringify(accounts.concat([{ id, token }])));
+ await set('accounts', accounts.concat([{ id, token }]));
}
}
@@ -47,7 +69,7 @@ function fetchAccount(token): Promise<Account> {
})
.then(res => {
// When failed to authenticate user
- if (res.status >= 400 && res.status < 500) {
+ if (res.status !== 200 && res.status < 500) {
return signout();
}
@@ -69,15 +91,22 @@ export function updateAccount(data) {
}
export function refreshAccount() {
- fetchAccount($i.token).then(updateAccount);
+ return fetchAccount($i.token).then(updateAccount);
}
-export async function login(token: Account['token']) {
+export async function login(token: Account['token'], redirect?: string) {
waiting();
if (_DEV_) console.log('logging as token ', token);
const me = await fetchAccount(token);
localStorage.setItem('account', JSON.stringify(me));
- addAccount(me.id, token);
+ await addAccount(me.id, token);
+
+ if (redirect) {
+ reloadChannel.postMessage('reload');
+ location.href = redirect;
+ return;
+ }
+
unisonReload();
}
diff --git a/src/client/init.ts b/src/client/init.ts
index 1580ef3e08..0313af4374 100644
--- a/src/client/init.ts
+++ b/src/client/init.ts
@@ -4,6 +4,15 @@
import '@client/style.scss';
+//#region account indexedDB migration
+import { set } from '@client/scripts/idb-proxy';
+
+if (localStorage.getItem('accounts') != null) {
+ set('accounts', JSON.parse(localStorage.getItem('accounts')));
+ localStorage.removeItem('accounts');
+}
+//#endregion
+
import * as Sentry from '@sentry/browser';
import { Integrations } from '@sentry/tracing';
import { computed, createApp, watch, markRaw } from 'vue';
diff --git a/src/client/pages/settings/accounts.vue b/src/client/pages/settings/accounts.vue
index 53e28bdf6f..ca6f53776a 100644
--- a/src/client/pages/settings/accounts.vue
+++ b/src/client/pages/settings/accounts.vue
@@ -48,10 +48,10 @@ export default defineComponent({
title: this.$ts.accounts,
icon: 'fas fa-users',
},
- storedAccounts: getAccounts().filter(x => x.id !== this.$i.id),
+ storedAccounts: getAccounts().then(accounts => accounts.filter(x => x.id !== this.$i.id)),
accounts: null,
- init: () => os.api('users/show', {
- userIds: this.storedAccounts.map(x => x.id)
+ init: async () => os.api('users/show', {
+ userIds: (await this.storedAccounts).map(x => x.id)
}).then(accounts => {
this.accounts = accounts;
}),
@@ -104,8 +104,8 @@ export default defineComponent({
}, 'closed');
},
- switchAccount(account: any) {
- const storedAccounts = getAccounts();
+ async switchAccount(account: any) {
+ const storedAccounts = await getAccounts();
const token = storedAccounts.find(x => x.id === account.id).token;
this.switchAccountWithToken(token);
},
diff --git a/src/client/scripts/get-account-from-id.ts b/src/client/scripts/get-account-from-id.ts
new file mode 100644
index 0000000000..065b41118c
--- /dev/null
+++ b/src/client/scripts/get-account-from-id.ts
@@ -0,0 +1,7 @@
+import { get } from '@client/scripts/idb-proxy';
+
+export async function getAccountFromId(id: string) {
+ const accounts = await get('accounts') as { token: string; id: string; }[];
+ if (!accounts) console.log('Accounts are not recorded');
+ return accounts.find(e => e.id === id);
+}
diff --git a/src/client/scripts/idb-proxy.ts b/src/client/scripts/idb-proxy.ts
new file mode 100644
index 0000000000..21c4dcff65
--- /dev/null
+++ b/src/client/scripts/idb-proxy.ts
@@ -0,0 +1,38 @@
+// FirefoxのプライベートモードなどではindexedDBが使用不可能なので、
+// indexedDBが使えない環境ではlocalStorageを使う
+import {
+ get as iget,
+ set as iset,
+ del as idel,
+ createStore,
+} from 'idb-keyval';
+
+const fallbackName = (key: string) => `idbfallback::${key}`;
+
+let idbAvailable = typeof window !== 'undefined' ? !!window.indexedDB : true;
+
+if (idbAvailable) {
+ try {
+ await createStore('keyval-store', 'keyval');
+ } catch (e) {
+ console.error('idb open error', e);
+ idbAvailable = false;
+ }
+}
+
+if (!idbAvailable) console.error('indexedDB is unavailable. It will use localStorage.');
+
+export async function get(key: string) {
+ if (idbAvailable) return iget(key);
+ return JSON.parse(localStorage.getItem(fallbackName(key)));
+}
+
+export async function set(key: string, val: any) {
+ if (idbAvailable) return iset(key, val);
+ return localStorage.setItem(fallbackName(key), JSON.stringify(val));
+}
+
+export async function del(key: string) {
+ if (idbAvailable) return idel(key);
+ return localStorage.removeItem(fallbackName(key));
+}
diff --git a/src/client/ui/_common_/sidebar.vue b/src/client/ui/_common_/sidebar.vue
index b7b88faeac..333d0ac392 100644
--- a/src/client/ui/_common_/sidebar.vue
+++ b/src/client/ui/_common_/sidebar.vue
@@ -135,7 +135,7 @@ export default defineComponent({
},
async openAccountMenu(ev) {
- const storedAccounts = getAccounts().filter(x => x.id !== this.$i.id);
+ const storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== this.$i.id));
const accountsPromise = os.api('users/show', { userIds: storedAccounts.map(x => x.id) });
const accountItemPromises = storedAccounts.map(a => new Promise(res => {
@@ -195,8 +195,8 @@ export default defineComponent({
}, 'closed');
},
- switchAccount(account: any) {
- const storedAccounts = getAccounts();
+ async switchAccount(account: any) {
+ const storedAccounts = await getAccounts();
const token = storedAccounts.find(x => x.id === account.id).token;
this.switchAccountWithToken(token);
},
diff --git a/src/client/ui/default.header.vue b/src/client/ui/default.header.vue
index df2e99f13a..6fbdd625c7 100644
--- a/src/client/ui/default.header.vue
+++ b/src/client/ui/default.header.vue
@@ -101,7 +101,7 @@ export default defineComponent({
},
async openAccountMenu(ev) {
- const storedAccounts = getAccounts().filter(x => x.id !== this.$i.id);
+ const storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== this.$i.id));
const accountsPromise = os.api('users/show', { userIds: storedAccounts.map(x => x.id) });
const accountItemPromises = storedAccounts.map(a => new Promise(res => {
@@ -161,8 +161,8 @@ export default defineComponent({
}, 'closed');
},
- switchAccount(account: any) {
- const storedAccounts = getAccounts();
+ async switchAccount(account: any) {
+ const storedAccounts = await getAccounts();
const token = storedAccounts.find(x => x.id === account.id).token;
this.switchAccountWithToken(token);
},
diff --git a/src/client/ui/default.sidebar.vue b/src/client/ui/default.sidebar.vue
index b500ab582c..be907aa2a4 100644
--- a/src/client/ui/default.sidebar.vue
+++ b/src/client/ui/default.sidebar.vue
@@ -121,7 +121,7 @@ export default defineComponent({
},
async openAccountMenu(ev) {
- const storedAccounts = getAccounts().filter(x => x.id !== this.$i.id);
+ const storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== this.$i.id));
const accountsPromise = os.api('users/show', { userIds: storedAccounts.map(x => x.id) });
const accountItemPromises = storedAccounts.map(a => new Promise(res => {
@@ -181,8 +181,8 @@ export default defineComponent({
}, 'closed');
},
- switchAccount(account: any) {
- const storedAccounts = getAccounts();
+ async switchAccount(account: any) {
+ const storedAccounts = await getAccounts();
const token = storedAccounts.find(x => x.id === account.id).token;
this.switchAccountWithToken(token);
},