initial import

This commit is contained in:
kevin
2020-07-26 17:09:05 +08:00
commit 7e3a369a8f
647 changed files with 54754 additions and 0 deletions

40
core/conf/config.go Normal file
View File

@@ -0,0 +1,40 @@
package conf
import (
"fmt"
"io/ioutil"
"log"
"path"
"zero/core/mapping"
)
var loaders = map[string]func([]byte, interface{}) error{
".json": LoadConfigFromJsonBytes,
".yaml": LoadConfigFromYamlBytes,
".yml": LoadConfigFromYamlBytes,
}
func LoadConfig(file string, v interface{}) error {
if content, err := ioutil.ReadFile(file); err != nil {
return err
} else if loader, ok := loaders[path.Ext(file)]; ok {
return loader(content, v)
} else {
return fmt.Errorf("unrecoginized file type: %s", file)
}
}
func LoadConfigFromJsonBytes(content []byte, v interface{}) error {
return mapping.UnmarshalJsonBytes(content, v)
}
func LoadConfigFromYamlBytes(content []byte, v interface{}) error {
return mapping.UnmarshalYamlBytes(content, v)
}
func MustLoad(path string, v interface{}) {
if err := LoadConfig(path, v); err != nil {
log.Fatalf("error: config file %s, %s", path, err.Error())
}
}

109
core/conf/properties.go Normal file
View File

@@ -0,0 +1,109 @@
package conf
import (
"fmt"
"strconv"
"strings"
"sync"
"zero/core/iox"
)
// PropertyError represents a configuration error message.
type PropertyError struct {
error
message string
}
// Properties interface provides the means to access configuration.
type Properties interface {
GetString(key string) string
SetString(key, value string)
GetInt(key string) int
SetInt(key string, value int)
ToString() string
}
// Properties config is a key/value pair based configuration structure.
type mapBasedProperties struct {
properties map[string]string
lock sync.RWMutex
}
// Loads the properties into a properties configuration instance. May return the
// configuration itself along with an error that indicates if there was a problem loading the configuration.
func LoadProperties(filename string) (Properties, error) {
lines, err := iox.ReadTextLines(filename, iox.WithoutBlank(), iox.OmitWithPrefix("#"))
if err != nil {
return nil, nil
}
raw := make(map[string]string)
for i := range lines {
pair := strings.Split(lines[i], "=")
if len(pair) != 2 {
// invalid property format
return nil, &PropertyError{
message: fmt.Sprintf("invalid property format: %s", pair),
}
}
key := strings.TrimSpace(pair[0])
value := strings.TrimSpace(pair[1])
raw[key] = value
}
return &mapBasedProperties{
properties: raw,
}, nil
}
func (config *mapBasedProperties) GetString(key string) string {
config.lock.RLock()
ret := config.properties[key]
config.lock.RUnlock()
return ret
}
func (config *mapBasedProperties) SetString(key, value string) {
config.lock.Lock()
config.properties[key] = value
config.lock.Unlock()
}
func (config *mapBasedProperties) GetInt(key string) int {
config.lock.RLock()
// default 0
value, _ := strconv.Atoi(config.properties[key])
config.lock.RUnlock()
return value
}
func (config *mapBasedProperties) SetInt(key string, value int) {
config.lock.Lock()
config.properties[key] = strconv.Itoa(value)
config.lock.Unlock()
}
// Dumps the configuration internal map into a string.
func (config *mapBasedProperties) ToString() string {
config.lock.RLock()
ret := fmt.Sprintf("%s", config.properties)
config.lock.RUnlock()
return ret
}
// Returns the error message.
func (configError *PropertyError) Error() string {
return configError.message
}
// Builds a new properties configuration structure
func NewProperties() Properties {
return &mapBasedProperties{
properties: make(map[string]string),
}
}

View File

@@ -0,0 +1,44 @@
package conf
import (
"os"
"testing"
"zero/core/fs"
"github.com/stretchr/testify/assert"
)
func TestProperties(t *testing.T) {
text := `app.name = test
app.program=app
# this is comment
app.threads = 5`
tmpfile, err := fs.TempFilenameWithText(text)
assert.Nil(t, err)
defer os.Remove(tmpfile)
props, err := LoadProperties(tmpfile)
assert.Nil(t, err)
assert.Equal(t, "test", props.GetString("app.name"))
assert.Equal(t, "app", props.GetString("app.program"))
assert.Equal(t, 5, props.GetInt("app.threads"))
}
func TestSetString(t *testing.T) {
key := "a"
value := "the value of a"
props := NewProperties()
props.SetString(key, value)
assert.Equal(t, value, props.GetString(key))
}
func TestSetInt(t *testing.T) {
key := "a"
value := 101
props := NewProperties()
props.SetInt(key, value)
assert.Equal(t, value, props.GetInt(key))
}