package data import ( "os" "maps" "errors" "encoding/json" ) type FileDatastore struct { /* A very simple datastructure, implementing the IDatastore interface. It * uses a simple text file to the data as json. */ path string } func NewFileDatastore(path string) (*FileDatastore, error) { /* Creates a new FileDatastore object, creating the storage file in the * process. */ fds := &FileDatastore{ path: path } if _, err := fds.readMapObj(); err != nil { if err := fds.writeMapObj(make(map[string]string)); err != nil { return nil, err } } return fds, nil } func (fds *FileDatastore) readMapObj() (map[string]string, error) { /* Read the contents of the storage file and convert to a map object. May * throw an error, if the file does not exit or the file content can not be * converted. */ dat, err := os.ReadFile(fds.path) if err != nil { return nil, err } var mapobj map[string]string err = json.Unmarshal(dat, &mapobj) if err != nil { return nil, err } return mapobj, nil } func (fds *FileDatastore) writeMapObj(m map[string]string) error { /* Write the map object to the storage file. Will overwrite the content of * the file. May throw an error, if the file cannot be created or written * to. */ file, err := os.Create(fds.path) if err != nil { return err } defer file.Close() encoder := json.NewEncoder(file) if err := encoder.Encode(m); err != nil { return err } return nil } // --- implement IDatastore interface --- func (fds *FileDatastore) Set(key string, val string) error { /* Sets the key value pair given, overwriting if the key already exists. * May through an error if the file cannot be opened or the contents cannot * be decoded correctly. */ m, err := fds.readMapObj() if err != nil { return err } m[key] = val err = fds.writeMapObj(m) if err != nil { return err } return nil } func (fds *FileDatastore) KeyExists(key string) (bool, error) { /* Check if for the given key a entry does exit. May through an error if * the file cannot be opened or the contents cannot be decoded correctly. */ m, err := fds.readMapObj() if err != nil { return false, err } _, ok := m[key] return ok, nil } func (fds *FileDatastore) Get(key string) (string, error) { /* Gets the value for the given key. May through an error if the key does * not exit, the file cannot be opened or the contents cannot be decoded * correctly. */ m, err := fds.readMapObj() if err != nil { return "", err } val, ok := m[key] if !ok { return "", errors.New("key not found") } return val, nil } func (fds *FileDatastore) GetAll() (map[string]string, error) { /* Gets all the key value pairs from the file and returns them as a map * object. May through an error if the file cannot be opened or the contents * cannot be decoded correctly. */ return fds.readMapObj() } func (fds *FileDatastore) GetAllKeys() (map[string]bool, error) { /* Gets all the key the file and returns them as a map object. May through * an error if the file cannot be opened or the contents cannot be decoded * correctly. */ m, err := fds.readMapObj() if err != nil { return nil, err } out := make(map[string]bool) for key := range maps.Keys(m) { out[key] = true } return out, nil }