diff --git a/package-lock.json b/package-lock.json index 90ea73b..1ab6919 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,22 @@ } } }, + "aggregate-error": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz", + "integrity": "sha1-iINE2tAiCnLjr1CQYRf0h3GSX6w=", + "requires": { + "clean-stack": "1.3.0", + "indent-string": "3.2.0" + }, + "dependencies": { + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" + } + } + }, "ajv": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", @@ -760,6 +776,11 @@ } } }, + "clean-stack": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz", + "integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE=" + }, "cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", @@ -4933,6 +4954,14 @@ "os-tmpdir": "1.0.2" } }, + "p-any": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-any/-/p-any-1.1.0.tgz", + "integrity": "sha512-Ef0tVa4CZ5pTAmKn+Cg3w8ABBXh+hHO1aV8281dKOoUHfX+3tjG2EaFcC+aZyagg9b4EYGsHEjz21DnEE8Og2g==", + "requires": { + "p-some": "2.0.1" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -4954,6 +4983,14 @@ "p-limit": "1.2.0" } }, + "p-some": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-some/-/p-some-2.0.1.tgz", + "integrity": "sha1-Zdh8ixVO289SIdFnd4ttLhUPbwY=", + "requires": { + "aggregate-error": "1.0.0" + } + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", diff --git a/package.json b/package.json index 195fdc6..da879c4 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "node-fetch": "^1.7.3", "node-sass": "^4.7.2", "npm-run-all": "^4.1.2", + "p-any": "^1.1.0", "performance-now": "^2.1.0", "pify": "^3.0.0", "quick-lru": "^1.1.0", diff --git a/routes/_utils/database/databaseCore.js b/routes/_utils/database/databaseCore.js index 3b68b94..b3fd22b 100644 --- a/routes/_utils/database/databaseCore.js +++ b/routes/_utils/database/databaseCore.js @@ -39,6 +39,18 @@ if (process.browser && process.env.NODE_ENV !== 'production') { } } +function setInCache(cache, instanceName, key, value) { + return cache.set(`${instanceName}/${key}`, value) +} + +function getInCache(cache, instanceName, key) { + return cache.get(`${instanceName}/${key}`) +} + +function hasInCache(cache, instanceName, key) { + return cache.has(`${instanceName}/${key}`) +} + // // timelines/statuses // @@ -68,10 +80,10 @@ export async function getTimeline(instanceName, timeline, maxId = null, limit = export async function insertStatuses(instanceName, timeline, statuses) { for (let status of statuses) { - statusesCache.set(status.id, status) - accountsCache.set(status.account.id, status.account) + setInCache(statusesCache, instanceName, status.id, status) + setInCache(accountsCache, instanceName, status.account.id, status.account) if (status.reblog) { - accountsCache.set(status.reblog.account.id, status.reblog.account) + setInCache(accountsCache, instanceName, status.reblog.account.id, status.reblog.account) } } const db = await getDatabase(instanceName, timeline) @@ -93,11 +105,11 @@ export async function insertStatuses(instanceName, timeline, statuses) { } export async function getStatus(instanceName, statusId) { - if (statusesCache.has(statusId)) { + if (hasInCache(statusesCache, instanceName, statusId)) { if (process.browser && process.env.NODE_ENV !== 'production') { window.cacheStats.statuses.hits++ } - return statusesCache.get(statusId) + return getInCache(statusesCache, instanceName, statusId) } const db = await getDatabase(instanceName) let result = await dbPromise(db, STATUSES_STORE, 'readonly', (store, callback) => { @@ -105,7 +117,7 @@ export async function getStatus(instanceName, statusId) { callback(e.target.result && e.target.result) } }) - statusesCache.set(statusId, result) + setInCache(statusesCache, instanceName, statusId, result) if (process.browser && process.env.NODE_ENV !== 'production') { window.cacheStats.statuses.misses++ } @@ -117,11 +129,11 @@ export async function getStatus(instanceName, statusId) { // async function getMetaProperty(instanceName, key) { - if (metaCache.has(key)) { + if (hasInCache(metaCache, instanceName, key)) { if (process.browser && process.env.NODE_ENV !== 'production') { window.cacheStats.meta.hits++ } - return metaCache.get(key) + return getInCache(metaCache, instanceName, key) } const db = await getDatabase(instanceName) let result = await dbPromise(db, META_STORE, 'readonly', (store, callback) => { @@ -129,7 +141,7 @@ async function getMetaProperty(instanceName, key) { callback(e.target.result && e.target.result.value) } }) - metaCache.set(key, result) + setInCache(metaCache, instanceName, key, result) if (process.browser && process.env.NODE_ENV !== 'production') { window.cacheStats.meta.misses++ } @@ -137,7 +149,7 @@ async function getMetaProperty(instanceName, key) { } async function setMetaProperty(instanceName, key, value) { - metaCache.set(key, value) + setInCache(metaCache, instanceName, key, value) const db = await getDatabase(instanceName) return await dbPromise(db, META_STORE, 'readwrite', (store) => { store.put({ @@ -168,11 +180,11 @@ export async function setInstanceInfo(instanceName, value) { // export async function getAccount(instanceName, accountId) { - if (accountsCache.has(accountId)) { + if (hasInCache(accountsCache, instanceName, accountId)) { if (process.browser && process.env.NODE_ENV !== 'production') { window.cacheStats.accounts.hits++ } - return accountsCache.get(accountId) + return getInCache(accountsCache, instanceName, accountId) } const db = await getDatabase(instanceName) let result = await dbPromise(db, ACCOUNTS_STORE, 'readonly', (store, callback) => { diff --git a/routes/settings/instances/[instanceName].html b/routes/settings/instances/[instanceName].html index 70d1284..1d7eee7 100644 --- a/routes/settings/instances/[instanceName].html +++ b/routes/settings/instances/[instanceName].html @@ -97,12 +97,13 @@ import { store } from '../../_utils/store' import Layout from '../../_components/Layout.html' import SettingsLayout from '../_components/SettingsLayout.html' - import { getVerifyCredentials } from '../../_utils/mastodon/user' - import { database } from '../../_utils/database/database' + import { + changeTheme, + switchToInstance, + logOutOfInstance, + updateVerifyCredentialsForInstance + } from './_actions/[instanceName]' import { themes } from '../../_static/themes' - import { switchToTheme } from '../../_utils/themeEngine' - import { goto } from 'sapper/runtime.js' - import { toast } from '../../_utils/toast' export default { components: { @@ -111,73 +112,32 @@ }, store: () => store, data: () => ({ - themes: themes + themes: themes, }), - oncreate: async function () { - let instanceName = this.get('params').instanceName - let loggedInInstances = this.store.get('loggedInInstances') - let instanceThemes = this.store.get('instanceThemes') - let instanceData = loggedInInstances[instanceName] - let verifyCredentials = await database.getInstanceVerifyCredentials(instanceName) - if (verifyCredentials) { // update in background - getVerifyCredentials(instanceName, instanceData.access_token).then(verifyCredentials => { - database.setInstanceVerifyCredentials(instanceName, verifyCredentials) - }) - } else { // go to network - verifyCredentials = await getVerifyCredentials(instanceName, instanceData.access_token) - database.setInstanceVerifyCredentials(instanceName, verifyCredentials) - } - this.set({ - verifyCredentials: verifyCredentials, - selectedTheme: instanceThemes[instanceName] - }) + async oncreate() { + let instanceName = this.get('instanceName') + await updateVerifyCredentialsForInstance(instanceName) + }, + computed: { + instanceName: (params) => params.instanceName, + selectedTheme: ($instanceThemes, instanceName) => $instanceThemes[instanceName], + verifyCredentials: ($verifyCredentials, instanceName) => $verifyCredentials && $verifyCredentials[instanceName] }, methods: { onThemeChange() { let newTheme = this.get('selectedTheme') - let instanceName = this.get('params').instanceName - let instanceThemes = this.store.get('instanceThemes') - instanceThemes[instanceName] = newTheme - this.store.set({instanceThemes: instanceThemes}) - this.store.save() - if (this.get('params').instanceName === this.store.get('currentInstance')) { - switchToTheme(newTheme) - } + let instanceName = this.get('instanceName') + changeTheme(instanceName, newTheme) }, onSwitchToThisInstance(e) { e.preventDefault() - let instanceName = this.get('params').instanceName - let instanceThemes = this.store.get('instanceThemes') - this.store.set({ - currentInstance: instanceName - }) - this.store.save() - switchToTheme(instanceThemes[instanceName]) + let instanceName = this.get('instanceName') + switchToInstance(instanceName) }, onLogOut(e) { e.preventDefault() - let loggedInInstances = this.store.get('loggedInInstances') - let instanceThemes = this.store.get('instanceThemes') - let loggedInInstancesInOrder = this.store.get('loggedInInstancesInOrder') - let instanceName = this.get('params').instanceName - let currentInstance = this.store.get('currentInstance') - loggedInInstancesInOrder.splice(loggedInInstancesInOrder.indexOf(instanceName), 1) - let newInstance = instanceName === currentInstance ? - loggedInInstancesInOrder[0] : - currentInstance - delete loggedInInstances[instanceName] - delete instanceThemes[instanceName] - this.store.set({ - loggedInInstances: loggedInInstances, - instanceThemes: instanceThemes, - loggedInInstancesInOrder: loggedInInstancesInOrder, - currentInstance: newInstance - }) - this.store.save() - database.clearDatabaseForInstance(instanceName) - switchToTheme(instanceThemes[newInstance] || 'default') - toast.say(`Logged out of ${instanceName}`) - goto('/settings/instances') + let instanceName = this.get('instanceName') + logOutOfInstance(instanceName) } } } diff --git a/routes/settings/instances/_actions/[instanceName].js b/routes/settings/instances/_actions/[instanceName].js new file mode 100644 index 0000000..6231294 --- /dev/null +++ b/routes/settings/instances/_actions/[instanceName].js @@ -0,0 +1,68 @@ +import { getVerifyCredentials } from '../../../_utils/mastodon/user' +import { store } from '../../../_utils/store' +import { switchToTheme } from '../../../_utils/themeEngine' +import { toast } from '../../../_utils/toast' +import { database } from '../../../_utils/database/database' +import { goto } from 'sapper/runtime.js' +import pAny from 'p-any' + +export function changeTheme(instanceName, newTheme) { + let instanceThemes = store.get('instanceThemes') + instanceThemes[instanceName] = newTheme + store.set({instanceThemes: instanceThemes}) + store.save() + if (instanceName === store.get('currentInstance')) { + switchToTheme(newTheme) + } +} + +export function switchToInstance(instanceName) { + let instanceThemes = store.get('instanceThemes') + store.set({currentInstance: instanceName}) + store.save() + switchToTheme(instanceThemes[instanceName]) +} + +export async function logOutOfInstance(instanceName) { + let loggedInInstances = store.get('loggedInInstances') + let instanceThemes = store.get('instanceThemes') + let loggedInInstancesInOrder = store.get('loggedInInstancesInOrder') + let currentInstance = store.get('currentInstance') + loggedInInstancesInOrder.splice(loggedInInstancesInOrder.indexOf(instanceName), 1) + let newInstance = instanceName === currentInstance ? + loggedInInstancesInOrder[0] : + currentInstance + delete loggedInInstances[instanceName] + delete instanceThemes[instanceName] + store.set({ + loggedInInstances: loggedInInstances, + instanceThemes: instanceThemes, + loggedInInstancesInOrder: loggedInInstancesInOrder, + currentInstance: newInstance + }) + store.save() + toast.say(`Logged out of ${instanceName}`) + switchToTheme(instanceThemes[newInstance] || 'default') + await database.clearDatabaseForInstance(instanceName) + goto('/settings/instances') +} + +function setStoreVerifyCredentials(instanceName, thisVerifyCredentials) { + let verifyCredentials = store.get('verifyCredentials') || {} + verifyCredentials[instanceName] = thisVerifyCredentials + store.set({verifyCredentials: verifyCredentials}) +} + +export async function updateVerifyCredentialsForInstance(instanceName) { + let loggedInInstances = store.get('loggedInInstances') + let instanceData = loggedInInstances[instanceName] + await pAny([ + database.getInstanceVerifyCredentials(instanceName).then(verifyCredentials => { + setStoreVerifyCredentials(instanceName, verifyCredentials) + }), + getVerifyCredentials(instanceName, instanceData.access_token).then(verifyCredentials => { + setStoreVerifyCredentials(instanceName, verifyCredentials) + return database.setInstanceVerifyCredentials(instanceName, verifyCredentials) + }) + ]) +} \ No newline at end of file diff --git a/routes/settings/instances/_actions/add.js b/routes/settings/instances/_actions/add.js index e574601..743a87d 100644 --- a/routes/settings/instances/_actions/add.js +++ b/routes/settings/instances/_actions/add.js @@ -1,10 +1,10 @@ import { getAccessTokenFromAuthCode, registerApplication, generateAuthLink } from '../../../_utils/mastodon/oauth' -import { getVerifyCredentials } from '../../../_utils/mastodon/user' import { getInstanceInfo } from '../../../_utils/mastodon/instance' import { goto } from 'sapper/runtime.js' import { switchToTheme } from '../../../_utils/themeEngine' import { database } from '../../../_utils/database/database' import { store } from '../../../_utils/store' +import { updateVerifyCredentialsForInstance } from './[instanceName]' const REDIRECT_URI = (typeof location !== 'undefined' ? location.origin : 'https://pinafore.social') + '/settings/instances/add' @@ -86,9 +86,7 @@ async function registerNewInstance(code) { store.save() switchToTheme('default') // fire off request for account so it's cached - getVerifyCredentials(currentRegisteredInstanceName, instanceData.access_token).then(verifyCredentials => { - database.setInstanceVerifyCredentials(currentRegisteredInstanceName, verifyCredentials) - }) + updateVerifyCredentialsForInstance(currentRegisteredInstanceName) goto('/') }