From 07587339b9f203c396d332efcffaa82cf1de23ea Mon Sep 17 00:00:00 2001 From: Kesuaheli Date: Sat, 9 Nov 2024 15:10:07 +0100 Subject: [PATCH] feat: added basic cache --- .gitignore | 1 + cache.go | 76 +++++++++++++++++++++++++++++++++++ examples/with_cache/README.md | 0 examples/with_cache/main.go | 23 +++++++++++ go.mod | 2 + go.sum | 2 + go_manifest.go | 6 +++ 7 files changed, 110 insertions(+) create mode 100644 cache.go create mode 100644 examples/with_cache/README.md create mode 100644 examples/with_cache/main.go create mode 100644 go.sum diff --git a/.gitignore b/.gitignore index cfae2d0..1da03d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .vscode /assets/ +.cache/ diff --git a/cache.go b/cache.go new file mode 100644 index 0000000..0b9db66 --- /dev/null +++ b/cache.go @@ -0,0 +1,76 @@ +package manifest + +import ( + "encoding/gob" + "fmt" + "os" + + "github.com/patrickmn/go-cache" +) + +var ( + versionCache *cache.Cache +) + +func init() { + gob.Register(&Version{}) + + finfo, _ := os.Stat(".cache/versions") + if finfo == nil { + versionCache = cache.New(cache.NoExpiration, cache.NoExpiration) + return + } + f, err := os.Open(".cache/versions") + if err != nil { + fmt.Printf("Failed to open cache file: %+v\n", err.(*os.PathError)) + return + } + defer f.Close() + + items := make(map[string]cache.Item) + err = gob.NewDecoder(f).Decode(&items) + if err != nil { + fmt.Printf("Failed to decode cache file: %+v\n", err.(*os.PathError)) + return + } + versionCache = cache.NewFrom(cache.NoExpiration, cache.NoExpiration, items) + fmt.Printf("Loaded cache from .cache/versions (%d items)\n", versionCache.ItemCount()) +} + +// SaveCache saves the cache to the .cache folder +func SaveCache() { + versionCache.DeleteExpired() + finfo, _ := os.Stat(".cache") + var err error + if finfo == nil { + err = os.Mkdir(".cache", 0755) + if err != nil { + fmt.Printf("Failed to create cache directory: %+v\n", err.(*os.PathError)) + return + } + } + + finfo, _ = os.Stat(".cache/versions") + var f *os.File + if finfo == nil { + f, err = os.Create(".cache/versions") + if err != nil { + fmt.Printf("Failed to create cache file: %+v\n", err.(*os.PathError)) + return + } + } else { + f, err = os.OpenFile(".cache/versions", os.O_TRUNC|os.O_WRONLY, 0644) + if err != nil { + fmt.Printf("Failed to create cache file: %+v\n", err.(*os.PathError)) + return + } + } + defer f.Close() + + err = gob.NewEncoder(f).Encode(versionCache.Items()) + if err != nil { + fmt.Printf("Failed to save cache: %+v\n", err) + return + } + fmt.Printf("Saved cache to .cache/versions (%d items)\n", versionCache.ItemCount()) +} diff --git a/examples/with_cache/README.md b/examples/with_cache/README.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/with_cache/main.go b/examples/with_cache/main.go new file mode 100644 index 0000000..6e3f50d --- /dev/null +++ b/examples/with_cache/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "time" + + "github.com/Kesuaheli/go-manifest" +) + +func main() { + // make sure the cache will be saved as files on exit + defer manifest.SaveCache() + + for range make([]int, 5) { + now := time.Now() + _, err := manifest.GetVersion("1.7.10") + if err != nil { + panic(err) + } + fmt.Printf("Got version in %s\n", time.Since(now)) + time.Sleep(2 * time.Second) + } +} diff --git a/go.mod b/go.mod index ce1bdfa..68dc68b 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/Kesuaheli/go-manifest go 1.23.1 + +require github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..33c1ec4 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= diff --git a/go_manifest.go b/go_manifest.go index 04615bf..3f28c19 100644 --- a/go_manifest.go +++ b/go_manifest.go @@ -42,6 +42,10 @@ func GetManifest() (manifest *Manifest, err error) { // // v can be any version id like "1.7.10" or "24w10a" or even "a1.0.4". func GetVersion(v string) (version *Version, err error) { + if cachedVersion, ok := versionCache.Get(v); ok { + return cachedVersion.(*Version), nil + } + manifest, err := GetManifest() if err != nil { return &Version{}, fmt.Errorf("get version: %w", err) @@ -61,6 +65,8 @@ func GetVersion(v string) (version *Version, err error) { if err != nil { err = fmt.Errorf("get version: failed to decode body: %w", err) } + + versionCache.SetDefault(v, version) return version, err }