Last active
April 11, 2020 02:39
-
-
Save VirtualWolf/e0e303f0c6c84eeeed202b3b9ed2b589 to your computer and use it in GitHub Desktop.
sendUpdate() before and after
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Original version using callbacks | |
sendUpdate: callback => { | |
const request = require('superagent'); | |
HipChatWeather.find({}) | |
.exec((HipChatWeatherModelError, results) => { | |
if (HipChatWeatherModelError) { sails.log.error(HipChatWeatherModelError); return callback(HipChatWeatherModelError, null); } | |
if (results.length === 0) { return callback(null, null); } | |
ninjaBlockService.getCurrentTemperatureAndHumidity({location: 'outdoor'}, (ninjaBlockServiceError, data) => { | |
if (ninjaBlockServiceError) { return callback(ninjaBlockServiceError, null); } | |
async.parallel(results.map(install => cb => { | |
hipChatTokenService.getToken({ | |
capabilitiesUrl: install.capabilitiesurl, | |
oauthId: install.oauthid, | |
oauthSecret: install.oauthsecret, | |
}, (tokenError, tokenData) => { | |
if (tokenError) { return cb(tokenError, null); } | |
request.post(`${tokenData.apiUrl}/addon/ui/room/${install.roomid}`) | |
.set('Authorization', `Bearer ${tokenData.accessToken}`) | |
.send({ | |
glance: [ | |
{ | |
content: { | |
label: { | |
type: 'html', | |
value: `<b>${data.temperature}</b>°C & ${data.humidity}%`, | |
}, | |
}, | |
key: 'weather-glance', | |
}, | |
], | |
}) | |
.end((postUpdateError, res) => { | |
if (postUpdateError) { return cb(postUpdateError.response.res.body, null); } | |
return cb(null, res.body); | |
}); | |
}); | |
}), (err, results) => { | |
if (err) { return callback(err, null); } | |
return callback(null, results); | |
}); | |
}); | |
}); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Updated version using Promises. Much easier to follow! | |
sendUpdate: () => { | |
const request = require('superagent'); | |
const getRoomDetails = options => { | |
return hipChatTokenService.getToken({ | |
capabilitiesUrl: options.capabilitiesUrl, | |
oauthId: options.oauthId, | |
oauthSecret: options.oauthSecret, | |
}).then(results => { | |
return { | |
roomId: options.roomId, | |
groupId: options.groupId, | |
accessToken: results.accessToken, | |
apiUrl: results.apiUrl, | |
}; | |
}); | |
}; | |
const postUpdate = options => { | |
return request.post(`${options.apiUrl}/addon/ui/room/${options.roomId}`) | |
.set('Authorization', `Bearer ${options.accessToken}`) | |
.send({ | |
glance: [{ | |
content: { | |
label: { | |
type: 'html', | |
value: `<b>${options.temperature}</b>°C & ${options.humidity}%`, | |
}, | |
}, | |
key: 'weather-glance', | |
},], | |
}).then(response => { | |
return response; | |
}).catch(err => { | |
throw new Error(err); | |
}); | |
}; | |
return HipChatWeather.find({}) | |
.then(results => { | |
if (results.length === 0) { throw new Error('No installations registered'); } | |
return results; | |
}).then(results => { | |
return Promise.all(results.map(installation => { | |
return getRoomDetails({ | |
roomId: installation.roomid, | |
groupId: installation.groupid, | |
capabilitiesUrl: installation.capabilitiesurl, | |
oauthId: installation.oauthid, | |
oauthSecret: installation.oauthsecret, | |
}); | |
})); | |
}).then(rooms => { | |
return Promise.all([ | |
rooms, | |
ninjaBlockService.getCurrentTemperatureAndHumidity({location: 'outdoor'}), | |
]); | |
}).then(results => { | |
const rooms = results[0]; | |
const currentTemperatureData = results[1]; | |
return Promise.all(rooms.map(room => { | |
return postUpdate({ | |
apiUrl: room.apiUrl, | |
accessToken: room.accessToken, | |
roomId: room.roomId, | |
temperature: currentTemperatureData.temperature, | |
humidity: currentTemperatureData.humidity, | |
}); | |
})); | |
}).catch(err => { | |
throw err; | |
}); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The original Promise version above turned out to be not particularly easy to follow when coming back to it after several months! | |
// | |
// This is a fair bit longer than either of the above, but contains _all_ of the little helper functions along the way (the previous | |
// versions cheated a bit by not including everything). The final updateGlance() function is the one that hooks it all together. | |
findCurrentInstallations: () => { | |
return HipChatWeather.find({}) | |
.then(results => { | |
if (results.length === 0) { throw new Error('No installations registered'); } | |
return results; | |
}).catch(err => { | |
throw err; | |
}) | |
}; | |
getTokenAndApiUrls: capabilitiesUrl => { | |
return request.get(capabilitiesUrl) | |
.then(result => { | |
return { | |
tokenUrl: result.body.capabilities.oauth2Provider.tokenUrl, | |
apiUrl: result.body.links.api, | |
} | |
}) | |
.catch(err => { | |
throw err; | |
}); | |
}; | |
generateAccessTokenTuples: (installations, tokenAndApiUrls) => { | |
return Promise.all(installations.map((install, index, array) => { | |
return { | |
tokenUrl: tokenAndApiUrls[index].tokenUrl, | |
apiUrl: tokenAndApiUrls[index].apiUrl, | |
oauthId: install.oauthid, | |
oauthSecret: install.oauthsecret, | |
roomId: install.roomid, | |
} | |
})); | |
}; | |
getAccessToken: ({tokenUrl, oauthId, oauthSecret}) => { | |
return request.post(tokenUrl) | |
.type('form') | |
.send('grant_type=client_credentials') | |
.auth(oauthId, oauthSecret) | |
.then(result => result.body.access_token) | |
.catch(err => { | |
throw err; | |
}); | |
}; | |
postUpdateToHipChat: ({apiUrl, roomId, accessToken, payload}) => { | |
const url = `${apiUrl}/addon/ui/room/${roomId}`; | |
return request.post(url) | |
.set('Authorization', `Bearer ${accessToken}`) | |
.send(payload) | |
.catch(err => { | |
throw err; | |
}) | |
}; | |
updateGlance: () => { | |
return hipChatService.findCurrentInstallations() | |
.then(results => Promise.all([ | |
results, | |
Promise.all(results.map(result => hipChatService.getTokenAndApiUrls(result.capabilitiesurl))), | |
])) | |
.then(results => { | |
const [installations, tokenAndApiUrls] = results; | |
return hipChatService.generateAccessTokenTuples(installations, tokenAndApiUrls); | |
}) | |
.then(results => { | |
return Promise.all([ | |
results, | |
Promise.all(results.map(result => hipChatService.getAccessToken({ | |
tokenUrl: result.tokenUrl, | |
oauthId: result.oauthId, | |
oauthSecret: result.oauthSecret}) | |
)) | |
]) | |
}) | |
.then(results => { | |
return Promise.all([ | |
results, | |
weatherService.getCurrentTemperatureAndHumidity({location: 'outdoor'}), | |
]); | |
}) | |
.then(results => { | |
const [[installations, tokens], weather] = results; | |
const payload = { | |
glance: [ | |
{ | |
content: { | |
label: { | |
type: 'html', | |
value: `<b>${weather.temperature}</b>°C & ${weather.humidity}%`, | |
}, | |
}, | |
key: 'weather-glance', | |
}, | |
], | |
}; | |
return Promise.all(installations.map((install, index, array) => { | |
return hipChatService.postUpdateToHipChat({ | |
apiUrl: install.apiUrl, | |
roomId: install.roomId, | |
accessToken: tokens[index], | |
payload, | |
}); | |
})); | |
}) | |
.catch(err => { | |
throw err; | |
}); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The above file _still_ wasn't great. updateGlance() at the bottom is hard to follow, and thanks | |
// to all the `Promise.all`s, if any of the steps failed at any point, the other installations wouldn't | |
// be updated. This updated version uses Bluebird instead of native Promises and passes each call's | |
// results along via `this`, and each installation is fired off independently of the others. I find it | |
// reads a hell a lot more easily, especially sendUpdateToHipChatInstallation() on line 34. | |
module.exports = { | |
updateGlances: () => { | |
return findCurrentInstallations() | |
.then(function(results) { | |
return results.map(function(result) { | |
return Promise | |
.resolve() | |
.bind(result) | |
.then(sendUpdateToHipChatInstallation); | |
}); | |
}) | |
.catch(err => { | |
throw err; | |
}); | |
}, | |
}; | |
function findCurrentInstallations() { | |
return HipChatWeather.find({}) | |
.then(results => { | |
if (results.length === 0) { throw new Error('No installations registered'); } | |
return results; | |
}).catch(err => { | |
throw err; | |
}); | |
} | |
function sendUpdateToHipChatInstallation() { | |
return Promise | |
.resolve() | |
.bind(this) | |
.then(getTokenAndApiUrls) | |
.then(getAccessToken) | |
.then(getLatestWeatherData) | |
.then(postUpdateToHipChat) | |
.catch(err => { | |
sails.log.error(err); | |
}); | |
} | |
function getTokenAndApiUrls() { | |
return Promise | |
.resolve() | |
.bind(this) | |
.then(function() { | |
return request.get(this.capabilitiesurl); | |
}) | |
.then(function(result) { | |
this.tokenurl = result.body.capabilities.oauth2Provider.tokenUrl; | |
this.apiurl = result.body.links.api; | |
return this; | |
}) | |
.catch(err => { | |
throw new Error(err.message); | |
}); | |
} | |
function getAccessToken() { | |
return Promise | |
.resolve() | |
.bind(this) | |
.then(function() { | |
return request.post(this.tokenurl) | |
.type('form') | |
.send('grant_type=client_credentials') | |
.auth(this.oauthid, this.oauthsecret); | |
}) | |
.then(function(result) { | |
this.accesstoken = result.body.access_token; | |
return this; | |
}) | |
.catch(err => { | |
throw new Error(err.message); | |
}); | |
} | |
function getLatestWeatherData() { | |
return Promise | |
.resolve() | |
.bind(this) | |
.then(function() { | |
return weatherService.getCurrentTemperatureAndHumidity({location: 'outdoor'}); | |
}) | |
.then(function(result) { | |
this.weatherData = result; | |
return this; | |
}) | |
.catch(err => { | |
throw err; | |
}); | |
} | |
function postUpdateToHipChat() { | |
return Promise | |
.resolve() | |
.bind(this) | |
.then(function() { | |
const payload = { glance: [ { | |
content: { | |
label: { | |
type: 'html', | |
value: `<b>${this.weatherData.temperature}</b>°C & ${this.weatherData.humidity}%`, | |
}, | |
}, | |
key: 'weather-glance', | |
}]}; | |
return request.post(`${this.apiurl}/addon/ui/room/${this.roomid}`) | |
.set('Authorization', `Bearer ${this.accesstoken}`) | |
.send(payload); | |
}) | |
.catch(err => { | |
throw new Error(err.message); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// And finally, ES2017's async/await! I'm not sure it could be much simpler than this, and it reads | |
// just like regular synchronous code. It does the same as above, triggering updateGlances() will | |
// fire off individual requests to each installation, independent of the others. | |
module.exports = { | |
updateGlances: async () => { | |
const installations = await findCurrentInstallations(); | |
return await Promise.all(installations.map(async function(result) { | |
await sendUpdateToHipChatInstallation(result); | |
})); | |
}, | |
}; | |
async function findCurrentInstallations() { | |
const results = await HipChatWeather.find({}); | |
if (results.length === 0) { throw new Error('No installations registered'); } | |
return results; | |
} | |
async function sendUpdateToHipChatInstallation(installation) { | |
const {oauthid, oauthsecret, capabilitiesurl, roomid, groupid} = installation; | |
try { | |
const {tokenurl, apiurl} = await getTokenAndApiUrls(capabilitiesurl); | |
const accesstoken = await getAccessToken({tokenurl, oauthid, oauthsecret}); | |
const weatherData = await weatherService.getCurrentTemperatureAndHumidity({location: 'outdoor'}); | |
await postUpdateToHipChat({apiurl, roomid, accesstoken, weatherData}); | |
} catch (err) { | |
sails.log.error(err); | |
} | |
} | |
async function getTokenAndApiUrls(capabilitiesurl) { | |
const result = await request.get(capabilitiesurl); | |
return { | |
tokenurl: result.body.capabilities.oauth2Provider.tokenUrl, | |
apiurl: result.body.links.api, | |
} | |
} | |
async function getAccessToken({tokenurl, oauthid, oauthsecret}) { | |
const result = await request.post(tokenurl) | |
.type('form') | |
.send('grant_type=client_credentials') | |
.auth(oauthid, oauthsecret); | |
return result.body.access_token; | |
} | |
async function postUpdateToHipChat({apiurl, roomid, accesstoken, weatherData}) { | |
const payload = { | |
glance: [ { | |
content: { | |
label: { | |
type: 'html', | |
value: `<b>${weatherData.temperature}</b>°C & ${weatherData.humidity}%`, | |
}, | |
}, | |
key: 'weather-glance', | |
}, ], | |
}; | |
return await request.post(`${apiurl}/addon/ui/room/${roomid}`) | |
.set('Authorization', `Bearer ${accesstoken}`) | |
.send(payload); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment