discord-community/metastore.go
2021-08-22 15:23:23 +02:00

102 lines
1.9 KiB
Go

package main
import (
"encoding/json"
"os"
"sync"
"github.com/pkg/errors"
)
type metaStore struct {
ModuleAttributes map[string]moduleAttributeStore `json:"module_attributes"`
filename string
lock sync.RWMutex
}
func newMetaStoreFromDisk(filename string) (*metaStore, error) {
out := &metaStore{
ModuleAttributes: map[string]moduleAttributeStore{},
filename: filename,
}
s, err := os.Stat(filename)
switch {
case err == nil:
// This is fine
case os.IsNotExist(err):
// No store yet, return empty store
return out, nil
default:
return nil, errors.Wrap(err, "getting file stats for store")
}
if s.IsDir() {
// A directory was provided
return nil, errors.New("store location is directory")
}
if s.Size() == 0 {
// An empty file was created, we don't care and will overwrite on save
return out, nil
}
f, err := os.Open(filename)
if err != nil {
return nil, errors.Wrap(err, "opening store")
}
defer f.Close()
return out, errors.Wrap(
json.NewDecoder(f).Decode(out),
"decoding store",
)
}
func (m *metaStore) Save() error {
m.lock.RLock()
defer m.lock.RUnlock()
return m.save()
}
func (m *metaStore) save() error {
f, err := os.Create(m.filename)
if err != nil {
return errors.Wrap(err, "creating storage file")
}
defer f.Close()
return errors.Wrap(
json.NewEncoder(f).Encode(m),
"encoding storage file",
)
}
func (m *metaStore) Set(moduleID, key string, value interface{}) error {
m.lock.Lock()
defer m.lock.Unlock()
if m.ModuleAttributes[moduleID] == nil {
m.ModuleAttributes[moduleID] = make(moduleAttributeStore)
}
m.ModuleAttributes[moduleID][key] = value
return errors.Wrap(m.save(), "saving store")
}
func (m *metaStore) ReadWithLock(moduleID string, fn func(m moduleAttributeStore) error) error {
m.lock.RLock()
defer m.lock.RUnlock()
if m.ModuleAttributes[moduleID] == nil {
return fn(moduleAttributeStore{})
}
return fn(m.ModuleAttributes[moduleID])
}