package main import ( "encoding/json" "log" "net/http" "regexp" "sync" "time" "github.com/mmcdole/gofeed" ) type Update struct { Version string `json:"version"` Build string `json:"build"` Published string `json:"published"` // ISO date string YYYY-MM-DD } var ( cacheMu sync.Mutex cachedUpdates []Update cacheExpiry time.Time cacheDuration = 5 * time.Minute // adjust as needed ) func fetchUpdates(feedURL string) ([]Update, error) { parser := gofeed.NewParser() feed, err := parser.ParseURL(feedURL) if err != nil { return nil, err } versionRe := regexp.MustCompile(`(?i)(?:^|\s)(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)(?:\s+)?Update|Update\s+(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)`) buildRe := regexp.MustCompile(`SteamDB Build (\d+)`) var updates []Update for _, item := range feed.Items { buildMatch := buildRe.FindStringSubmatch(item.Description) versionMatch := versionRe.FindStringSubmatch(item.Description) if len(buildMatch) > 1 && len(versionMatch) > 1 { version := versionMatch[1] if version == "" && len(versionMatch) > 2 { version = versionMatch[2] } build := buildMatch[1] pubTime, err := time.Parse(time.RFC1123Z, item.Published) if err != nil { log.Printf("Error parsing date for item %s: %v", item.Title, err) continue } updates = append(updates, Update{ Version: version, Build: build, Published: pubTime.Format("2006-01-02"), }) } } return updates, nil } func getCachedUpdates(feedURL string) ([]Update, error) { cacheMu.Lock() defer cacheMu.Unlock() if time.Now().Before(cacheExpiry) && cachedUpdates != nil { return cachedUpdates, nil } updates, err := fetchUpdates(feedURL) if err != nil { return nil, err } cachedUpdates = updates cacheExpiry = time.Now().Add(cacheDuration) return updates, nil } func invalidateCache(w http.ResponseWriter, r *http.Request) { cacheMu.Lock() defer cacheMu.Unlock() cachedUpdates = nil cacheExpiry = time.Time{} // zero time to force refresh on next request w.WriteHeader(http.StatusOK) w.Write([]byte("Cache invalidated\n")) } func updatesHandler(w http.ResponseWriter, r *http.Request) { const feedURL = "https://steamdb.info/api/PatchnotesRSS/?appid=1874880" updates, err := getCachedUpdates(feedURL) if err != nil { http.Error(w, "Failed to fetch updates: "+err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(updates); err != nil { http.Error(w, "Failed to encode JSON: "+err.Error(), http.StatusInternalServerError) } } func main() { http.HandleFunc("/updates", updatesHandler) http.HandleFunc("/invalidate-cache", invalidateCache) log.Println("Listening on http://localhost:8080/") log.Fatal(http.ListenAndServe(":8080", nil)) }