diff --git a/cmd/server/config.go b/cmd/server/config.go index 7897a40..ef498a4 100644 --- a/cmd/server/config.go +++ b/cmd/server/config.go @@ -3,14 +3,18 @@ package main import ( "fmt" "os" + "strconv" "strings" + "time" "github.com/BurntSushi/toml" ) type rawConfig struct { Config - EnvFile string `toml:"env_file"` + EnvFile string `toml:"env_file"` + MaxCacheSize string `toml:"max_cache_size"` + MaxCacheAgeStr string `toml:"max_cache_age"` } type Config struct { @@ -19,19 +23,10 @@ type Config struct { MirroredRepos []string `toml:"mirrored_repos"` Port string `toml:"port"` Token string + MaxCacheSize int64 + MaxCacheAge time.Duration } -/* Function kept for reference for future logic -func NewConfig() *Config { - return &Config{ - CacheRoot: "/home/ewpt3ch/dev/pacman-cache-server/tmprepo", - MirrorURLs: "https://us.mirrors.cicku.me/archlinux/", - Port: "8090", - Auth: AuthConfig{Token: "FakeToken"}, - } -} -*/ - func ReadConfig(path string) (*Config, error) { var rawcfg rawConfig @@ -47,6 +42,21 @@ func ReadConfig(path string) (*Config, error) { return nil, fmt.Errorf("error getting token: %v", err) } + if rawcfg.MaxCacheSize == "" { + return nil, fmt.Errorf("max_cache_size must be set") + } + sizeBytes, err := strconv.ParseInt(strings.TrimSuffix(rawcfg.MaxCacheSize, "GB"), 10, 64) + sizeBytes = sizeBytes * 1024 * 1024 * 1024 + if err != nil { + return nil, fmt.Errorf("invalid cache size string") + } + cfg.MaxCacheSize = sizeBytes + + cfg.MaxCacheAge, err = time.ParseDuration(rawcfg.MaxCacheAgeStr) + if err != nil { + return nil, fmt.Errorf("error getting max_cache_age: %v", err) + } + if err = cfg.validate(); err != nil { return nil, fmt.Errorf("invalid config: %w", err) } diff --git a/cmd/server/config_test.go b/cmd/server/config_test.go index f95b487..2ced343 100644 --- a/cmd/server/config_test.go +++ b/cmd/server/config_test.go @@ -49,6 +49,8 @@ func defaultCfgMap() map[string]string { "mirrored_repos": `["core", "extra"]`, "port": `"8090"`, "PKGSTASH_TOKEN": "testtoken", + "max_cache_size": `"1GB"`, + "max_cache_age": `"1h"`, } } diff --git a/cmd/server/handler_test.go b/cmd/server/handler_test.go index 4007b1c..2481198 100644 --- a/cmd/server/handler_test.go +++ b/cmd/server/handler_test.go @@ -9,6 +9,7 @@ import ( "strings" "sync/atomic" "testing" + "time" "github.com/ewpt3ch/pkgstash/internal/cache" "github.com/ewpt3ch/pkgstash/internal/repomaint" @@ -39,8 +40,10 @@ func newTestServer(t *testing.T, mirrorHandler http.HandlerFunc) (*httptest.Serv croot := t.TempDir() mrepos := []string{"core"} + maxCacheSize := int64(1 * 1024 * 1024 * 1024) + maxCacheAge := time.Duration(time.Hour) - c, err := cache.NewCache(croot, []string{mirror.URL + "/"}, mrepos) + c, err := cache.NewCache(croot, []string{mirror.URL + "/"}, mrepos, maxCacheSize, maxCacheAge) if err != nil { t.Fatalf("failed to create cache: %v", err) } diff --git a/cmd/server/main.go b/cmd/server/main.go index b15b35c..47a200d 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -53,7 +53,7 @@ func main() { os.Exit(1) } - c, err := cache.NewCache(cfg.CacheRoot, cfg.MirrorURLs, cfg.MirroredRepos) + c, err := cache.NewCache(cfg.CacheRoot, cfg.MirrorURLs, cfg.MirroredRepos, cfg.MaxCacheSize, cfg.MaxCacheAge) if err != nil { slog.Error("failed to create cache", "err", err) os.Exit(1) diff --git a/deploy/pkgstash.toml.example b/deploy/pkgstash.toml.example index 59546c4..b1c7b72 100644 --- a/deploy/pkgstash.toml.example +++ b/deploy/pkgstash.toml.example @@ -9,3 +9,7 @@ mirror_urls = [ # or pacman docs for more info mirrored_repos = ["core", "extra"] port = "8090" +# cache eviction parameters, size expressed in GB, 0 means no limit +# time in a duration in hours: h, defaults to 1 year: 8760h +max_cache_size = "10GB" +max_cache_age = "8760h" diff --git a/go.mod b/go.mod index b1d981f..0aa3bb2 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 2d2505b..69184ff 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= diff --git a/internal/cache/cache.go b/internal/cache/cache.go index f9a8cac..061b137 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -13,7 +13,10 @@ import ( "time" ) -const userAgent = "pacman/7.1.0 (Linux x86_64) libalpm/16.0.1" +const ( + userAgent = "pacman/7.1.0 (Linux x86_64) libalpm/16.0.1" + repoArch = "os/x86_64" +) type Cache struct { cfg CacheConfig @@ -30,6 +33,8 @@ type CacheConfig struct { DialTimeout time.Duration ResponseHeaderTimeout time.Duration ClientTimeout time.Duration + MaxCacheSize int64 + MaxCacheAge time.Duration } type inFlight struct { @@ -46,13 +51,15 @@ type CacheFile struct { Filename string } -func NewCache(cacheRoot string, mirrorURLs []string, mirroredRepos []string) (*Cache, error) { +func NewCache(cacheRoot string, mirrorURLs []string, mirroredRepos []string, maxCacheSize int64, maxCacheAge time.Duration) (*Cache, error) { cfg := CacheConfig{ mirrorURLs: mirrorURLs, mirroredRepos: mirroredRepos, DialTimeout: 5 * time.Second, ResponseHeaderTimeout: 10 * time.Second, ClientTimeout: 0 * time.Second, + MaxCacheSize: maxCacheSize, + MaxCacheAge: maxCacheAge, } transport := &http.Transport{ diff --git a/internal/cache/cache_test.go b/internal/cache/cache_test.go index b6229ec..a88778d 100644 --- a/internal/cache/cache_test.go +++ b/internal/cache/cache_test.go @@ -30,7 +30,9 @@ func newTestCache(t *testing.T, mirrorURLs []string) *Cache { // set slog to debug slog.SetLogLoggerLevel(slog.LevelDebug) mirroredRepos := []string{"core", "extra"} - c, err := NewCache(t.TempDir(), mirrorURLs, mirroredRepos) + maxSize := int64(1024) + maxAge := time.Duration(10 * time.Second) + c, err := NewCache(t.TempDir(), mirrorURLs, mirroredRepos, maxSize, maxAge) if err != nil { t.Fatalf("failed to create cache: %v", err) }