summaryrefslogtreecommitdiff
path: root/server/data.go
diff options
context:
space:
mode:
authorraven <citrons@mondecitronne.com>2026-03-20 14:29:52 -0500
committerraven <citrons@mondecitronne.com>2026-03-20 14:29:52 -0500
commitc3d63652a4b80add587ee17f5c9f3773417203ad (patch)
treee26e1d36f912f1bca210e1aaa3e314668d0b010b /server/data.go
initial commit
Diffstat (limited to 'server/data.go')
-rw-r--r--server/data.go87
1 files changed, 87 insertions, 0 deletions
diff --git a/server/data.go b/server/data.go
new file mode 100644
index 0000000..b7ed280
--- /dev/null
+++ b/server/data.go
@@ -0,0 +1,87 @@
+package server
+
+import (
+ "os"
+ "encoding/binary"
+ "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() {
+ 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 + ".bin")
+ if err != nil {
+ dataManager.errHand.OnSaveError(from, err)
+ return
+ }
+ defer f.Close()
+ err = binary.Write(f, binary.BigEndian, 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() {
+ f, err := os.Open("world/" + name + ".bin")
+ if err != nil {
+ if !os.IsNotExist(err) {
+ dataManager.errHand.OnLoadError(&dataManager, err)
+ }
+ return
+ }
+ defer f.Close()
+ var data T
+ err = binary.Read(f, binary.BigEndian, &data)
+ if err != nil {
+ dataManager.errHand.OnLoadError(&dataManager, err)
+ }
+ from.Act(nil, func() {reply(data, err == nil)})
+ })
+}
+