1 // Copyright (c) 2017 Matthew Brennan Jones <matthew.brennan.jones@gmail.com> 2 // Boost Software License - Version 1.0 3 // Get weather forecast with the D programming language 4 // https://github.com/workhorsy/d-weather-forecast 5 6 /++ 7 Get weather forecast with the D programming language. It first gets your longitude 8 and latitude using http://ipinfo.io. Then uses them to look up your 9 weather using http://forecast.weather.gov. 10 11 Home page: 12 $(LINK https://github.com/workhorsy/d-weather-forecast) 13 14 Version: 1.3.0 15 16 License: 17 Boost Software License - Version 1.0 18 19 Examples: 20 ---- 21 import std.stdio : stdout, stderr; 22 import weather_forecast : getForecast, WeatherData; 23 24 getForecast(delegate(WeatherData weather_data, Exception err) { 25 if (err) { 26 stderr.writefln("%s", err); 27 } else { 28 stdout.writefln("latitude: %s", weather_data.latitude); 29 stdout.writefln("longitude: %s", weather_data.longitude); 30 stdout.writefln("city: %s", weather_data.city); 31 stdout.writefln("region: %s", weather_data.region); 32 stdout.writefln("country: %s", weather_data.country); 33 stdout.writefln("postal: %s", weather_data.postal); 34 stdout.writefln("temperature: %s", weather_data.temperature); 35 stdout.writefln("summary: %s", weather_data.summary); 36 } 37 }); 38 ---- 39 +/ 40 41 module weather_forecast; 42 43 44 /++ 45 Data gathered in WeatherData: 46 ---- 47 struct WeatherData { 48 string latitude; 49 string longitude; 50 string city; 51 string region; 52 string country; 53 string postal; 54 string temperature; 55 string summary; 56 } 57 ---- 58 +/ 59 60 struct WeatherData { 61 string latitude; 62 string longitude; 63 string city; 64 string region; 65 string country; 66 string postal; 67 string temperature; 68 string summary; 69 } 70 71 /++ 72 Returns the weather forecast using a callback. 73 74 Params: 75 cb = The callback to fire when weather info has been downloaded. The callback 76 sends the WeatherData data and an Exception if there was any problem. 77 +/ 78 void getForecast(void delegate(WeatherData weather_data, Exception err) cb) { 79 import std.stdio : stdout, stderr; 80 import std.json : JSONValue, parseJSON; 81 import std..string : chomp, format; 82 import std.array : split; 83 import std.conv : to; 84 import ipinfo : getIpinfo, IpinfoData, httpGet; 85 86 WeatherData weather_data; 87 88 getIpinfo(delegate(IpinfoData ipinfo_data, Exception err) { 89 if (err) { 90 cb(WeatherData.init, err); 91 } else { 92 const string URL = "http://forecast.weather.gov/MapClick.php?lat=" ~ ipinfo_data.latitude ~ "&lon=" ~ ipinfo_data.longitude ~ "&FcstType=json"; 93 94 httpGet(URL, delegate(int status, string response) { 95 if (status != 200) { 96 auto err = new Exception("Request for \"%s\" failed with status code: %s".format(URL, status)); 97 cb(WeatherData.init, err); 98 return; 99 } 100 101 try { 102 JSONValue j = parseJSON(response); 103 104 weather_data.latitude = ipinfo_data.latitude; 105 weather_data.longitude = ipinfo_data.longitude; 106 weather_data.city = ipinfo_data.city; 107 weather_data.region = ipinfo_data.region; 108 weather_data.country = ipinfo_data.country; 109 weather_data.postal = ipinfo_data.postal; 110 weather_data.temperature = j["currentobservation"]["Temp"].str(); 111 weather_data.summary = j["data"]["weather"][0].str(); 112 } catch (Throwable) { 113 auto err = new Exception("Failed to parse \"%s\" JSON response".format(URL)); 114 cb(WeatherData.init, err); 115 return; 116 } 117 118 cb(weather_data, null); 119 }); 120 } 121 }); 122 }