Fixed workspace ID dependency

This commit is contained in:
benweet 2017-12-11 00:53:46 +00:00
parent 9596339684
commit 8263e14bcc
9 changed files with 117 additions and 116 deletions

View File

@ -14,6 +14,8 @@ import Modal from './Modal';
import Notification from './Notification'; import Notification from './Notification';
import SplashScreen from './SplashScreen'; import SplashScreen from './SplashScreen';
import syncSvc from '../services/syncSvc'; import syncSvc from '../services/syncSvc';
import networkSvc from '../services/networkSvc';
import sponsorSvc from '../services/sponsorSvc';
import timeSvc from '../services/timeSvc'; import timeSvc from '../services/timeSvc';
import store from '../store'; import store from '../store';
@ -77,6 +79,8 @@ export default {
created() { created() {
syncSvc.init() syncSvc.init()
.then(() => { .then(() => {
networkSvc.init();
sponsorSvc.init();
this.ready = true; this.ready = true;
}); });
}, },

View File

@ -4,7 +4,6 @@ import store from '../store';
import welcomeFile from '../data/welcomeFile.md'; import welcomeFile from '../data/welcomeFile.md';
const dbVersion = 1; const dbVersion = 1;
const dbVersionKey = `${utils.workspaceId}/localDbVersion`;
const dbStoreName = 'objects'; const dbStoreName = 'objects';
const exportBackup = utils.queryParams.exportBackup; const exportBackup = utils.queryParams.exportBackup;
if (exportBackup) { if (exportBackup) {
@ -15,11 +14,18 @@ const deleteMarkerMaxAge = 1000;
const checkSponsorshipAfter = (5 * 60 * 1000) + (30 * 1000); // tokenExpirationMargin + 30 sec const checkSponsorshipAfter = (5 * 60 * 1000) + (30 * 1000); // tokenExpirationMargin + 30 sec
class Connection { class Connection {
constructor(dbName) { constructor() {
this.getTxCbs = []; this.getTxCbs = [];
// Make the DB name
const workspaceId = store.getters['workspace/currentWorkspace'].id;
this.dbName = 'stackedit-db';
if (workspaceId !== 'main') {
this.dbName += `-${workspaceId}`;
}
// Init connection // Init connection
const request = indexedDB.open(dbName, dbVersion); const request = indexedDB.open(this.dbName, dbVersion);
request.onerror = () => { request.onerror = () => {
throw new Error("Can't connect to IndexedDB."); throw new Error("Can't connect to IndexedDB.");
@ -27,7 +33,6 @@ class Connection {
request.onsuccess = (event) => { request.onsuccess = (event) => {
this.db = event.target.result; this.db = event.target.result;
localStorage[dbVersionKey] = this.db.version; // Safari does not support onversionchange
this.db.onversionchange = () => window.location.reload(); this.db.onversionchange = () => window.location.reload();
this.getTxCbs.forEach(({ onTx, onError }) => this.createTx(onTx, onError)); this.getTxCbs.forEach(({ onTx, onError }) => this.createTx(onTx, onError));
@ -67,11 +72,6 @@ class Connection {
return this.getTxCbs.push({ onTx, onError }); return this.getTxCbs.push({ onTx, onError });
} }
// If DB version has changed (Safari support)
if (parseInt(localStorage[dbVersionKey], 10) !== this.db.version) {
return window.location.reload();
}
// Open transaction in read/write will prevent conflict with other tabs // Open transaction in read/write will prevent conflict with other tabs
const tx = this.db.transaction(this.db.objectStoreNames, 'readwrite'); const tx = this.db.transaction(this.db.objectStoreNames, 'readwrite');
tx.onerror = onError; tx.onerror = onError;
@ -102,7 +102,7 @@ const localDbSvc = {
*/ */
init() { init() {
// Create the connection // Create the connection
this.connection = new Connection(store.getters['data/dbName']); this.connection = new Connection();
// Load the DB // Load the DB
return localDbSvc.sync() return localDbSvc.sync()
@ -131,7 +131,7 @@ const localDbSvc = {
// If app was last opened 7 days ago and synchronization is off // If app was last opened 7 days ago and synchronization is off
if (!store.getters['data/loginToken'] && if (!store.getters['data/loginToken'] &&
(utils.lastOpened + utils.cleanTrashAfter < Date.now()) (store.getters['workspace/lastFocus'] + utils.cleanTrashAfter < Date.now())
) { ) {
// Clean files // Clean files
store.getters['file/items'] store.getters['file/items']
@ -447,7 +447,6 @@ const localDbSvc = {
request.onsuccess = resolve; request.onsuccess = resolve;
}) })
.then(() => { .then(() => {
localStorage.removeItem(dbVersionKey);
window.location.reload(); window.location.reload();
}, () => store.dispatch('notification/error', 'Could not delete local database.')); }, () => store.dispatch('notification/error', 'Could not delete local database.'));
}, },

View File

@ -5,8 +5,88 @@ const scriptLoadingPromises = Object.create(null);
const oauth2AuthorizationTimeout = 120 * 1000; // 2 minutes const oauth2AuthorizationTimeout = 120 * 1000; // 2 minutes
const networkTimeout = 30 * 1000; // 30 sec const networkTimeout = 30 * 1000; // 30 sec
let isConnectionDown = false; let isConnectionDown = false;
const userInactiveAfter = 2 * 60 * 1000; // 2 minutes
export default { export default {
init() {
// Keep track of the last user activity
this.lastActivity = 0;
const setLastActivity = () => {
this.lastActivity = Date.now();
};
window.document.addEventListener('mousedown', setLastActivity);
window.document.addEventListener('keydown', setLastActivity);
window.document.addEventListener('touchstart', setLastActivity);
// Keep track of the last window focus
this.lastFocus = 0;
const setLastFocus = () => {
this.lastFocus = Date.now();
localStorage.setItem(store.getters['workspace/lastFocusKey'], this.lastFocus);
setLastActivity();
};
if (document.hasFocus()) {
setLastFocus();
}
window.addEventListener('focus', setLastFocus);
// Check browser is online periodically
const checkOffline = () => {
const isBrowserOffline = window.navigator.onLine === false;
if (!isBrowserOffline &&
store.state.lastOfflineCheck + networkTimeout + 5000 < Date.now() &&
this.isUserActive()
) {
store.commit('updateLastOfflineCheck');
new Promise((resolve, reject) => {
const script = document.createElement('script');
let timeout;
let clean = (cb) => {
clearTimeout(timeout);
document.head.removeChild(script);
clean = () => {}; // Prevent from cleaning several times
cb();
};
script.onload = () => clean(resolve);
script.onerror = () => clean(reject);
script.src = `https://apis.google.com/js/api.js?${Date.now()}`;
try {
document.head.appendChild(script); // This can fail with bad network
timeout = setTimeout(() => clean(reject), networkTimeout);
} catch (e) {
reject(e);
}
})
.then(() => {
isConnectionDown = false;
}, () => {
isConnectionDown = true;
});
}
const offline = isBrowserOffline || isConnectionDown;
if (store.state.offline !== offline) {
store.commit('setOffline', offline);
if (offline) {
store.dispatch('notification/error', 'You are offline.');
} else {
store.dispatch('notification/info', 'You are back online!');
}
}
};
utils.setInterval(checkOffline, 1000);
window.addEventListener('online', () => {
isConnectionDown = false;
checkOffline();
});
window.addEventListener('offline', checkOffline);
},
isWindowFocused() {
return parseInt(localStorage.getItem(this.lastFocusKey), 10) === this.lastFocus;
},
isUserActive() {
return this.lastActivity > Date.now() - userInactiveAfter && this.isWindowFocused();
},
loadScript(url) { loadScript(url) {
if (!scriptLoadingPromises[url]) { if (!scriptLoadingPromises[url]) {
scriptLoadingPromises[url] = new Promise((resolve, reject) => { scriptLoadingPromises[url] = new Promise((resolve, reject) => {
@ -217,53 +297,3 @@ export default {
return attempt(); return attempt();
}, },
}; };
function checkOffline() {
const isBrowserOffline = window.navigator.onLine === false;
if (!isBrowserOffline &&
store.state.lastOfflineCheck + networkTimeout + 5000 < Date.now() &&
utils.isUserActive()
) {
store.commit('updateLastOfflineCheck');
new Promise((resolve, reject) => {
const script = document.createElement('script');
let timeout;
let clean = (cb) => {
clearTimeout(timeout);
document.head.removeChild(script);
clean = () => {}; // Prevent from cleaning several times
cb();
};
script.onload = () => clean(resolve);
script.onerror = () => clean(reject);
script.src = `https://apis.google.com/js/api.js?${Date.now()}`;
try {
document.head.appendChild(script); // This can fail with bad network
timeout = setTimeout(() => clean(reject), networkTimeout);
} catch (e) {
reject(e);
}
})
.then(() => {
isConnectionDown = false;
}, () => {
isConnectionDown = true;
});
}
const offline = isBrowserOffline || isConnectionDown;
if (store.state.offline !== offline) {
store.commit('setOffline', offline);
if (offline) {
store.dispatch('notification/error', 'You are offline.');
} else {
store.dispatch('notification/info', 'You are back online!');
}
}
}
utils.setInterval(checkOffline, 1000);
window.addEventListener('online', () => {
isConnectionDown = false;
checkOffline();
});
window.addEventListener('offline', checkOffline);

View File

@ -1,6 +1,7 @@
import localDbSvc from './localDbSvc'; import localDbSvc from './localDbSvc';
import store from '../store'; import store from '../store';
import utils from './utils'; import utils from './utils';
import networkSvc from './networkSvc';
import exportSvc from './exportSvc'; import exportSvc from './exportSvc';
import providerRegistry from './providers/providerRegistry'; import providerRegistry from './providers/providerRegistry';
@ -114,7 +115,7 @@ function requestPublish() {
let intervalId; let intervalId;
const attempt = () => { const attempt = () => {
// Only start publishing when these conditions are met // Only start publishing when these conditions are met
if (utils.isUserActive()) { if (networkSvc.isUserActive()) {
clearInterval(intervalId); clearInterval(intervalId);
if (!hasCurrentFilePublishLocations()) { if (!hasCurrentFilePublishLocations()) {
// Cancel sync // Cancel sync

View File

@ -23,7 +23,7 @@ const isGoogleSponsor = () => {
const checkPayment = () => { const checkPayment = () => {
const currentDate = Date.now(); const currentDate = Date.now();
if (!isGoogleSponsor() && utils.isUserActive() && !store.state.offline && if (!isGoogleSponsor() && networkSvc.isUserActive() && !store.state.offline &&
lastCheck + checkPaymentEvery < currentDate lastCheck + checkPaymentEvery < currentDate
) { ) {
lastCheck = currentDate; lastCheck = currentDate;
@ -39,9 +39,10 @@ const checkPayment = () => {
} }
}; };
utils.setInterval(checkPayment, 2000);
export default { export default {
init: () => {
utils.setInterval(checkPayment, 2000);
},
getToken() { getToken() {
if (isGoogleSponsor() || store.state.offline) { if (isGoogleSponsor() || store.state.offline) {
return Promise.resolve(); return Promise.resolve();

View File

@ -2,6 +2,7 @@ import localDbSvc from './localDbSvc';
import store from '../store'; import store from '../store';
import utils from './utils'; import utils from './utils';
import diffUtils from './diffUtils'; import diffUtils from './diffUtils';
import networkSvc from './networkSvc';
import providerRegistry from './providers/providerRegistry'; import providerRegistry from './providers/providerRegistry';
import googleDriveAppDataProvider from './providers/googleDriveAppDataProvider'; import googleDriveAppDataProvider from './providers/googleDriveAppDataProvider';
@ -14,9 +15,9 @@ let workspaceProvider;
/** /**
* Use a lock in the local storage to prevent multiple windows concurrency. * Use a lock in the local storage to prevent multiple windows concurrency.
*/ */
const lastSyncActivityKey = `${utils.workspaceId}/lastSyncActivity`;
let lastSyncActivity; let lastSyncActivity;
const getLastStoredSyncActivity = () => parseInt(localStorage[lastSyncActivityKey], 10) || 0; const getLastStoredSyncActivity = () =>
parseInt(localStorage.getItem(store.getters['workspace/lastSyncActivityKey']), 10) || 0;
/** /**
* Return true if workspace sync is possible. * Return true if workspace sync is possible.
@ -51,7 +52,7 @@ function isSyncWindow() {
} }
/** /**
* Return true if auto sync can start, ie that lastSyncActivity is old enough. * Return true if auto sync can start, ie if lastSyncActivity is old enough.
*/ */
function isAutoSyncReady() { function isAutoSyncReady() {
const storedLastSyncActivity = getLastStoredSyncActivity(); const storedLastSyncActivity = getLastStoredSyncActivity();
@ -64,7 +65,7 @@ function isAutoSyncReady() {
function setLastSyncActivity() { function setLastSyncActivity() {
const currentDate = Date.now(); const currentDate = Date.now();
lastSyncActivity = currentDate; lastSyncActivity = currentDate;
localStorage[lastSyncActivityKey] = currentDate; localStorage.setItem(store.getters['workspace/lastSyncActivityKey'], currentDate);
} }
/** /**
@ -626,7 +627,7 @@ function requestSync() {
let intervalId; let intervalId;
const attempt = () => { const attempt = () => {
// Only start syncing when these conditions are met // Only start syncing when these conditions are met
if (utils.isUserActive() && isSyncWindow()) { if (networkSvc.isUserActive() && isSyncWindow()) {
clearInterval(intervalId); clearInterval(intervalId);
if (!isSyncPossible()) { if (!isSyncPossible()) {
// Cancel sync // Cancel sync
@ -704,7 +705,7 @@ export default {
// Sync periodically // Sync periodically
utils.setInterval(() => { utils.setInterval(() => {
if (isSyncPossible() && if (isSyncPossible() &&
utils.isUserActive() && networkSvc.isUserActive() &&
isSyncWindow() && isSyncWindow() &&
isAutoSyncReady() isAutoSyncReady()
) { ) {

View File

@ -2,7 +2,6 @@ import yaml from 'js-yaml';
import '../libs/clunderscore'; import '../libs/clunderscore';
import defaultProperties from '../data/defaultFileProperties.yml'; import defaultProperties from '../data/defaultFileProperties.yml';
const workspaceId = 'main';
const origin = `${location.protocol}//${location.host}`; const origin = `${location.protocol}//${location.host}`;
// For uid() // For uid()
@ -12,30 +11,6 @@ const alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
const radix = alphabet.length; const radix = alphabet.length;
const array = new Uint32Array(uidLength); const array = new Uint32Array(uidLength);
// For isUserActive
const inactiveAfter = 2 * 60 * 1000; // 2 minutes
let lastActivity;
const setLastActivity = () => {
lastActivity = Date.now();
};
window.document.addEventListener('mousedown', setLastActivity);
window.document.addEventListener('keydown', setLastActivity);
window.document.addEventListener('touchstart', setLastActivity);
// For isWindowFocused
let lastFocus;
const lastFocusKey = `${workspaceId}/lastWindowFocus`;
const lastOpened = parseInt(localStorage[lastFocusKey], 10) || 0;
const setLastFocus = () => {
lastFocus = Date.now();
localStorage[lastFocusKey] = lastFocus;
setLastActivity();
};
if (document.hasFocus()) {
setLastFocus();
}
window.addEventListener('focus', setLastFocus);
// For parseQueryParams() // For parseQueryParams()
const parseQueryParams = (params) => { const parseQueryParams = (params) => {
const result = {}; const result = {};
@ -50,11 +25,9 @@ const parseQueryParams = (params) => {
const urlParser = window.document.createElement('a'); const urlParser = window.document.createElement('a');
export default { export default {
workspaceId,
origin, origin,
queryParams: parseQueryParams(location.hash.slice(1)), queryParams: parseQueryParams(location.hash.slice(1)),
oauth2RedirectUri: `${origin}/oauth2/callback`, oauth2RedirectUri: `${origin}/oauth2/callback`,
lastOpened,
cleanTrashAfter: 7 * 24 * 60 * 60 * 1000, // 7 days cleanTrashAfter: 7 * 24 * 60 * 60 * 1000, // 7 days
types: [ types: [
'contentState', 'contentState',
@ -147,12 +120,6 @@ export default {
setInterval(func, interval) { setInterval(func, interval) {
return setInterval(() => func(), this.randomize(interval)); return setInterval(() => func(), this.randomize(interval));
}, },
isWindowFocused() {
return parseInt(localStorage[lastFocusKey], 10) === lastFocus;
},
isUserActive() {
return lastActivity > Date.now() - inactiveAfter && this.isWindowFocused();
},
parseQueryParams, parseQueryParams,
addQueryParams(url = '', params = {}) { addQueryParams(url = '', params = {}) {
const keys = Object.keys(params).filter(key => params[key] != null); const keys = Object.keys(params).filter(key => params[key] != null);

View File

@ -131,17 +131,6 @@ export default {
}); });
return result; return result;
}, },
dbName: (state, getters) => {
let dbName;
Object.keys(getters.workspaces).some((id) => {
dbName = 'stackedit-db';
if (id !== 'main') {
dbName += `-${id}`;
}
return dbName;
});
return dbName;
},
settings: getter('settings'), settings: getter('settings'),
computedSettings: (state, getters) => { computedSettings: (state, getters) => {
const customSettings = yaml.safeLoad(getters.settings); const customSettings = yaml.safeLoad(getters.settings);

View File

@ -23,6 +23,15 @@ export default {
const workspaces = rootGetters['data/workspaces']; const workspaces = rootGetters['data/workspaces'];
return workspaces[state.currentWorkspaceId] || workspaces.main; return workspaces[state.currentWorkspaceId] || workspaces.main;
}, },
lastSyncActivityKey: (state, getters) => {
const workspaceId = getters.currentWorkspace.id;
return `${workspaceId}/lastSyncActivity`;
},
lastFocusKey: (state, getters) => {
const workspaceId = getters.currentWorkspace.id;
return `${workspaceId}/lastWindowFocus`;
},
lastFocus: (state, getters) => parseInt(localStorage.getItem(getters.lastFocusKey), 10) || 0,
}, },
actions: { actions: {
}, },