Files
go-cart-actor/disk-storage.go
matst80 ae421674d2 stuffs
2024-11-07 22:57:18 +01:00

125 lines
2.4 KiB
Go

package main
import (
"encoding/gob"
"encoding/json"
"errors"
"fmt"
"log"
"os"
"time"
)
type DiskStorage struct {
stateFile string
lastSave int64
LastSaves map[string]int64
}
func NewDiskStorage(stateFile string) (*DiskStorage, error) {
ret := &DiskStorage{
stateFile: stateFile,
LastSaves: make(map[string]int64),
}
err := ret.loadState()
return ret, err
}
func saveMessages(messages []Message, id string) error {
log.Printf("%d messages to save for %s", len(messages), id)
if len(messages) == 0 {
return nil
}
var file *os.File
var err error
path := getCartPath(id)
file, err = os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
// z := gzip.NewWriter(file)
// defer z.Close()
enc := gob.NewEncoder(file)
for _, m := range messages {
err = enc.Encode(m)
}
return err
}
func getCartPath(id string) string {
return fmt.Sprintf("data/%s.gob", id)
}
func loadMessages(grain Grain, id string) error {
var err error
path := getCartPath(id)
if _, err = os.Stat(path); errors.Is(err, os.ErrNotExist) {
return err
}
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
// z, err := gzip.NewReader(file)
// if err != nil {
// return err
// }
// defer z.Close()
var reply CartGrain
decoder := gob.NewDecoder(file)
for err == nil {
var message Message
err = decoder.Decode(&message)
if err != nil {
grain.HandleMessage(&message, true, &reply)
}
}
if err.Error() == "EOF" {
return nil
}
return err
}
func (s *DiskStorage) saveState() error {
tmpFile := s.stateFile + "_tmp"
file, err := os.Create(tmpFile)
if err != nil {
return err
}
defer file.Close()
err = json.NewEncoder(file).Encode(s.LastSaves)
if err != nil {
return err
}
os.Remove(s.stateFile + ".bak")
os.Rename(s.stateFile, s.stateFile+".bak")
return os.Rename(tmpFile, s.stateFile)
}
func (s *DiskStorage) loadState() error {
file, err := os.Open("data/state.json")
if err != nil {
return err
}
defer file.Close()
return json.NewDecoder(file).Decode(&s.LastSaves)
}
func (s *DiskStorage) Store(id string, grain Grain) error {
lastSavedMessage, ok := s.LastSaves[id]
if ok && lastSavedMessage > grain.GetLastChange() {
return nil
}
err := saveMessages(grain.GetStorageMessage(lastSavedMessage), id)
if err != nil {
return err
}
ts := time.Now().Unix()
s.LastSaves[id] = ts
s.lastSave = ts
return nil
}