From 6097d2d357bed480c80eebbb39cb3b48b0b0923d Mon Sep 17 00:00:00 2001 From: lnu Date: Thu, 23 Sep 2021 23:46:06 +0200 Subject: [PATCH] feat(owm): response caching added default timeout of 10 minutes. A value of 0 disables the cache. Original concept by boarder2 --- docs/docs/segment-owm.md | 4 +++- src/segment_owm.go | 46 +++++++++++++++++++++++++++++++++---- src/segment_owm_test.go | 49 +++++++++++++++++++++++++++++++--------- themes/schema.json | 6 +++++ 4 files changed, 88 insertions(+), 17 deletions(-) diff --git a/docs/docs/segment-owm.md b/docs/docs/segment-owm.md index cbcac9a7..296ff0a3 100644 --- a/docs/docs/segment-owm.md +++ b/docs/docs/segment-owm.md @@ -29,7 +29,8 @@ The free tier for *Current weather and forecasts collection* is sufficient. "location": "AMSTERDAM,NL", "units": "metric", "enable_hyperlink" : false, - "http_timeout": 20 + "http_timeout": 20, + "cache_timeout": 10 } } ``` @@ -44,3 +45,4 @@ The free tier for *Current weather and forecasts collection* is sufficient. Available values are standard (kelvin), metric (celsius), and imperial (fahrenheit) - defaults to `standard` - enable_hyperlink: `bool` - Displays an hyperlink to get openweathermap data - http_timeout: `int` - The default timeout for http request is 20ms. +- cache_timeout: `int` - The default timeout for request caching is 10m. A value of 0 disables the cache. diff --git a/src/segment_owm.go b/src/segment_owm.go index 75843104..488d1d6a 100644 --- a/src/segment_owm.go +++ b/src/segment_owm.go @@ -21,6 +21,8 @@ const ( LOCATION Property = "location" // UNITS openweathermap units UNITS Property = "units" + // CACHETIMEOUT cache timeout + CACHETIMEOUT Property = "cachetimeout" ) type weather struct { @@ -61,22 +63,57 @@ func (d *owm) string() string { return text } -func (d *owm) setStatus() error { +func (d *owm) getResult() (*OWMDataResponse, error) { apikey := d.props.getString(APIKEY, ".") location := d.props.getString(LOCATION, "De Bilt,NL") units := d.props.getString(UNITS, "standard") timeout := d.props.getInt(HTTPTimeout, DefaultHTTPTimeout) + cachetimeout := int64(d.props.getInt(CACHETIMEOUT, 10)) - url := fmt.Sprintf("http://api.openweathermap.org/data/2.5/weather?q=%s&units=%s&appid=%s", location, units, apikey) - body, err := d.env.doGet(url, timeout) + d.url = fmt.Sprintf("http://api.openweathermap.org/data/2.5/weather?q=%s&units=%s&appid=%s", location, units, apikey) + + if cachetimeout > 0 { + // check if data stored in cache + val, found := d.env.cache().get("owm_response") + // we got something from te cache + if found { + q := new(OWMDataResponse) + err := json.Unmarshal([]byte(val), q) + if err != nil { + return nil, err + } + return q, nil + } + } + + body, err := d.env.doGet(d.url, timeout) if err != nil { - return err + return new(OWMDataResponse), err } q := new(OWMDataResponse) err = json.Unmarshal(body, &q) + if err != nil { + return new(OWMDataResponse), err + } + + if cachetimeout > 0 { + // persist new forecasts in cache + d.env.cache().set("owm_response", string(body), cachetimeout) + if err != nil { + return nil, err + } + } + return q, nil +} + +func (d *owm) setStatus() error { + units := d.props.getString(UNITS, "standard") + + q, err := d.getResult() if err != nil { return err } + d.temperature = q.temperature.Value icon := "" switch q.Data[0].TypeID { @@ -118,7 +155,6 @@ func (d *owm) setStatus() error { icon = "\ue313" } d.weather = icon - d.url = url d.units = units return nil } diff --git a/src/segment_owm_test.go b/src/segment_owm_test.go index 513e2cde..7bf32eaf 100644 --- a/src/segment_owm_test.go +++ b/src/segment_owm_test.go @@ -8,6 +8,10 @@ import ( "github.com/stretchr/testify/assert" ) +const ( + OWMAPIURL = "http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key" +) + func TestOWMSegmentSingle(t *testing.T) { cases := []struct { Case string @@ -34,15 +38,14 @@ func TestOWMSegmentSingle(t *testing.T) { env := &MockedEnvironment{} props := &properties{ values: map[Property]interface{}{ - APIKEY: "key", - LOCATION: "AMSTERDAM,NL", - UNITS: "metric", + APIKEY: "key", + LOCATION: "AMSTERDAM,NL", + UNITS: "metric", + CACHETIMEOUT: 0, }, } - url := "http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key" - - env.On("doGet", url).Return([]byte(tc.JSONResponse), tc.Error) + env.On("doGet", OWMAPIURL).Return([]byte(tc.JSONResponse), tc.Error) o := &owm{ props: props, @@ -162,17 +165,17 @@ func TestOWMSegmentIcons(t *testing.T) { env := &MockedEnvironment{} props := &properties{ values: map[Property]interface{}{ - APIKEY: "key", - LOCATION: "AMSTERDAM,NL", - UNITS: "metric", + APIKEY: "key", + LOCATION: "AMSTERDAM,NL", + UNITS: "metric", + CACHETIMEOUT: 0, }, } - url := "http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key" response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, tc.IconID) expectedString := fmt.Sprintf("%s (20°C)", tc.ExpectedIconString) - env.On("doGet", url).Return([]byte(response), nil) + env.On("doGet", OWMAPIURL).Return([]byte(response), nil) o := &owm{ props: props, @@ -183,3 +186,27 @@ func TestOWMSegmentIcons(t *testing.T) { assert.Equal(t, expectedString, o.string(), tc.Case) } } +func TestOWMSegmentFromCache(t *testing.T) { + response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, "01d") + expectedString := fmt.Sprintf("%s (20°C)", "\ufa98") + + env := &MockedEnvironment{} + cache := &MockedCache{} + props := &properties{ + values: map[Property]interface{}{ + APIKEY: "key", + LOCATION: "AMSTERDAM,NL", + UNITS: "metric", + }, + } + o := &owm{ + props: props, + env: env, + } + cache.On("get", "owm_response").Return(response, true) + cache.On("set").Return() + env.On("cache", nil).Return(cache) + + assert.Nil(t, o.setStatus()) + assert.Equal(t, expectedString, o.string()) +} diff --git a/themes/schema.json b/themes/schema.json index b467872b..667dc451 100644 --- a/themes/schema.json +++ b/themes/schema.json @@ -1547,6 +1547,12 @@ }, "http_timeout": { "$ref": "#/definitions/http_timeout" + }, + "cache_timeout": { + "type": "integer", + "title": "cache timeout", + "description": "The number of minutes the response is cached. A value of 0 disables the cache.", + "default": 10 } } }