From 5cdbbd22966ee62a315acb4bc686f2791ca982f8 Mon Sep 17 00:00:00 2001 From: "Felipe M." Date: Sun, 23 Mar 2025 20:59:57 +0100 Subject: [PATCH 1/2] feat: cache --- cache/file.go | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ cache/memory.go | 53 ++++++++++++++++++++++++++++++++++ model/cache.go | 18 ++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 cache/file.go create mode 100644 cache/memory.go create mode 100644 model/cache.go diff --git a/cache/file.go b/cache/file.go new file mode 100644 index 0000000..23a87ae --- /dev/null +++ b/cache/file.go @@ -0,0 +1,77 @@ +package cache + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "time" + + "git.nakama.town/fmartingr/gotoolkit/model" +) + +var _ model.Cache = (*FileCache)(nil) + +type FileCache struct { + path string +} + +func (c *FileCache) Get(key string) (result any, err error) { + path := filepath.Join(c.path, key) + + contents, err := os.ReadFile(path) + if err != nil { + if errors.Is(err, os.ErrNotExist) || errors.Is(err, os.ErrPermission) { + return result, model.ErrCacheKeyDontExist + } + return + } + + return contents, nil +} + +func (c *FileCache) GetWithExpiry(key string, expiration time.Duration) (result any, err error) { + path := filepath.Join(c.path, key) + info, err := os.Stat(path) + if err != nil { + return result, model.ErrCacheKeyDontExist + } + + if info.ModTime().Add(expiration).Before(time.Now()) { + c.Delete(key) + return result, model.ErrCacheKeyDontExist + } + + return c.Get(key) +} + +func (c *FileCache) Set(key string, value any) error { + path := filepath.Join(c.path, key) + + if err := os.WriteFile(path, value.([]byte), 0766); err != nil { + return fmt.Errorf("error writting cache file: %s", err) + } + + return nil +} + +func (c *FileCache) Delete(key string) error { + path := filepath.Join(c.path, key) + return os.Remove(path) +} + +func NewFileCache(folderName string) (*FileCache, error) { + userCacheDir, err := os.UserCacheDir() + if err != nil { + return nil, fmt.Errorf("Could not retrieve user cache directory: %w", err) + } + path := filepath.Join(userCacheDir, folderName) + + if err := os.MkdirAll(path, 0755); err != nil { + return nil, fmt.Errorf("couldn't create cache directory: %w", err) + } + + return &FileCache{ + path: path, + }, nil +} diff --git a/cache/memory.go b/cache/memory.go new file mode 100644 index 0000000..94b7482 --- /dev/null +++ b/cache/memory.go @@ -0,0 +1,53 @@ +package cache + +import ( + "sync" + "time" + + "git.nakama.town/fmartingr/gotoolkit/model" +) + +var _ model.Cache = (*MemoryCache)(nil) + +type MemoryCache struct { + data map[string]any + dataMu sync.RWMutex +} + +func (c *MemoryCache) Get(key string) (result any, err error) { + c.dataMu.RLock() + defer c.dataMu.RUnlock() + + result, exists := c.data[key] + if !exists { + return result, model.ErrCacheKeyDontExist + } + + return +} + +func (c *MemoryCache) GetWithExpiry(key string, expiration time.Duration) (any, error) { + // TODO: Implement expiration in memory cache. + return c.Get(key) +} + +func (c *MemoryCache) Set(key string, value any) error { + c.dataMu.Lock() + c.data[key] = value + c.dataMu.Unlock() + + return nil +} + +func (c *MemoryCache) Delete(key string) error { + c.dataMu.Lock() + delete(c.data, key) + c.dataMu.Unlock() + return nil +} + +func NewMemoryCache() *MemoryCache { + return &MemoryCache{ + data: make(map[string]any), + } +} diff --git a/model/cache.go b/model/cache.go new file mode 100644 index 0000000..a241f73 --- /dev/null +++ b/model/cache.go @@ -0,0 +1,18 @@ +package model + +import ( + "errors" +) + +var ErrCacheKeyDontExist = errors.New("cache key don't exist") + +type Cache interface { + Get(key string) (any, error) + GetWithOptions(key string, opts ...CacheGetOption) + Set(key string, value any) error + SetWithOptions(key string, value any, opts ...CacheSetOption) + Delete(key string) error +} + +type CacheGetOption func() +type CacheSetOption func() From 92732f9682ac5022710df1d1f03cf23141ec8482 Mon Sep 17 00:00:00 2001 From: "Felipe M." Date: Sun, 23 Mar 2025 21:00:03 +0100 Subject: [PATCH 2/2] feat: paths --- paths/user.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 paths/user.go diff --git a/paths/user.go b/paths/user.go new file mode 100644 index 0000000..0810c9d --- /dev/null +++ b/paths/user.go @@ -0,0 +1,20 @@ +package paths + +import ( + "os/user" + "path/filepath" + "strings" +) + +func ExpandUser(providedPath string) string { + var path string = providedPath + usr, _ := user.Current() + dir := usr.HomeDir + + if providedPath == "~" { + path = dir + } else if strings.HasPrefix(providedPath, "~/") { + path = filepath.Join(dir, providedPath[2:]) + } + return path +}