github.com/lingyao2333/mo-zero@v1.4.1/core/conf/properties.go (about)

     1  package conf
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strconv"
     7  	"strings"
     8  	"sync"
     9  
    10  	"github.com/lingyao2333/mo-zero/core/iox"
    11  )
    12  
    13  // PropertyError represents a configuration error message.
    14  type PropertyError struct {
    15  	error
    16  	message string
    17  }
    18  
    19  // Properties interface provides the means to access configuration.
    20  type Properties interface {
    21  	GetString(key string) string
    22  	SetString(key, value string)
    23  	GetInt(key string) int
    24  	SetInt(key string, value int)
    25  	ToString() string
    26  }
    27  
    28  // Properties config is a key/value pair based configuration structure.
    29  type mapBasedProperties struct {
    30  	properties map[string]string
    31  	lock       sync.RWMutex
    32  }
    33  
    34  // LoadProperties loads the properties into a properties configuration instance.
    35  // Returns an error that indicates if there was a problem loading the configuration.
    36  func LoadProperties(filename string, opts ...Option) (Properties, error) {
    37  	lines, err := iox.ReadTextLines(filename, iox.WithoutBlank(), iox.OmitWithPrefix("#"))
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	var opt options
    43  	for _, o := range opts {
    44  		o(&opt)
    45  	}
    46  
    47  	raw := make(map[string]string)
    48  	for i := range lines {
    49  		pair := strings.Split(lines[i], "=")
    50  		if len(pair) != 2 {
    51  			// invalid property format
    52  			return nil, &PropertyError{
    53  				message: fmt.Sprintf("invalid property format: %s", pair),
    54  			}
    55  		}
    56  
    57  		key := strings.TrimSpace(pair[0])
    58  		value := strings.TrimSpace(pair[1])
    59  		if opt.env {
    60  			raw[key] = os.ExpandEnv(value)
    61  		} else {
    62  			raw[key] = value
    63  		}
    64  	}
    65  
    66  	return &mapBasedProperties{
    67  		properties: raw,
    68  	}, nil
    69  }
    70  
    71  func (config *mapBasedProperties) GetString(key string) string {
    72  	config.lock.RLock()
    73  	ret := config.properties[key]
    74  	config.lock.RUnlock()
    75  
    76  	return ret
    77  }
    78  
    79  func (config *mapBasedProperties) SetString(key, value string) {
    80  	config.lock.Lock()
    81  	config.properties[key] = value
    82  	config.lock.Unlock()
    83  }
    84  
    85  func (config *mapBasedProperties) GetInt(key string) int {
    86  	config.lock.RLock()
    87  	// default 0
    88  	value, _ := strconv.Atoi(config.properties[key])
    89  	config.lock.RUnlock()
    90  
    91  	return value
    92  }
    93  
    94  func (config *mapBasedProperties) SetInt(key string, value int) {
    95  	config.lock.Lock()
    96  	config.properties[key] = strconv.Itoa(value)
    97  	config.lock.Unlock()
    98  }
    99  
   100  // ToString dumps the configuration internal map into a string.
   101  func (config *mapBasedProperties) ToString() string {
   102  	config.lock.RLock()
   103  	ret := fmt.Sprintf("%s", config.properties)
   104  	config.lock.RUnlock()
   105  
   106  	return ret
   107  }
   108  
   109  // Error returns the error message.
   110  func (configError *PropertyError) Error() string {
   111  	return configError.message
   112  }
   113  
   114  // NewProperties builds a new properties configuration structure.
   115  func NewProperties() Properties {
   116  	return &mapBasedProperties{
   117  		properties: make(map[string]string),
   118  	}
   119  }