Feat: add models/cache/config
This commit is contained in:
144
pkg/cache/impl.go
vendored
Normal file
144
pkg/cache/impl.go
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const storeFileName = "store.json"
|
||||
|
||||
// var MemCache Cache
|
||||
var (
|
||||
MemCache *MemoryCache
|
||||
)
|
||||
|
||||
func readJSON(fileName string) (map[string][]byte, error) {
|
||||
data := make(map[string][]byte)
|
||||
file, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
defer file.Close()
|
||||
decoder := json.NewDecoder(file)
|
||||
if err := decoder.Decode(&data); err != nil {
|
||||
return data, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
data, err := readJSON(storeFileName)
|
||||
if err != nil {
|
||||
slog.Error("failed to load store from file")
|
||||
}
|
||||
MemCache = &MemoryCache{
|
||||
data: data,
|
||||
timeMap: make(map[string]time.Time),
|
||||
lock: &sync.RWMutex{},
|
||||
}
|
||||
MemCache.StartExpiryRoutine(time.Minute)
|
||||
MemCache.StartBackupRoutine(time.Minute)
|
||||
}
|
||||
|
||||
type MemoryCache struct {
|
||||
data map[string][]byte
|
||||
timeMap map[string]time.Time
|
||||
lock *sync.RWMutex
|
||||
}
|
||||
|
||||
// Get a value by key from the cache
|
||||
func (mc *MemoryCache) Get(key string) (value []byte, err error) {
|
||||
var ok bool
|
||||
mc.lock.RLock()
|
||||
if value, ok = mc.data[key]; !ok {
|
||||
err = fmt.Errorf("not found data in mc for the key: %v", key)
|
||||
}
|
||||
mc.lock.RUnlock()
|
||||
return value, err
|
||||
}
|
||||
|
||||
// Update a single value in the cache
|
||||
func (mc *MemoryCache) Set(key string, value []byte) {
|
||||
// no async writing
|
||||
mc.lock.Lock()
|
||||
mc.data[key] = value
|
||||
mc.lock.Unlock()
|
||||
}
|
||||
|
||||
func (mc *MemoryCache) Expire(key string, exp int64) {
|
||||
mc.lock.RLock()
|
||||
mc.timeMap[key] = time.Now().Add(time.Duration(exp) * time.Second)
|
||||
mc.lock.RUnlock()
|
||||
}
|
||||
|
||||
func (mc *MemoryCache) GetAll() (resp map[string][]byte) {
|
||||
resp = make(map[string][]byte)
|
||||
mc.lock.RLock()
|
||||
for k, v := range mc.data {
|
||||
resp[k] = v
|
||||
}
|
||||
mc.lock.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (mc *MemoryCache) GetAllTime() (resp map[string]time.Time) {
|
||||
resp = make(map[string]time.Time)
|
||||
mc.lock.RLock()
|
||||
for k, v := range mc.timeMap {
|
||||
resp[k] = v
|
||||
}
|
||||
mc.lock.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (mc *MemoryCache) RemoveKey(key string) {
|
||||
mc.lock.RLock()
|
||||
delete(mc.data, key)
|
||||
delete(mc.timeMap, key)
|
||||
mc.lock.RUnlock()
|
||||
}
|
||||
|
||||
func (mc *MemoryCache) StartExpiryRoutine(n time.Duration) {
|
||||
ticker := time.NewTicker(n)
|
||||
go func() {
|
||||
for {
|
||||
<-ticker.C
|
||||
// get all
|
||||
timeData := mc.GetAllTime()
|
||||
// check time
|
||||
currentTS := time.Now()
|
||||
for k, ts := range timeData {
|
||||
if ts.Before(currentTS) {
|
||||
// delete exp keys
|
||||
mc.RemoveKey(k)
|
||||
slog.Debug("remove by expiry", "key", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (mc *MemoryCache) StartBackupRoutine(n time.Duration) {
|
||||
ticker := time.NewTicker(n)
|
||||
go func() {
|
||||
for {
|
||||
<-ticker.C
|
||||
// get all
|
||||
data := mc.GetAll()
|
||||
jsonString, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
slog.Warn("failed to marshal", "err", err)
|
||||
continue
|
||||
}
|
||||
err = os.WriteFile(storeFileName, jsonString, os.ModePerm)
|
||||
if err != nil {
|
||||
slog.Warn("failed to write", "err", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
9
pkg/cache/main.go
vendored
Normal file
9
pkg/cache/main.go
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package cache
|
||||
|
||||
type Cache interface {
|
||||
Get(key string) ([]byte, error)
|
||||
Set(key string, value []byte)
|
||||
Expire(key string, exp int64)
|
||||
GetAll() (resp map[string][]byte)
|
||||
RemoveKey(key string)
|
||||
}
|
Reference in New Issue
Block a user