diff --git a/pkg/torznab/cache.go b/pkg/torznab/cache.go new file mode 100644 index 0000000..db6fb34 --- /dev/null +++ b/pkg/torznab/cache.go @@ -0,0 +1,31 @@ +package torznab + +import ( + "polaris/log" + "polaris/pkg/utils" + + "github.com/robfig/cron" + + "time" +) + +var cache utils.Map[string, TimedResponse] = utils.Map[string, TimedResponse]{} + +type TimedResponse struct { + Response + T time.Time +} + +func init() { + cr := cron.New() + cr.AddFunc("@ervery 1m", func() { + cache.Range(func(key string, value TimedResponse) bool { + if time.Since(value.T) > 30*time.Minute { + log.Debugf("delete old cache: %v", key) + cache.Delete(key) + } + return true + }) + }) + cr.Start() +} diff --git a/pkg/torznab/torznab.go b/pkg/torznab/torznab.go index 9f02f92..da7d67d 100644 --- a/pkg/torznab/torznab.go +++ b/pkg/torznab/torznab.go @@ -3,6 +3,7 @@ package torznab import ( "context" "encoding/xml" + "fmt" "io" "net/http" "net/url" @@ -112,7 +113,7 @@ func tryParseFloat(s string) float32 { return float32(r) } -func Search(indexer *db.TorznabInfo, api, keyWord string) ([]Result, error) { +func Search(indexer *db.TorznabInfo, keyWord string) ([]Result, error) { ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second) defer cancel() @@ -121,26 +122,32 @@ func Search(indexer *db.TorznabInfo, api, keyWord string) ([]Result, error) { return nil, errors.Wrap(err, "new request") } var q = url.Values{} - q.Add("apikey", api) + q.Add("apikey", indexer.ApiKey) q.Add("t", "search") q.Add("q", keyWord) req.URL.RawQuery = q.Encode() + key := fmt.Sprintf("%s: %s", indexer.Name, keyWord) - resp, err := http.DefaultClient.Do(req) - if err != nil { - return nil, errors.Wrap(err, "do http") + cacheRes, ok := cache.Load(key) + if !ok { + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, errors.Wrap(err, "do http") + } + defer resp.Body.Close() + data, err := io.ReadAll(resp.Body) + if err != nil { + return nil, errors.Wrap(err, "read http body") + } + var res Response + err = xml.Unmarshal(data, &res) + if err != nil { + return nil, errors.Wrap(err, "json unmarshal") + } + cacheRes = TimedResponse{Response: res, T: time.Now()} + cache.Store(key, cacheRes) } - defer resp.Body.Close() - data, err := io.ReadAll(resp.Body) - if err != nil { - return nil, errors.Wrap(err, "read http body") - } - var res Response - err = xml.Unmarshal(data, &res) - if err != nil { - return nil, errors.Wrap(err, "json unmarshal") - } - return res.ToResults(indexer), nil + return cacheRes.ToResults(indexer), nil } type Result struct { diff --git a/server/core/torrent.go b/server/core/torrent.go index 70fc8e8..640361f 100644 --- a/server/core/torrent.go +++ b/server/core/torrent.go @@ -159,7 +159,7 @@ func searchWithTorznab(db *db.Client, q string) []torznab.Result { go func() { log.Debugf("search torznab %v with %v", tor.Name, q) defer wg.Done() - resp, err := torznab.Search(tor, tor.ApiKey, q) + resp, err := torznab.Search(tor, q) if err != nil { log.Errorf("search %s error: %v", tor.Name, err) return