Update getData and httpRequest to modern TypeScript

This commit is contained in:
Matthew Oslan
2019-05-09 13:20:49 -04:00
parent 6acb40eed1
commit f2f40d2253

View File

@@ -14,42 +14,46 @@ var http = require( "http" ),
// If location does not match GPS or PWS/ICAO, then attempt to resolve // If location does not match GPS or PWS/ICAO, then attempt to resolve
// location using Weather Underground autocomplete API // location using Weather Underground autocomplete API
function resolveCoordinates( location, callback ) { async function resolveCoordinates( location, callback ) {
// Generate URL for autocomplete request // Generate URL for autocomplete request
var url = "http://autocomplete.wunderground.com/aq?h=0&query=" + var url = "http://autocomplete.wunderground.com/aq?h=0&query=" +
encodeURIComponent( location ); encodeURIComponent( location );
httpRequest( url, function( data ) { let data;
try {
data = await getData( url );
} catch (err) {
// If the request fails, indicate no data was found.
callback( false );
}
// Parse the reply for JSON data // Check if the data is valid
data = JSON.parse( data ); if ( typeof data.RESULTS === "object" && data.RESULTS.length && data.RESULTS[ 0 ].tz !== "MISSING" ) {
// Check if the data is valid // If it is, reply with an array containing the GPS coordinates
if ( typeof data.RESULTS === "object" && data.RESULTS.length && data.RESULTS[ 0 ].tz !== "MISSING" ) { callback( [ data.RESULTS[ 0 ].lat, data.RESULTS[ 0 ].lon ], moment().tz( data.RESULTS[ 0 ].tz ).utcOffset() );
} else {
// If it is, reply with an array containing the GPS coordinates // Otherwise, indicate no data was found
callback( [ data.RESULTS[ 0 ].lat, data.RESULTS[ 0 ].lon ], moment().tz( data.RESULTS[ 0 ].tz ).utcOffset() ); callback( false );
} else { }
// Otherwise, indicate no data was found
callback( false );
}
} );
} }
function getData( url, callback ) { /**
* Makes an HTTP GET request to the specified URL and parses the JSON response body.
httpRequest( url, function( data ) { * @param url The URL to fetch.
try { * @return A Promise that will be resolved the with parsed response body if the request succeeds, or will be rejected
data = JSON.parse( data ); * with an Error if the request or JSON parsing fails.
} catch (err) { */
callback( {} ); async function getData( url: string ): Promise< any > {
return; try {
} const data: string = await httpRequest(url);
callback( data ); return JSON.parse(data);
return; } catch (err) {
} ); // Reject the promise if there was an error making the request or parsing the JSON.
throw err;
}
} }
// Retrieve data from Open Weather Map for water level calculations // Retrieve data from Open Weather Map for water level calculations
@@ -57,34 +61,41 @@ function getOWMWateringData( location, callback ) {
var OWM_API_KEY = process.env.OWM_API_KEY, var OWM_API_KEY = process.env.OWM_API_KEY,
forecastUrl = "http://api.openweathermap.org/data/2.5/forecast?appid=" + OWM_API_KEY + "&units=imperial&lat=" + location[ 0 ] + "&lon=" + location[ 1 ]; forecastUrl = "http://api.openweathermap.org/data/2.5/forecast?appid=" + OWM_API_KEY + "&units=imperial&lat=" + location[ 0 ] + "&lon=" + location[ 1 ];
getTimeData( location, function( weather ) { getTimeData( location, async function( weather ) {
// Perform the HTTP request to retrieve the weather data // Perform the HTTP request to retrieve the weather data
getData( forecastUrl, function( forecast ) { let forecast;
try {
if ( !forecast || !forecast.list ) { forecast = await getData( forecastUrl );
callback( weather ); } catch (err) {
return; // Return just the time data if retrieving the forecast fails.
}
weather.temp = 0;
weather.humidity = 0;
weather.precip = 0;
var periods = Math.min(forecast.list.length, 10);
for ( var index = 0; index < periods; index++ ) {
weather.temp += parseFloat( forecast.list[ index ].main.temp );
weather.humidity += parseInt( forecast.list[ index ].main.humidity );
weather.precip += ( forecast.list[ index ].rain ? parseFloat( forecast.list[ index ].rain[ "3h" ] || 0 ) : 0 );
}
weather.temp = weather.temp / periods;
weather.humidity = weather.humidity / periods;
weather.precip = weather.precip / 25.4;
weather.raining = ( forecast.list[ 0 ].rain ? ( parseFloat( forecast.list[ 0 ].rain[ "3h" ] || 0 ) > 0 ) : false );
callback( weather ); callback( weather );
} ); return;
}
// Return just the time data if the forecast data is incomplete.
if ( !forecast || !forecast.list ) {
callback( weather );
return;
}
weather.temp = 0;
weather.humidity = 0;
weather.precip = 0;
var periods = Math.min(forecast.list.length, 10);
for ( var index = 0; index < periods; index++ ) {
weather.temp += parseFloat( forecast.list[ index ].main.temp );
weather.humidity += parseInt( forecast.list[ index ].main.humidity );
weather.precip += ( forecast.list[ index ].rain ? parseFloat( forecast.list[ index ].rain[ "3h" ] || 0 ) : 0 );
}
weather.temp = weather.temp / periods;
weather.humidity = weather.humidity / periods;
weather.precip = weather.precip / 25.4;
weather.raining = ( forecast.list[ 0 ].rain ? ( parseFloat( forecast.list[ 0 ].rain[ "3h" ] || 0 ) > 0 ) : false );
callback( weather );
} ); } );
} }
@@ -94,43 +105,48 @@ function getOWMWeatherData( location, callback ) {
currentUrl = "http://api.openweathermap.org/data/2.5/weather?appid=" + OWM_API_KEY + "&units=imperial&lat=" + location[ 0 ] + "&lon=" + location[ 1 ], currentUrl = "http://api.openweathermap.org/data/2.5/weather?appid=" + OWM_API_KEY + "&units=imperial&lat=" + location[ 0 ] + "&lon=" + location[ 1 ],
forecastDailyUrl = "http://api.openweathermap.org/data/2.5/forecast/daily?appid=" + OWM_API_KEY + "&units=imperial&lat=" + location[ 0 ] + "&lon=" + location[ 1 ]; forecastDailyUrl = "http://api.openweathermap.org/data/2.5/forecast/daily?appid=" + OWM_API_KEY + "&units=imperial&lat=" + location[ 0 ] + "&lon=" + location[ 1 ];
getTimeData( location, function( weather ) { getTimeData( location, async function( weather ) {
getData( currentUrl, function( current ) { let current, forecast;
try {
current = await getData( currentUrl );
forecast = await getData( forecastDailyUrl );
} catch (err) {
// Return just the time data if retrieving weather data fails.
callback( weather );
return;
}
getData( forecastDailyUrl, function( forecast ) { // Return just the time data if the weather data is incomplete.
if ( !current || !current.main || !current.wind || !current.weather || !forecast || !forecast.list ) {
callback( weather );
return;
}
if ( !current || !current.main || !current.wind || !current.weather || !forecast || !forecast.list ) { weather.temp = parseInt( current.main.temp );
callback( weather ); weather.humidity = parseInt( current.main.humidity );
return; weather.wind = parseInt( current.wind.speed );
} weather.description = current.weather[0].description;
weather.icon = current.weather[0].icon;
weather.temp = parseInt( current.main.temp ); weather.region = forecast.city.country;
weather.humidity = parseInt( current.main.humidity ); weather.city = forecast.city.name;
weather.wind = parseInt( current.wind.speed ); weather.minTemp = parseInt( forecast.list[ 0 ].temp.min );
weather.description = current.weather[0].description; weather.maxTemp = parseInt( forecast.list[ 0 ].temp.max );
weather.icon = current.weather[0].icon; weather.precip = ( forecast.list[ 0 ].rain ? parseFloat( forecast.list[ 0 ].rain || 0 ) : 0 ) / 25.4;
weather.forecast = [];
weather.region = forecast.city.country; for ( var index = 0; index < forecast.list.length; index++ ) {
weather.city = forecast.city.name; weather.forecast.push( {
weather.minTemp = parseInt( forecast.list[ 0 ].temp.min ); temp_min: parseInt( forecast.list[ index ].temp.min ),
weather.maxTemp = parseInt( forecast.list[ 0 ].temp.max ); temp_max: parseInt( forecast.list[ index ].temp.max ),
weather.precip = ( forecast.list[ 0 ].rain ? parseFloat( forecast.list[ 0 ].rain || 0 ) : 0 ) / 25.4; date: parseInt( forecast.list[ index ].dt ),
weather.forecast = []; icon: forecast.list[ index ].weather[ 0 ].icon,
description: forecast.list[ index ].weather[ 0 ].description
for ( var index = 0; index < forecast.list.length; index++ ) {
weather.forecast.push( {
temp_min: parseInt( forecast.list[ index ].temp.min ),
temp_max: parseInt( forecast.list[ index ].temp.max ),
date: parseInt( forecast.list[ index ].dt ),
icon: forecast.list[ index ].weather[ 0 ].icon,
description: forecast.list[ index ].weather[ 0 ].description
} );
}
callback( weather );
} ); } );
} ); }
callback( weather );
} ); } );
} }
@@ -386,33 +402,40 @@ exports.getWateringData = function( req, res ) {
} }
}; };
// Generic HTTP request handler that parses the URL and uses the /**
// native Node.js http module to perform the request * Makes an HTTP GET request to the specified URL and returns the response body.
function httpRequest( url, callback ) { * @param url The URL to fetch.
url = url.match( filters.url ); * @return A Promise that will be resolved the with response body if the request succeeds, or will be rejected with an
* Error if the request fails.
*/
async function httpRequest( url: string ): Promise< string > {
return new Promise< any >( ( resolve, reject ) => {
var options = { const splitUrl: string[] = url.match( filters.url );
host: url[ 1 ],
port: url[ 2 ] || 80,
path: url[ 3 ]
};
http.get( options, function( response ) { const options = {
var data = ""; host: splitUrl[ 1 ],
port: splitUrl[ 2 ] || 80,
path: splitUrl[ 3 ]
};
// Reassemble the data as it comes in http.get( options, ( response ) => {
response.on( "data", function( chunk ) { let data = "";
data += chunk;
} );
// Once the data is completely received, return it to the callback // Reassemble the data as it comes in
response.on( "end", function() { response.on( "data", ( chunk ) => {
callback( data ); data += chunk;
} ); } );
} ).on( "error", function() {
// If the HTTP request fails, return false // Once the data is completely received, resolve the promise
callback( false ); response.on( "end", () => {
resolve( data );
} );
} ).on( "error", ( err ) => {
// If the HTTP request fails, reject the promise
reject( err );
} );
} ); } );
} }