summaryrefslogtreecommitdiffstats
path: root/nws
diff options
context:
space:
mode:
Diffstat (limited to 'nws')
-rw-r--r--nws/nws.go19
-rw-r--r--nws/nws_test.go57
2 files changed, 53 insertions, 23 deletions
diff --git a/nws/nws.go b/nws/nws.go
index a1fd4ef..7caecc9 100644
--- a/nws/nws.go
+++ b/nws/nws.go
@@ -92,6 +92,7 @@ type ForecastBundle struct {
var pCache *cache.Cache
var fCache *cache.Cache
var fhCache *cache.Cache
+var aCache *cache.Cache
var baseUrl *url.URL
func init() {
@@ -100,6 +101,7 @@ func init() {
pCache = cache.NewCache()
fCache = cache.NewCache()
fhCache = cache.NewCache()
+ aCache = cache.NewCache()
// Parse NWS base url.
baseUrl, err = url.Parse("https://api.weather.gov")
@@ -270,19 +272,28 @@ func GetAlerts(lat, lng float32) (fc *FeatureCollection, err *Error) {
return
}
+ // Point: lat,lng.
+ ll := fmt.Sprintf("%.4f,%.4f", lat, lng)
+
// Build query.
q := url.Values{}
q.Add("status", "actual")
q.Add("message_type", "alert")
- q.Add("point", fmt.Sprintf("%.4f,%.4f", lat, lng))
+ q.Add("point", ll)
q.Add("urgency", "Immediate,Expected")
q.Add("certainty", "Observed,Likely,Possible")
u.RawQuery = q.Encode()
// Hit it.
- body, _, err := get(u.String())
- if err != nil {
- return
+ var expires time.Time
+ var body []byte
+ if body = aCache.Get(ll); len(body) == 0 {
+ body, expires, err = get(u.String())
+ if err != nil {
+ return
+ }
+ // Cache it.
+ aCache.Set(ll, body, expires)
}
// Unmarshal.
diff --git a/nws/nws_test.go b/nws/nws_test.go
index 0607f42..623ec83 100644
--- a/nws/nws_test.go
+++ b/nws/nws_test.go
@@ -247,6 +247,7 @@ func TestNWSGetWrapper(t *testing.T) {
func TestAlerts(t *testing.T) {
// Initialize test NWS server.
fail := false
+ alert := `{"@context":["https://geojson.org/geojson-ld/geojson-context.jsonld",{"@version":"1.1","wx":"https://api.weather.gov/ontology#","@vocab":"https://api.weather.gov/ontology#"}],"type":"FeatureCollection","features":[{"id":"https://api.weather.gov/alerts/urn:oid:2.49.0.1.840.0.b17674895f0389f4cb276c6db9c15d0aed41460f.001.1","type":"Feature","geometry":null,"properties":{"@id":"https://api.weather.gov/alerts/urn:oid:2.49.0.1.840.0.b17674895f0389f4cb276c6db9c15d0aed41460f.001.1","@type":"wx:Alert","id":"urn:oid:2.49.0.1.840.0.b17674895f0389f4cb276c6db9c15d0aed41460f.001.1","areaDesc":"Coffee; Dale; Henry; Geneva; Houston; North Walton; Central Walton; Holmes; Washington; Jackson; Inland Bay; Calhoun; Inland Gulf; Inland Franklin; Gadsden; Leon; Inland Jefferson; Madison; Liberty; Inland Wakulla; Inland Taylor; Lafayette; Inland Dixie; South Walton; Coastal Bay; Coastal Gulf; Coastal Franklin; Coastal Jefferson; Coastal Wakulla; Coastal Taylor; Coastal Dixie; Quitman; Clay; Randolph; Calhoun; Terrell; Dougherty; Lee; Worth; Turner; Tift; Ben Hill; Irwin; Early; Miller; Baker; Mitchell; Colquitt; Cook; Berrien; Seminole; Decatur; Grady; Thomas; Brooks; Lowndes; Lanier","geocode":{"SAME":["001031","001045","001067","001061","001069","012131","012059","012133","012063","012005","012013","012045","012037","012039","012073","012065","012079","012077","012129","012123","012067","012029","013239","013061","013243","013037","013273","013095","013177","013321","013287","013277","013017","013155","013099","013201","013007","013205","013071","013075","013019","013253","013087","013131","013275","013027","013185","013173"],"UGC":["ALZ065","ALZ066","ALZ067","ALZ068","ALZ069","FLZ007","FLZ008","FLZ009","FLZ010","FLZ011","FLZ012","FLZ013","FLZ014","FLZ015","FLZ016","FLZ017","FLZ018","FLZ019","FLZ026","FLZ027","FLZ028","FLZ029","FLZ034","FLZ108","FLZ112","FLZ114","FLZ115","FLZ118","FLZ127","FLZ128","FLZ134","GAZ120","GAZ121","GAZ122","GAZ123","GAZ124","GAZ125","GAZ126","GAZ127","GAZ128","GAZ129","GAZ130","GAZ131","GAZ142","GAZ143","GAZ144","GAZ145","GAZ146","GAZ147","GAZ148","GAZ155","GAZ156","GAZ157","GAZ158","GAZ159","GAZ160","GAZ161"]},"affectedZones":["https://api.weather.gov/zones/forecast/ALZ065","https://api.weather.gov/zones/forecast/ALZ066","https://api.weather.gov/zones/forecast/ALZ067","https://api.weather.gov/zones/forecast/ALZ068","https://api.weather.gov/zones/forecast/ALZ069","https://api.weather.gov/zones/forecast/FLZ007","https://api.weather.gov/zones/forecast/FLZ008","https://api.weather.gov/zones/forecast/FLZ009","https://api.weather.gov/zones/forecast/FLZ010","https://api.weather.gov/zones/forecast/FLZ011","https://api.weather.gov/zones/forecast/FLZ012","https://api.weather.gov/zones/forecast/FLZ013","https://api.weather.gov/zones/forecast/FLZ014","https://api.weather.gov/zones/forecast/FLZ015","https://api.weather.gov/zones/forecast/FLZ016","https://api.weather.gov/zones/forecast/FLZ017","https://api.weather.gov/zones/forecast/FLZ018","https://api.weather.gov/zones/forecast/FLZ019","https://api.weather.gov/zones/forecast/FLZ026","https://api.weather.gov/zones/forecast/FLZ027","https://api.weather.gov/zones/forecast/FLZ028","https://api.weather.gov/zones/forecast/FLZ029","https://api.weather.gov/zones/forecast/FLZ034","https://api.weather.gov/zones/forecast/FLZ108","https://api.weather.gov/zones/forecast/FLZ112","https://api.weather.gov/zones/forecast/FLZ114","https://api.weather.gov/zones/forecast/FLZ115","https://api.weather.gov/zones/forecast/FLZ118","https://api.weather.gov/zones/forecast/FLZ127","https://api.weather.gov/zones/forecast/FLZ128","https://api.weather.gov/zones/forecast/FLZ134","https://api.weather.gov/zones/forecast/GAZ120","https://api.weather.gov/zones/forecast/GAZ121","https://api.weather.gov/zones/forecast/GAZ122","https://api.weather.gov/zones/forecast/GAZ123","https://api.weather.gov/zones/forecast/GAZ124","https://api.weather.gov/zones/forecast/GAZ125","https://api.weather.gov/zones/forecast/GAZ126","https://api.weather.gov/zones/forecast/GAZ127","https://api.weather.gov/zones/forecast/GAZ128","https://api.weather.gov/zones/forecast/GAZ129","https://api.weather.gov/zones/forecast/GAZ130","https://api.weather.gov/zones/forecast/GAZ131","https://api.weather.gov/zones/forecast/GAZ142","https://api.weather.gov/zones/forecast/GAZ143","https://api.weather.gov/zones/forecast/GAZ144","https://api.weather.gov/zones/forecast/GAZ145","https://api.weather.gov/zones/forecast/GAZ146","https://api.weather.gov/zones/forecast/GAZ147","https://api.weather.gov/zones/forecast/GAZ148","https://api.weather.gov/zones/forecast/GAZ155","https://api.weather.gov/zones/forecast/GAZ156","https://api.weather.gov/zones/forecast/GAZ157","https://api.weather.gov/zones/forecast/GAZ158","https://api.weather.gov/zones/forecast/GAZ159","https://api.weather.gov/zones/forecast/GAZ160","https://api.weather.gov/zones/forecast/GAZ161"],"references":[],"sent":"2022-06-17T16:00:00-04:00","effective":"2022-06-17T16:00:00-04:00","onset":"2022-06-18T12:00:00-04:00","expires":"2022-06-17T22:00:00-04:00","ends":"2022-06-18T20:00:00-04:00","status":"Actual","messageType":"Alert","category":"Met","severity":"Moderate","certainty":"Likely","urgency":"Expected","event":"Heat Advisory","sender":"w-nws.webmaster@noaa.gov","senderName":"NWS Tallahassee FL","headline":"Heat Advisory issued June 17 at 4:00PM EDT until June 18 at 8:00PM EDT by NWS Tallahassee FL","description":"* WHAT...Heat index values of 108 to 112 expected.\n\n* WHERE...Portions of southeast Alabama, south central and\nsouthwest Georgia, and the Big Bend and Panhandle of Florida.\n\n* WHEN...For the first Heat Advisory, until 8 PM EDT /7 PM CDT/\nthis evening. For the second Heat Advisory, from noon EDT /11\nAM CDT/ to 8 PM EDT /7 PM CDT/ Saturday.\n\n* IMPACTS...Hot temperatures and high humidity may cause heat\nillnesses to occur.","instruction":"Drink plenty of fluids, stay in an air-conditioned room, stay out\nof the sun, and check up on relatives and neighbors. Young\nchildren and pets should never be left unattended in vehicles\nunder any circumstances.\n\nTake extra precautions if you work or spend time outside. When\npossible reschedule strenuous activities to early morning or\nevening. Know the signs and symptoms of heat exhaustion and heat\nstroke. Wear lightweight and loose fitting clothing when\npossible. To reduce risk during outdoor work, the Occupational\nSafety and Health Administration recommends scheduling frequent\nrest breaks in shaded or air conditioned environments. Anyone\novercome by heat should be moved to a cool and shaded location.\nHeat stroke is an emergency! Call 9 1 1.","response":"Execute","parameters":{"AWIPSidentifier":["NPWTAE"],"WMOidentifier":["WWUS72 KTAE 172000"],"NWSheadline":["HEAT ADVISORY REMAINS IN EFFECT UNTIL 8 PM EDT /7 PM CDT/ THIS EVENING... ...HEAT ADVISORY IN EFFECT FROM NOON EDT /11 AM CDT/ TO 8 PM EDT /7 PM CDT/ SATURDAY"],"BLOCKCHANNEL":["EAS","NWEM","CMAS"],"VTEC":["/O.NEW.KTAE.HT.Y.0005.220618T1600Z-220619T0000Z/"],"eventEndingTime":["2022-06-19T00:00:00+00:00"]}}}],"title":"current watches, warnings, and advisories for 30.7848 N, 83.5601 W","updated":"2022-06-18T00:00:00+00:00"}`
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if fail {
http.Error(w, `{"type":"urn:noaa:nws:api:UnexpectedProblem","title":"Unexpected Problem","status":500,"detail":"An unexpected problem has occurred.","instance":"urn:noaa:nws:api:request:493c3a1d-f87e-407f-ae2c-24483f5aab63","correlationId":"493c3a1d-f87e-407f-ae2c-24483f5aab63","additionalProp1":{}}`, 500)
@@ -258,12 +259,37 @@ func TestAlerts(t *testing.T) {
time.Now().Add(time.Second*60).Format(time.RFC1123))
// Success.
- fmt.Fprintln(w, `{"@context":["https://geojson.org/geojson-ld/geojson-context.jsonld",{"@version":"1.1","wx":"https://api.weather.gov/ontology#","@vocab":"https://api.weather.gov/ontology#"}],"type":"FeatureCollection","features":[{"id":"https://api.weather.gov/alerts/urn:oid:2.49.0.1.840.0.b17674895f0389f4cb276c6db9c15d0aed41460f.001.1","type":"Feature","geometry":null,"properties":{"@id":"https://api.weather.gov/alerts/urn:oid:2.49.0.1.840.0.b17674895f0389f4cb276c6db9c15d0aed41460f.001.1","@type":"wx:Alert","id":"urn:oid:2.49.0.1.840.0.b17674895f0389f4cb276c6db9c15d0aed41460f.001.1","areaDesc":"Coffee; Dale; Henry; Geneva; Houston; North Walton; Central Walton; Holmes; Washington; Jackson; Inland Bay; Calhoun; Inland Gulf; Inland Franklin; Gadsden; Leon; Inland Jefferson; Madison; Liberty; Inland Wakulla; Inland Taylor; Lafayette; Inland Dixie; South Walton; Coastal Bay; Coastal Gulf; Coastal Franklin; Coastal Jefferson; Coastal Wakulla; Coastal Taylor; Coastal Dixie; Quitman; Clay; Randolph; Calhoun; Terrell; Dougherty; Lee; Worth; Turner; Tift; Ben Hill; Irwin; Early; Miller; Baker; Mitchell; Colquitt; Cook; Berrien; Seminole; Decatur; Grady; Thomas; Brooks; Lowndes; Lanier","geocode":{"SAME":["001031","001045","001067","001061","001069","012131","012059","012133","012063","012005","012013","012045","012037","012039","012073","012065","012079","012077","012129","012123","012067","012029","013239","013061","013243","013037","013273","013095","013177","013321","013287","013277","013017","013155","013099","013201","013007","013205","013071","013075","013019","013253","013087","013131","013275","013027","013185","013173"],"UGC":["ALZ065","ALZ066","ALZ067","ALZ068","ALZ069","FLZ007","FLZ008","FLZ009","FLZ010","FLZ011","FLZ012","FLZ013","FLZ014","FLZ015","FLZ016","FLZ017","FLZ018","FLZ019","FLZ026","FLZ027","FLZ028","FLZ029","FLZ034","FLZ108","FLZ112","FLZ114","FLZ115","FLZ118","FLZ127","FLZ128","FLZ134","GAZ120","GAZ121","GAZ122","GAZ123","GAZ124","GAZ125","GAZ126","GAZ127","GAZ128","GAZ129","GAZ130","GAZ131","GAZ142","GAZ143","GAZ144","GAZ145","GAZ146","GAZ147","GAZ148","GAZ155","GAZ156","GAZ157","GAZ158","GAZ159","GAZ160","GAZ161"]},"affectedZones":["https://api.weather.gov/zones/forecast/ALZ065","https://api.weather.gov/zones/forecast/ALZ066","https://api.weather.gov/zones/forecast/ALZ067","https://api.weather.gov/zones/forecast/ALZ068","https://api.weather.gov/zones/forecast/ALZ069","https://api.weather.gov/zones/forecast/FLZ007","https://api.weather.gov/zones/forecast/FLZ008","https://api.weather.gov/zones/forecast/FLZ009","https://api.weather.gov/zones/forecast/FLZ010","https://api.weather.gov/zones/forecast/FLZ011","https://api.weather.gov/zones/forecast/FLZ012","https://api.weather.gov/zones/forecast/FLZ013","https://api.weather.gov/zones/forecast/FLZ014","https://api.weather.gov/zones/forecast/FLZ015","https://api.weather.gov/zones/forecast/FLZ016","https://api.weather.gov/zones/forecast/FLZ017","https://api.weather.gov/zones/forecast/FLZ018","https://api.weather.gov/zones/forecast/FLZ019","https://api.weather.gov/zones/forecast/FLZ026","https://api.weather.gov/zones/forecast/FLZ027","https://api.weather.gov/zones/forecast/FLZ028","https://api.weather.gov/zones/forecast/FLZ029","https://api.weather.gov/zones/forecast/FLZ034","https://api.weather.gov/zones/forecast/FLZ108","https://api.weather.gov/zones/forecast/FLZ112","https://api.weather.gov/zones/forecast/FLZ114","https://api.weather.gov/zones/forecast/FLZ115","https://api.weather.gov/zones/forecast/FLZ118","https://api.weather.gov/zones/forecast/FLZ127","https://api.weather.gov/zones/forecast/FLZ128","https://api.weather.gov/zones/forecast/FLZ134","https://api.weather.gov/zones/forecast/GAZ120","https://api.weather.gov/zones/forecast/GAZ121","https://api.weather.gov/zones/forecast/GAZ122","https://api.weather.gov/zones/forecast/GAZ123","https://api.weather.gov/zones/forecast/GAZ124","https://api.weather.gov/zones/forecast/GAZ125","https://api.weather.gov/zones/forecast/GAZ126","https://api.weather.gov/zones/forecast/GAZ127","https://api.weather.gov/zones/forecast/GAZ128","https://api.weather.gov/zones/forecast/GAZ129","https://api.weather.gov/zones/forecast/GAZ130","https://api.weather.gov/zones/forecast/GAZ131","https://api.weather.gov/zones/forecast/GAZ142","https://api.weather.gov/zones/forecast/GAZ143","https://api.weather.gov/zones/forecast/GAZ144","https://api.weather.gov/zones/forecast/GAZ145","https://api.weather.gov/zones/forecast/GAZ146","https://api.weather.gov/zones/forecast/GAZ147","https://api.weather.gov/zones/forecast/GAZ148","https://api.weather.gov/zones/forecast/GAZ155","https://api.weather.gov/zones/forecast/GAZ156","https://api.weather.gov/zones/forecast/GAZ157","https://api.weather.gov/zones/forecast/GAZ158","https://api.weather.gov/zones/forecast/GAZ159","https://api.weather.gov/zones/forecast/GAZ160","https://api.weather.gov/zones/forecast/GAZ161"],"references":[],"sent":"2022-06-17T16:00:00-04:00","effective":"2022-06-17T16:00:00-04:00","onset":"2022-06-18T12:00:00-04:00","expires":"2022-06-17T22:00:00-04:00","ends":"2022-06-18T20:00:00-04:00","status":"Actual","messageType":"Alert","category":"Met","severity":"Moderate","certainty":"Likely","urgency":"Expected","event":"Heat Advisory","sender":"w-nws.webmaster@noaa.gov","senderName":"NWS Tallahassee FL","headline":"Heat Advisory issued June 17 at 4:00PM EDT until June 18 at 8:00PM EDT by NWS Tallahassee FL","description":"* WHAT...Heat index values of 108 to 112 expected.\n\n* WHERE...Portions of southeast Alabama, south central and\nsouthwest Georgia, and the Big Bend and Panhandle of Florida.\n\n* WHEN...For the first Heat Advisory, until 8 PM EDT /7 PM CDT/\nthis evening. For the second Heat Advisory, from noon EDT /11\nAM CDT/ to 8 PM EDT /7 PM CDT/ Saturday.\n\n* IMPACTS...Hot temperatures and high humidity may cause heat\nillnesses to occur.","instruction":"Drink plenty of fluids, stay in an air-conditioned room, stay out\nof the sun, and check up on relatives and neighbors. Young\nchildren and pets should never be left unattended in vehicles\nunder any circumstances.\n\nTake extra precautions if you work or spend time outside. When\npossible reschedule strenuous activities to early morning or\nevening. Know the signs and symptoms of heat exhaustion and heat\nstroke. Wear lightweight and loose fitting clothing when\npossible. To reduce risk during outdoor work, the Occupational\nSafety and Health Administration recommends scheduling frequent\nrest breaks in shaded or air conditioned environments. Anyone\novercome by heat should be moved to a cool and shaded location.\nHeat stroke is an emergency! Call 9 1 1.","response":"Execute","parameters":{"AWIPSidentifier":["NPWTAE"],"WMOidentifier":["WWUS72 KTAE 172000"],"NWSheadline":["HEAT ADVISORY REMAINS IN EFFECT UNTIL 8 PM EDT /7 PM CDT/ THIS EVENING... ...HEAT ADVISORY IN EFFECT FROM NOON EDT /11 AM CDT/ TO 8 PM EDT /7 PM CDT/ SATURDAY"],"BLOCKCHANNEL":["EAS","NWEM","CMAS"],"VTEC":["/O.NEW.KTAE.HT.Y.0005.220618T1600Z-220619T0000Z/"],"eventEndingTime":["2022-06-19T00:00:00+00:00"]}}}],"title":"current watches, warnings, and advisories for 30.7848 N, 83.5601 W","updated":"2022-06-18T00:00:00+00:00"}`)
+ fmt.Fprint(w, alert)
}))
defer ts.Close()
baseUrl, _ = url.Parse(ts.URL)
// Hit it.
+ fail = true
+ _, nwsErr := GetAlerts(33.2938, -83.9674)
+ if nwsErr == nil {
+ t.Errorf("alerts: expected it to fail")
+ return
+ }
+ if nwsErr.Title != "Unexpected Problem" {
+ t.Errorf("alerts: Error.Title: %v", nwsErr.Title)
+ return
+ }
+ if nwsErr.Type != "urn:noaa:nws:api:UnexpectedProblem" {
+ t.Errorf("alerts: Error.Type: %v", nwsErr.Type)
+ return
+ }
+ if nwsErr.Status != 500 {
+ t.Errorf("alerts: Error.Status: %v", nwsErr.Status)
+ return
+ }
+ if nwsErr.Detail != "An unexpected problem has occurred." {
+ t.Errorf("alerts: Error.Detail: %v", nwsErr.Detail)
+ return
+ }
+
+ // Hit it again.
+ fail = false
fc, nwsErr := GetAlerts(33.2938, -83.9674)
if nwsErr != nil {
t.Errorf("alerts: %v", nwsErr)
@@ -295,28 +321,21 @@ func TestAlerts(t *testing.T) {
return
}
- // Hit it again.
- fail = true
- _, nwsErr = GetAlerts(33.2938, -83.9674)
- if nwsErr == nil {
- t.Errorf("alerts: expected it fail")
+ // Check if the alert is cached.
+ ll := fmt.Sprintf("%.4f,%.4f", 33.2938, -83.9674)
+ cachedRawAlert := aCache.Get(ll)
+ if len(cachedRawAlert) < 1 {
+ t.Errorf("alerts: cache: empty: %v", cachedRawAlert)
return
}
- if nwsErr.Title != "Unexpected Problem" {
- t.Errorf("alerts: Error.Title: %v", nwsErr.Title)
+ if len(cachedRawAlert) != len(alert) {
+ t.Errorf("alerts: cached entry size: %d != %d",
+ len(cachedRawAlert), len(alert))
return
}
- if nwsErr.Type != "urn:noaa:nws:api:UnexpectedProblem" {
- t.Errorf("alerts: Error.Type: %v", nwsErr.Type)
+ if string(cachedRawAlert[:]) != alert {
+ t.Errorf("alerts: cached entry does not match alert: %s != %s",
+ cachedRawAlert, alert)
return
}
- if nwsErr.Status != 500 {
- t.Errorf("alerts: Error.Status: %v", nwsErr.Status)
- return
- }
- if nwsErr.Detail != "An unexpected problem has occurred." {
- t.Errorf("alerts: Error.Detail: %v", nwsErr.Detail)
- return
- }
-
}