refactor: storage 要求 Load 等函数返回错误信息

This commit is contained in:
kercylan98 2023-07-20 09:50:35 +08:00
parent 7c5edb8bef
commit 0d1a985e69
10 changed files with 59 additions and 68 deletions

View File

@ -13,12 +13,12 @@ mindmap
root((Minotaur)) root((Minotaur))
/component 通用组件接口定义 /component 通用组件接口定义
/components 通用组件内置实现 /components 通用组件内置实现
/config 针对配置导表的配置加载 /configuration 配置管理功能
/game 游戏通用功能接口定义 /game 游戏通用功能接口定义
/builtin 游戏通用功能内置实现 /builtin 游戏通用功能内置实现
/notify 通知功能接口定义 /notify 通知功能接口定义
/planner 策划相关工具目录 /planner 策划相关工具目录
/configexport 配置导表功能实现 /pce 配置导表功能实现
/report 数据埋点及上报功能 /report 数据埋点及上报功能
/server 网络服务器支持 /server 网络服务器支持
/cross 内置跨服功能实现 /cross 内置跨服功能实现
@ -113,7 +113,6 @@ func main() {
``` ```
其他的一些支持事件的结构体(非所有): 其他的一些支持事件的结构体(非所有):
- `game.Room` 游戏房间实现 - `game.Room` 游戏房间实现
- `synchronization.Map` 并发安全的`Map`实现
- ... - ...
### 可选项 ### 可选项
大部分的 `New` 函数均可使用可选项进行创建,具体函数前缀通常为 `With` 大部分的 `New` 函数均可使用可选项进行创建,具体函数前缀通常为 `With`

View File

@ -1,14 +1,17 @@
package storage package storage
// NewGlobalData 创建全局数据 // NewGlobalData 创建全局数据
func NewGlobalData[T any](name string, storage GlobalDataStorage[T]) *GlobalData[T] { func NewGlobalData[T any](name string, storage GlobalDataStorage[T]) (*GlobalData[T], error) {
data := &GlobalData[T]{ data := &GlobalData[T]{
storage: storage, storage: storage,
name: name, name: name,
data: storage.Load(name),
} }
globalDataSaveHandles = append(globalDataSaveHandles, data.SaveData) var err error
return data data.data, err = storage.Load(name)
if err != nil {
return nil, err
}
return data, nil
} }
// GlobalData 全局数据 // GlobalData 全局数据
@ -29,8 +32,13 @@ func (slf *GlobalData[T]) GetData() T {
} }
// LoadData 加载数据 // LoadData 加载数据
func (slf *GlobalData[T]) LoadData() { func (slf *GlobalData[T]) LoadData() error {
slf.data = slf.storage.Load(slf.GetName()) data, err := slf.storage.Load(slf.GetName())
if err != nil {
return err
}
slf.data = data
return nil
} }
// SaveData 保存数据 // SaveData 保存数据

View File

@ -4,7 +4,7 @@ package storage
type GlobalDataStorage[T any] interface { type GlobalDataStorage[T any] interface {
// Load 加载全局数据 // Load 加载全局数据
// - 当全局数据不存在时,应当返回新的全局数据实例 // - 当全局数据不存在时,应当返回新的全局数据实例
Load(name string) T Load(name string) (T, error)
// Save 保存全局数据 // Save 保存全局数据
Save(name string, data T) error Save(name string, data T) error
} }

View File

@ -6,13 +6,17 @@ import (
) )
// NewIndexData 创建索引数据 // NewIndexData 创建索引数据
func NewIndexData[I generic.Ordered, T IndexDataItem[I]](name string, storage IndexDataStorage[I, T]) *IndexData[I, T] { func NewIndexData[I generic.Ordered, T IndexDataItem[I]](name string, storage IndexDataStorage[I, T]) (*IndexData[I, T], error) {
data := &IndexData[I, T]{ data := &IndexData[I, T]{
storage: storage, storage: storage,
name: name, name: name,
data: storage.LoadAll(name),
} }
return data var err error
data.data, err = storage.LoadAll(name)
if err != nil {
return nil, err
}
return data, nil
} }
// IndexData 全局数据 // IndexData 全局数据
@ -29,11 +33,7 @@ func (slf *IndexData[I, T]) GetName() string {
// GetData 获取数据 // GetData 获取数据
func (slf *IndexData[I, T]) GetData(index I) T { func (slf *IndexData[I, T]) GetData(index I) T {
data, exist := slf.data[index] data, _ := slf.data[index]
if !exist {
slf.LoadData(index)
data = slf.data[index]
}
return data return data
} }
@ -43,13 +43,23 @@ func (slf *IndexData[I, T]) GetAllData() map[I]T {
} }
// LoadData 加载数据 // LoadData 加载数据
func (slf *IndexData[I, T]) LoadData(index I) { func (slf *IndexData[I, T]) LoadData(index I) error {
slf.data[index] = slf.storage.Load(slf.GetName(), index) data, err := slf.storage.Load(slf.GetName(), index)
if err != nil {
return err
}
slf.data[index] = data
return nil
} }
// LoadAllData 加载所有数据 // LoadAllData 加载所有数据
func (slf *IndexData[I, T]) LoadAllData() { func (slf *IndexData[I, T]) LoadAllData() error {
slf.data = slf.storage.LoadAll(slf.GetName()) data, err := slf.storage.LoadAll(slf.GetName())
if err != nil {
return err
}
slf.data = data
return nil
} }
// SaveData 保存数据 // SaveData 保存数据

