//go:build !nocache package main import ( "encoding/json" "strings" "time" "github.com/dgraph-io/badger" ) var cache = Cache{} type Cache struct { *badger.DB } func (c *Cache) initialize() func() { db, err := badger.Open(badger.DefaultOptions(s.DiskCachePath)) if err != nil { log.Fatal().Err(err).Str("path", s.DiskCachePath).Msg("failed to open badger") } c.DB = db go func() { ticker := time.NewTicker(2 * time.Hour) defer ticker.Stop() for range ticker.C { again: err := db.RunValueLogGC(0.8) if err == nil { goto again } } }() return func() { db.Close() } } func (c *Cache) Get(key string) ([]byte, bool) { var val []byte err := c.DB.View(func(txn *badger.Txn) error { b, err := txn.Get([]byte(key)) if err != nil { return err } val, err = b.ValueCopy(nil) return err }) if err == badger.ErrKeyNotFound { return nil, false } if err != nil { log.Fatal().Err(err).Str("key", key).Msg("error getting key from cache") } return val, true } func (c *Cache) GetPaginatedkeys(prefix string, page int, size int) []string { keys := []string{} err := c.DB.View(func(txn *badger.Txn) error { opts := badger.DefaultIteratorOptions opts.PrefetchValues = false it := txn.NewIterator(opts) defer it.Close() start := (page-1)*size + 1 index := 1 for it.Seek([]byte(prefix)); it.ValidForPrefix([]byte(prefix)); it.Next() { if index < start { index++ continue } if index > start+size-1 { break } item := it.Item() k := item.Key() keys = append(keys, strings.TrimPrefix(string(k), prefix+":")) index++ } return nil }) if err != nil { log.Fatal().Err(err).Msg("") } return keys } func (c *Cache) GetJSON(key string, recv any) bool { b, ok := c.Get(key) if !ok { return ok } json.Unmarshal(b, recv) return true } func (c *Cache) Set(key string, value []byte) { err := c.DB.Update(func(txn *badger.Txn) error { return txn.Set([]byte(key), value) }) if err != nil { log.Fatal().Err(err).Msg("") } } func (c *Cache) SetJSON(key string, value any) { j, _ := json.Marshal(value) c.Set(key, j) } func (c *Cache) SetWithTTL(key string, value []byte, ttl time.Duration) { err := c.DB.Update(func(txn *badger.Txn) error { return txn.SetEntry( badger.NewEntry([]byte(key), value).WithTTL(ttl), ) }) if err != nil { log.Fatal().Err(err).Msg("") } } func (c *Cache) SetJSONWithTTL(key string, value any, ttl time.Duration) { j, _ := json.Marshal(value) c.SetWithTTL(key, j, ttl) }