From d321d96fefdda274ef8a2cff706fefe7ac32801b Mon Sep 17 00:00:00 2001 From: Ron Rise Date: Wed, 21 Jan 2026 21:08:26 -0500 Subject: [PATCH] Refactor caching logic and add support for a new feature --- go.mod | 2 +- http/handler.go | 6 +- main.go | 2 + reddit/client.go | 9 ++- reddit/fetcher.go | 194 +++++++++++++++++++++++++--------------------- redis/client.go | 9 +++ 6 files changed, 128 insertions(+), 94 deletions(-) diff --git a/go.mod b/go.mod index 097f507..1902eaa 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/siteworxpro/top-wallpaper -go 1.25.0 +go 1.25.6 require ( github.com/labstack/echo/v4 v4.13.4 diff --git a/http/handler.go b/http/handler.go index 85c1125..9b9c504 100644 --- a/http/handler.go +++ b/http/handler.go @@ -2,6 +2,7 @@ package http import ( "net/http" + "os" "github.com/labstack/echo/v4" "github.com/siteworxpro/top-wallpaper/redis" @@ -14,7 +15,10 @@ func Get(c echo.Context) error { return c.String(http.StatusInternalServerError, "Internal Server Error: "+err.Error()) } - val, err := rc.Get(redis.CacheKey) + defer rc.Close() + + nsfw := (c.QueryParam("nsfw") == "true" || c.QueryParam("nsfw") == "1") && os.Getenv("NSFW_MODE") == "true" + val, err := rc.Get(rc.GetCacheKey(nsfw)) if err != nil || val == "" { return c.NoContent(http.StatusNoContent) diff --git a/main.go b/main.go index f5a9b2b..0f5fca0 100644 --- a/main.go +++ b/main.go @@ -28,6 +28,8 @@ func main() { } e := echo.New() + defer e.Close() + e.AcquireContext().Set("redisClient", rc) e.Logger.SetOutput(os.Stdout) diff --git a/reddit/client.go b/reddit/client.go index 7fe76b1..802301a 100644 --- a/reddit/client.go +++ b/reddit/client.go @@ -54,9 +54,14 @@ type redditResponse struct { } `json:"data"` } -func GetLatestImage(httpGet func(url string) (*http.Response, error)) (string, error) { +const ( + wallpaperURL = "https://www.reddit.com/r/wallpaper/.json" + nsfwWallpaperURL = "https://www.reddit.com/r/NSFW_Wallpapers/.json" +) - response, err := httpGet("https://www.reddit.com/r/wallpaper/.json") +func GetLatestImage(httpGet func() (*http.Response, error)) (string, error) { + + response, err := httpGet() if err != nil { return "", err } diff --git a/reddit/fetcher.go b/reddit/fetcher.go index ff59a1e..abf77f1 100644 --- a/reddit/fetcher.go +++ b/reddit/fetcher.go @@ -50,99 +50,113 @@ func Fetch(ctx context.Context) { return default: - val, err := rc.Get(redis.CacheKey) - if err != nil { - l.Error("Error fetching from Redis: ", err) - break + doFetch(rc, l, false, size) + + if os.Getenv("NSFW_MODE") == "true" { + doFetch(rc, l, true, size) } - - if val != "" { - l.Info("Reddit image fetched from cache...") - - break - } - - l.Info("Fetching latest image from Reddit...") - - latestImageVal, err := GetLatestImage(func(u string) (*http.Response, error) { - - request := &http.Request{ - Method: http.MethodGet, - Header: http.Header{ - "User-Agent": []string{"Mozilla/5.0 (compatible; RedditBot/1.0; +https://www.reddit.com/wiki/redditauth)"}, - }, - URL: &url.URL{ - Scheme: "https", - Host: "www.reddit.com", - Path: strings.TrimPrefix(u, "https://www.reddit.com"), - }, - } - - httpClient := &http.Client{ - Timeout: 10 * time.Second, - } - - response, e := httpClient.Do(request) - - if e != nil { - l.Error("Error fetching image from Reddit: ", e) - return nil, e - } - - if response.StatusCode != http.StatusOK { - l.Error("Error fetching image from Reddit: ", response.Status) - return nil, &echo.HTTPError{ - Code: response.StatusCode, - Message: "Error fetching image from Reddit", - } - } - - return response, nil - }) - - if err != nil { - l.Error("Error getting latest image URL: ", err) - break - } - - response, err := http.Get(latestImageVal) - if err != nil { - l.Error("Error fetching image from Reddit: ", err) - - break - } - - if response.StatusCode != http.StatusOK { - l.Error("Error fetching image from Reddit: ", response.Status) - - break - } - - imageDataBytes, err := io.ReadAll(response.Body) - if err != nil { - l.Error("Error reading image data: ", err) - _ = response.Body.Close() - break - } - - _ = response.Body.Close() - - imageData := string(imageDataBytes) - resized, err := resize.Shrink(imageData, uint(size), 70) - - if err != nil { - l.Error("Error resizing image: ", err) - break - } - - err = rc.Set(redis.CacheKey, resized, 10*time.Minute) - if err != nil { - l.Warn("could not cache image") - } - - l.Info("Reddit image fetched and resized successfully, cached for 10 minutes.") } time.Sleep(10 * time.Minute) } } + +func doFetch(rc *redis.Redis, l echo.Logger, nsfw bool, size int) { + val, err := rc.Get(rc.GetCacheKey(nsfw)) + if err != nil { + l.Error("Error fetching from Redis: ", err) + return + } + + if val != "" { + l.Info("Reddit image fetched from cache...") + + return + } + + l.Info("Fetching latest image from Reddit...") + + latestImageVal, err := GetLatestImage(func() (*http.Response, error) { + + jsonUrl := wallpaperURL + nsfwMode := os.Getenv("NSFW_MODE") + if nsfwMode == "true" { + jsonUrl = nsfwWallpaperURL + } + + request := &http.Request{ + Method: http.MethodGet, + Header: http.Header{ + "User-Agent": []string{"Mozilla/5.0 (compatible; RedditBot/1.0; +https://www.reddit.com/wiki/redditauth)"}, + }, + URL: &url.URL{ + Scheme: "https", + Host: "www.reddit.com", + Path: strings.TrimPrefix(jsonUrl, "https://www.reddit.com"), + }, + } + + httpClient := &http.Client{ + Timeout: 10 * time.Second, + } + + response, e := httpClient.Do(request) + + if e != nil { + l.Error("Error fetching image from Reddit: ", e) + return nil, e + } + + if response.StatusCode != http.StatusOK { + l.Error("Error fetching image from Reddit: ", response.Status) + return nil, &echo.HTTPError{ + Code: response.StatusCode, + Message: "Error fetching image from Reddit", + } + } + + return response, nil + }) + + if err != nil { + l.Error("Error getting latest image URL: ", err) + return + } + + response, err := http.Get(latestImageVal) + if err != nil { + l.Error("Error fetching image from Reddit: ", err) + + return + } + + if response.StatusCode != http.StatusOK { + l.Error("Error fetching image from Reddit: ", response.Status) + + return + } + + imageDataBytes, err := io.ReadAll(response.Body) + if err != nil { + l.Error("Error reading image data: ", err) + _ = response.Body.Close() + return + } + + _ = response.Body.Close() + + imageData := string(imageDataBytes) + resized, err := resize.Shrink(imageData, uint(size), 70) + + if err != nil { + l.Error("Error resizing image: ", err) + return + } + + err = rc.Set(rc.GetCacheKey(nsfw), resized, 10*time.Minute) + if err != nil { + l.Warn("could not cache image") + } + + l.Info("Reddit image fetched and resized successfully, cached for 10 minutes.") +} diff --git a/redis/client.go b/redis/client.go index c20c6e8..92ce187 100644 --- a/redis/client.go +++ b/redis/client.go @@ -16,6 +16,7 @@ type contextKey string const redisKey contextKey = "redisClient" const CacheKey = "top-wallpaper:latestImage" +const NsfwCacheKey = "top-wallpaper-nsfw:latestImage" type Cache interface { Get(key string) (string, error) @@ -92,6 +93,14 @@ func (r *Redis) Set(key string, value string, expiration time.Duration) error { return nil } +func (*Redis) GetCacheKey(nsfw bool) string { + if nsfw { + return NsfwCacheKey + } + + return CacheKey +} + func (r *Redis) Close() error { if r.client == nil { return nil