Change: manage sync status in background

This commit is contained in:
eight 2019-10-01 20:26:22 +08:00
parent f6567eef12
commit 93698e728b
2 changed files with 87 additions and 52 deletions

View File

@ -1,9 +1,13 @@
/* global dbToCloud styleManager chromeLocal prefs tokenManager */ /* global dbToCloud styleManager chromeLocal prefs tokenManager msg */
/* exported sync */ /* exported sync */
'use strict'; 'use strict';
const sync = (() => { const sync = (() => {
const status = {
state: 'disconnected',
syncing: false
};
let currentDrive; let currentDrive;
const ctrl = dbToCloud.dbToCloud({ const ctrl = dbToCloud.dbToCloud({
onGet(id) { onGet(id) {
@ -58,9 +62,37 @@ const sync = (() => {
stop, stop,
put: ctrl.put, put: ctrl.put,
delete: ctrl.delete, delete: ctrl.delete,
syncNow: () => ctrl.syncNow().catch(handle401Error) syncNow
}; };
function withFinally(p, cleanup) {
return p.then(
result => {
cleanup();
return result;
},
err => {
cleanup();
throw err;
}
);
}
function syncNow() {
if (status.syncing) {
return Promise.reject(new Error('still syncing'));
}
status.syncing = true;
emitChange();
return withFinally(
ctrl.syncNow().catch(handle401Error),
() => {
status.syncing = false;
emitChange();
}
);
}
function handle401Error(err) { function handle401Error(err) {
if (err.code === 401) { if (err.code === 401) {
return tokenManager.revokeToken(currentDrive.name) return tokenManager.revokeToken(currentDrive.name)
@ -71,6 +103,10 @@ const sync = (() => {
throw err; throw err;
} }
function emitChange() {
msg.broadcastExtension({method: 'syncStatusUpdate', status});
}
function start(name) { function start(name) {
if (currentDrive) { if (currentDrive) {
return Promise.resolve(); return Promise.resolve();
@ -78,18 +114,26 @@ const sync = (() => {
currentDrive = getDrive(name); currentDrive = getDrive(name);
ctrl.use(currentDrive); ctrl.use(currentDrive);
prefs.set('sync.enabled', name); prefs.set('sync.enabled', name);
return ctrl.start() status.state = 'connecting';
.catch(err => { status.syncing = true;
if (/Authorization page could not be loaded/i.test(err.message)) { emitChange();
// FIXME: Chrome always fail at the first login so we try again return withFinally(
return ctrl.syncNow(); ctrl.start()
} .catch(err => {
throw err; if (/Authorization page could not be loaded/i.test(err.message)) {
}) // FIXME: Chrome always fail at the first login so we try again
.catch(handle401Error) return ctrl.syncNow();
.then(() => { }
throw err;
})
.catch(handle401Error),
() => {
chrome.alarms.create('syncNow', {periodInMinutes: 30}); chrome.alarms.create('syncNow', {periodInMinutes: 30});
}); status.state = 'connected';
status.syncing = false;
emitChange();
}
);
} }
function getDrive(name) { function getDrive(name) {
@ -107,12 +151,18 @@ const sync = (() => {
return Promise.resolve(); return Promise.resolve();
} }
chrome.alarms.clear('syncNow'); chrome.alarms.clear('syncNow');
return ctrl.stop() status.state = 'disconnecting';
.then(() => tokenManager.revokeToken(currentDrive.name)) emitChange();
.then(() => chromeLocal.remove(`sync/state/${currentDrive.name}`)) return withFinally(
.then(() => { ctrl.stop()
.then(() => tokenManager.revokeToken(currentDrive.name))
.then(() => chromeLocal.remove(`sync/state/${currentDrive.name}`)),
() => {
currentDrive = null; currentDrive = null;
prefs.set('sync.enabled', 'none'); prefs.set('sync.enabled', 'none');
}); status.state = 'disconnected';
emitChange();
}
);
} }
})(); })();

View File

@ -81,15 +81,21 @@ document.onclick = e => {
const disconnectButton = document.querySelector('.sync-options .disconnect'); const disconnectButton = document.querySelector('.sync-options .disconnect');
const syncButton = document.querySelector('.sync-options .sync-now'); const syncButton = document.querySelector('.sync-options .sync-now');
let connected = false; let status = {};
let syncing = false;
prefs.subscribe(['sync.enabled'], (key, value) => { msg.onExtension(e => {
cloud.value = value; if (e.method === 'syncStatusUpdate') {
connected = value !== 'none'; status = e.status;
updateButtons(); updateButtons();
}
}); });
API.getSyncStatus()
.then(_status => {
status = _status;
updateButtons();
});
function validClick(e) { function validClick(e) {
return e.button === 0 && !e.ctrl && !e.alt && !e.shift; return e.button === 0 && !e.ctrl && !e.alt && !e.shift;
} }
@ -97,48 +103,27 @@ document.onclick = e => {
cloud.addEventListener('change', updateButtons); cloud.addEventListener('change', updateButtons);
function updateButtons() { function updateButtons() {
cloud.disabled = connected; cloud.disabled = status.state !== 'disconnected';
connectButton.disabled = connected || cloud.value === 'none'; connectButton.disabled = status.state !== 'disconnected' || cloud.value === 'none';
disconnectButton.disabled = !connected || syncing; disconnectButton.disabled = status.state !== 'connected' || status.syncing;
syncButton.disabled = !connected || syncing; syncButton.disabled = status.state !== 'connected' || status.syncing;
} }
connectButton.addEventListener('click', e => { connectButton.addEventListener('click', e => {
if (validClick(e)) { if (validClick(e)) {
syncing = true; API.syncStart(cloud.value).catch(console.error);
updateButtons();
API.syncStart(cloud.value)
.catch(console.error)
.then(() => {
syncing = false;
updateButtons();
});
} }
}); });
disconnectButton.addEventListener('click', e => { disconnectButton.addEventListener('click', e => {
if (validClick(e)) { if (validClick(e)) {
syncing = true; API.syncStop().catch(console.error);
updateButtons();
API.syncStop()
.catch(console.error)
.then(() => {
syncing = false;
updateButtons();
});
} }
}); });
syncButton.addEventListener('click', e => { syncButton.addEventListener('click', e => {
if (validClick(e)) { if (validClick(e)) {
syncing = true; API.syncNow().catch(console.error);
updateButtons();
API.syncNow()
.catch(console.error)
.then(() => {
syncing = false;
updateButtons();
});
} }
}); });
})(); })();