[local-sync] Ensure all imap operations are wrapped with timeout

Summary:
Specifically, these imap connections have been known to hang when you close your laptop or go offline/online, even though we are passing a `socketTimeout` to node-imap. When they hang, everything freezes because the promise waiting for the result never resolves.

`_createConnectionPromise` wraps the operations with a timeout we implemented ourselves, and correctly rejects on timeout.

This commit wraps other imap operations that were missing. (I notices because I encountered the hanging on one of these operations)

Test Plan: manual

Reviewers: evan, mark, spang

Reviewed By: spang

Differential Revision: https://phab.nylas.com/D3720
This commit is contained in:
Juan Tejada 2017-01-16 22:38:31 -08:00
parent 944b677d3e
commit e1f1b22ee2

View file

@ -1,5 +1,4 @@
const _ = require('underscore');
const PromiseUtils = require('./promise-utils')
const {
IMAPConnectionNotReadyError,
@ -147,60 +146,89 @@ class IMAPBox {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::addFlags`)
}
return this._conn._imap.addFlagsAsync(range, flags)
return this._conn.createConnectionPromise((resolve, reject) => {
return this._conn._imap.addFlagsAsync(range, flags)
.then((...args) => resolve(...args))
.catch((...args) => reject(...args))
})
}
delFlags(range, flags) {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::delFlags`)
}
return this._conn._imap.delFlagsAsync(range, flags)
return this._conn.createConnectionPromise((resolve, reject) => {
return this._conn._imap.delFlagsAsync(range, flags)
.then((...args) => resolve(...args))
.catch((...args) => reject(...args))
})
}
moveFromBox(range, folderName) {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::moveFromBox`)
}
return this._conn._imap.moveAsync(range, folderName)
return this._conn.createConnectionPromise((resolve, reject) => {
return this._conn._imap.moveAsync(range, folderName)
.then((...args) => resolve(...args))
.catch((...args) => reject(...args))
})
}
setLabels(range, labels) {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::moveFromBox`)
}
return this._conn._imap.setLabelsAsync(range, labels)
return this._conn.createConnectionPromise((resolve, reject) => {
return this._conn._imap.setLabelsAsync(range, labels)
.then((...args) => resolve(...args))
.catch((...args) => reject(...args))
})
}
removeLabels(range, labels) {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::moveFromBox`)
}
return this._conn._imap.delLabelsAsync(range, labels)
return this._conn.createConnectionPromise((resolve, reject) => {
return this._conn._imap.delLabelsAsync(range, labels)
.then((...args) => resolve(...args))
.catch((...args) => reject(...args))
})
}
append(rawMime, options) {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::append`)
}
return PromiseUtils.promisify(this._conn._imap.append).call(
this._conn._imap, rawMime, options
);
return this._conn.createConnectionPromise((resolve, reject) => {
return this._conn._imap.appendAsync(rawMime, options)
.then((...args) => resolve(...args))
.catch((...args) => reject(...args))
})
}
search(criteria) {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::search`)
}
return PromiseUtils.promisify(this._conn._imap.search).call(
this._conn._imap, criteria
);
return this._conn.createConnectionPromise((resolve, reject) => {
return this._conn._imap.searchAsync(criteria)
.then((...args) => resolve(...args))
.catch((...args) => reject(...args))
})
}
closeBox({expunge = true} = {}) {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::closeBox`)
}
return this._conn._imap.closeBoxAsync(expunge)
return this._conn.createConnectionPromise((resolve, reject) => {
return this._conn._imap.closeBoxAsync(expunge)
.then((...args) => resolve(...args))
.catch((...args) => reject(...args))
})
}
}