非test文件 恢复 原样

This commit is contained in:
piaohao 2019-06-13 12:41:20 +08:00
parent d305d25935
commit 80cf3e833b
3 changed files with 708 additions and 715 deletions

View File

@ -17,17 +17,17 @@ import (
)
const (
// Separator char for hierarchical data access.
gDEFAULT_SPLIT_CHAR = '.'
// Separator char for hierarchical data access.
gDEFAULT_SPLIT_CHAR = '.'
)
// The customized JSON struct.
type Json struct {
mu *rwmutex.RWMutex
p *interface{} // Pointer for hierarchical data access, it's the root of data in default.
c byte // Char separator('.' in default).
vc bool // Violence Check(false in default), which is used to access data
// when the hierarchical data key contains separator char.
mu *rwmutex.RWMutex
p *interface{} // Pointer for hierarchical data access, it's the root of data in default.
c byte // Char separator('.' in default).
vc bool // Violence Check(false in default), which is used to access data
// when the hierarchical data key contains separator char.
}
// Set <value> by <pattern>.
@ -35,306 +35,300 @@ type Json struct {
// 1. If value is nil and removed is true, means deleting this value;
// 2. It's quite complicated in hierarchical data search, node creating and data assignment;
func (j *Json) setValue(pattern string, value interface{}, removed bool) error {
array := strings.Split(pattern, string(j.c))
length := len(array)
value = j.convertValue(value)
// 初始化判断
if *j.p == nil {
if gstr.IsNumeric(array[0]) {
*j.p = make([]interface{}, 0)
} else {
*j.p = make(map[string]interface{})
}
}
var pparent *interface{} = nil // 父级元素项(设置时需要根据子级的内容确定数据类型,所以必须记录父级)
var pointer *interface{} = j.p // 当前操作层级项
j.mu.Lock()
defer j.mu.Unlock()
for i := 0; i < length; i++ {
switch (*pointer).(type) {
case map[string]interface{}:
if i == length-1 {
if removed && value == nil {
// 删除map元素
delete((*pointer).(map[string]interface{}), array[i])
} else {
(*pointer).(map[string]interface{})[array[i]] = value
}
} else {
// 当键名不存在的情况这里会进行处理
if v, ok := (*pointer).(map[string]interface{})[array[i]]; !ok {
if removed && value == nil {
goto done
}
// 创建新节点
if gstr.IsNumeric(array[i+1]) {
// 创建array节点
n, _ := strconv.Atoi(array[i+1])
var v interface{} = make([]interface{}, n+1)
pparent = j.setPointerWithValue(pointer, array[i], v)
pointer = &v
} else {
// 创建map节点
var v interface{} = make(map[string]interface{})
pparent = j.setPointerWithValue(pointer, array[i], v)
pointer = &v
}
} else {
pparent = pointer
pointer = &v
}
}
array := strings.Split(pattern, string(j.c))
length := len(array)
value = j.convertValue(value)
// 初始化判断
if *j.p == nil {
if gstr.IsNumeric(array[0]) {
*j.p = make([]interface{}, 0)
} else {
*j.p = make(map[string]interface{})
}
}
var pparent *interface{} = nil // 父级元素项(设置时需要根据子级的内容确定数据类型,所以必须记录父级)
var pointer *interface{} = j.p // 当前操作层级项
j.mu.Lock()
defer j.mu.Unlock()
for i:= 0; i < length; i++ {
switch (*pointer).(type) {
case map[string]interface{}:
if i == length - 1 {
if removed && value == nil {
// 删除map元素
delete((*pointer).(map[string]interface{}), array[i])
} else {
(*pointer).(map[string]interface{})[array[i]] = value
}
} else {
// 当键名不存在的情况这里会进行处理
if v, ok := (*pointer).(map[string]interface{})[array[i]]; !ok {
if removed && value == nil {
goto done
}
// 创建新节点
if gstr.IsNumeric(array[i + 1]) {
// 创建array节点
n, _ := strconv.Atoi(array[i + 1])
var v interface{} = make([]interface{}, n + 1)
pparent = j.setPointerWithValue(pointer, array[i], v)
pointer = &v
} else {
// 创建map节点
var v interface{} = make(map[string]interface{})
pparent = j.setPointerWithValue(pointer, array[i], v)
pointer = &v
}
} else {
pparent = pointer
pointer = &v
}
}
case []interface{}:
// 键名与当前指针类型不符合,需要执行**覆盖操作**
if !gstr.IsNumeric(array[i]) {
if i == length-1 {
*pointer = map[string]interface{}{array[i]: value}
} else {
var v interface{} = make(map[string]interface{})
*pointer = v
pparent = pointer
pointer = &v
}
continue
}
case []interface{}:
// 键名与当前指针类型不符合,需要执行**覆盖操作**
if !gstr.IsNumeric(array[i]) {
if i == length - 1 {
*pointer = map[string]interface{}{ array[i] : value }
} else {
var v interface{} = make(map[string]interface{})
*pointer = v
pparent = pointer
pointer = &v
}
continue
}
valn, err := strconv.Atoi(array[i])
if err != nil {
return err
}
// 叶子节点
if i == length-1 {
if len((*pointer).([]interface{})) > valn {
if removed && value == nil {
// 删除数据元素
j.setPointerWithValue(pparent, array[i-1], append((*pointer).([]interface{})[:valn], (*pointer).([]interface{})[valn+1:]...))
} else {
(*pointer).([]interface{})[valn] = value
}
} else {
if removed && value == nil {
goto done
}
if pparent == nil {
// 表示根节点
j.setPointerWithValue(pointer, array[i], value)
} else {
// 非根节点
s := make([]interface{}, valn+1)
copy(s, (*pointer).([]interface{}))
s[valn] = value
j.setPointerWithValue(pparent, array[i-1], s)
}
}
} else {
if gstr.IsNumeric(array[i+1]) {
n, _ := strconv.Atoi(array[i+1])
if len((*pointer).([]interface{})) > valn {
(*pointer).([]interface{})[valn] = make([]interface{}, n+1)
pparent = pointer
pointer = &(*pointer).([]interface{})[valn]
} else {
if removed && value == nil {
goto done
}
var v interface{} = make([]interface{}, n+1)
pparent = j.setPointerWithValue(pointer, array[i], v)
pointer = &v
}
} else {
var v interface{} = make(map[string]interface{})
pparent = j.setPointerWithValue(pointer, array[i], v)
pointer = &v
}
}
valn, err := strconv.Atoi(array[i])
if err != nil {
return err
}
// 叶子节点
if i == length - 1 {
if len((*pointer).([]interface{})) > valn {
if removed && value == nil {
// 删除数据元素
j.setPointerWithValue(pparent, array[i - 1], append((*pointer).([]interface{})[ : valn], (*pointer).([]interface{})[valn + 1 : ]...))
} else {
(*pointer).([]interface{})[valn] = value
}
} else {
if removed && value == nil {
goto done
}
if pparent == nil {
// 表示根节点
j.setPointerWithValue(pointer, array[i], value)
} else {
// 非根节点
s := make([]interface{}, valn + 1)
copy(s, (*pointer).([]interface{}))
s[valn] = value
j.setPointerWithValue(pparent, array[i - 1], s)
}
}
} else {
if gstr.IsNumeric(array[i + 1]) {
n, _ := strconv.Atoi(array[i + 1])
if len((*pointer).([]interface{})) > valn {
(*pointer).([]interface{})[valn] = make([]interface{}, n + 1)
pparent = pointer
pointer = &(*pointer).([]interface{})[valn]
} else {
if removed && value == nil {
goto done
}
var v interface{} = make([]interface{}, n + 1)
pparent = j.setPointerWithValue(pointer, array[i], v)
pointer = &v
}
} else {
var v interface{} = make(map[string]interface{})
pparent = j.setPointerWithValue(pointer, array[i], v)
pointer = &v
}
}
// 如果当前指针指向的变量不是引用类型的,
// 那么修改变量必须通过父级进行修改,即 pparent
default:
if removed && value == nil {
goto done
}
if gstr.IsNumeric(array[i]) {
n, _ := strconv.Atoi(array[i])
s := make([]interface{}, n+1)
if i == length-1 {
s[n] = value
}
if pparent != nil {
pparent = j.setPointerWithValue(pparent, array[i-1], s)
} else {
*pointer = s
pparent = pointer
}
} else {
var v interface{} = make(map[string]interface{})
if i == length-1 {
v = map[string]interface{}{
array[i]: value,
}
}
if pparent != nil {
pparent = j.setPointerWithValue(pparent, array[i-1], v)
} else {
*pointer = v
pparent = pointer
}
pointer = &v
}
}
}
// 如果当前指针指向的变量不是引用类型的,
// 那么修改变量必须通过父级进行修改,即 pparent
default:
if removed && value == nil {
goto done
}
if gstr.IsNumeric(array[i]) {
n, _ := strconv.Atoi(array[i])
s := make([]interface{}, n + 1)
if i == length - 1 {
s[n] = value
}
if pparent != nil {
pparent = j.setPointerWithValue(pparent, array[i - 1], s)
} else {
*pointer = s
pparent = pointer
}
} else {
var v interface{} = make(map[string]interface{})
if i == length - 1 {
v = map[string]interface{}{
array[i] : value,
}
}
if pparent != nil {
pparent = j.setPointerWithValue(pparent, array[i - 1], v)
} else {
*pointer = v
pparent = pointer
}
pointer = &v
}
}
}
done:
return nil
return nil
}
// Convert <value> to map[string]interface{} or []interface{},
// which can be supported for hierarchical data access.
func (j *Json) convertValue(value interface{}) interface{} {
switch value.(type) {
case map[string]interface{}:
return value
case []interface{}:
return value
default:
rv := reflect.ValueOf(value)
kind := rv.Kind()
if kind == reflect.Ptr {
rv = rv.Elem()
kind = rv.Kind()
}
switch kind {
case reflect.Array:
return gconv.Interfaces(value)
case reflect.Slice:
return gconv.Interfaces(value)
case reflect.Map:
return gconv.Map(value)
case reflect.Struct:
return gconv.Map(value)
default:
// Use json decode/encode at last.
b, _ := Encode(value)
v, _ := Decode(b)
return v
}
}
switch value.(type) {
case map[string]interface{}:
return value
case []interface{}:
return value
default:
rv := reflect.ValueOf(value)
kind := rv.Kind()
if kind == reflect.Ptr {
rv = rv.Elem()
kind = rv.Kind()
}
switch kind {
case reflect.Array: return gconv.Interfaces(value)
case reflect.Slice: return gconv.Interfaces(value)
case reflect.Map: return gconv.Map(value)
case reflect.Struct: return gconv.Map(value)
default:
// Use json decode/encode at last.
b, _ := Encode(value)
v, _ := Decode(b)
return v
}
}
}
// Set <key>:<value> to <pointer>, the <key> may be a map key or slice index.
// It returns the pointer to the new value set.
func (j *Json) setPointerWithValue(pointer *interface{}, key string, value interface{}) *interface{} {
switch (*pointer).(type) {
case map[string]interface{}:
(*pointer).(map[string]interface{})[key] = value
return &value
case []interface{}:
n, _ := strconv.Atoi(key)
if len((*pointer).([]interface{})) > n {
(*pointer).([]interface{})[n] = value
return &(*pointer).([]interface{})[n]
} else {
s := make([]interface{}, n+1)
copy(s, (*pointer).([]interface{}))
s[n] = value
*pointer = s
return &s[n]
}
default:
*pointer = value
}
return pointer
switch (*pointer).(type) {
case map[string]interface{}:
(*pointer).(map[string]interface{})[key] = value
return &value
case []interface{}:
n, _ := strconv.Atoi(key)
if len((*pointer).([]interface{})) > n {
(*pointer).([]interface{})[n] = value
return &(*pointer).([]interface{})[n]
} else {
s := make([]interface{}, n + 1)
copy(s, (*pointer).([]interface{}))
s[n] = value
*pointer = s
return &s[n]
}
default:
*pointer = value
}
return pointer
}
// Get a pointer to the value by specified <pattern>.
func (j *Json) getPointerByPattern(pattern string) *interface{} {
if j.vc {
return j.getPointerByPatternWithViolenceCheck(pattern)
} else {
return j.getPointerByPatternWithoutViolenceCheck(pattern)
}
if j.vc {
return j.getPointerByPatternWithViolenceCheck(pattern)
} else {
return j.getPointerByPatternWithoutViolenceCheck(pattern)
}
}
// Get a pointer to the value of specified <pattern> with violence check.
func (j *Json) getPointerByPatternWithViolenceCheck(pattern string) *interface{} {
//todo 此判断冗余
if !j.vc {
return j.getPointerByPatternWithoutViolenceCheck(pattern)
}
index := len(pattern)
start := 0
length := 0
pointer := j.p
if index == 0 {
return pointer
}
for {
if r := j.checkPatternByPointer(pattern[start:index], pointer); r != nil {
length += index - start
if start > 0 {
length += 1
}
start = index + 1
index = len(pattern)
if length == len(pattern) {
return r
} else {
pointer = r
}
} else {
// Get the position for next separator char.
index = strings.LastIndexByte(pattern[start:index], j.c)
if index != -1 && length > 0 {
index += length + 1
}
}
if start >= index {
break
}
}
return nil
if !j.vc {
return j.getPointerByPatternWithoutViolenceCheck(pattern)
}
index := len(pattern)
start := 0
length := 0
pointer := j.p
if index == 0 {
return pointer
}
for {
if r := j.checkPatternByPointer(pattern[start:index], pointer); r != nil {
length += index - start
if start > 0 {
length += 1
}
start = index + 1
index = len(pattern)
if length == len(pattern) {
return r
} else {
pointer = r
}
} else {
// Get the position for next separator char.
index = strings.LastIndexByte(pattern[start:index], j.c)
if index != -1 && length > 0 {
index += length + 1
}
}
if start >= index {
break
}
}
return nil
}
// Get a pointer to the value of specified <pattern>, with no violence check.
func (j *Json) getPointerByPatternWithoutViolenceCheck(pattern string) *interface{} {
//todo 此判断冗余
if j.vc {
return j.getPointerByPatternWithViolenceCheck(pattern)
}
pointer := j.p
if len(pattern) == 0 {
return pointer
}
array := strings.Split(pattern, string(j.c))
for k, v := range array {
if r := j.checkPatternByPointer(v, pointer); r != nil {
if k == len(array)-1 {
return r
} else {
pointer = r
}
} else {
break
}
}
return nil
if j.vc {
return j.getPointerByPatternWithViolenceCheck(pattern)
}
pointer := j.p
if len(pattern) == 0 {
return pointer
}
array := strings.Split(pattern, string(j.c))
for k, v := range array {
if r := j.checkPatternByPointer(v, pointer); r != nil {
if k == len(array) - 1 {
return r
} else {
pointer = r
}
} else {
break
}
}
return nil
}
// Check whether there's value by <key> in specified <pointer>.
// It returns a pointer to the value.
func (j *Json) checkPatternByPointer(key string, pointer *interface{}) *interface{} {
switch (*pointer).(type) {
case map[string]interface{}:
if v, ok := (*pointer).(map[string]interface{})[key]; ok {
return &v
}
case []interface{}:
if gstr.IsNumeric(key) {
n, err := strconv.Atoi(key)
if err == nil && len((*pointer).([]interface{})) > n {
return &(*pointer).([]interface{})[n]
}
}
}
return nil
switch (*pointer).(type) {
case map[string]interface{}:
if v, ok := (*pointer).(map[string]interface{})[key]; ok {
return &v
}
case []interface{}:
if gstr.IsNumeric(key) {
n, err := strconv.Atoi(key)
if err == nil && len((*pointer).([]interface{})) > n {
return &(*pointer).([]interface{})[n]
}
}
}
return nil
}

View File

@ -27,165 +27,163 @@ import (
// or it will make no sense.
// The <unsafe> param specifies whether using this Json object
// in un-concurrent-safe context, which is false in default.
func New(data interface{}, unsafe ...bool) *Json {
j := (*Json)(nil)
switch data.(type) {
case string, []byte:
if r, err := LoadContent(gconv.Bytes(data)); err == nil {
j = r
} else {
j = &Json{
p: &data,
c: byte(gDEFAULT_SPLIT_CHAR),
vc: false,
}
}
default:
rv := reflect.ValueOf(data)
kind := rv.Kind()
if kind == reflect.Ptr {
rv = rv.Elem()
kind = rv.Kind()
}
switch kind {
case reflect.Slice:
fallthrough
case reflect.Array:
i := interface{}(nil)
i = gconv.Interfaces(data)
j = &Json{
p: &i,
c: byte(gDEFAULT_SPLIT_CHAR),
vc: false,
}
case reflect.Map:
fallthrough
case reflect.Struct:
i := interface{}(nil)
i = gconv.Map(data, "json")
j = &Json{
p: &i,
c: byte(gDEFAULT_SPLIT_CHAR),
vc: false,
}
default:
j = &Json{
p: &data,
c: byte(gDEFAULT_SPLIT_CHAR),
vc: false,
}
}
}
j.mu = rwmutex.New(unsafe...)
return j
func New(data interface{}, unsafe...bool) *Json {
j := (*Json)(nil)
switch data.(type) {
case string, []byte:
if r, err := LoadContent(gconv.Bytes(data)); err == nil {
j = r
} else {
j = &Json {
p : &data,
c : byte(gDEFAULT_SPLIT_CHAR),
vc : false ,
}
}
default:
rv := reflect.ValueOf(data)
kind := rv.Kind()
if kind == reflect.Ptr {
rv = rv.Elem()
kind = rv.Kind()
}
switch kind {
case reflect.Slice: fallthrough
case reflect.Array:
i := interface{}(nil)
i = gconv.Interfaces(data)
j = &Json {
p : &i,
c : byte(gDEFAULT_SPLIT_CHAR),
vc : false ,
}
case reflect.Map: fallthrough
case reflect.Struct:
i := interface{}(nil)
i = gconv.Map(data, "json")
j = &Json {
p : &i,
c : byte(gDEFAULT_SPLIT_CHAR),
vc : false ,
}
default:
j = &Json {
p : &data,
c : byte(gDEFAULT_SPLIT_CHAR),
vc : false ,
}
}
}
j.mu = rwmutex.New(unsafe...)
return j
}
// NewUnsafe creates a un-concurrent-safe Json object.
func NewUnsafe(data ...interface{}) *Json {
if len(data) > 0 {
return New(data[0], true)
}
return New(nil, true)
func NewUnsafe(data...interface{}) *Json {
if len(data) > 0 {
return New(data[0], true)
}
return New(nil, true)
}
// Valid checks whether <data> is a valid JSON data type.
func Valid(data interface{}) bool {
return json.Valid(gconv.Bytes(data))
return json.Valid(gconv.Bytes(data))
}
// Encode encodes <value> to JSON data type of bytes.
func Encode(value interface{}) ([]byte, error) {
return json.Marshal(value)
return json.Marshal(value)
}
// Decode decodes <data>(string/[]byte) to golang variable.
func Decode(data interface{}) (interface{}, error) {
var value interface{}
if err := DecodeTo(gconv.Bytes(data), &value); err != nil {
return nil, err
} else {
return value, nil
}
var value interface{}
if err := DecodeTo(gconv.Bytes(data), &value); err != nil {
return nil, err
} else {
return value, nil
}
}
// Decode decodes <data>(string/[]byte) to specified golang variable <v>.
// The <v> should be a pointer type.
func DecodeTo(data interface{}, v interface{}) error {
decoder := json.NewDecoder(bytes.NewReader(gconv.Bytes(data)))
decoder.UseNumber()
return decoder.Decode(v)
decoder := json.NewDecoder(bytes.NewReader(gconv.Bytes(data)))
decoder.UseNumber()
return decoder.Decode(v)
}
// DecodeToJson codes <data>(string/[]byte) to a Json object.
func DecodeToJson(data interface{}, unsafe ...bool) (*Json, error) {
if v, err := Decode(gconv.Bytes(data)); err != nil {
return nil, err
} else {
return New(v, unsafe...), nil
}
func DecodeToJson(data interface{}, unsafe...bool) (*Json, error) {
if v, err := Decode(gconv.Bytes(data)); err != nil {
return nil, err
} else {
return New(v, unsafe...), nil
}
}
// Load loads content from specified file <path>,
// and creates a Json object from its content.
func Load(path string, unsafe ...bool) (*Json, error) {
return LoadContent(gfcache.GetBinContents(path), unsafe...)
func Load(path string, unsafe...bool) (*Json, error) {
return LoadContent(gfcache.GetBinContents(path), unsafe...)
}
// LoadContent creates a Json object from given content,
// it checks the data type of <content> automatically,
// supporting JSON, XML, YAML and TOML types of data.
func LoadContent(data interface{}, unsafe ...bool) (*Json, error) {
var err error
var result interface{}
b := gconv.Bytes(data)
t := ""
func LoadContent(data interface{}, unsafe...bool) (*Json, error) {
var err error
var result interface{}
b := gconv.Bytes(data)
t := ""
if len(b) == 0 {
return New(nil, unsafe...), nil
}
// auto check data type
if json.Valid(b) {
t = "json"
} else if gregex.IsMatch(`^<.+>[\S\s]+<.+>$`, b) {
t = "xml"
} else if gregex.IsMatch(`^[\s\t]*\w+\s*:\s*.+`, b) || gregex.IsMatch(`\n[\s\t]*\w+\s*:\s*.+`, b) {
t = "yml"
} else if gregex.IsMatch(`^[\s\t]*\w+\s*=\s*.+`, b) || gregex.IsMatch(`\n[\s\t]*\w+\s*=\s*.+`, b) {
t = "toml"
} else {
return nil, errors.New("unsupported data type")
}
// convert to json type data
switch t {
case "json", ".json":
// ok
case "xml", ".xml":
// TODO UseNumber
b, err = gxml.ToJson(b)
// auto check data type
if json.Valid(b) {
t = "json"
} else if gregex.IsMatch(`^<.+>[\S\s]+<.+>$`, b) {
t = "xml"
} else if gregex.IsMatch(`^[\s\t]*\w+\s*:\s*.+`, b) || gregex.IsMatch(`\n[\s\t]*\w+\s*:\s*.+`, b) {
t = "yml"
} else if gregex.IsMatch(`^[\s\t]*\w+\s*=\s*.+`, b) || gregex.IsMatch(`\n[\s\t]*\w+\s*=\s*.+`, b) {
t = "toml"
} else {
return nil, errors.New("unsupported data type")
}
// convert to json type data
switch t {
case "json", ".json":
// ok
case "xml", ".xml":
// TODO UseNumber
b, err = gxml.ToJson(b)
case "yml", "yaml", ".yml", ".yaml":
// TODO UseNumber
b, err = gyaml.ToJson(b)
case "yml", "yaml", ".yml", ".yaml":
// TODO UseNumber
b, err = gyaml.ToJson(b)
case "toml", ".toml":
// TODO UseNumber
b, err = gtoml.ToJson(b)
//todo 不可达
default:
err = errors.New("nonsupport type " + t)
}
if err != nil {
return nil, err
}
if result == nil {
decoder := json.NewDecoder(bytes.NewReader(b))
decoder.UseNumber()
if err := decoder.Decode(&result); err != nil {
return nil, err
}
switch result.(type) {
case string, []byte:
return nil, fmt.Errorf(`json decoding failed for content: %s`, string(b))
}
}
return New(result, unsafe...), nil
case "toml", ".toml":
// TODO UseNumber
b, err = gtoml.ToJson(b)
default:
err = errors.New("nonsupport type " + t)
}
if err != nil {
return nil, err
}
if result == nil {
decoder := json.NewDecoder(bytes.NewReader(b))
decoder.UseNumber()
if err := decoder.Decode(&result); err != nil {
return nil, err
}
switch result.(type) {
case string, []byte:
return nil, fmt.Errorf(`json decoding failed for content: %s`, string(b))
}
}
return New(result, unsafe...), nil
}

View File

@ -26,32 +26,32 @@ import (
)
const (
// Default configuration file name.
DEFAULT_CONFIG_FILE = "config.toml"
// Default configuration file name.
DEFAULT_CONFIG_FILE = "config.toml"
)
// Configuration struct.
type Config struct {
name *gtype.String // Default configuration file name.
paths *garray.StringArray // Searching path array.
jsons *gmap.StrAnyMap // The pared JSON objects for configuration files.
vc *gtype.Bool // Whether do violence check in value index searching.
// It affects the performance when set true(false in default).
name *gtype.String // Default configuration file name.
paths *garray.StringArray // Searching path array.
jsons *gmap.StrAnyMap // The pared JSON objects for configuration files.
vc *gtype.Bool // Whether do violence check in value index searching.
// It affects the performance when set true(false in default).
}
// New returns a new configuration management object.
// The param <file> specifies the default configuration file name for reading.
func New(file ...string) *Config {
name := DEFAULT_CONFIG_FILE
if len(file) > 0 {
name = file[0]
}
c := &Config{
name: gtype.NewString(name),
paths: garray.NewStringArray(),
jsons: gmap.NewStrAnyMap(),
vc: gtype.NewBool(),
}
func New(file...string) *Config {
name := DEFAULT_CONFIG_FILE
if len(file) > 0 {
name = file[0]
}
c := &Config {
name : gtype.NewString(name),
paths : garray.NewStringArray(),
jsons : gmap.NewStrAnyMap(),
vc : gtype.NewBool(),
}
// Customized dir path from env/cmd.
if envPath := cmdenv.Get("gf.gcfg.path").String(); envPath != "" {
if gfile.Exists(envPath) {
@ -71,85 +71,85 @@ func New(file ...string) *Config {
_ = c.AddPath(mainPath)
}
}
return c
return c
}
// filePath returns the absolute configuration file path for the given filename by <file>.
func (c *Config) filePath(file ...string) (path string) {
name := c.name.Val()
if len(file) > 0 {
name = file[0]
}
path = c.FilePath(name)
if path == "" {
buffer := bytes.NewBuffer(nil)
if c.paths.Len() > 0 {
buffer.WriteString(fmt.Sprintf("[gcfg] cannot find config file \"%s\" in following paths:", name))
c.paths.RLockFunc(func(array []string) {
index := 1
for _, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v))
index++
buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v+gfile.Separator+"config"))
index++
}
})
} else {
buffer.WriteString(fmt.Sprintf("[gcfg] cannot find config file \"%s\" with no path set/add", name))
}
glog.Error(buffer.String())
}
return path
func (c *Config) filePath(file...string) (path string) {
name := c.name.Val()
if len(file) > 0 {
name = file[0]
}
path = c.FilePath(name)
if path == "" {
buffer := bytes.NewBuffer(nil)
if c.paths.Len() > 0 {
buffer.WriteString(fmt.Sprintf("[gcfg] cannot find config file \"%s\" in following paths:", name))
c.paths.RLockFunc(func(array []string) {
index := 1
for _, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v))
index++
buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v + gfile.Separator + "config"))
index++
}
})
} else {
buffer.WriteString(fmt.Sprintf("[gcfg] cannot find config file \"%s\" with no path set/add", name))
}
glog.Error(buffer.String())
}
return path
}
// SetPath sets the configuration directory path for file search.
// The param <path> can be absolute or relative path,
// but absolute path is strongly recommended.
func (c *Config) SetPath(path string) error {
// Absolute path.
realPath := gfile.RealPath(path)
if realPath == "" {
// Relative path.
c.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ := gspath.Search(v, path); path != "" {
realPath = path
break
}
}
})
}
// Path not exist.
if realPath == "" {
buffer := bytes.NewBuffer(nil)
if c.paths.Len() > 0 {
buffer.WriteString(fmt.Sprintf("[gcfg] SetPath failed: cannot find directory \"%s\" in following paths:", path))
c.paths.RLockFunc(func(array []string) {
for k, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
}
})
} else {
buffer.WriteString(fmt.Sprintf(`[gcfg] SetPath failed: path "%s" does not exist`, path))
}
err := errors.New(buffer.String())
glog.Error(err)
return err
}
// Should be a directory.
if !gfile.IsDir(realPath) {
err := errors.New(fmt.Sprintf(`[gcfg] SetPath failed: path "%s" should be directory type`, path))
glog.Error(err)
return err
}
// Repeated path check.
if c.paths.Search(realPath) != -1 {
return nil
}
c.jsons.Clear()
c.paths.Clear()
c.paths.Append(realPath)
return nil
// Absolute path.
realPath := gfile.RealPath(path)
if realPath == "" {
// Relative path.
c.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ := gspath.Search(v, path); path != "" {
realPath = path
break
}
}
})
}
// Path not exist.
if realPath == "" {
buffer := bytes.NewBuffer(nil)
if c.paths.Len() > 0 {
buffer.WriteString(fmt.Sprintf("[gcfg] SetPath failed: cannot find directory \"%s\" in following paths:", path))
c.paths.RLockFunc(func(array []string) {
for k, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s",k + 1, v))
}
})
} else {
buffer.WriteString(fmt.Sprintf(`[gcfg] SetPath failed: path "%s" does not exist`, path))
}
err := errors.New(buffer.String())
glog.Error(err)
return err
}
// Should be a directory.
if !gfile.IsDir(realPath) {
err := errors.New(fmt.Sprintf(`[gcfg] SetPath failed: path "%s" should be directory type`, path))
glog.Error(err)
return err
}
// Repeated path check.
if c.paths.Search(realPath) != -1 {
return nil
}
c.jsons.Clear()
c.paths.Clear()
c.paths.Append(realPath)
return nil
}
// SetViolenceCheck sets whether to perform hierarchical conflict check.
@ -159,58 +159,58 @@ func (c *Config) SetPath(path string) error {
// and it is not recommended to allow separators in the key names.
// It is best to avoid this on the application side.
func (c *Config) SetViolenceCheck(check bool) {
c.vc.Set(check)
c.Clear()
c.vc.Set(check)
c.Clear()
}
// AddPath adds a absolute or relative path to the search paths.
func (c *Config) AddPath(path string) error {
// Absolute path.
realPath := gfile.RealPath(path)
if realPath == "" {
// Relative path.
c.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ := gspath.Search(v, path); path != "" {
realPath = path
break
}
}
})
}
if realPath == "" {
buffer := bytes.NewBuffer(nil)
if c.paths.Len() > 0 {
buffer.WriteString(fmt.Sprintf("[gcfg] AddPath failed: cannot find directory \"%s\" in following paths:", path))
c.paths.RLockFunc(func(array []string) {
for k, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
}
})
} else {
buffer.WriteString(fmt.Sprintf(`[gcfg] AddPath failed: path "%s" does not exist`, path))
}
err := errors.New(buffer.String())
glog.Error(err)
return err
}
if !gfile.IsDir(realPath) {
err := errors.New(fmt.Sprintf(`[gcfg] AddPath failed: path "%s" should be directory type`, path))
glog.Error(err)
return err
}
// Repeated path check.
if c.paths.Search(realPath) != -1 {
return nil
}
c.paths.Append(realPath)
//glog.Debug("[gcfg] AddPath:", realPath)
return nil
// Absolute path.
realPath := gfile.RealPath(path)
if realPath == "" {
// Relative path.
c.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ := gspath.Search(v, path); path != "" {
realPath = path
break
}
}
})
}
if realPath == "" {
buffer := bytes.NewBuffer(nil)
if c.paths.Len() > 0 {
buffer.WriteString(fmt.Sprintf("[gcfg] AddPath failed: cannot find directory \"%s\" in following paths:", path))
c.paths.RLockFunc(func(array []string) {
for k, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s", k + 1, v))
}
})
} else {
buffer.WriteString(fmt.Sprintf(`[gcfg] AddPath failed: path "%s" does not exist`, path))
}
err := errors.New(buffer.String())
glog.Error(err)
return err
}
if !gfile.IsDir(realPath) {
err := errors.New(fmt.Sprintf(`[gcfg] AddPath failed: path "%s" should be directory type`, path))
glog.Error(err)
return err
}
// Repeated path check.
if c.paths.Search(realPath) != -1 {
return nil
}
c.paths.Append(realPath)
//glog.Debug("[gcfg] AddPath:", realPath)
return nil
}
// Deprecated.
// Alias of FilePath.
func (c *Config) GetFilePath(file ...string) (path string) {
func (c *Config) GetFilePath(file...string) (path string) {
return c.FilePath(file...)
}
@ -218,274 +218,275 @@ func (c *Config) GetFilePath(file ...string) (path string) {
// If <file> is not passed, it returns the configuration file path of the default name.
// If the specified configuration file does not exist,
// an empty string is returned.
func (c *Config) FilePath(file ...string) (path string) {
name := c.name.Val()
if len(file) > 0 {
name = file[0]
}
c.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ = gspath.Search(v, name); path != "" {
break
}
if path, _ = gspath.Search(v+gfile.Separator+"config", name); path != "" {
break
}
}
})
return
func (c *Config) FilePath(file...string) (path string) {
name := c.name.Val()
if len(file) > 0 {
name = file[0]
}
c.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ = gspath.Search(v, name); path != "" {
break
}
if path, _ = gspath.Search(v + gfile.Separator + "config", name); path != "" {
break
}
}
})
return
}
// SetFileName sets the default configuration file name.
func (c *Config) SetFileName(name string) {
c.name.Set(name)
c.name.Set(name)
}
// GetFileName returns the default configuration file name.
func (c *Config) GetFileName() string {
return c.name.Val()
return c.name.Val()
}
// getJson returns a gjson.Json object for the specified <file> content.
// It would print error if file reading fails.
// If any error occurs, it return nil.
func (c *Config) getJson(file ...string) *gjson.Json {
name := c.name.Val()
//todo 此函数file参数无效没有地方调用且有SetFileName函数提供链式操作因此建议去掉
if len(file) > 0 {
name = file[0]
}
r := c.jsons.GetOrSetFuncLock(name, func() interface{} {
content := ""
filePath := ""
if content = GetContent(name); content == "" {
filePath = c.filePath(name)
if filePath == "" {
return nil
}
content = gfile.GetContents(filePath)
}
if j, err := gjson.LoadContent(content); err == nil {
j.SetViolenceCheck(c.vc.Val())
// Add monitor for this configuration file,
// any changes of this file will refresh its cache in Config object.
if filePath != "" {
gfsnotify.Add(filePath, func(event *gfsnotify.Event) {
c.jsons.Remove(name)
})
}
return j
} else {
if filePath != "" {
glog.Criticalf(`[gcfg] Load config file "%s" failed: %s`, filePath, err.Error())
} else {
glog.Criticalf(`[gcfg] Load configuration failed: %s`, err.Error())
}
}
return nil
})
if r != nil {
return r.(*gjson.Json)
}
return nil
func (c *Config) getJson(file...string) *gjson.Json {
name := c.name.Val()
if len(file) > 0 {
name = file[0]
}
r := c.jsons.GetOrSetFuncLock(name, func() interface{} {
content := ""
filePath := ""
if content = GetContent(name); content == "" {
filePath = c.filePath(name)
if filePath == "" {
return nil
}
content = gfile.GetContents(filePath)
}
if j, err := gjson.LoadContent(content); err == nil {
j.SetViolenceCheck(c.vc.Val())
// Add monitor for this configuration file,
// any changes of this file will refresh its cache in Config object.
if filePath != "" {
gfsnotify.Add(filePath, func(event *gfsnotify.Event) {
c.jsons.Remove(name)
})
}
return j
} else {
if filePath != "" {
glog.Criticalf(`[gcfg] Load config file "%s" failed: %s`, filePath, err.Error())
} else {
glog.Criticalf(`[gcfg] Load configuration failed: %s`, err.Error())
}
}
return nil
})
if r != nil {
return r.(*gjson.Json)
}
return nil
}
func (c *Config) Get(pattern string, def ...interface{}) interface{} {
if j := c.getJson(); j != nil {
return j.Get(pattern, def...)
}
return nil
func (c *Config) Get(pattern string, def...interface{}) interface{} {
if j := c.getJson(); j != nil {
return j.Get(pattern, def...)
}
return nil
}
func (c *Config) GetVar(pattern string, def ...interface{}) *gvar.Var {
if j := c.getJson(); j != nil {
return gvar.New(j.Get(pattern, def...), true)
}
return gvar.New(nil, true)
func (c *Config) GetVar(pattern string, def...interface{}) *gvar.Var {
if j := c.getJson(); j != nil {
return gvar.New(j.Get(pattern, def...), true)
}
return gvar.New(nil, true)
}
func (c *Config) Contains(pattern string) bool {
if j := c.getJson(); j != nil {
return j.Contains(pattern)
}
return false
if j := c.getJson(); j != nil {
return j.Contains(pattern)
}
return false
}
func (c *Config) GetMap(pattern string, def ...interface{}) map[string]interface{} {
if j := c.getJson(); j != nil {
return j.GetMap(pattern, def...)
}
return nil
func (c *Config) GetMap(pattern string, def...interface{}) map[string]interface{} {
if j := c.getJson(); j != nil {
return j.GetMap(pattern, def...)
}
return nil
}
func (c *Config) GetArray(pattern string, def ...interface{}) []interface{} {
if j := c.getJson(); j != nil {
return j.GetArray(pattern, def...)
}
return nil
func (c *Config) GetArray(pattern string, def...interface{}) []interface{} {
if j := c.getJson(); j != nil {
return j.GetArray(pattern, def...)
}
return nil
}
func (c *Config) GetString(pattern string, def ...interface{}) string {
if j := c.getJson(); j != nil {
return j.GetString(pattern, def...)
}
return ""
func (c *Config) GetString(pattern string, def...interface{}) string {
if j := c.getJson(); j != nil {
return j.GetString(pattern, def...)
}
return ""
}
func (c *Config) GetStrings(pattern string, def ...interface{}) []string {
if j := c.getJson(); j != nil {
return j.GetStrings(pattern, def...)
}
return nil
func (c *Config) GetStrings(pattern string, def...interface{}) []string {
if j := c.getJson(); j != nil {
return j.GetStrings(pattern, def...)
}
return nil
}
func (c *Config) GetInterfaces(pattern string, def ...interface{}) []interface{} {
if j := c.getJson(); j != nil {
return j.GetInterfaces(pattern, def...)
}
return nil
func (c *Config) GetInterfaces(pattern string, def...interface{}) []interface{} {
if j := c.getJson(); j != nil {
return j.GetInterfaces(pattern, def...)
}
return nil
}
func (c *Config) GetBool(pattern string, def ...interface{}) bool {
if j := c.getJson(); j != nil {
return j.GetBool(pattern, def...)
}
return false
func (c *Config) GetBool(pattern string, def...interface{}) bool {
if j := c.getJson(); j != nil {
return j.GetBool(pattern, def...)
}
return false
}
func (c *Config) GetFloat32(pattern string, def ...interface{}) float32 {
if j := c.getJson(); j != nil {
return j.GetFloat32(pattern, def...)
}
return 0
func (c *Config) GetFloat32(pattern string, def...interface{}) float32 {
if j := c.getJson(); j != nil {
return j.GetFloat32(pattern, def...)
}
return 0
}
func (c *Config) GetFloat64(pattern string, def ...interface{}) float64 {
if j := c.getJson(); j != nil {
return j.GetFloat64(pattern, def...)
}
return 0
func (c *Config) GetFloat64(pattern string, def...interface{}) float64 {
if j := c.getJson(); j != nil {
return j.GetFloat64(pattern, def...)
}
return 0
}
func (c *Config) GetFloats(pattern string, def ...interface{}) []float64 {
if j := c.getJson(); j != nil {
return j.GetFloats(pattern, def...)
}
return nil
func (c *Config) GetFloats(pattern string, def...interface{}) []float64 {
if j := c.getJson(); j != nil {
return j.GetFloats(pattern, def...)
}
return nil
}
func (c *Config) GetInt(pattern string, def ...interface{}) int {
if j := c.getJson(); j != nil {
return j.GetInt(pattern, def...)
}
return 0
func (c *Config) GetInt(pattern string, def...interface{}) int {
if j := c.getJson(); j != nil {
return j.GetInt(pattern, def...)
}
return 0
}
func (c *Config) GetInt8(pattern string, def ...interface{}) int8 {
if j := c.getJson(); j != nil {
return j.GetInt8(pattern, def...)
}
return 0
func (c *Config) GetInt8(pattern string, def...interface{}) int8 {
if j := c.getJson(); j != nil {
return j.GetInt8(pattern, def...)
}
return 0
}
func (c *Config) GetInt16(pattern string, def ...interface{}) int16 {
if j := c.getJson(); j != nil {
return j.GetInt16(pattern, def...)
}
return 0
func (c *Config) GetInt16(pattern string, def...interface{}) int16 {
if j := c.getJson(); j != nil {
return j.GetInt16(pattern, def...)
}
return 0
}
func (c *Config) GetInt32(pattern string, def ...interface{}) int32 {
if j := c.getJson(); j != nil {
return j.GetInt32(pattern, def...)
}
return 0
func (c *Config) GetInt32(pattern string, def...interface{}) int32 {
if j := c.getJson(); j != nil {
return j.GetInt32(pattern, def...)
}
return 0
}
func (c *Config) GetInt64(pattern string, def ...interface{}) int64 {
if j := c.getJson(); j != nil {
return j.GetInt64(pattern, def...)
}
return 0
func (c *Config) GetInt64(pattern string, def...interface{}) int64 {
if j := c.getJson(); j != nil {
return j.GetInt64(pattern, def...)
}
return 0
}
func (c *Config) GetInts(pattern string, def ...interface{}) []int {
if j := c.getJson(); j != nil {
return j.GetInts(pattern, def...)
}
return nil
func (c *Config) GetInts(pattern string, def...interface{}) []int {
if j := c.getJson(); j != nil {
return j.GetInts(pattern, def...)
}
return nil
}
func (c *Config) GetUint(pattern string, def ...interface{}) uint {
if j := c.getJson(); j != nil {
return j.GetUint(pattern, def...)
}
return 0
func (c *Config) GetUint(pattern string, def...interface{}) uint {
if j := c.getJson(); j != nil {
return j.GetUint(pattern, def...)
}
return 0
}
func (c *Config) GetUint8(pattern string, def ...interface{}) uint8 {
if j := c.getJson(); j != nil {
return j.GetUint8(pattern, def...)
}
return 0
func (c *Config) GetUint8(pattern string, def...interface{}) uint8 {
if j := c.getJson(); j != nil {
return j.GetUint8(pattern, def...)
}
return 0
}
func (c *Config) GetUint16(pattern string, def ...interface{}) uint16 {
if j := c.getJson(); j != nil {
return j.GetUint16(pattern, def...)
}
return 0
func (c *Config) GetUint16(pattern string, def...interface{}) uint16 {
if j := c.getJson(); j != nil {
return j.GetUint16(pattern, def...)
}
return 0
}
func (c *Config) GetUint32(pattern string, def ...interface{}) uint32 {
if j := c.getJson(); j != nil {
return j.GetUint32(pattern, def...)
}
return 0
func (c *Config) GetUint32(pattern string, def...interface{}) uint32 {
if j := c.getJson(); j != nil {
return j.GetUint32(pattern, def...)
}
return 0
}
func (c *Config) GetUint64(pattern string, def ...interface{}) uint64 {
if j := c.getJson(); j != nil {
return j.GetUint64(pattern, def...)
}
return 0
func (c *Config) GetUint64(pattern string, def...interface{}) uint64 {
if j := c.getJson(); j != nil {
return j.GetUint64(pattern, def...)
}
return 0
}
func (c *Config) GetTime(pattern string, format ...string) time.Time {
func (c *Config) GetTime(pattern string, format...string) time.Time {
if j := c.getJson(); j != nil {
return j.GetTime(pattern, format...)
}
return time.Time{}
}
func (c *Config) GetDuration(pattern string, def ...interface{}) time.Duration {
func (c *Config) GetDuration(pattern string, def...interface{}) time.Duration {
if j := c.getJson(); j != nil {
return j.GetDuration(pattern, def...)
}
return 0
}
func (c *Config) GetGTime(pattern string, format ...string) *gtime.Time {
func (c *Config) GetGTime(pattern string, format...string) *gtime.Time {
if j := c.getJson(); j != nil {
return j.GetGTime(pattern, format...)
}
return nil
}
func (c *Config) GetToStruct(pattern string, pointer interface{}, def ...interface{}) error {
if j := c.getJson(); j != nil {
return j.GetToStruct(pattern, pointer)
}
return errors.New("config file not found")
func (c *Config) GetToStruct(pattern string, pointer interface{}, def...interface{}) error {
if j := c.getJson(); j != nil {
return j.GetToStruct(pattern, pointer)
}
return errors.New("config file not found")
}
// Deprecated. See Clear.
func (c *Config) Reload() {
c.jsons.Clear()
c.jsons.Clear()
}
// Clear removes all parsed configuration files content cache,
// which will force reload configuration content from file.
func (c *Config) Clear() {
c.jsons.Clear()
c.jsons.Clear()
}