speicher/map.go
2025-02-13 04:58:27 +00:00

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
}