Implement “sync now concept” in C++, trigger “sync now” when coming back online

This commit is contained in:
Ben Gotow 2017-08-29 13:55:32 -07:00
parent 1d29ed466c
commit 320b37fb4d
7 changed files with 60 additions and 76 deletions

View file

@ -28,6 +28,8 @@
{
"label": "File",
"submenu": [
{ "label": "Sync New Mail Now", "command": "window:sync-mail-now" },
{ "type": "separator" },
{ "label": "New Message", "command": "application:new-message" },
{ "type": "separator" },
{ "label": "Close Window", "command": "window:close" },

View file

@ -3,6 +3,8 @@
{
"label": "&File",
"submenu": [
{ "label": "Sync New Mail Now", "command": "window:sync-mail-now" },
{ "type": "separator" },
{ "label": "&New Message...", "command": "application:new-message" },
{ "type": "separator" },
{ "label": "Add Account...", "command": "application:add-account", "args": {"source": "Menu"}},

View file

@ -79,6 +79,8 @@
"command": "application:view-help"
},
{ "type": "separator" },
{ "label": "Sync New Mail Now", "command": "window:sync-mail-now" },
{ "type": "separator" },
{ "label": "Preferences", "command": "application:open-preferences" },
{ "label": "Add Account...", "command": "application:add-account", "args": {"source": "Menu"}},
{ "label": "Change Theme...", "command": "window:launch-theme-picker" },

View file

@ -6,6 +6,7 @@ import TaskQueue from './stores/task-queue';
import IdentityStore from './stores/identity-store';
import AccountStore from './stores/account-store';
import DatabaseStore from './stores/database-store';
import OnlineStatusStore from './stores/online-status-store';
import DatabaseChangeRecord from './stores/database-change-record';
import DatabaseObjectRegistry from '../registries/database-object-registry';
import MailsyncProcess from '../mailsync-process';
@ -37,6 +38,7 @@ export default class MailsyncBridge {
// }, this);
AccountStore.listen(this.ensureClients, this);
OnlineStatusStore.listen(this.onOnlineStatusChanged, this);
NylasEnv.onBeforeUnload(this.onBeforeUnload);
process.nextTick(() => {
@ -173,6 +175,19 @@ export default class MailsyncBridge {
return true;
}
onOnlineStatusChanged = ({onlineDidChange}) => {
if (onlineDidChange && OnlineStatusStore.isOnline()) {
this.sendSyncMailNow();
}
}
sendSyncMailNow() {
console.warn("Sending `wake` to all mailsync workers...");
for (const client of Object.values(this._clients)) {
client.sendMessage({type: "wake-workers"});
}
}
sendMessageToAccount(accountId, json) {
if (!this._clients[accountId]) {
const err = new Error(`No mailsync worker is running.`);

View file

@ -4,111 +4,70 @@ import Actions from '../actions';
let isOnlineModule = null;
const CHECK_ONLINE_INTERVAL = 30 * 1000
const CHECK_ONLINE_INTERVAL = 30 * 1000;
class OnlineStatusStore extends NylasStore {
constructor() {
super()
this._isOnline = true
this._retryingInSeconds = 0
this._countdownInterval = null
this._checkOnlineTimeout = null
this._backoffScheduler = new ExponentialBackoffScheduler({jitter: false})
this._online = true;
this._countdownSeconds = 0;
this.setupEmitter()
this._interval = null;
this._timeout = null;
this._backoffScheduler = new ExponentialBackoffScheduler({jitter: false});
if (NylasEnv.isMainWindow()) {
Actions.checkOnlineStatus.listen(() => this._checkOnlineStatus());
setTimeout(() => {
this._checkOnlineStatus();
}, 3000);
Actions.checkOnlineStatus.listen(this._checkOnlineStatus);
setTimeout(this._checkOnlineStatus, 3 * 1000); // initial check
}
}
isOnline() {
return this._isOnline
return this._online;
}
retryingInSeconds() {
return this._retryingInSeconds
return this._countdownSeconds;
}
async _setNextOnlineState() {
isOnlineModule = isOnlineModule || require('is-online'); //eslint-disable-line
const nextIsOnline = await isOnlineModule();
if (this._isOnline !== nextIsOnline) {
this._isOnline = nextIsOnline
this.trigger()
if (this._online !== nextIsOnline) {
this._online = nextIsOnline
this.trigger({onlineDidChange: true, countdownDidChange: false})
}
}
async _checkOnlineStatus() {
this._clearCheckOnlineInterval()
this._clearRetryCountdown()
_checkOnlineStatus = async () => {
clearInterval(this._interval);
clearTimeout(this._timeout);
// If we are currently offline, this trigger will show the `Retrying now...`
// message
this._retryingInSeconds = 0
this.trigger()
// If we are currently offline, this trigger will show `Retrying now...`
this._countdownSeconds = 0
this.trigger({onlineDidChange: false, countdownDidChange: true});
await this._setNextOnlineState()
if (!this._isOnline) {
this._checkOnlineStatusAfterBackoff()
if (this._online) {
// just check again later
this._backoffScheduler.reset();
this._timeout = setTimeout(this._checkOnlineStatus, CHECK_ONLINE_INTERVAL);
} else {
this._backoffScheduler.reset()
this._checkOnlineTimeout = setTimeout(() => {
this._checkOnlineStatus()
}, CHECK_ONLINE_INTERVAL)
}
}
async _checkOnlineStatusAfterBackoff() {
const nextDelayMs = this._backoffScheduler.nextDelay()
try {
await this._countdownRetryingInSeconds(nextDelayMs)
this._checkOnlineStatus()
} catch (err) {
// This means the retry countdown was cleared, in which case we don't
// want to do anything
}
}
async _countdownRetryingInSeconds(nextDelayMs) {
this._retryingInSeconds = Math.ceil(nextDelayMs / 1000)
this.trigger()
return new Promise((resolve, reject) => {
this._clearRetryCountdown()
this._emitter.once('clear-retry-countdown', () => reject(new Error('Retry countdown cleared')))
this._countdownInterval = setInterval(() => {
this._retryingInSeconds = Math.max(0, this._retryingInSeconds - 1)
this.trigger()
if (this._retryingInSeconds === 0) {
this._clearCountdownInterval()
resolve()
// count down an inreasing delay and check again
this._countdownSeconds = Math.ceil(this._backoffScheduler.nextDelay() / 1000);
this._interval = setInterval(() => {
this._countdownSeconds = Math.max(0, this._countdownSeconds - 1);
if (this._countdownSeconds === 0) {
this._checkOnlineStatus();
} else {
this.trigger({onlineDidChange: false, countdownDidChange: true});
}
}, 1000)
})
}
_clearCheckOnlineInterval() {
clearInterval(this._checkOnlineTimeout)
this._checkOnlineTimeout = null
}
_clearCountdownInterval() {
clearInterval(this._countdownInterval)
this._countdownInterval = null
}
_clearRetryCountdown() {
this._clearCountdownInterval()
this._emitter.emit('clear-retry-countdown')
}, 1000);
}
}
}

View file

@ -79,6 +79,10 @@ export default class WindowEventHandler {
NylasEnv.mailsyncBridge.openLogs();
});
NylasEnv.commands.add(document.body, 'window:sync-mail-now', () => {
NylasEnv.mailsyncBridge.sendSyncMailNow();
});
NylasEnv.commands.add(document.body, 'window:attach-to-xcode', () => {
const client = Object.values(NylasEnv.mailsyncBridge.clients()).pop();
if (client) {

@ -1 +1 @@
Subproject commit 76ad51ec511685bada33583ebc7b3e33b5db71a9
Subproject commit 17f139ca4b015835d0ae478d18e6b6c0fae780d5