package lib import ( "bytes" "encoding/json" "io" "net/http" ) // Entry represents a single fetched item. type Entry struct { Title string URL string } // Fetcher is the interface for a fetcher. type Fetcher interface { Name() string Fetch() []Entry } // BaseFetcher contains common fields for all fetchers. type BaseFetcher struct { BaseURL string Token string Cache *Cache } // TryCreateEntry checks the cache and creates an Entry if the value has changed. func (b *BaseFetcher) TryCreateEntry(cacheKey, cacheValue, title, url string) *Entry { if b.Cache.TryUpdate(cacheKey, cacheValue) { return &Entry{Title: title, URL: url} } return nil } // FetcherRequest represents a common HTTP request configuration. type FetcherRequest struct { BaseURL string Path string Method string Headers map[string]string Body []byte } // Run executes the HTTP request and decodes the JSON response into target. func (r FetcherRequest) Run(target interface{}) error { url := r.BaseURL + r.Path var body io.Reader if r.Body != nil { body = bytes.NewBuffer(r.Body) } req, err := http.NewRequest(r.Method, url, body) if err != nil { return err } for key, value := range r.Headers { req.Header.Set(key, value) } res, err := http.DefaultClient.Do(req) if err != nil { return err } defer res.Body.Close() return json.NewDecoder(res.Body).Decode(target) }