github.com/astaxie/beego@v1.12.3/config/json.go (about)

     1  // Copyright 2014 beego Author. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package config
    16  
    17  import (
    18  	"encoding/json"
    19  	"errors"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"strconv"
    24  	"strings"
    25  	"sync"
    26  )
    27  
    28  // JSONConfig is a json config parser and implements Config interface.
    29  type JSONConfig struct {
    30  }
    31  
    32  // Parse returns a ConfigContainer with parsed json config map.
    33  func (js *JSONConfig) Parse(filename string) (Configer, error) {
    34  	file, err := os.Open(filename)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	defer file.Close()
    39  	content, err := ioutil.ReadAll(file)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	return js.ParseData(content)
    45  }
    46  
    47  // ParseData returns a ConfigContainer with json string
    48  func (js *JSONConfig) ParseData(data []byte) (Configer, error) {
    49  	x := &JSONConfigContainer{
    50  		data: make(map[string]interface{}),
    51  	}
    52  	err := json.Unmarshal(data, &x.data)
    53  	if err != nil {
    54  		var wrappingArray []interface{}
    55  		err2 := json.Unmarshal(data, &wrappingArray)
    56  		if err2 != nil {
    57  			return nil, err
    58  		}
    59  		x.data["rootArray"] = wrappingArray
    60  	}
    61  
    62  	x.data = ExpandValueEnvForMap(x.data)
    63  
    64  	return x, nil
    65  }
    66  
    67  // JSONConfigContainer A Config represents the json configuration.
    68  // Only when get value, support key as section:name type.
    69  type JSONConfigContainer struct {
    70  	data map[string]interface{}
    71  	sync.RWMutex
    72  }
    73  
    74  // Bool returns the boolean value for a given key.
    75  func (c *JSONConfigContainer) Bool(key string) (bool, error) {
    76  	val := c.getData(key)
    77  	if val != nil {
    78  		return ParseBool(val)
    79  	}
    80  	return false, fmt.Errorf("not exist key: %q", key)
    81  }
    82  
    83  // DefaultBool return the bool value if has no error
    84  // otherwise return the defaultval
    85  func (c *JSONConfigContainer) DefaultBool(key string, defaultval bool) bool {
    86  	if v, err := c.Bool(key); err == nil {
    87  		return v
    88  	}
    89  	return defaultval
    90  }
    91  
    92  // Int returns the integer value for a given key.
    93  func (c *JSONConfigContainer) Int(key string) (int, error) {
    94  	val := c.getData(key)
    95  	if val != nil {
    96  		if v, ok := val.(float64); ok {
    97  			return int(v), nil
    98  		} else if v, ok := val.(string); ok {
    99  			return strconv.Atoi(v)
   100  		}
   101  		return 0, errors.New("not valid value")
   102  	}
   103  	return 0, errors.New("not exist key:" + key)
   104  }
   105  
   106  // DefaultInt returns the integer value for a given key.
   107  // if err != nil return defaultval
   108  func (c *JSONConfigContainer) DefaultInt(key string, defaultval int) int {
   109  	if v, err := c.Int(key); err == nil {
   110  		return v
   111  	}
   112  	return defaultval
   113  }
   114  
   115  // Int64 returns the int64 value for a given key.
   116  func (c *JSONConfigContainer) Int64(key string) (int64, error) {
   117  	val := c.getData(key)
   118  	if val != nil {
   119  		if v, ok := val.(float64); ok {
   120  			return int64(v), nil
   121  		}
   122  		return 0, errors.New("not int64 value")
   123  	}
   124  	return 0, errors.New("not exist key:" + key)
   125  }
   126  
   127  // DefaultInt64 returns the int64 value for a given key.
   128  // if err != nil return defaultval
   129  func (c *JSONConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
   130  	if v, err := c.Int64(key); err == nil {
   131  		return v
   132  	}
   133  	return defaultval
   134  }
   135  
   136  // Float returns the float value for a given key.
   137  func (c *JSONConfigContainer) Float(key string) (float64, error) {
   138  	val := c.getData(key)
   139  	if val != nil {
   140  		if v, ok := val.(float64); ok {
   141  			return v, nil
   142  		}
   143  		return 0.0, errors.New("not float64 value")
   144  	}
   145  	return 0.0, errors.New("not exist key:" + key)
   146  }
   147  
   148  // DefaultFloat returns the float64 value for a given key.
   149  // if err != nil return defaultval
   150  func (c *JSONConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
   151  	if v, err := c.Float(key); err == nil {
   152  		return v
   153  	}
   154  	return defaultval
   155  }
   156  
   157  // String returns the string value for a given key.
   158  func (c *JSONConfigContainer) String(key string) string {
   159  	val := c.getData(key)
   160  	if val != nil {
   161  		if v, ok := val.(string); ok {
   162  			return v
   163  		}
   164  	}
   165  	return ""
   166  }
   167  
   168  // DefaultString returns the string value for a given key.
   169  // if err != nil return defaultval
   170  func (c *JSONConfigContainer) DefaultString(key string, defaultval string) string {
   171  	// TODO FIXME should not use "" to replace non existence
   172  	if v := c.String(key); v != "" {
   173  		return v
   174  	}
   175  	return defaultval
   176  }
   177  
   178  // Strings returns the []string value for a given key.
   179  func (c *JSONConfigContainer) Strings(key string) []string {
   180  	stringVal := c.String(key)
   181  	if stringVal == "" {
   182  		return nil
   183  	}
   184  	return strings.Split(c.String(key), ";")
   185  }
   186  
   187  // DefaultStrings returns the []string value for a given key.
   188  // if err != nil return defaultval
   189  func (c *JSONConfigContainer) DefaultStrings(key string, defaultval []string) []string {
   190  	if v := c.Strings(key); v != nil {
   191  		return v
   192  	}
   193  	return defaultval
   194  }
   195  
   196  // GetSection returns map for the given section
   197  func (c *JSONConfigContainer) GetSection(section string) (map[string]string, error) {
   198  	if v, ok := c.data[section]; ok {
   199  		return v.(map[string]string), nil
   200  	}
   201  	return nil, errors.New("nonexist section " + section)
   202  }
   203  
   204  // SaveConfigFile save the config into file
   205  func (c *JSONConfigContainer) SaveConfigFile(filename string) (err error) {
   206  	// Write configuration file by filename.
   207  	f, err := os.Create(filename)
   208  	if err != nil {
   209  		return err
   210  	}
   211  	defer f.Close()
   212  	b, err := json.MarshalIndent(c.data, "", "  ")
   213  	if err != nil {
   214  		return err
   215  	}
   216  	_, err = f.Write(b)
   217  	return err
   218  }
   219  
   220  // Set writes a new value for key.
   221  func (c *JSONConfigContainer) Set(key, val string) error {
   222  	c.Lock()
   223  	defer c.Unlock()
   224  	c.data[key] = val
   225  	return nil
   226  }
   227  
   228  // DIY returns the raw value by a given key.
   229  func (c *JSONConfigContainer) DIY(key string) (v interface{}, err error) {
   230  	val := c.getData(key)
   231  	if val != nil {
   232  		return val, nil
   233  	}
   234  	return nil, errors.New("not exist key")
   235  }
   236  
   237  // section.key or key
   238  func (c *JSONConfigContainer) getData(key string) interface{} {
   239  	if len(key) == 0 {
   240  		return nil
   241  	}
   242  
   243  	c.RLock()
   244  	defer c.RUnlock()
   245  
   246  	sectionKeys := strings.Split(key, "::")
   247  	if len(sectionKeys) >= 2 {
   248  		curValue, ok := c.data[sectionKeys[0]]
   249  		if !ok {
   250  			return nil
   251  		}
   252  		for _, key := range sectionKeys[1:] {
   253  			if v, ok := curValue.(map[string]interface{}); ok {
   254  				if curValue, ok = v[key]; !ok {
   255  					return nil
   256  				}
   257  			}
   258  		}
   259  		return curValue
   260  	}
   261  	if v, ok := c.data[key]; ok {
   262  		return v
   263  	}
   264  	return nil
   265  }
   266  
   267  func init() {
   268  	Register("json", &JSONConfig{})
   269  }