1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
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)
}
|