View File

@ -9,9 +9,9 @@ import (
type IndexDataStorage[I generic.Ordered, T IndexDataItem[I]] interface { type IndexDataStorage[I generic.Ordered, T IndexDataItem[I]] interface {
// Load 加载特定索引数据 // Load 加载特定索引数据
// - 通常情况下当数据不存在时,应当返回空指针 // - 通常情况下当数据不存在时,应当返回空指针
Load(name string, index I) T Load(name string, index I) (T, error)
// LoadAll 加载所有数据 // LoadAll 加载所有数据
LoadAll(name string) map[I]T LoadAll(name string) (map[I]T, error)
// Save 保存特定索引数据 // Save 保存特定索引数据
Save(name string, index I, data T) error Save(name string, index I, data T) error
// SaveAll 保存所有数据 // SaveAll 保存所有数据

View File

@ -1,26 +0,0 @@
package storage
import "time"
var (
// globalDataSaveHandles 全局数据保存句柄
globalDataSaveHandles []func() error
)
// SaveAll 保存所有数据
// - errorHandle 错误处理中如果返回 false 将重试,否则跳过当前保存下一个
func SaveAll(errorHandle func(err error) bool, retryInterval time.Duration) {
var err error
for _, handle := range globalDataSaveHandles {
for {
if err = handle(); err != nil {
if !errorHandle(err) {
time.Sleep(retryInterval)
continue
}
break
}
break
}
}
}

View File

@ -43,14 +43,13 @@ type GlobalDataFileStorage[T any] struct {
} }
// Load 从文件中加载数据,如果文件不存在则使用 generate 生成数据 // Load 从文件中加载数据,如果文件不存在则使用 generate 生成数据
func (slf *GlobalDataFileStorage[T]) Load(name string) T { func (slf *GlobalDataFileStorage[T]) Load(name string) (T, error) {
bytes, err := file.ReadOnce(filepath.Join(slf.dir, fmt.Sprintf("%s.%s", name, slf.suffix))) bytes, err := file.ReadOnce(filepath.Join(slf.dir, fmt.Sprintf("%s.%s", name, slf.suffix)))
if err != nil { if err != nil {
return slf.generate(name) return slf.generate(name), nil
} }
var data = slf.generate(name) var data = slf.generate(name)
_ = slf.decoder(bytes, data) return data, slf.decoder(bytes, data)
return data
} }
// Save 将数据保存到文件中 // Save 将数据保存到文件中

View File

@ -15,28 +15,28 @@ type GlobalData struct {
func TestGlobalDataFileStorage_Save(t *testing.T) { func TestGlobalDataFileStorage_Save(t *testing.T) {
Convey("TestGlobalDataFileStorage_Save", t, func() { Convey("TestGlobalDataFileStorage_Save", t, func() {
data := storage.NewGlobalData[*GlobalData]("global_data_file_test", storages.NewGlobalDataFileStorage[*GlobalData]("./example-data", func(name string) *GlobalData { data, err := storage.NewGlobalData[*GlobalData]("global_data_file_test", storages.NewGlobalDataFileStorage[*GlobalData]("./example-data", func(name string) *GlobalData {
return &GlobalData{ return &GlobalData{
CreateAt: time.Now(), CreateAt: time.Now(),
} }
})) }))
So(err, ShouldBeNil)
data.Handle(func(name string, data *GlobalData) { data.Handle(func(name string, data *GlobalData) {
data.TotalCount = 10 data.TotalCount = 10
}) })
if err := data.SaveData(); err != nil { So(data.SaveData(), ShouldBeNil)
t.Fatal(err)
}
So(data.GetData().TotalCount, ShouldEqual, 10) So(data.GetData().TotalCount, ShouldEqual, 10)
}) })
} }
func TestGlobalDataFileStorage_Load(t *testing.T) { func TestGlobalDataFileStorage_Load(t *testing.T) {
Convey("TestGlobalDataFileStorage_Load", t, func() { Convey("TestGlobalDataFileStorage_Load", t, func() {
data := storage.NewGlobalData[*GlobalData]("global_data_file_test", storages.NewGlobalDataFileStorage[*GlobalData]("./example-data", func(name string) *GlobalData { data, err := storage.NewGlobalData[*GlobalData]("global_data_file_test", storages.NewGlobalDataFileStorage[*GlobalData]("./example-data", func(name string) *GlobalData {
return &GlobalData{ return &GlobalData{
CreateAt: time.Now(), CreateAt: time.Now(),
} }
})) }))
So(err, ShouldBeNil)
So(data.GetData().TotalCount, ShouldEqual, 10) So(data.GetData().TotalCount, ShouldEqual, 10)
}) })
} }

View File

@ -44,21 +44,20 @@ type IndexDataFileStorage[I generic.Ordered, T storage.IndexDataItem[I]] struct
decoder FileStorageDecoder[T] decoder FileStorageDecoder[T]
} }
func (slf *IndexDataFileStorage[I, T]) Load(name string, index I) T { func (slf *IndexDataFileStorage[I, T]) Load(name string, index I) (T, error) {
bytes, err := file.ReadOnce(filepath.Join(slf.dir, fmt.Sprintf(indexNameFormat, name, index, slf.suffix))) bytes, err := file.ReadOnce(filepath.Join(slf.dir, fmt.Sprintf(indexNameFormat, name, index, slf.suffix)))
if err != nil { if err != nil {
return slf.generate(name, index) return slf.generate(name, index), nil
} }
var data = slf.generate(name, index) var data = slf.generate(name, index)
_ = slf.decoder(bytes, data) return data, slf.decoder(bytes, data)
return data
} }
func (slf *IndexDataFileStorage[I, T]) LoadAll(name string) map[I]T { func (slf *IndexDataFileStorage[I, T]) LoadAll(name string) (map[I]T, error) {
var result = make(map[I]T) var result = make(map[I]T)
files, err := os.ReadDir(slf.dir) files, err := os.ReadDir(slf.dir)
if err != nil { if err != nil {
return result return result, err
} }
for _, entry := range files { for _, entry := range files {
if entry.IsDir() || !strings.HasPrefix(entry.Name(), name) || !strings.HasSuffix(entry.Name(), slf.suffix) { if entry.IsDir() || !strings.HasPrefix(entry.Name(), name) || !strings.HasSuffix(entry.Name(), slf.suffix) {
@ -73,7 +72,7 @@ func (slf *IndexDataFileStorage[I, T]) LoadAll(name string) map[I]T {
result[data.GetIndex()] = data result[data.GetIndex()] = data
} }
} }
return result return result, err
} }
func (slf *IndexDataFileStorage[I, T]) Save(name string, index I, data T) error { func (slf *IndexDataFileStorage[I, T]) Save(name string, index I, data T) error {

View File

@ -18,11 +18,12 @@ func (slf *IndexData[I]) GetIndex() I {
func TestIndexDataFileStorage_Save(t *testing.T) { func TestIndexDataFileStorage_Save(t *testing.T) {
Convey("TestIndexDataFileStorage_Save", t, func() { Convey("TestIndexDataFileStorage_Save", t, func() {
data := storage.NewIndexData[string, *IndexData[string]]("index_data_file_test", storages.NewIndexDataFileStorage[string, *IndexData[string]]("./example-data", func(name string, index string) *IndexData[string] { data, err := storage.NewIndexData[string, *IndexData[string]]("index_data_file_test", storages.NewIndexDataFileStorage[string, *IndexData[string]]("./example-data", func(name string, index string) *IndexData[string] {
return &IndexData[string]{ID: index} return &IndexData[string]{ID: index}
}, func(name string) *IndexData[string] { }, func(name string) *IndexData[string] {
return new(IndexData[string]) return new(IndexData[string])
})) }))
So(err, ShouldBeNil)
data.Handle("INDEX_001", func(name string, index string, data *IndexData[string]) { data.Handle("INDEX_001", func(name string, index string, data *IndexData[string]) {
data.Value = 10 data.Value = 10
}) })
@ -35,11 +36,12 @@ func TestIndexDataFileStorage_Save(t *testing.T) {
func TestIndexDataFileStorage_Load(t *testing.T) { func TestIndexDataFileStorage_Load(t *testing.T) {
Convey("TestIndexDataFileStorage_Load", t, func() { Convey("TestIndexDataFileStorage_Load", t, func() {
data := storage.NewIndexData[string, *IndexData[string]]("index_data_file_test", storages.NewIndexDataFileStorage[string, *IndexData[string]]("./example-data", func(name string, index string) *IndexData[string] { data, err := storage.NewIndexData[string, *IndexData[string]]("index_data_file_test", storages.NewIndexDataFileStorage[string, *IndexData[string]]("./example-data", func(name string, index string) *IndexData[string] {
return &IndexData[string]{ID: index} return &IndexData[string]{ID: index}
}, func(name string) *IndexData[string] { }, func(name string) *IndexData[string] {
return new(IndexData[string]) return new(IndexData[string])
})) }))
So(err, ShouldBeNil)
So(data.GetData("INDEX_001").Value, ShouldEqual, 10) So(data.GetData("INDEX_001").Value, ShouldEqual, 10)
}) })
} }