go-ayo/common을 gocommon으로 분리
This commit is contained in:
22
document/document.go
Normal file
22
document/document.go
Normal file
@ -0,0 +1,22 @@
|
||||
package document
|
||||
|
||||
import "errors"
|
||||
|
||||
// Document interface
|
||||
type Document interface {
|
||||
ReadBool(path string) (bool, error)
|
||||
ReadString(path string) (string, error)
|
||||
Read(path string) (interface{}, error)
|
||||
|
||||
Write(path string, val interface{})
|
||||
Serialize() error
|
||||
}
|
||||
|
||||
// ErrDocumentNotExist : 문서가 존재하지 않을 때
|
||||
var ErrDocumentNotExist = errors.New("document does not exist")
|
||||
|
||||
// ErrDocumentPathNotExist : 문서의 경로가 존재하지 않을 때
|
||||
var ErrDocumentPathNotExist = errors.New("given document path does not exist")
|
||||
|
||||
// ErrDocumentPathTypeMismatch : 해당 경로의 값 타입이 다름
|
||||
var ErrDocumentPathTypeMismatch = errors.New("given document path has different value of type")
|
||||
179
document/document_filebase.go
Normal file
179
document/document_filebase.go
Normal file
@ -0,0 +1,179 @@
|
||||
package document
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getDocumentFilepath(owner string) string {
|
||||
return fmt.Sprintf("./docs/%s.json", owner)
|
||||
}
|
||||
|
||||
type fileDocument struct {
|
||||
owner string
|
||||
root map[string]interface{}
|
||||
dirty bool
|
||||
}
|
||||
|
||||
// LoadFileDocument : 파일로 도큐먼트 로딩
|
||||
func LoadFileDocument(owner string) (Document, error) {
|
||||
bt, err := os.ReadFile(getDocumentFilepath(owner))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(bt) == 0 {
|
||||
return &fileDocument{
|
||||
owner: owner,
|
||||
root: make(map[string]interface{}),
|
||||
dirty: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var doc map[string]interface{}
|
||||
err = json.Unmarshal(bt, &doc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &fileDocument{
|
||||
owner: owner,
|
||||
root: doc,
|
||||
dirty: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func findNodeInterface(doc map[string]interface{}, path string) (interface{}, error) {
|
||||
if doc == nil {
|
||||
return nil, ErrDocumentNotExist
|
||||
}
|
||||
|
||||
parent := doc
|
||||
for {
|
||||
idx := strings.IndexRune(path, '/')
|
||||
var nodename string
|
||||
if idx < 0 {
|
||||
nodename = path
|
||||
path = ""
|
||||
} else {
|
||||
nodename = path[:idx]
|
||||
path = path[idx+1:]
|
||||
}
|
||||
child, ok := parent[nodename]
|
||||
|
||||
if !ok {
|
||||
return nil, ErrDocumentPathNotExist
|
||||
}
|
||||
|
||||
if len(path) == 0 {
|
||||
return child, nil
|
||||
}
|
||||
|
||||
if parent, ok = child.(map[string]interface{}); !ok {
|
||||
return nil, ErrDocumentPathTypeMismatch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findEdgeContainer(doc map[string]interface{}, path string) (map[string]interface{}, string) {
|
||||
parent := doc
|
||||
for {
|
||||
idx := strings.IndexRune(path, '/')
|
||||
var nodename string
|
||||
if idx < 0 {
|
||||
nodename = path
|
||||
path = ""
|
||||
} else {
|
||||
nodename = path[:idx]
|
||||
path = path[idx+1:]
|
||||
}
|
||||
|
||||
if len(path) == 0 {
|
||||
return parent, nodename
|
||||
}
|
||||
|
||||
child, ok := parent[nodename]
|
||||
if !ok {
|
||||
child = make(map[string]interface{})
|
||||
parent[nodename] = child
|
||||
}
|
||||
|
||||
parent = child.(map[string]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
// ReadBool :
|
||||
func (doc *fileDocument) ReadBool(path string) (bool, error) {
|
||||
val, err := findNodeInterface(doc.root, path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
out, ok := val.(bool)
|
||||
if !ok {
|
||||
return false, ErrDocumentPathTypeMismatch
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ReadString :
|
||||
func (doc *fileDocument) ReadString(path string) (string, error) {
|
||||
val, err := findNodeInterface(doc.root, path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
out, ok := val.(string)
|
||||
if !ok {
|
||||
return "", ErrDocumentPathTypeMismatch
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Read :
|
||||
func (doc *fileDocument) Read(path string) (interface{}, error) {
|
||||
return findNodeInterface(doc.root, path)
|
||||
}
|
||||
|
||||
// WriteBool :
|
||||
func (doc *fileDocument) Write(path string, val interface{}) {
|
||||
container, edge := findEdgeContainer(doc.root, path)
|
||||
container[edge] = val
|
||||
doc.dirty = true
|
||||
}
|
||||
|
||||
// Serialize :
|
||||
func (doc *fileDocument) Serialize() error {
|
||||
if !doc.dirty {
|
||||
return nil
|
||||
}
|
||||
|
||||
bt, err := json.Marshal(doc.root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filepath := getDocumentFilepath(doc.owner)
|
||||
if err := os.WriteFile(filepath, bt, 0644); err != nil {
|
||||
if _, patherr := err.(*os.PathError); !patherr {
|
||||
return err
|
||||
}
|
||||
|
||||
dir := path.Dir(filepath)
|
||||
if err = os.MkdirAll(dir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.WriteFile(filepath, bt, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
doc.dirty = false
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user