2016-11-29 09:33:14 +08:00
|
|
|
import _ from 'underscore';
|
2016-12-03 03:44:41 +08:00
|
|
|
import {
|
|
|
|
Actions,
|
|
|
|
N1CloudAPI,
|
|
|
|
DatabaseStore,
|
|
|
|
NylasLongConnection,
|
|
|
|
} from 'nylas-exports';
|
2016-11-29 09:33:14 +08:00
|
|
|
import DeltaStreamingConnection from './delta-streaming-connection';
|
2016-12-22 10:44:17 +08:00
|
|
|
import DeltaStreamingInMemoryConnection from './delta-streaming-in-memory-connection';
|
2016-12-01 06:55:09 +08:00
|
|
|
import DeltaProcessor from './delta-processor'
|
2016-11-29 09:33:14 +08:00
|
|
|
import ContactRankingsCache from './contact-rankings-cache';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This manages the syncing of N1 assets. We create one worker per email
|
|
|
|
* account. We save the state of the worker in the database.
|
|
|
|
*
|
|
|
|
* The `state` takes the following schema:
|
|
|
|
* this._state = {
|
|
|
|
* "deltaCursors": {
|
|
|
|
* n1Cloud: 523,
|
|
|
|
* localSync: 1108,
|
|
|
|
* }
|
|
|
|
* "deltaStatus": {
|
|
|
|
* n1Cloud: "closed",
|
|
|
|
* localSync: "connecting",
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* It can be null to indicate
|
|
|
|
*/
|
|
|
|
export default class NylasSyncWorker {
|
|
|
|
|
|
|
|
constructor(account) {
|
2016-12-01 06:55:09 +08:00
|
|
|
this._state = { deltaCursors: {}, deltaStatus: {} }
|
2016-12-03 03:44:41 +08:00
|
|
|
this._writeStateDebounced = _.debounce(this._writeState, 100)
|
2016-11-29 09:33:14 +08:00
|
|
|
this._account = account;
|
2016-12-03 03:44:41 +08:00
|
|
|
this._unlisten = Actions.retrySync.listen(this.refresh.bind(this), this);
|
2016-11-29 09:33:14 +08:00
|
|
|
this._deltaStreams = this._setupDeltaStreams(account);
|
|
|
|
this._refreshingCaches = [new ContactRankingsCache(account.id)];
|
2016-12-03 03:44:41 +08:00
|
|
|
NylasEnv.onBeforeUnload = (readyToUnload) => {
|
|
|
|
this._writeState().finally(readyToUnload)
|
|
|
|
}
|
2016-12-22 10:44:17 +08:00
|
|
|
NylasEnv.localSyncEmitter.on("refreshLocalDeltas", (accountId) => {
|
|
|
|
if (accountId !== account.id) return;
|
|
|
|
this._deltaStreams.localSync.end()
|
|
|
|
this._deltaStreams.localSync.start()
|
|
|
|
})
|
2016-11-29 09:33:14 +08:00
|
|
|
}
|
|
|
|
|
2016-12-01 06:55:09 +08:00
|
|
|
loadStateFromDatabase() {
|
2016-11-29 09:33:14 +08:00
|
|
|
return DatabaseStore.findJSONBlob(`NylasSyncWorker:${this._account.id}`).then(json => {
|
|
|
|
if (!json) return;
|
|
|
|
this._state = json;
|
|
|
|
if (!this._state.deltaCursors) this._state.deltaCursors = {}
|
|
|
|
if (!this._state.deltaStatus) this._state.deltaStatus = {}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
account() {
|
|
|
|
return this._account;
|
|
|
|
}
|
|
|
|
|
2016-12-02 01:04:37 +08:00
|
|
|
refresh() {
|
|
|
|
this.cleanup();
|
|
|
|
// Cleanup defaults to an "ENDED" socket. We need to indicate it's
|
|
|
|
// merely closed and can be re-opened again immediately.
|
|
|
|
_.map(this._deltaStreams, s => s.setStatus(NylasLongConnection.Status.Closed))
|
2016-12-02 02:17:41 +08:00
|
|
|
return this.start();
|
2016-12-02 01:04:37 +08:00
|
|
|
}
|
|
|
|
|
2016-12-03 03:44:41 +08:00
|
|
|
start = () => {
|
2016-12-01 06:55:09 +08:00
|
|
|
this._refreshingCaches.map(c => c.start());
|
2016-11-29 09:33:14 +08:00
|
|
|
_.map(this._deltaStreams, s => s.start())
|
|
|
|
}
|
|
|
|
|
2016-12-01 06:55:09 +08:00
|
|
|
cleanup() {
|
|
|
|
this._unlisten();
|
|
|
|
_.map(this._deltaStreams, s => s.end())
|
|
|
|
this._refreshingCaches.map(c => c.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
_setupDeltaStreams = (account) => {
|
2016-12-22 10:44:17 +08:00
|
|
|
const localSync = new DeltaStreamingInMemoryConnection(account.id, this._deltaStreamOpts("localSync"));
|
2016-12-01 06:55:09 +08:00
|
|
|
|
|
|
|
const n1Cloud = new DeltaStreamingConnection(N1CloudAPI,
|
|
|
|
account.id, this._deltaStreamOpts("n1Cloud"));
|
|
|
|
|
|
|
|
return {localSync, n1Cloud};
|
|
|
|
}
|
|
|
|
|
|
|
|
_deltaStreamOpts = (streamName) => {
|
|
|
|
return {
|
|
|
|
getCursor: () => this._state.deltaCursors[streamName],
|
2016-12-01 08:13:26 +08:00
|
|
|
setCursor: (val) => {
|
2016-12-01 06:55:09 +08:00
|
|
|
this._state.deltaCursors[streamName] = val;
|
2016-12-03 03:44:41 +08:00
|
|
|
this._writeStateDebounced();
|
2016-12-01 06:55:09 +08:00
|
|
|
},
|
|
|
|
onDeltas: DeltaProcessor.process.bind(DeltaProcessor),
|
2016-12-03 03:44:41 +08:00
|
|
|
onStatusChanged: (status) => {
|
2016-12-01 06:55:09 +08:00
|
|
|
this._state.deltaStatus[streamName] = status;
|
2016-12-03 03:44:41 +08:00
|
|
|
this._writeStateDebounced();
|
2016-11-29 09:33:14 +08:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_writeState() {
|
2016-12-03 03:44:41 +08:00
|
|
|
return DatabaseStore.inTransaction(t => {
|
|
|
|
return t.persistJSONBlob(`NylasSyncWorker:${this._account.id}`, this._state);
|
|
|
|
});
|
2016-11-29 09:33:14 +08:00
|
|
|
}
|
|
|
|
}
|