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 }