forked from xiaonanln/goworld
/
filesystem.go
121 lines (101 loc) · 3.22 KB
/
filesystem.go
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
111
112
113
114
115
116
117
118
119
120
121
package entitystoragefilesystem
import (
"path/filepath"
"io/ioutil"
"encoding/json"
"encoding/base64"
"os"
"strings"
"github.com/xiaonanln/goworld/engine/common"
"github.com/xiaonanln/goworld/engine/consts"
"github.com/xiaonanln/goworld/engine/gwlog"
"github.com/xiaonanln/goworld/engine/storage/storage_common"
)
// FileSystemEntityStorage is an implementation of Entity Storage using filesystem
type FileSystemEntityStorage struct {
directory string
}
func getFileName(name string, entityID common.EntityID) string {
return name + "$" + base64.URLEncoding.EncodeToString([]byte(entityID))
}
func (es *FileSystemEntityStorage) getFilePath(typeName string, entityID common.EntityID) string {
return filepath.Join(es.directory, getFileName(typeName, entityID))
}
// Write writes entity data to entity storage
func (es *FileSystemEntityStorage) Write(typeName string, entityID common.EntityID, data interface{}) error {
stringSaveFile := es.getFilePath(typeName, entityID)
dataBytes, err := json.MarshalIndent(data, "", "\t")
if err != nil {
return err
}
if consts.DEBUG_SAVE_LOAD {
gwlog.Debugf("Saving to file %s: %s", stringSaveFile, string(dataBytes))
}
return ioutil.WriteFile(stringSaveFile, dataBytes, 0644)
}
// Read reads entity data from entity storage
func (es *FileSystemEntityStorage) Read(typeName string, entityID common.EntityID) (interface{}, error) {
stringSaveFile := es.getFilePath(typeName, entityID)
dataBytes, err := ioutil.ReadFile(stringSaveFile)
if err != nil {
if os.IsNotExist(err) {
// file not exist
return nil, nil
}
return nil, err
}
var data interface{}
err = json.Unmarshal(dataBytes, &data)
if err != nil {
return nil, err
}
return data, nil
}
// Exists checks if entity is in entity storage
func (es *FileSystemEntityStorage) Exists(typeName string, entityID common.EntityID) (exists bool, err error) {
stringSaveFile := es.getFilePath(typeName, entityID)
_, err = os.Stat(stringSaveFile)
exists = err == nil || os.IsExist(err)
return
}
// List retrives all entity IDs in entity storage of specified type
func (es *FileSystemEntityStorage) List(typeName string) ([]common.EntityID, error) {
prefix := typeName + "$"
pat := filepath.Join(es.directory, prefix+"*")
files, err := filepath.Glob(pat)
if err != nil {
return nil, err
}
res := make([]common.EntityID, 0, len(files))
prefixLen := len(prefix)
for _, fpath := range files {
_, fn := filepath.Split(fpath)
if !strings.HasPrefix(fn, prefix) {
gwlog.Errorf("invalid file: %s", fpath)
}
idbytes, err := base64.URLEncoding.DecodeString(fn[prefixLen:])
if err != nil {
gwlog.TraceError("fail to parse file %s", fpath)
continue
}
res = append(res, common.MustEntityID(string(idbytes)))
}
return res, nil
}
// Close the entity storage
func (es *FileSystemEntityStorage) Close() {
// need to do nothing
}
// IsEOF check if the error is an EOF error
func (es *FileSystemEntityStorage) IsEOF(err error) bool {
return false
}
// OpenDirectory opens the directory as filesystem entity storage
func OpenDirectory(directory string) (storagecommon.EntityStorage, error) {
if err := os.MkdirAll(directory, 0755); err != nil {
return nil, err
}
return &FileSystemEntityStorage{
directory: directory,
}, nil
}