120 lines
2.2 KiB
Go
120 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/gob"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
type DiskStorage struct {
|
|
stateFile string
|
|
lastSave int64
|
|
LastSaves map[CartId]int64
|
|
}
|
|
|
|
func NewDiskStorage(stateFile string) (*DiskStorage, error) {
|
|
ret := &DiskStorage{
|
|
stateFile: stateFile,
|
|
LastSaves: make(map[CartId]int64),
|
|
}
|
|
err := ret.loadState()
|
|
return ret, err
|
|
}
|
|
|
|
func saveMessages(messages []StorableMessage, id CartId) error {
|
|
|
|
if len(messages) == 0 {
|
|
return nil
|
|
}
|
|
log.Printf("%d messages to save for grain id %s", len(messages), id)
|
|
var file *os.File
|
|
var err error
|
|
path := getCartPath(id.String())
|
|
file, err = os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
for _, m := range messages {
|
|
err := m.Write(file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func getCartPath(id string) string {
|
|
return fmt.Sprintf("data/%s.prot", id)
|
|
}
|
|
|
|
func loadMessages(grain Grain, id CartId) error {
|
|
var err error
|
|
path := getCartPath(id.String())
|
|
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
for err == nil {
|
|
var msg Message
|
|
err = ReadMessage(file, &msg)
|
|
if err == nil {
|
|
grain.HandleMessage(&msg, true)
|
|
}
|
|
}
|
|
|
|
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 = gob.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(s.stateFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
return gob.NewDecoder(file).Decode(&s.LastSaves)
|
|
}
|
|
|
|
func (s *DiskStorage) Store(id CartId, grain *CartGrain) 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
|
|
}
|