refactor: storage 要求 Load 等函数返回错误信息
This commit is contained in:
parent
7c5edb8bef
commit
0d1a985e69
|
@ -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`。
|
||||||
|
|
|
@ -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 保存数据
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 保存数据
|
||||||
|
|
|
@ -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 保存所有数据
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 将数据保存到文件中
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue