refactor: storage interface
This commit is contained in:
@@ -1,26 +0,0 @@
|
|||||||
package storage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Name of the file under the storage's root where [model.State] is stored.
|
|
||||||
stateFileName = "state.dat"
|
|
||||||
|
|
||||||
// Suffix of a Game's file inder the storage's root where [model.GameData] is stored.
|
|
||||||
gameDataFileSuffix = ".dat"
|
|
||||||
)
|
|
||||||
|
|
||||||
// StateFilePath returns client's state file path relative to the root,
|
|
||||||
// file name and extension are pre-defined constant.
|
|
||||||
func StateFilePath(root string) string {
|
|
||||||
return filepath.Join(root, stateFileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GameDataPath returns game's data file path relative to the root,
|
|
||||||
// data file name is GameID string representation and extension is a pre-defined constant.
|
|
||||||
func GameDataFilePath(root string, id fmt.Stringer) string {
|
|
||||||
return filepath.Join(root, id.String()) + gameDataFileSuffix
|
|
||||||
}
|
|
||||||
+57
-12
@@ -1,30 +1,75 @@
|
|||||||
// fs implements galaxy/storage.Storage with filesystem
|
// fs implements galaxy/storage.Storage with filesystem
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Общие правила:
|
||||||
|
|
||||||
|
1. Все хранимые объекты сериализуются / десериализуются как JSON.
|
||||||
|
|
||||||
|
2. Структура хранения файлов:
|
||||||
|
|
||||||
|
- storageRoot \
|
||||||
|
|
|
||||||
|
+-- state.dat
|
||||||
|
|
|
||||||
|
+-- {GameID} \
|
||||||
|
| |
|
||||||
|
| +-- {Turn}.dat (client.GameData)
|
||||||
|
| +-- {Turn}.dat (client.GameData)
|
||||||
|
| +-- ...
|
||||||
|
|
|
||||||
|
+-- {GameID} \
|
||||||
|
|
|
||||||
|
+-- ...
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"galaxy/util"
|
"galaxy/util"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fsStorage struct {
|
const (
|
||||||
path string
|
// Name of the file under the storage's root where [model.State] is stored.
|
||||||
|
stateFileName = "state.dat"
|
||||||
|
|
||||||
|
// Suffix of a Game's file inder the storage's root where [model.GameData] is stored.
|
||||||
|
gameDataFileSuffix = ".dat"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StateFilePath returns client's state file path relative to the root,
|
||||||
|
// file name and extension are pre-defined constant.
|
||||||
|
func StateFilePath(root string) string {
|
||||||
|
return filepath.Join(root, stateFileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFS returns on-filesystem implementation of the "galaxy/storage.Storage" with root located at rootPath.
|
// GameDataPath returns game's data file path relative to the root,
|
||||||
// rootPath must me a directory and has write access to the current user. If initial checks failed, return nil and non-nil error.
|
// data file name is GameID string representation and extension is a pre-defined constant.
|
||||||
func NewStorage(path string) (*fsStorage, error) {
|
func GameDataFilePath(root string, id fmt.Stringer) string {
|
||||||
if ok, err := util.PathExists(path, true); err != nil {
|
return filepath.Join(root, id.String()) + gameDataFileSuffix
|
||||||
return nil, fmt.Errorf("new storage: check path %q exists: %w", path, err)
|
}
|
||||||
|
|
||||||
|
type fsStorage struct {
|
||||||
|
storageRoot string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFS returns on-filesystem implementation of the "galaxy/storage.Storage" with root located at storageRoot.
|
||||||
|
// storageRoot must me a directory and has write access to the current user. If initial checks failed, return nil and non-nil error.
|
||||||
|
func NewStorage(storageRoot string) (*fsStorage, error) {
|
||||||
|
if ok, err := util.PathExists(storageRoot, true); err != nil {
|
||||||
|
return nil, fmt.Errorf("new storage: check path %q exists: %w", storageRoot, err)
|
||||||
} else if !ok {
|
} else if !ok {
|
||||||
return nil, fmt.Errorf("new storage: path %q does not exists", path)
|
return nil, fmt.Errorf("new storage: path %q does not exists", storageRoot)
|
||||||
}
|
}
|
||||||
if ok, err := util.Writable(path); err != nil {
|
if ok, err := util.Writable(storageRoot); err != nil {
|
||||||
return nil, fmt.Errorf("new storage: check path %q writable: %w", path, err)
|
return nil, fmt.Errorf("new storage: check path %q writable: %w", storageRoot, err)
|
||||||
} else if !ok {
|
} else if !ok {
|
||||||
return nil, fmt.Errorf("new storage: path %q is not writable", path)
|
return nil, fmt.Errorf("new storage: path %q is not writable", storageRoot)
|
||||||
}
|
}
|
||||||
s := &fsStorage{
|
s := &fsStorage{
|
||||||
path: path,
|
storageRoot: storageRoot,
|
||||||
}
|
}
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,16 +37,16 @@ type UIStorage interface {
|
|||||||
// otherwise callback func accepts loaded [report.Report].
|
// otherwise callback func accepts loaded [report.Report].
|
||||||
LoadReport(client.GameID, uint, func(report.Report, error))
|
LoadReport(client.GameID, uint, func(report.Report, error))
|
||||||
|
|
||||||
// PutReport stores given [report.Report] for a given [model.GameID] and turn number at the filesystem asynchronously.
|
// SaveReport stores given [report.Report] for a given [model.GameID] and turn number at the filesystem asynchronously.
|
||||||
// I/O or encoding error may occur, it that case callback func will be called with non-nil error.
|
// I/O or encoding error may occur, it that case callback func will be called with non-nil error.
|
||||||
PutReport(client.GameID, uint, report.Report, func(error))
|
SaveReport(client.GameID, uint, report.Report, func(error))
|
||||||
|
|
||||||
// LoadOrder loads a [order.Order] for a given [model.GameID] and turn number from filesystem asynchronously.
|
// LoadOrder loads a [order.Order] for a given [model.GameID] and turn number from filesystem asynchronously.
|
||||||
// Passed callback func will will accept non-nil error in case of I/O or decoding errors occuried,
|
// Passed callback func will will accept non-nil error in case of I/O or decoding errors occuried,
|
||||||
// otherwise callback func accepts loaded [order.Order].
|
// otherwise callback func accepts loaded [order.Order].
|
||||||
LoadOrder(client.GameID, uint, func(order.Order, error))
|
LoadOrder(client.GameID, uint, func(order.Order, error))
|
||||||
|
|
||||||
// PutOrder stores given [order.Order] for a given [model.GameID] and turn number at the filesystem asynchronously.
|
// SaveOrder stores given [order.Order] for a given [model.GameID] and turn number at the filesystem asynchronously.
|
||||||
// I/O or encoding error may occur, it that case callback func will be called with non-nil error.
|
// I/O or encoding error may occur, it that case callback func will be called with non-nil error.
|
||||||
PutOrder(client.GameID, uint, order.Order, func(error))
|
SaveOrder(client.GameID, uint, order.Order, func(error))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user