Mailspring/sync/sync-worker.js

164 lines
4.4 KiB
JavaScript
Raw Normal View History

const IMAPConnection = require('./imap/connection');
2016-06-20 15:19:16 +08:00
const RefreshMailboxesOperation = require('./imap/refresh-mailboxes-operation')
const SyncMailboxOperation = require('./imap/sync-mailbox-operation')
2016-06-21 08:33:23 +08:00
//
// account.syncPolicy = {
// afterSync: 'idle',
// limit: {
// after: Date.now() - 7 * 24 * 60 * 60 * 1000,
// count: 10000,
// },
// interval: 60 * 1000,
// folderSyncOptions: {
// deepFolderScan: 5 * 60 * 1000,
2016-06-21 08:33:23 +08:00
// },
// expiration: Date.now() + 60 * 60 * 1000,
// }
2016-06-19 18:02:32 +08:00
2016-06-20 15:19:16 +08:00
class SyncWorker {
2016-06-21 08:33:23 +08:00
2016-06-20 15:19:16 +08:00
constructor(account, db) {
2016-06-21 08:33:23 +08:00
this._db = db;
this._conn = null;
this._account = account;
this._lastSyncTime = null;
2016-06-19 18:02:32 +08:00
2016-06-21 08:33:23 +08:00
this._syncTimer = null;
this._expirationTimer = null;
2016-06-19 18:02:32 +08:00
2016-06-21 08:33:23 +08:00
this.syncNow();
this.scheduleExpiration();
}
2016-06-19 18:02:32 +08:00
2016-06-21 08:33:23 +08:00
// TODO: How does this get called?
onAccountChanged() {
this.syncNow();
this.scheduleExpiration();
}
onExpired() {
// Returning syncs to the unclaimed queue every so often is healthy.
// TODO: That.
}
onSyncDidComplete() {
const {afterSync} = this._account.syncPolicy;
if (afterSync === 'idle') {
this.getInboxCategory().then((inboxCategory) => {
this._conn.openBox(inboxCategory.name, true).then(() => {
console.log(" - Idling on inbox category");
});
2016-06-19 18:02:32 +08:00
});
2016-06-21 08:33:23 +08:00
} else if (afterSync === 'close') {
console.log(" - Closing connection");
this._conn.end();
this._conn = null;
} else {
throw new Error(`onSyncDidComplete: Unknown afterSync behavior: ${afterSync}`)
}
}
onConnectionIdleUpdate() {
this.syncNow();
2016-06-21 08:33:23 +08:00
}
2016-06-19 18:02:32 +08:00
2016-06-21 08:33:23 +08:00
getInboxCategory() {
return this._db.Category.find({where: {role: 'inbox'}})
}
ensureConnection() {
if (this._conn) {
return this._conn.connect();
}
return new Promise((resolve) => {
const settings = this._account.connectionSettings;
const credentials = this._account.decryptedCredentials();
if (!settings || !settings.imap) {
throw new Error("ensureConnection: There are no IMAP connection settings for this account.")
}
if (!credentials || !credentials.imap) {
throw new Error("ensureConnection: There are no IMAP connection credentials for this account.")
}
const conn = new IMAPConnection(this._db, Object.assign({}, settings.imap, credentials.imap));
2016-06-21 08:33:23 +08:00
conn.on('mail', () => {
this.onConnectionIdleUpdate();
})
conn.on('update', () => {
this.onConnectionIdleUpdate();
})
conn.on('queue-empty', () => {
});
this._conn = conn;
resolve(this._conn.connect());
});
2016-06-21 08:33:23 +08:00
}
queueOperationsForUpdates() {
// todo: syncback operations belong here!
return this._conn.runOperation(new RefreshMailboxesOperation())
}
queueOperationsForFolderSyncs() {
2016-06-20 15:19:16 +08:00
const {Category} = this._db;
const {folderSyncOptions} = this._account.syncPolicy;
2016-06-21 08:33:23 +08:00
return Category.findAll().then((categories) => {
const priority = ['inbox', 'drafts', 'sent'].reverse();
const categoriesToSync = categories.sort((a, b) =>
(priority.indexOf(a.role) - priority.indexOf(b.role)) * -1
2016-06-21 08:33:23 +08:00
)
// const filtered = sorted.filter(cat =>
// ['[Gmail]/All Mail', '[Gmail]/Trash', '[Gmail]/Spam'].includes(cat.name)
// )
return Promise.all(categoriesToSync.map((cat) =>
this._conn.runOperation(new SyncMailboxOperation(cat, folderSyncOptions))
2016-06-21 08:33:23 +08:00
)).then(() => {
this._lastSyncTime = Date.now();
2016-06-21 08:33:23 +08:00
});
2016-06-20 15:19:16 +08:00
});
2016-06-19 18:02:32 +08:00
}
2016-06-21 08:33:23 +08:00
syncNow() {
clearTimeout(this._syncTimer);
this.ensureConnection().then(() =>
this.queueOperationsForUpdates().then(() =>
this.queueOperationsForFolderSyncs()
)
).catch((err) => {
// Sync has failed for some reason. What do we do?!
console.error(err);
}).finally(() => {
this.onSyncDidComplete();
this.scheduleNextSync();
});
}
scheduleExpiration() {
const {expiration} = this._account.syncPolicy;
clearTimeout(this._expirationTimer);
this._expirationTimer = setTimeout(() => this.onExpired(), expiration);
}
scheduleNextSync() {
const {interval} = this._account.syncPolicy;
if (interval) {
const target = this._lastSyncTime + interval;
console.log(`Next sync scheduled for ${new Date(target).toLocaleString()}`);
this._syncTimer = setTimeout(() => {
this.syncNow();
}, target - Date.now());
2016-06-21 08:33:23 +08:00
}
}
2016-06-19 18:02:32 +08:00
}
module.exports = SyncWorker;