diff --git a/g/encoding/gjson/gjson.go b/g/encoding/gjson/gjson.go index ed8e2ef0f..3b63289bd 100644 --- a/g/encoding/gjson/gjson.go +++ b/g/encoding/gjson/gjson.go @@ -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 by . @@ -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 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 : to , the 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 . 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 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 , 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 in specified . // 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 } diff --git a/g/encoding/gjson/gjson_api_new_load.go b/g/encoding/gjson/gjson_api_new_load.go index ab206191b..712a4dd51 100644 --- a/g/encoding/gjson/gjson_api_new_load.go +++ b/g/encoding/gjson/gjson_api_new_load.go @@ -27,165 +27,163 @@ import ( // or it will make no sense. // The 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 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 to JSON data type of bytes. func Encode(value interface{}) ([]byte, error) { - return json.Marshal(value) + return json.Marshal(value) } // Decode decodes (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 (string/[]byte) to specified golang variable . // The 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 (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 , // 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 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 } diff --git a/g/os/gcfg/gcfg.go b/g/os/gcfg/gcfg.go index 451e9a275..057216f16 100644 --- a/g/os/gcfg/gcfg.go +++ b/g/os/gcfg/gcfg.go @@ -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 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 . -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 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 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 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() } +