From e0113bf06718ae2e9e4518ea5160cc7fc8494b2c Mon Sep 17 00:00:00 2001 From: vinayak3010 Date: Sat, 5 Oct 2024 22:18:39 +0530 Subject: [PATCH] feat: Add caching mechanism to optimize weather data fetching from OpenMeteo API --- backends/open-meteo.com.go | 34 +++++++++++++++++++++++++--- backends/openweathermap.org.go | 41 +++++++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/backends/open-meteo.com.go b/backends/open-meteo.com.go index 696ba1e..e6a2696 100644 --- a/backends/open-meteo.com.go +++ b/backends/open-meteo.com.go @@ -9,15 +9,23 @@ import ( "net/http" "regexp" "strings" + "sync" "time" "github.com/schachmat/wego/iface" ) +type cachedData struct { + Data iface.Data + Timestamp time.Time +} + type openmeteoConfig struct { - apiKey string - language string - debug bool + apiKey string + language string + debug bool + cache map[string]cachedData // adding a cache map + cacheDuration time.Duration // adding the duration for which the data will be valid } type curCond struct { @@ -110,6 +118,8 @@ var ( func (opmeteo *openmeteoConfig) Setup() { flag.StringVar(&opmeteo.apiKey, "openmeteo-api-key", "", "openmeteo backend: the api `KEY` to use if commercial usage") flag.BoolVar(&opmeteo.debug, "openmeteo-debug", false, "openmeteo backend: print raw requests and responses") + opmeteo.cache = make(map[string]cachedData) // initializing a cache + opmeteo.cacheDuration = 1 * time.Hour // setting the cache duation to 1 hour } func (opmeteo *openmeteoConfig) parseDaily(dailyInfo Hourly) []iface.Day { @@ -161,11 +171,22 @@ func parseCurCond(current curCond) (ret iface.Cond) { } +var mu sync.Mutex + func (opmeteo *openmeteoConfig) Fetch(location string, numdays int) iface.Data { var ret iface.Data var params []string var loc string + //checking cache before fething the data + mu.Lock() + if cached, ok := opmeteo.cache[location]; ok { + if time.Since(cached.Timestamp) < opmeteo.cacheDuration { + return cached.Data + } + } + mu.Unlock() + if numdays <= 0 { log.Fatal("Number of days less than 1 ") } @@ -219,6 +240,13 @@ func (opmeteo *openmeteoConfig) Fetch(location string, numdays int) iface.Data { ret.Forecast = forecast } + mu.Lock() + opmeteo.cache[location] = cachedData{ + Data: ret, //store the fetched data in the cache + Timestamp: time.Now(), // store the current time in the cache + } + mu.Unlock() + return ret } diff --git a/backends/openweathermap.org.go b/backends/openweathermap.org.go index 1eae102..091be8c 100644 --- a/backends/openweathermap.org.go +++ b/backends/openweathermap.org.go @@ -4,30 +4,39 @@ import ( "encoding/json" "flag" "fmt" - "github.com/schachmat/wego/iface" "io" "log" "net/http" "regexp" "strings" + "sync" "time" + + "github.com/schachmat/wego/iface" ) type openWeatherConfig struct { - apiKey string - lang string - debug bool + apiKey string + lang string + debug bool + cache map[string]cacheEntry + cacheMux sync.Mutex +} + +type cacheEntry struct { + data iface.Data + Timestamp time.Time } type openWeatherResponse struct { Cod string `json:"cod"` City struct { - Name string `json:"name"` - Country string `json:"country"` - TimeZone int64 `json: "timezone"` + Name string `json:"name"` + Country string `json:"country"` + TimeZone int64 `json: "timezone"` // sunrise/sunset are once per call SunRise int64 `json: "sunrise"` - SunSet int64 `json: "sunset"` + SunSet int64 `json: "sunset"` } `json:"city"` List []dataBlock `json:"list"` } @@ -57,12 +66,15 @@ type dataBlock struct { const ( openweatherURI = "http://api.openweathermap.org/data/2.5/forecast?%s&appid=%s&units=metric&lang=%s" + cacheDuration = 1 * time.Hour ) func (c *openWeatherConfig) Setup() { flag.StringVar(&c.apiKey, "owm-api-key", "", "openweathermap backend: the api `KEY` to use") flag.StringVar(&c.lang, "owm-lang", "en", "openweathermap backend: the `LANGUAGE` to request from openweathermap") flag.BoolVar(&c.debug, "owm-debug", false, "openweathermap backend: print raw requests and responses") + + c.cache = make(map[string]cacheEntry) // initializing the cache } func (c *openWeatherConfig) fetch(url string) (*openWeatherResponse, error) { @@ -236,6 +248,14 @@ func (c *openWeatherConfig) Fetch(location string, numdays int) iface.Data { if len(c.apiKey) == 0 { log.Fatal("No openweathermap.org API key specified.\nYou have to register for one at https://home.openweathermap.org/users/sign_up") } + + c.cacheMux.Lock() + if entry, found := c.cache[location]; found && time.Since(entry.Timestamp)