answer/pkg/cache/directory.go

161 lines
2.7 KiB
Go

package cache
import (
"bytes"
"context"
"encoding/json"
"io"
"os"
"path/filepath"
"sync"
"time"
)
type Directory struct {
BaseFolder string
MaxLife time.Duration
lock sync.Mutex
}
var _ Cache = &Directory{}
func (d *Directory) GetPath(key string) string {
return filepath.Join(d.BaseFolder, key+".json")
}
func (d *Directory) Cleanup(_ context.Context) error {
d.lock.Lock()
defer func() {
d.lock.Unlock()
}()
// go through the BaseFilder looking for any files that are older than MaxLife
return filepath.Walk(d.BaseFolder, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// ignore directories
if info.IsDir() {
return nil
}
// only files that end in .json
if filepath.Ext(path) != ".json" {
return nil
}
// if the openFile is older than MaxLife, delete it
if time.Since(info.ModTime()) > d.MaxLife {
return os.Remove(path)
}
return nil
})
}
// AutoCleanupRoutine will continually loop and cleanup the directory, until the context is cancelled or an error occurs
// returns nil on context cancellation, or an error if one occurs during cleanup
func (d *Directory) AutoCleanupRoutine(ctx context.Context) error {
for {
select {
case <-ctx.Done():
return nil
case <-time.After(d.MaxLife):
err := d.Cleanup(ctx)
if err != nil {
return err
}
}
}
}
func (d *Directory) openFile(key string) (*os.File, error) {
path := d.GetPath(key)
return os.Open(path)
}
func (d *Directory) Set(key string, value io.Reader) error {
d.lock.Lock()
defer d.lock.Unlock()
fp, err := d.openFile(key)
if err != nil {
return err
}
defer func(fp *os.File) {
_ = fp.Close()
}(fp)
_, err = io.Copy(fp, value)
return err
}
func (d *Directory) SetJSON(key string, value any) error {
d.lock.Lock()
defer d.lock.Unlock()
fp, err := d.openFile(key)
if err != nil {
return err
}
defer func(fp *os.File) {
_ = fp.Close()
}(fp)
return json.NewEncoder(fp).Encode(value)
}
func (d *Directory) SetString(key, value string) error {
return d.Set(key, bytes.NewReader([]byte(value)))
}
func (d *Directory) Get(key string, w io.Writer) error {
d.lock.Lock()
defer d.lock.Unlock()
fp, err := d.openFile(key)
if err != nil {
return err
}
defer fp.Close()
_, err = io.Copy(w, fp)
return err
}
func (d *Directory) GetJSON(key string, v any) error {
d.lock.Lock()
defer d.lock.Unlock()
fp, err := d.openFile(key)
if err != nil {
return err
}
defer fp.Close()
return json.NewEncoder(fp).Encode(v)
}
func (d *Directory) GetString(key string) (string, error) {
var buf bytes.Buffer
err := d.Get(key, &buf)
return buf.String(), err
}
func (d *Directory) Delete(key string) error {
d.lock.Lock()
defer d.lock.Unlock()
return os.Remove(d.GetPath(key))
}