mirror of
https://github.com/cwinfo/matterbridge.git
synced 2025-07-03 13:07:44 +00:00
Update vendor (#1265)
This commit is contained in:
12
vendor/github.com/wiggin77/cfg/.gitignore
generated
vendored
Normal file
12
vendor/github.com/wiggin77/cfg/.gitignore
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
5
vendor/github.com/wiggin77/cfg/.travis.yml
generated
vendored
Normal file
5
vendor/github.com/wiggin77/cfg/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
language: go
|
||||
sudo: false
|
||||
before_script:
|
||||
- go vet ./...
|
||||
|
21
vendor/github.com/wiggin77/cfg/LICENSE
generated
vendored
Normal file
21
vendor/github.com/wiggin77/cfg/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 wiggin77
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
43
vendor/github.com/wiggin77/cfg/README.md
generated
vendored
Normal file
43
vendor/github.com/wiggin77/cfg/README.md
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
# cfg
|
||||
|
||||
[](https://godoc.org/github.com/wiggin77/cfg)
|
||||
[](https://travis-ci.org/wiggin77/cfg)
|
||||
|
||||
Go package for app configuration. Supports chained configuration sources for multiple levels of defaults.
|
||||
Includes APIs for loading Linux style configuration files (name/value pairs) or INI files, map based properties,
|
||||
or easily create new configuration sources (e.g. load from database).
|
||||
|
||||
Supports monitoring configuration sources for changes, hot loading properties, and notifying listeners of changes.
|
||||
|
||||
## Usage
|
||||
|
||||
```Go
|
||||
config := &cfg.Config{}
|
||||
defer config.Shutdown() // stops monitoring
|
||||
|
||||
// load file via filespec string, os.File
|
||||
src, err := Config.NewSrcFileFromFilespec("./myfile.conf")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// add src to top of chain, meaning first searched
|
||||
cfg.PrependSource(src)
|
||||
|
||||
// fetch prop 'retries', default to 3 if not found
|
||||
val := config.Int("retries", 3)
|
||||
```
|
||||
|
||||
See [example](./example_test.go) for more complete example, including listening for configuration changes.
|
||||
|
||||
Config API parses the following data types:
|
||||
|
||||
| type | method | example property values |
|
||||
| ------- | ------ | -------- |
|
||||
| string | Config.String | test, "" |
|
||||
| int | Config.Int | -1, 77, 0 |
|
||||
| int64 | Config.Int64 | -9223372036854775, 372036854775808 |
|
||||
| float64 | Config.Float64 | -77.3456, 95642331.1 |
|
||||
| bool | Config.Bool | T,t,true,True,1,0,False,false,f,F |
|
||||
| time.Duration | Config.Duration | "10ms", "2 hours", "5 min" * |
|
||||
|
||||
\* Units of measure supported: ms, sec, min, hour, day, week, year.
|
366
vendor/github.com/wiggin77/cfg/config.go
generated
vendored
Normal file
366
vendor/github.com/wiggin77/cfg/config.go
generated
vendored
Normal file
@ -0,0 +1,366 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/wiggin77/cfg/timeconv"
|
||||
)
|
||||
|
||||
// ErrNotFound returned when an operation is attempted on a
|
||||
// resource that doesn't exist, such as fetching a non-existing
|
||||
// property name.
|
||||
var ErrNotFound = errors.New("not found")
|
||||
|
||||
type sourceEntry struct {
|
||||
src Source
|
||||
props map[string]string
|
||||
}
|
||||
|
||||
// Config provides methods for retrieving property values from one or more
|
||||
// configuration sources.
|
||||
type Config struct {
|
||||
mutexSrc sync.RWMutex
|
||||
mutexListeners sync.RWMutex
|
||||
srcs []*sourceEntry
|
||||
chgListeners []ChangedListener
|
||||
shutdown chan interface{}
|
||||
wantPanicOnError bool
|
||||
}
|
||||
|
||||
// PrependSource inserts one or more `Sources` at the beginning of
|
||||
// the list of sources such that the first source will be the
|
||||
// source checked first when resolving a property value.
|
||||
func (config *Config) PrependSource(srcs ...Source) {
|
||||
arr := config.wrapSources(srcs...)
|
||||
|
||||
config.mutexSrc.Lock()
|
||||
if config.shutdown == nil {
|
||||
config.shutdown = make(chan interface{})
|
||||
}
|
||||
config.srcs = append(arr, config.srcs...)
|
||||
config.mutexSrc.Unlock()
|
||||
|
||||
for _, se := range arr {
|
||||
if _, ok := se.src.(SourceMonitored); ok {
|
||||
config.monitor(se)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AppendSource appends one or more `Sources` at the end of
|
||||
// the list of sources such that the last source will be the
|
||||
// source checked last when resolving a property value.
|
||||
func (config *Config) AppendSource(srcs ...Source) {
|
||||
arr := config.wrapSources(srcs...)
|
||||
|
||||
config.mutexSrc.Lock()
|
||||
if config.shutdown == nil {
|
||||
config.shutdown = make(chan interface{})
|
||||
}
|
||||
config.srcs = append(config.srcs, arr...)
|
||||
config.mutexSrc.Unlock()
|
||||
|
||||
for _, se := range arr {
|
||||
if _, ok := se.src.(SourceMonitored); ok {
|
||||
config.monitor(se)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wrapSources wraps one or more Source's and returns
|
||||
// them as an array of `sourceEntry`.
|
||||
func (config *Config) wrapSources(srcs ...Source) []*sourceEntry {
|
||||
arr := make([]*sourceEntry, 0, len(srcs))
|
||||
for _, src := range srcs {
|
||||
se := &sourceEntry{src: src}
|
||||
config.reloadProps(se)
|
||||
arr = append(arr, se)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// SetWantPanicOnError sets the flag determining if Config
|
||||
// should panic when `GetProps` or `GetLastModified` errors
|
||||
// for a `Source`.
|
||||
func (config *Config) SetWantPanicOnError(b bool) {
|
||||
config.mutexSrc.Lock()
|
||||
config.wantPanicOnError = b
|
||||
config.mutexSrc.Unlock()
|
||||
}
|
||||
|
||||
// ShouldPanicOnError gets the flag determining if Config
|
||||
// should panic when `GetProps` or `GetLastModified` errors
|
||||
// for a `Source`.
|
||||
func (config *Config) ShouldPanicOnError() (b bool) {
|
||||
config.mutexSrc.RLock()
|
||||
b = config.wantPanicOnError
|
||||
config.mutexSrc.RUnlock()
|
||||
return b
|
||||
}
|
||||
|
||||
// getProp returns the value of a named property.
|
||||
// Each `Source` is checked, in the order created by adding via
|
||||
// `AppendSource` and `PrependSource`, until a value for the
|
||||
// property is found.
|
||||
func (config *Config) getProp(name string) (val string, ok bool) {
|
||||
config.mutexSrc.RLock()
|
||||
defer config.mutexSrc.RUnlock()
|
||||
|
||||
var s string
|
||||
for _, se := range config.srcs {
|
||||
if se.props != nil {
|
||||
if s, ok = se.props[name]; ok {
|
||||
val = strings.TrimSpace(s)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// String returns the value of the named prop as a string.
|
||||
// If the property is not found then the supplied default `def`
|
||||
// and `ErrNotFound` are returned.
|
||||
func (config *Config) String(name string, def string) (val string, err error) {
|
||||
if v, ok := config.getProp(name); ok {
|
||||
val = v
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
err = ErrNotFound
|
||||
val = def
|
||||
return
|
||||
}
|
||||
|
||||
// Int returns the value of the named prop as an `int`.
|
||||
// If the property is not found then the supplied default `def`
|
||||
// and `ErrNotFound` are returned.
|
||||
//
|
||||
// See config.String
|
||||
func (config *Config) Int(name string, def int) (val int, err error) {
|
||||
var s string
|
||||
if s, err = config.String(name, ""); err == nil {
|
||||
var i int64
|
||||
if i, err = strconv.ParseInt(s, 10, 32); err == nil {
|
||||
val = int(i)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
val = def
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Int64 returns the value of the named prop as an `int64`.
|
||||
// If the property is not found then the supplied default `def`
|
||||
// and `ErrNotFound` are returned.
|
||||
//
|
||||
// See config.String
|
||||
func (config *Config) Int64(name string, def int64) (val int64, err error) {
|
||||
var s string
|
||||
if s, err = config.String(name, ""); err == nil {
|
||||
val, err = strconv.ParseInt(s, 10, 64)
|
||||
}
|
||||
if err != nil {
|
||||
val = def
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Float64 returns the value of the named prop as a `float64`.
|
||||
// If the property is not found then the supplied default `def`
|
||||
// and `ErrNotFound` are returned.
|
||||
//
|
||||
// See config.String
|
||||
func (config *Config) Float64(name string, def float64) (val float64, err error) {
|
||||
var s string
|
||||
if s, err = config.String(name, ""); err == nil {
|
||||
val, err = strconv.ParseFloat(s, 64)
|
||||
}
|
||||
if err != nil {
|
||||
val = def
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Bool returns the value of the named prop as a `bool`.
|
||||
// If the property is not found then the supplied default `def`
|
||||
// and `ErrNotFound` are returned.
|
||||
//
|
||||
// Supports (t, true, 1, y, yes) for true, and (f, false, 0, n, no) for false,
|
||||
// all case-insensitive.
|
||||
//
|
||||
// See config.String
|
||||
func (config *Config) Bool(name string, def bool) (val bool, err error) {
|
||||
var s string
|
||||
if s, err = config.String(name, ""); err == nil {
|
||||
switch strings.ToLower(s) {
|
||||
case "t", "true", "1", "y", "yes":
|
||||
val = true
|
||||
case "f", "false", "0", "n", "no":
|
||||
val = false
|
||||
default:
|
||||
err = errors.New("invalid syntax")
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
val = def
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Duration returns the value of the named prop as a `time.Duration`, representing
|
||||
// a span of time.
|
||||
//
|
||||
// Units of measure are supported: ms, sec, min, hour, day, week, year.
|
||||
// See config.UnitsToMillis for a complete list of units supported.
|
||||
//
|
||||
// If the property is not found then the supplied default `def`
|
||||
// and `ErrNotFound` are returned.
|
||||
//
|
||||
// See config.String
|
||||
func (config *Config) Duration(name string, def time.Duration) (val time.Duration, err error) {
|
||||
var s string
|
||||
if s, err = config.String(name, ""); err == nil {
|
||||
var ms int64
|
||||
ms, err = timeconv.ParseMilliseconds(s)
|
||||
val = time.Duration(ms) * time.Millisecond
|
||||
}
|
||||
if err != nil {
|
||||
val = def
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AddChangedListener adds a listener that will receive notifications
|
||||
// whenever one or more property values change within the config.
|
||||
func (config *Config) AddChangedListener(l ChangedListener) {
|
||||
config.mutexListeners.Lock()
|
||||
defer config.mutexListeners.Unlock()
|
||||
|
||||
config.chgListeners = append(config.chgListeners, l)
|
||||
}
|
||||
|
||||
// RemoveChangedListener removes all instances of a ChangedListener.
|
||||
// Returns `ErrNotFound` if the listener was not present.
|
||||
func (config *Config) RemoveChangedListener(l ChangedListener) error {
|
||||
config.mutexListeners.Lock()
|
||||
defer config.mutexListeners.Unlock()
|
||||
|
||||
dest := make([]ChangedListener, 0, len(config.chgListeners))
|
||||
err := ErrNotFound
|
||||
|
||||
// Remove all instances of the listener by
|
||||
// copying list while filtering.
|
||||
for _, s := range config.chgListeners {
|
||||
if s != l {
|
||||
dest = append(dest, s)
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
config.chgListeners = dest
|
||||
return err
|
||||
}
|
||||
|
||||
// Shutdown can be called to stop monitoring of all config sources.
|
||||
func (config *Config) Shutdown() {
|
||||
config.mutexSrc.RLock()
|
||||
defer config.mutexSrc.RUnlock()
|
||||
if config.shutdown != nil {
|
||||
close(config.shutdown)
|
||||
}
|
||||
}
|
||||
|
||||
// onSourceChanged is called whenever one or more properties of a
|
||||
// config source has changed.
|
||||
func (config *Config) onSourceChanged(src SourceMonitored) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
fmt.Println(p)
|
||||
}
|
||||
}()
|
||||
config.mutexListeners.RLock()
|
||||
defer config.mutexListeners.RUnlock()
|
||||
for _, l := range config.chgListeners {
|
||||
l.ConfigChanged(config, src)
|
||||
}
|
||||
}
|
||||
|
||||
// monitor periodically checks a config source for changes.
|
||||
func (config *Config) monitor(se *sourceEntry) {
|
||||
go func(se *sourceEntry, shutdown <-chan interface{}) {
|
||||
var src SourceMonitored
|
||||
var ok bool
|
||||
if src, ok = se.src.(SourceMonitored); !ok {
|
||||
return
|
||||
}
|
||||
paused := false
|
||||
last := time.Time{}
|
||||
freq := src.GetMonitorFreq()
|
||||
if freq <= 0 {
|
||||
paused = true
|
||||
freq = 10
|
||||
last, _ = src.GetLastModified()
|
||||
}
|
||||
timer := time.NewTimer(freq)
|
||||
for {
|
||||
select {
|
||||
case <-timer.C:
|
||||
if !paused {
|
||||
if latest, err := src.GetLastModified(); err != nil {
|
||||
if config.ShouldPanicOnError() {
|
||||
panic(fmt.Sprintf("error <%v> getting last modified for %v", err, src))
|
||||
}
|
||||
} else {
|
||||
if last.Before(latest) {
|
||||
last = latest
|
||||
config.reloadProps(se)
|
||||
// TODO: calc diff and provide detailed changes
|
||||
config.onSourceChanged(src)
|
||||
}
|
||||
}
|
||||
}
|
||||
freq = src.GetMonitorFreq()
|
||||
if freq <= 0 {
|
||||
paused = true
|
||||
freq = 10
|
||||
} else {
|
||||
paused = false
|
||||
}
|
||||
timer.Reset(freq)
|
||||
case <-shutdown:
|
||||
// stop the timer and exit
|
||||
if !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}(se, config.shutdown)
|
||||
}
|
||||
|
||||
// reloadProps causes a Source to reload its properties.
|
||||
func (config *Config) reloadProps(se *sourceEntry) {
|
||||
config.mutexSrc.Lock()
|
||||
defer config.mutexSrc.Unlock()
|
||||
|
||||
m, err := se.src.GetProps()
|
||||
if err != nil {
|
||||
if config.wantPanicOnError {
|
||||
panic(fmt.Sprintf("GetProps error for %v", se.src))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
se.props = make(map[string]string)
|
||||
for k, v := range m {
|
||||
se.props[k] = v
|
||||
}
|
||||
}
|
5
vendor/github.com/wiggin77/cfg/go.mod
generated
vendored
Normal file
5
vendor/github.com/wiggin77/cfg/go.mod
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
module github.com/wiggin77/cfg
|
||||
|
||||
go 1.12
|
||||
|
||||
require github.com/wiggin77/merror v1.0.2
|
2
vendor/github.com/wiggin77/cfg/go.sum
generated
vendored
Normal file
2
vendor/github.com/wiggin77/cfg/go.sum
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
github.com/wiggin77/merror v1.0.2 h1:V0nH9eFp64ASyaXC+pB5WpvBoCg7NUwvaCSKdzlcHqw=
|
||||
github.com/wiggin77/merror v1.0.2/go.mod h1:uQTcIU0Z6jRK4OwqganPYerzQxSFJ4GSHM3aurxxQpg=
|
167
vendor/github.com/wiggin77/cfg/ini/ini.go
generated
vendored
Normal file
167
vendor/github.com/wiggin77/cfg/ini/ini.go
generated
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
package ini
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Ini provides parsing and querying of INI format or simple name/value pairs
|
||||
// such as a simple config file.
|
||||
// A name/value pair format is just an INI with no sections, and properties can
|
||||
// be queried using an empty section name.
|
||||
type Ini struct {
|
||||
mutex sync.RWMutex
|
||||
m map[string]*Section
|
||||
lm time.Time
|
||||
}
|
||||
|
||||
// LoadFromFilespec loads an INI file from string containing path and filename.
|
||||
func (ini *Ini) LoadFromFilespec(filespec string) error {
|
||||
f, err := os.Open(filespec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ini.LoadFromFile(f)
|
||||
}
|
||||
|
||||
// LoadFromFile loads an INI file from `os.File`.
|
||||
func (ini *Ini) LoadFromFile(file *os.File) error {
|
||||
|
||||
fi, err := file.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lm := fi.ModTime()
|
||||
|
||||
if err := ini.LoadFromReader(file); err != nil {
|
||||
return err
|
||||
}
|
||||
ini.lm = lm
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadFromReader loads an INI file from an `io.Reader`.
|
||||
func (ini *Ini) LoadFromReader(reader io.Reader) error {
|
||||
data, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ini.LoadFromString(string(data))
|
||||
}
|
||||
|
||||
// LoadFromString parses an INI from a string .
|
||||
func (ini *Ini) LoadFromString(s string) error {
|
||||
m, err := getSections(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ini.mutex.Lock()
|
||||
ini.m = m
|
||||
ini.lm = time.Now()
|
||||
ini.mutex.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLastModified returns the last modified timestamp of the
|
||||
// INI contents.
|
||||
func (ini *Ini) GetLastModified() time.Time {
|
||||
return ini.lm
|
||||
}
|
||||
|
||||
// GetSectionNames returns the names of all sections in this INI.
|
||||
// Note, the returned section names are a snapshot in time, meaning
|
||||
// other goroutines may change the contents of this INI as soon as
|
||||
// the method returns.
|
||||
func (ini *Ini) GetSectionNames() []string {
|
||||
ini.mutex.RLock()
|
||||
defer ini.mutex.RUnlock()
|
||||
|
||||
arr := make([]string, 0, len(ini.m))
|
||||
for key := range ini.m {
|
||||
arr = append(arr, key)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// GetKeys returns the names of all keys in the specified section.
|
||||
// Note, the returned key names are a snapshot in time, meaning other
|
||||
// goroutines may change the contents of this INI as soon as the
|
||||
// method returns.
|
||||
func (ini *Ini) GetKeys(sectionName string) ([]string, error) {
|
||||
sec, err := ini.getSection(sectionName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sec.getKeys(), nil
|
||||
}
|
||||
|
||||
// getSection returns the named section.
|
||||
func (ini *Ini) getSection(sectionName string) (*Section, error) {
|
||||
ini.mutex.RLock()
|
||||
defer ini.mutex.RUnlock()
|
||||
|
||||
sec, ok := ini.m[sectionName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("section '%s' not found", sectionName)
|
||||
}
|
||||
return sec, nil
|
||||
}
|
||||
|
||||
// GetFlattenedKeys returns all section names plus keys as one
|
||||
// flattened array.
|
||||
func (ini *Ini) GetFlattenedKeys() []string {
|
||||
ini.mutex.RLock()
|
||||
defer ini.mutex.RUnlock()
|
||||
|
||||
arr := make([]string, 0, len(ini.m)*2)
|
||||
for _, section := range ini.m {
|
||||
keys := section.getKeys()
|
||||
for _, key := range keys {
|
||||
name := section.GetName()
|
||||
if name != "" {
|
||||
key = name + "." + key
|
||||
}
|
||||
arr = append(arr, key)
|
||||
}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// GetProp returns the value of the specified key in the named section.
|
||||
func (ini *Ini) GetProp(section string, key string) (val string, ok bool) {
|
||||
sec, err := ini.getSection(section)
|
||||
if err != nil {
|
||||
return val, false
|
||||
}
|
||||
return sec.GetProp(key)
|
||||
}
|
||||
|
||||
// ToMap returns a flattened map of the section name plus keys mapped
|
||||
// to values.
|
||||
func (ini *Ini) ToMap() map[string]string {
|
||||
m := make(map[string]string)
|
||||
|
||||
ini.mutex.RLock()
|
||||
defer ini.mutex.RUnlock()
|
||||
|
||||
for _, section := range ini.m {
|
||||
for _, key := range section.getKeys() {
|
||||
val, ok := section.GetProp(key)
|
||||
if ok {
|
||||
name := section.GetName()
|
||||
var mapkey string
|
||||
if name != "" {
|
||||
mapkey = name + "." + key
|
||||
} else {
|
||||
mapkey = key
|
||||
}
|
||||
m[mapkey] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
142
vendor/github.com/wiggin77/cfg/ini/parser.go
generated
vendored
Normal file
142
vendor/github.com/wiggin77/cfg/ini/parser.go
generated
vendored
Normal file
@ -0,0 +1,142 @@
|
||||
package ini
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/wiggin77/merror"
|
||||
)
|
||||
|
||||
// LF is linefeed
|
||||
const LF byte = 0x0A
|
||||
|
||||
// CR is carriage return
|
||||
const CR byte = 0x0D
|
||||
|
||||
// getSections parses an INI formatted string, or string containing just name/value pairs,
|
||||
// returns map of `Section`'s.
|
||||
//
|
||||
// Any name/value pairs appearing before a section name are added to the section named
|
||||
// with an empty string (""). Also true for Linux-style config files where all props
|
||||
// are outside a named section.
|
||||
//
|
||||
// Any errors encountered are aggregated and returned, along with the partially parsed
|
||||
// sections.
|
||||
func getSections(str string) (map[string]*Section, error) {
|
||||
merr := merror.New()
|
||||
mapSections := make(map[string]*Section)
|
||||
lines := buildLineArray(str)
|
||||
section := newSection("")
|
||||
|
||||
for _, line := range lines {
|
||||
name, ok := parseSection(line)
|
||||
if ok {
|
||||
// A section name encountered. Stop processing the current one.
|
||||
// Don't add the current section to the map if the section name is blank
|
||||
// and the prop map is empty.
|
||||
nameCurr := section.GetName()
|
||||
if nameCurr != "" || section.hasKeys() {
|
||||
mapSections[nameCurr] = section
|
||||
}
|
||||
// Start processing a new section.
|
||||
section = newSection(name)
|
||||
} else {
|
||||
// Parse the property and add to the current section, or ignore if comment.
|
||||
if k, v, comment, err := parseProp(line); !comment && err == nil {
|
||||
section.setProp(k, v)
|
||||
} else if err != nil {
|
||||
merr.Append(err) // aggregate errors
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// If the current section is not empty, add it.
|
||||
if section.hasKeys() {
|
||||
mapSections[section.GetName()] = section
|
||||
}
|
||||
return mapSections, merr.ErrorOrNil()
|
||||
}
|
||||
|
||||
// buildLineArray parses the given string buffer and creates a list of strings,
|
||||
// one for each line in the string buffer.
|
||||
//
|
||||
// A line is considered to be terminated by any one of a line feed ('\n'),
|
||||
// a carriage return ('\r'), or a carriage return followed immediately by a
|
||||
// linefeed.
|
||||
//
|
||||
// Lines prefixed with ';' or '#' are considered comments and skipped.
|
||||
func buildLineArray(str string) []string {
|
||||
arr := make([]string, 0, 10)
|
||||
str = str + "\n"
|
||||
|
||||
iLen := len(str)
|
||||
iPos, iBegin := 0, 0
|
||||
var ch byte
|
||||
|
||||
for iPos < iLen {
|
||||
ch = str[iPos]
|
||||
if ch == LF || ch == CR {
|
||||
sub := str[iBegin:iPos]
|
||||
sub = strings.TrimSpace(sub)
|
||||
if sub != "" && !strings.HasPrefix(sub, ";") && !strings.HasPrefix(sub, "#") {
|
||||
arr = append(arr, sub)
|
||||
}
|
||||
iPos++
|
||||
if ch == CR && iPos < iLen && str[iPos] == LF {
|
||||
iPos++
|
||||
}
|
||||
iBegin = iPos
|
||||
} else {
|
||||
iPos++
|
||||
}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// parseSection parses the specified string for a section name enclosed in square brackets.
|
||||
// Returns the section name found, or `ok=false` if `str` is not a section header.
|
||||
func parseSection(str string) (name string, ok bool) {
|
||||
str = strings.TrimSpace(str)
|
||||
if !strings.HasPrefix(str, "[") {
|
||||
return "", false
|
||||
}
|
||||
iCloser := strings.Index(str, "]")
|
||||
if iCloser == -1 {
|
||||
return "", false
|
||||
}
|
||||
return strings.TrimSpace(str[1:iCloser]), true
|
||||
}
|
||||
|
||||
// parseProp parses the specified string and extracts a key/value pair.
|
||||
//
|
||||
// If the string is a comment (prefixed with ';' or '#') then `comment=true`
|
||||
// and key will be empty.
|
||||
func parseProp(str string) (key string, val string, comment bool, err error) {
|
||||
iLen := len(str)
|
||||
iEqPos := strings.Index(str, "=")
|
||||
if iEqPos == -1 {
|
||||
return "", "", false, fmt.Errorf("not a key/value pair:'%s'", str)
|
||||
}
|
||||
|
||||
key = str[0:iEqPos]
|
||||
key = strings.TrimSpace(key)
|
||||
if iEqPos+1 < iLen {
|
||||
val = str[iEqPos+1:]
|
||||
val = strings.TrimSpace(val)
|
||||
}
|
||||
|
||||
// Check that the key has at least 1 char.
|
||||
if key == "" {
|
||||
return "", "", false, fmt.Errorf("key is empty for '%s'", str)
|
||||
}
|
||||
|
||||
// Check if this line is a comment that just happens
|
||||
// to have an equals sign in it. Not an error, but not a
|
||||
// useable line either.
|
||||
if strings.HasPrefix(key, ";") || strings.HasPrefix(key, "#") {
|
||||
key = ""
|
||||
val = ""
|
||||
comment = true
|
||||
}
|
||||
return key, val, comment, err
|
||||
}
|
109
vendor/github.com/wiggin77/cfg/ini/section.go
generated
vendored
Normal file
109
vendor/github.com/wiggin77/cfg/ini/section.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
package ini
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Section represents a section in an INI file. The section has a name, which is
|
||||
// enclosed in square brackets in the file. The section also has an array of
|
||||
// key/value pairs.
|
||||
type Section struct {
|
||||
name string
|
||||
props map[string]string
|
||||
mtx sync.RWMutex
|
||||
}
|
||||
|
||||
func newSection(name string) *Section {
|
||||
sec := &Section{}
|
||||
sec.name = name
|
||||
sec.props = make(map[string]string)
|
||||
return sec
|
||||
}
|
||||
|
||||
// addLines addes an array of strings containing name/value pairs
|
||||
// of the format `key=value`.
|
||||
//func addLines(lines []string) {
|
||||
// TODO
|
||||
//}
|
||||
|
||||
// GetName returns the name of the section.
|
||||
func (sec *Section) GetName() (name string) {
|
||||
sec.mtx.RLock()
|
||||
name = sec.name
|
||||
sec.mtx.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// GetProp returns the value associated with the given key, or
|
||||
// `ok=false` if key does not exist.
|
||||
func (sec *Section) GetProp(key string) (val string, ok bool) {
|
||||
sec.mtx.RLock()
|
||||
val, ok = sec.props[key]
|
||||
sec.mtx.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// SetProp sets the value associated with the given key.
|
||||
func (sec *Section) setProp(key string, val string) {
|
||||
sec.mtx.Lock()
|
||||
sec.props[key] = val
|
||||
sec.mtx.Unlock()
|
||||
}
|
||||
|
||||
// hasKeys returns true if there are one or more properties in
|
||||
// this section.
|
||||
func (sec *Section) hasKeys() (b bool) {
|
||||
sec.mtx.RLock()
|
||||
b = len(sec.props) > 0
|
||||
sec.mtx.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// getKeys returns an array containing all keys in this section.
|
||||
func (sec *Section) getKeys() []string {
|
||||
sec.mtx.RLock()
|
||||
defer sec.mtx.RUnlock()
|
||||
|
||||
arr := make([]string, len(sec.props))
|
||||
idx := 0
|
||||
for k := range sec.props {
|
||||
arr[idx] = k
|
||||
idx++
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// combine the given section with this one.
|
||||
func (sec *Section) combine(sec2 *Section) {
|
||||
sec.mtx.Lock()
|
||||
sec2.mtx.RLock()
|
||||
defer sec.mtx.Unlock()
|
||||
defer sec2.mtx.RUnlock()
|
||||
|
||||
for k, v := range sec2.props {
|
||||
sec.props[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a string representation of this section.
|
||||
func (sec *Section) String() string {
|
||||
return fmt.Sprintf("[%s]\n%s", sec.GetName(), sec.StringPropsOnly())
|
||||
}
|
||||
|
||||
// StringPropsOnly returns a string representation of this section
|
||||
// without the section header.
|
||||
func (sec *Section) StringPropsOnly() string {
|
||||
sec.mtx.RLock()
|
||||
defer sec.mtx.RUnlock()
|
||||
sb := &strings.Builder{}
|
||||
|
||||
for k, v := range sec.props {
|
||||
sb.WriteString(k)
|
||||
sb.WriteString("=")
|
||||
sb.WriteString(v)
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
return sb.String()
|
||||
}
|
11
vendor/github.com/wiggin77/cfg/listener.go
generated
vendored
Normal file
11
vendor/github.com/wiggin77/cfg/listener.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
package cfg
|
||||
|
||||
// ChangedListener interface is for receiving notifications
|
||||
// when one or more properties within monitored config sources
|
||||
// (SourceMonitored) have changed values.
|
||||
type ChangedListener interface {
|
||||
|
||||
// Changed is called when one or more properties in a `SourceMonitored` has a
|
||||
// changed value.
|
||||
ConfigChanged(cfg *Config, src SourceMonitored)
|
||||
}
|
11
vendor/github.com/wiggin77/cfg/nocopy.go
generated
vendored
Normal file
11
vendor/github.com/wiggin77/cfg/nocopy.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
package cfg
|
||||
|
||||
// noCopy may be embedded into structs which must not be copied
|
||||
// after the first use.
|
||||
//
|
||||
// See https://golang.org/issues/8005#issuecomment-190753527
|
||||
// for details.
|
||||
type noCopy struct{}
|
||||
|
||||
// Lock is a no-op used by -copylocks checker from `go vet`.
|
||||
func (*noCopy) Lock() {}
|
58
vendor/github.com/wiggin77/cfg/source.go
generated
vendored
Normal file
58
vendor/github.com/wiggin77/cfg/source.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Source is the interface required for any source of name/value pairs.
|
||||
type Source interface {
|
||||
|
||||
// GetProps fetches all the properties from a source and returns
|
||||
// them as a map.
|
||||
GetProps() (map[string]string, error)
|
||||
}
|
||||
|
||||
// SourceMonitored is the interface required for any config source that is
|
||||
// monitored for changes.
|
||||
type SourceMonitored interface {
|
||||
Source
|
||||
|
||||
// GetLastModified returns the time of the latest modification to any
|
||||
// property value within the source. If a source does not support
|
||||
// modifying properties at runtime then the zero value for `Time`
|
||||
// should be returned to ensure reload events are not generated.
|
||||
GetLastModified() (time.Time, error)
|
||||
|
||||
// GetMonitorFreq returns the frequency as a `time.Duration` between
|
||||
// checks for changes to this config source.
|
||||
//
|
||||
// Returning zero (or less) will temporarily suspend calls to `GetLastModified`
|
||||
// and `GetMonitorFreq` will be called every 10 seconds until resumed, after which
|
||||
// `GetMontitorFreq` will be called at a frequency roughly equal to the `time.Duration`
|
||||
// returned.
|
||||
GetMonitorFreq() time.Duration
|
||||
}
|
||||
|
||||
// AbstractSourceMonitor can be embedded in a custom `Source` to provide the
|
||||
// basic plumbing for monitor frequency.
|
||||
type AbstractSourceMonitor struct {
|
||||
mutex sync.RWMutex
|
||||
freq time.Duration
|
||||
}
|
||||
|
||||
// GetMonitorFreq returns the frequency as a `time.Duration` between
|
||||
// checks for changes to this config source.
|
||||
func (asm *AbstractSourceMonitor) GetMonitorFreq() (freq time.Duration) {
|
||||
asm.mutex.RLock()
|
||||
freq = asm.freq
|
||||
asm.mutex.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// SetMonitorFreq sets the frequency between checks for changes to this config source.
|
||||
func (asm *AbstractSourceMonitor) SetMonitorFreq(freq time.Duration) {
|
||||
asm.mutex.Lock()
|
||||
asm.freq = freq
|
||||
asm.mutex.Unlock()
|
||||
}
|
63
vendor/github.com/wiggin77/cfg/srcfile.go
generated
vendored
Normal file
63
vendor/github.com/wiggin77/cfg/srcfile.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/wiggin77/cfg/ini"
|
||||
)
|
||||
|
||||
// SrcFile is a configuration `Source` backed by a file containing
|
||||
// name/value pairs or INI format.
|
||||
type SrcFile struct {
|
||||
AbstractSourceMonitor
|
||||
ini ini.Ini
|
||||
file *os.File
|
||||
}
|
||||
|
||||
// NewSrcFileFromFilespec creates a new SrcFile with the specified filespec.
|
||||
func NewSrcFileFromFilespec(filespec string) (*SrcFile, error) {
|
||||
file, err := os.Open(filespec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewSrcFile(file)
|
||||
}
|
||||
|
||||
// NewSrcFile creates a new SrcFile with the specified os.File.
|
||||
func NewSrcFile(file *os.File) (*SrcFile, error) {
|
||||
sf := &SrcFile{}
|
||||
sf.freq = time.Minute
|
||||
sf.file = file
|
||||
if err := sf.ini.LoadFromFile(file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sf, nil
|
||||
}
|
||||
|
||||
// GetProps fetches all the properties from a source and returns
|
||||
// them as a map.
|
||||
func (sf *SrcFile) GetProps() (map[string]string, error) {
|
||||
lm, err := sf.GetLastModified()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check if we need to reload.
|
||||
if sf.ini.GetLastModified() != lm {
|
||||
if err := sf.ini.LoadFromFile(sf.file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return sf.ini.ToMap(), nil
|
||||
}
|
||||
|
||||
// GetLastModified returns the time of the latest modification to any
|
||||
// property value within the source.
|
||||
func (sf *SrcFile) GetLastModified() (time.Time, error) {
|
||||
fi, err := sf.file.Stat()
|
||||
if err != nil {
|
||||
return time.Now(), err
|
||||
}
|
||||
return fi.ModTime(), nil
|
||||
}
|
78
vendor/github.com/wiggin77/cfg/srcmap.go
generated
vendored
Normal file
78
vendor/github.com/wiggin77/cfg/srcmap.go
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// SrcMap is a configuration `Source` backed by a simple map.
|
||||
type SrcMap struct {
|
||||
AbstractSourceMonitor
|
||||
m map[string]string
|
||||
lm time.Time
|
||||
}
|
||||
|
||||
// NewSrcMap creates an empty `SrcMap`.
|
||||
func NewSrcMap() *SrcMap {
|
||||
sm := &SrcMap{}
|
||||
sm.m = make(map[string]string)
|
||||
sm.lm = time.Now()
|
||||
sm.freq = time.Minute
|
||||
return sm
|
||||
}
|
||||
|
||||
// NewSrcMapFromMap creates a `SrcMap` containing a copy of the
|
||||
// specified map.
|
||||
func NewSrcMapFromMap(mapIn map[string]string) *SrcMap {
|
||||
sm := NewSrcMap()
|
||||
sm.PutAll(mapIn)
|
||||
return sm
|
||||
}
|
||||
|
||||
// Put inserts or updates a value in the `SrcMap`.
|
||||
func (sm *SrcMap) Put(key string, val string) {
|
||||
sm.mutex.Lock()
|
||||
sm.m[key] = val
|
||||
sm.lm = time.Now()
|
||||
sm.mutex.Unlock()
|
||||
}
|
||||
|
||||
// PutAll inserts a copy of `mapIn` into the `SrcMap`
|
||||
func (sm *SrcMap) PutAll(mapIn map[string]string) {
|
||||
sm.mutex.Lock()
|
||||
defer sm.mutex.Unlock()
|
||||
|
||||
for k, v := range mapIn {
|
||||
sm.m[k] = v
|
||||
}
|
||||
sm.lm = time.Now()
|
||||
}
|
||||
|
||||
// GetProps fetches all the properties from a source and returns
|
||||
// them as a map.
|
||||
func (sm *SrcMap) GetProps() (m map[string]string, err error) {
|
||||
sm.mutex.RLock()
|
||||
m = sm.m
|
||||
sm.mutex.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// GetLastModified returns the time of the latest modification to any
|
||||
// property value within the source. If a source does not support
|
||||
// modifying properties at runtime then the zero value for `Time`
|
||||
// should be returned to ensure reload events are not generated.
|
||||
func (sm *SrcMap) GetLastModified() (last time.Time, err error) {
|
||||
sm.mutex.RLock()
|
||||
last = sm.lm
|
||||
sm.mutex.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// GetMonitorFreq returns the frequency as a `time.Duration` between
|
||||
// checks for changes to this config source. Defaults to 1 minute
|
||||
// unless changed with `SetMonitorFreq`.
|
||||
func (sm *SrcMap) GetMonitorFreq() (freq time.Duration) {
|
||||
sm.mutex.RLock()
|
||||
freq = sm.freq
|
||||
sm.mutex.RUnlock()
|
||||
return
|
||||
}
|
108
vendor/github.com/wiggin77/cfg/timeconv/parse.go
generated
vendored
Normal file
108
vendor/github.com/wiggin77/cfg/timeconv/parse.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
package timeconv
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MillisPerSecond is the number of millseconds per second.
|
||||
const MillisPerSecond int64 = 1000
|
||||
|
||||
// MillisPerMinute is the number of millseconds per minute.
|
||||
const MillisPerMinute int64 = MillisPerSecond * 60
|
||||
|
||||
// MillisPerHour is the number of millseconds per hour.
|
||||
const MillisPerHour int64 = MillisPerMinute * 60
|
||||
|
||||
// MillisPerDay is the number of millseconds per day.
|
||||
const MillisPerDay int64 = MillisPerHour * 24
|
||||
|
||||
// MillisPerWeek is the number of millseconds per week.
|
||||
const MillisPerWeek int64 = MillisPerDay * 7
|
||||
|
||||
// MillisPerYear is the approximate number of millseconds per year.
|
||||
const MillisPerYear int64 = MillisPerDay*365 + int64((float64(MillisPerDay) * 0.25))
|
||||
|
||||
// ParseMilliseconds parses a string containing a number plus
|
||||
// a unit of measure for time and returns the number of milliseconds
|
||||
// it represents.
|
||||
//
|
||||
// Example:
|
||||
// * "1 second" returns 1000
|
||||
// * "1 minute" returns 60000
|
||||
// * "1 hour" returns 3600000
|
||||
//
|
||||
// See config.UnitsToMillis for a list of supported units of measure.
|
||||
func ParseMilliseconds(str string) (int64, error) {
|
||||
s := strings.TrimSpace(str)
|
||||
reg := regexp.MustCompile("([0-9\\.\\-+]*)(.*)")
|
||||
matches := reg.FindStringSubmatch(s)
|
||||
if matches == nil || len(matches) < 1 || matches[1] == "" {
|
||||
return 0, fmt.Errorf("invalid syntax - '%s'", s)
|
||||
}
|
||||
digits := matches[1]
|
||||
units := "ms"
|
||||
if len(matches) > 1 && matches[2] != "" {
|
||||
units = matches[2]
|
||||
}
|
||||
|
||||
fDigits, err := strconv.ParseFloat(digits, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
msPerUnit, err := UnitsToMillis(units)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Check for overflow.
|
||||
fms := float64(msPerUnit) * fDigits
|
||||
if fms > math.MaxInt64 || fms < math.MinInt64 {
|
||||
return 0, fmt.Errorf("out of range - '%s' overflows", s)
|
||||
}
|
||||
ms := int64(fms)
|
||||
return ms, nil
|
||||
}
|
||||
|
||||
// UnitsToMillis returns the number of milliseconds represented by the specified unit of measure.
|
||||
//
|
||||
// Example:
|
||||
// * "second" returns 1000 <br/>
|
||||
// * "minute" returns 60000 <br/>
|
||||
// * "hour" returns 3600000 <br/>
|
||||
//
|
||||
// Supported units of measure:
|
||||
// * "milliseconds", "millis", "ms", "millisecond"
|
||||
// * "seconds", "sec", "s", "second"
|
||||
// * "minutes", "mins", "min", "m", "minute"
|
||||
// * "hours", "h", "hour"
|
||||
// * "days", "d", "day"
|
||||
// * "weeks", "w", "week"
|
||||
// * "years", "y", "year"
|
||||
func UnitsToMillis(units string) (ms int64, err error) {
|
||||
u := strings.TrimSpace(units)
|
||||
u = strings.ToLower(u)
|
||||
switch u {
|
||||
case "milliseconds", "millisecond", "millis", "ms":
|
||||
ms = 1
|
||||
case "seconds", "second", "sec", "s":
|
||||
ms = MillisPerSecond
|
||||
case "minutes", "minute", "mins", "min", "m":
|
||||
ms = MillisPerMinute
|
||||
case "hours", "hour", "h":
|
||||
ms = MillisPerHour
|
||||
case "days", "day", "d":
|
||||
ms = MillisPerDay
|
||||
case "weeks", "week", "w":
|
||||
ms = MillisPerWeek
|
||||
case "years", "year", "y":
|
||||
ms = MillisPerYear
|
||||
default:
|
||||
err = fmt.Errorf("invalid syntax - '%s' not a supported unit of measure", u)
|
||||
}
|
||||
return
|
||||
}
|
Reference in New Issue
Block a user