mirror of https://gitee.com/godoos/godoos.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
2.6 KiB
144 lines
2.6 KiB
package cache
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// fileCache 文件缓存实现
|
|
type fileCache struct {
|
|
mu sync.RWMutex
|
|
dir string
|
|
}
|
|
|
|
// NewFileCache 创建文件缓存实例
|
|
func NewFileCache(dir string) *fileCache {
|
|
return &fileCache{
|
|
dir: dir,
|
|
}
|
|
}
|
|
|
|
func (c *fileCache) Set(key string, value interface{}, ttl time.Duration) error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
if err := os.MkdirAll(c.dir, 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 强制将 Value 转换为 []byte
|
|
var data []byte
|
|
switch v := value.(type) {
|
|
case string:
|
|
data = []byte(v)
|
|
case []byte:
|
|
data = v
|
|
default:
|
|
var err error
|
|
data, err = json.Marshal(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
item := struct {
|
|
Data []byte `json:"data"`
|
|
ExpiresAt time.Time `json:"expires_at"`
|
|
}{
|
|
Data: data,
|
|
ExpiresAt: time.Now().Add(ttl),
|
|
}
|
|
|
|
encoded, err := json.Marshal(item)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
filePath := filepath.Join(c.dir, key)
|
|
return os.WriteFile(filePath, encoded, 0644)
|
|
}
|
|
|
|
type FileCacheItem struct {
|
|
Data []byte `json:"data"`
|
|
ExpiresAt time.Time `json:"expires_at"`
|
|
}
|
|
|
|
func (c *fileCache) Get(key string) (interface{}, error) {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
filePath := filepath.Join(c.dir, key)
|
|
data, err := os.ReadFile(filePath)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, ErrCacheMiss
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
var item FileCacheItem
|
|
if err := json.Unmarshal(data, &item); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if item.ExpiresAt.Before(time.Now()) {
|
|
_ = os.Remove(filePath)
|
|
return nil, ErrCacheExpired
|
|
}
|
|
|
|
return item.Data, nil
|
|
}
|
|
func (c *fileCache) GetKey(key string, clientId string) (interface{}, error) {
|
|
return c.Get(key + ":" + clientId)
|
|
}
|
|
func (c *fileCache) Delete(key string) error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
filePath := filepath.Join(c.dir, key)
|
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
return os.Remove(filePath)
|
|
}
|
|
|
|
func (c *fileCache) Clear() error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
entries, err := os.ReadDir(c.dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
_ = os.Remove(filepath.Join(c.dir, entry.Name()))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *fileCache) Exists(key string) (bool, error) {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
filePath := filepath.Join(c.dir, key)
|
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
return false, nil
|
|
}
|
|
|
|
// 检查是否过期
|
|
val, err := c.Get(key)
|
|
if err == ErrCacheExpired {
|
|
return false, nil
|
|
}
|
|
return val != nil, err
|
|
}
|
|
|
|
// PathExists 检查路径是否存在
|
|
func PathExists(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return !os.IsNotExist(err)
|
|
}
|
|
|