Mailspring/internal_packages/participant-profile/lib/participant-profile-store.es6
Juan Tejada 1e34a2e33b 🎨 Fix unhandled api rejections/Prefer promises over success option for api requests
Summary:
This commit modifies the api of NylasAPIRequest to /not/ take `success`
or `error` callback options at all, and only returns a Promise which you
can `then` and `catch` to handle the api response.

The fact that it returned a promise, and /also/ took `success` and
`error` callback options made it really confusing to use.

Additionaly, when using the callbacks intead of a promise, any errors
would be unhandled and reported to Sentry because even though the `error`
callback was being passed, the promise returned by `run()` still rejected and
no one was handling that reject, so it reached the `unhandledRejection` event
listener. This is undesirable because if you passed an `error` callback, it
means that you intended to handle it.

An example of this is calling the clearbit API, which will more often than
not return a 404, and even though we had an error handler which ignored the 404,
it still unecessarilly reported to Sentry, flooding it with events

Test Plan: manually check all updated codepaths still work

Reviewers: halla, spang, evan

Reviewed By: evan

Differential Revision: https://phab.nylas.com/D3869
2017-02-09 09:19:55 -08:00

88 lines
2.1 KiB
JavaScript

import {DatabaseStore, Utils} from 'nylas-exports'
import NylasStore from 'nylas-store'
import ClearbitDataSource from './clearbit-data-source'
// TODO: Back with Metadata
const contactCache = {}
const CACHE_SIZE = 100
const contactCacheKeyIndex = []
class ParticipantProfileStore extends NylasStore {
activate() {
this.cacheExpiry = 1000 * 60 * 60 * 24 // 1 day
this.dataSource = new ClearbitDataSource()
}
dataForContact(contact) {
if (!contact) {
return {}
}
if (Utils.likelyNonHumanEmail(contact.email)) {
return {}
}
if (this.inCache(contact)) {
const data = this.getCache(contact);
if (data.cacheDate) {
return data
}
return {}
}
this.dataSource.find({email: contact.email}).then((data) => {
if (data && data.email === contact.email) {
this.saveDataToContact(contact, data)
this.setCache(contact, data);
this.trigger()
}
}).catch((err = {}) => {
if (err.statusCode !== 404) {
throw err
}
})
return {}
}
// TODO: Back by metadata.
getCache(contact) {
return contactCache[contact.email]
}
inCache(contact) {
const cache = contactCache[contact.email]
if (!cache) { return false }
if (!cache.cacheDate || Date.now() - cache.cacheDate > this.cacheExpiry) {
return false
}
return true
}
setCache(contact, value) {
contactCache[contact.email] = value
contactCacheKeyIndex.push(contact.email)
if (contactCacheKeyIndex.length > CACHE_SIZE) {
delete contactCache[contactCacheKeyIndex.shift()]
}
return value
}
/**
* We save the clearbit data to the contat object in the database.
* This lets us load extra Clearbit data from other windows without
* needing to call a very expensive API again.
*/
saveDataToContact(contact, data) {
return DatabaseStore.inTransaction((t) => {
if (!contact.thirdPartyData) contact.thirdPartyData = {};
contact.thirdPartyData.clearbit = data
return t.persistModel(contact)
})
}
deactivate() {
// no op
}
}
const store = new ParticipantProfileStore()
export default store