Stackedit/src/services/syncSvc.js

140 lines
4.0 KiB
JavaScript
Raw Normal View History

2017-07-28 07:40:24 +00:00
import localDbSvc from './localDbSvc';
import store from '../store';
import welcomeFile from '../data/welcomeFile.md';
import utils from './utils';
2017-08-15 10:43:26 +00:00
import userActivitySvc from './userActivitySvc';
import googleHelper from './helpers/googleHelper';
const lastSyncActivityKey = 'lastSyncActivity';
let lastSyncActivity;
const getStoredLastSyncActivity = () => parseInt(localStorage[lastSyncActivityKey], 10) || 0;
const inactivityThreshold = 3 * 1000; // 3 sec
const autoSyncAfter = 60 * 1000; // 1 min
const isSyncAvailable = () => window.navigator.onLine !== false &&
!!store.getters['data/loginToken'];
function isSyncWindow() {
const storedLastSyncActivity = getStoredLastSyncActivity();
return lastSyncActivity === storedLastSyncActivity ||
Date.now() > inactivityThreshold + storedLastSyncActivity;
}
function isAutoSyncNeeded() {
const storedLastSyncActivity = getStoredLastSyncActivity();
return Date.now() > autoSyncAfter + storedLastSyncActivity;
}
function setLastSyncActivity() {
const currentDate = Date.now();
lastSyncActivity = currentDate;
localStorage[lastSyncActivityKey] = currentDate;
}
function sync() {
const googleToken = store.getters['data/loginToken'];
return googleHelper.getChanges(googleToken)
.then((changes) => {
console.log(changes);
const localChanges = [];
[
store.state.files,
].forEach((moduleState) => {
Object.keys(moduleState.itemMap).forEach((id) => {
localChanges.push(moduleState.itemMap[id]);
});
});
const uploadLocalChange = () => {
const localChange = localChanges.pop();
if (!localChange) {
return null;
}
return googleHelper.insertAppData(googleToken, localChange)
.then(() => uploadLocalChange());
};
return uploadLocalChange();
});
}
function requestSync() {
store.dispatch('queue/enqueueSyncRequest', () => new Promise((resolve, reject) => {
let intervalId;
const attempt = () => {
// Only start syncing when these conditions are met
if (userActivitySvc.isActive() && isSyncWindow()) {
clearInterval(intervalId);
if (!isSyncAvailable()) {
// Cancel sync
reject();
} else {
// Call setLastSyncActivity periodically
intervalId = utils.setInterval(() => setLastSyncActivity(), 1000);
setLastSyncActivity();
const cleaner = cb => (res) => {
clearInterval(intervalId);
cb(res);
};
sync().then(cleaner(resolve), cleaner(reject));
}
}
};
intervalId = utils.setInterval(() => attempt(), 1000);
attempt();
}));
}
// Sync periodically
utils.setInterval(() => {
if (isSyncAvailable() &&
userActivitySvc.isActive() &&
isSyncWindow() &&
isAutoSyncNeeded()
) {
requestSync();
}
}, 1000);
2017-07-28 07:40:24 +00:00
const ifNoId = cb => (obj) => {
if (obj.id) {
return obj;
}
return cb();
};
2017-07-31 09:04:01 +00:00
// Load the DB on boot
localDbSvc.sync()
2017-08-15 10:43:26 +00:00
// And watch file changing
2017-07-31 09:04:01 +00:00
.then(() => store.watch(
() => store.getters['files/current'].id,
() => Promise.resolve(store.getters['files/current'])
2017-08-15 10:43:26 +00:00
// If current file has no ID, get the most recent file
.then(ifNoId(() => store.getters['files/mostRecent']))
// If still no ID, create a new file
.then(ifNoId(() => {
const contentId = utils.uid();
store.commit('contents/setItem', {
id: contentId,
text: welcomeFile,
});
const fileId = utils.uid();
store.commit('files/setItem', {
id: fileId,
name: 'Welcome file',
contentId,
});
return store.state.files.itemMap[fileId];
}))
.then((currentFile) => {
store.commit('files/setCurrentId', currentFile.id);
store.dispatch('files/patchCurrent', {}); // Update `updated` field to make it the mostRecent
}), {
2017-07-31 09:04:01 +00:00
immediate: true,
}));
2017-07-28 07:40:24 +00:00
2017-08-15 10:43:26 +00:00
// Sync local DB periodically
utils.setInterval(() => localDbSvc.sync(), 1000);
export default {
isSyncAvailable,
requestSync,
};