120 lines
2.3 KiB
Go
120 lines
2.3 KiB
Go
package speicher
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
type (
|
|
MemoryMap[T any] struct {
|
|
data map[string]T
|
|
location string
|
|
mut sync.RWMutex
|
|
}
|
|
|
|
Map[T any] interface {
|
|
Get(key string) (T, bool)
|
|
Has(key string) bool
|
|
Set(key string, value T)
|
|
RangeKV() <-chan MapRangeEl[T]
|
|
RangeV() <-chan T
|
|
Save() error
|
|
Lock()
|
|
Unlock()
|
|
RLock()
|
|
RUnlock()
|
|
}
|
|
|
|
MapRangeEl[T any] struct {
|
|
Key string
|
|
Value T
|
|
}
|
|
)
|
|
|
|
func (m *MemoryMap[T]) Get(key string) (value T, found bool) {
|
|
value, found = m.data[key]
|
|
return
|
|
}
|
|
|
|
func (m *MemoryMap[T]) Has(key string) bool {
|
|
_, ok := m.data[key]
|
|
return ok
|
|
}
|
|
|
|
func (m *MemoryMap[T]) Set(key string, value T) {
|
|
m.data[key] = value
|
|
}
|
|
|
|
func (m *MemoryMap[T]) RangeKV() <-chan MapRangeEl[T] {
|
|
ch := make(chan MapRangeEl[T])
|
|
go func() {
|
|
defer close(ch)
|
|
for key, value := range m.data {
|
|
ch <- MapRangeEl[T]{Key: key, Value: value}
|
|
}
|
|
}()
|
|
return ch
|
|
}
|
|
|
|
func (m *MemoryMap[T]) RangeV() <-chan T {
|
|
ch := make(chan T)
|
|
go func() {
|
|
defer close(ch)
|
|
for _, value := range m.data {
|
|
ch <- value
|
|
}
|
|
}()
|
|
return ch
|
|
}
|
|
|
|
func (m *MemoryMap[T]) Lock() {
|
|
m.mut.Lock()
|
|
}
|
|
func (m *MemoryMap[T]) Unlock() {
|
|
m.mut.Unlock()
|
|
_ = m.Save()
|
|
}
|
|
|
|
func (m *MemoryMap[T]) RLock() {
|
|
m.mut.RLock()
|
|
}
|
|
func (m *MemoryMap[T]) RUnlock() {
|
|
m.mut.RUnlock()
|
|
}
|
|
|
|
func (m *MemoryMap[T]) Save() error {
|
|
f, err := os.OpenFile(m.location, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
|
if err != nil {
|
|
return errors.Join(fmt.Errorf("failed to open file %s", m.location), err)
|
|
}
|
|
encoder := json.NewEncoder(f)
|
|
if err := encoder.Encode(m.data); err != nil {
|
|
return errors.Join(fmt.Errorf("failed to encode json file %s", m.location), err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func LoadMap[T any](location string) (Map[T], error) {
|
|
if strings.HasSuffix(location, ".json") {
|
|
return loadMapFromJsonFile[T](location)
|
|
}
|
|
return nil, fmt.Errorf("unable to find loader for %s", location)
|
|
}
|
|
|
|
func loadMapFromJsonFile[T any](location string) (Map[T], error) {
|
|
f, err := os.OpenFile(location, os.O_RDONLY, 0644)
|
|
if err != nil {
|
|
return nil, errors.Join(fmt.Errorf("failed to open file %s", location), err)
|
|
}
|
|
decoder := json.NewDecoder(f)
|
|
m := &MemoryMap[T]{}
|
|
if err := decoder.Decode(&m.data); err != nil {
|
|
return nil, errors.Join(fmt.Errorf("failed to decode json file %s", location), err)
|
|
}
|
|
return m, nil
|
|
}
|