weather-promise
Version:
A module for obtaining weather information
125 lines (102 loc) • 3.67 kB
JavaScript
/*
* Weather
* For the full copyright and license information, please view the LICENSE.txt file.
*/
/* jslint node: true, sub: true */
const axios = require('axios');
const xml2JS = require('xml2js');
const xmlParser = new xml2JS.Parser({
charkey: 'C$', attrkey: 'A$', explicitArray: true,
});
const defResCount = 1;
const defTimeout = 10000;
const findUrl = 'http://weather.service.msn.com/find.aspx';
function generateCurrent(current, url) {
let cur = null;
if (current instanceof Array && current.length > 0) {
if (typeof current[0].A$ === 'object') {
cur = current[0].A$;
cur.imageUrl = `${url}law/${cur.skycode}.gif`;
}
}
return cur;
}
function generateForcast(forcasts) {
if (forcasts instanceof Array) {
return forcasts.filter((f) => typeof f.A$ === 'object').map((f) => f.A$);
}
return null;
}
function genObject(data, current, forcasts) {
return {
location: {
name: data.weatherlocationname,
zipcode: data.zipcode,
lat: data.lat,
long: data.long,
timezone: data.timezone,
alert: data.alert,
degreetype: data.degreetype,
imagerelativeurl: data.imagerelativeurl,
// url: data['url'],
// code: data['weatherlocationcode'],
// entityid: data['entityid'],
// encodedlocationname: data['encodedlocationname']
},
current: generateCurrent(current, data.imagerelativeurl),
forecast: generateForcast(forcasts),
};
}
function validateOptions(options) {
return new Promise((resolve, reject) => {
if (!options || typeof options !== 'object') reject(new Error('invalid options'));
if (!options.search) reject(new Error('missing search input'));
resolve(options);
});
}
function find(ops, callback) {
return validateOptions(ops)
.then((options) => axios.get(findUrl, {
params: {
src: 'outlook',
weadegreetype: options.degreeType || 'F',
culture: options.lang || 'en-US',
weasearchstr: options.search,
},
timeout: options.timeout || defTimeout,
}))
.then((res) => res.data)
.then((body) => {
if (!body) throw new Error('failed to get body content');
// Check body content
if (body.indexOf('<') !== 0) {
if (body.search(/not found/i) !== -1) {
return [];
}
throw new Error('invalid body content');
}
// parse xml
return xmlParser.parseStringPromise(body);
})
.then((res) => {
if (res instanceof Array) return res;
if (!res || !res.weatherdata || !res.weatherdata.weather) throw new Error('failed to parse weather data');
const { weather } = res.weatherdata;
if (weather.A$ && weather.A$.errormessage) throw new Error(weather.A$.errormessage);
if (!(weather instanceof Array)) throw new Error('missing weather info');
return weather.filter((w) => typeof w.A$ === 'object')
.slice(0, ops.resCount || defResCount)
.map((w) => genObject(w.A$, w.current, w.forecast));
})
.then((results) => {
if (typeof callback === 'function') return callback(null, results);
return results;
})
.catch((err) => {
if (typeof callback === 'function') callback(err);
throw err;
});
}
module.exports = {
find,
};