package server import ( "os" "bufio" "encoding/json" "git.citrons.xyz/metronode/phony" ) var dataManager struct { phony.Inbox errHand interface { OnSaveError(from phony.Actor, err error) OnLoadError(from phony.Actor, err error) } } type atomicWriter struct { from phony.Actor name string tmpFile *os.File } func createAtomic(from phony.Actor, name string) (atomicWriter, error) { os.Mkdir("world", 0777) f, err := os.CreateTemp("world", "*.tmp") if err != nil { dataManager.errHand.OnSaveError(from, err) return atomicWriter {}, err } return atomicWriter {from, name, f}, nil } func (f atomicWriter) Write(b []byte) (n int, err error) { return f.tmpFile.Write(b) } func (f atomicWriter) Close() error { if f.tmpFile == nil { return nil } dataManager.Act(f.from, func() { f.tmpFile.Sync() err := f.tmpFile.Close() if err != nil { dataManager.errHand.OnSaveError(&dataManager, err) return } err = os.Rename(f.tmpFile.Name(), f.name) if err != nil { dataManager.errHand.OnSaveError(&dataManager, err) } }) return nil } func saveDataFile[T any](from phony.Actor, name string, data T) { f, err := createAtomic(from, "world/" + name + ".json") if err != nil { dataManager.errHand.OnSaveError(from, err) return } defer f.Close() enc := json.NewEncoder(f) err = enc.Encode(data) if err != nil { dataManager.errHand.OnSaveError(from, err) } } func loadDataFile[T any]( from phony.Actor, name string, reply func(data T, ok bool)) { dataManager.Act(from, func() { var ( data T f *os.File err error ) defer from.Act(nil, func() {reply(data, err == nil)}) f, err = os.Open("world/" + name + ".json") if err != nil { if !os.IsNotExist(err) { dataManager.errHand.OnLoadError(&dataManager, err) } return } defer f.Close() dec := json.NewDecoder(f) err = dec.Decode(&data) if err != nil { dataManager.errHand.OnLoadError(&dataManager, err) return } }) } func readDataField(rd *bufio.Reader, data any) error { line, err := rd.ReadBytes('\n') if err != nil { return err } return json.Unmarshal(line, data) } func writeDataField(wr *bufio.Writer, data any) error { enc := json.NewEncoder(wr) return enc.Encode(data) }