diff options
| author | GrailFinder <wohilas@gmail.com> | 2024-04-28 07:03:36 +0300 | 
|---|---|---|
| committer | GrailFinder <wohilas@gmail.com> | 2024-04-28 07:03:36 +0300 | 
| commit | 8d66ec58e2256412a2fd50ad9e651c09af1ea8cc (patch) | |
| tree | 23ad5c78ba2b2da32628e9004fe932e6fa63e26b /pkg | |
| parent | b33be53ea9c0be523988a9412fd8e3f6a24782b3 (diff) | |
Feat: auth middleware; login [wip]
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/cache/interface.go | 9 | ||||
| -rw-r--r-- | pkg/cache/main.go | 146 | 
2 files changed, 155 insertions, 0 deletions
| diff --git a/pkg/cache/interface.go b/pkg/cache/interface.go new file mode 100644 index 0000000..606f50f --- /dev/null +++ b/pkg/cache/interface.go @@ -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) +} diff --git a/pkg/cache/main.go b/pkg/cache/main.go new file mode 100644 index 0000000..d617f49 --- /dev/null +++ b/pkg/cache/main.go @@ -0,0 +1,146 @@ +package cache + +import ( +	"encoding/json" +	"fmt" +	"io/ioutil" +	"log/slog" +	"os" +	"sync" +	"time" +) + +const storeFileName = "store.json" + +// var MemCache Cache +var ( +	MemCache *MemoryCache +	log      = slog.New(slog.NewJSONHandler(os.Stdout, nil)) +) + +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 { +		log.Warn("failed to load store from file", "error", err) +	} +	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) +					log.Info("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 { +				log.Warn("failed to marshal kv store", "error", err) +				continue +			} +			err = ioutil.WriteFile(storeFileName, jsonString, os.ModePerm) +			if err != nil { +				log.Warn("failed to write to json file", "error", err) +				continue +			} +		} +	}() +} | 
