4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-07-03 06:07:45 +00:00

Update vendor (#1265)

This commit is contained in:
Wim
2020-10-19 23:40:00 +02:00
committed by GitHub
parent 950f2759bd
commit 075a84427f
242 changed files with 22338 additions and 1486 deletions

12
vendor/github.com/wiggin77/cfg/.gitignore generated vendored Normal file
View 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
View File

@ -0,0 +1,5 @@
language: go
sudo: false
before_script:
- go vet ./...

21
vendor/github.com/wiggin77/cfg/LICENSE generated vendored Normal file
View 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
View File

@ -0,0 +1,43 @@
# cfg
[![GoDoc](https://godoc.org/github.com/wiggin77/cfg?status.svg)](https://godoc.org/github.com/wiggin77/cfg)
[![Build Status](https://travis-ci.org/wiggin77/cfg.svg?branch=master)](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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
}

12
vendor/github.com/wiggin77/merror/.gitignore generated vendored Normal file
View 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

21
vendor/github.com/wiggin77/merror/LICENSE generated vendored Normal file
View 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.

2
vendor/github.com/wiggin77/merror/README.md generated vendored Normal file
View File

@ -0,0 +1,2 @@
# merror
Multiple Error aggregator for Golang.

43
vendor/github.com/wiggin77/merror/format.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
package merror
import (
"fmt"
"strings"
)
// FormatterFunc is a function that converts a merror
// to a string.
type FormatterFunc func(merr *MError) string
// GlobalFormatter is the global merror formatter.
// Set this to a custom formatter if desired.
var GlobalFormatter = defaultFormatter
// defaultFormatter
func defaultFormatter(merr *MError) string {
count := 0
overflow := 0
var format func(sb *strings.Builder, merr *MError, indent string)
format = func(sb *strings.Builder, merr *MError, indent string) {
count += merr.Len()
overflow += merr.Overflow()
fmt.Fprintf(sb, "%sMError:\n", indent)
for _, err := range merr.Errors() {
if e, ok := err.(*MError); ok {
format(sb, e, indent+" ")
} else {
fmt.Fprintf(sb, "%s%s\n", indent, err.Error())
}
}
}
sb := &strings.Builder{}
format(sb, merr, "")
fmt.Fprintf(sb, "%d errors total.\n", count)
if merr.overflow > 0 {
fmt.Fprintf(sb, "%d errors truncated.\n", overflow)
}
return sb.String()
}

1
vendor/github.com/wiggin77/merror/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/wiggin77/merror

87
vendor/github.com/wiggin77/merror/merror.go generated vendored Normal file
View File

@ -0,0 +1,87 @@
package merror
// MError represents zero or more errors that can be
// accumulated via the `Append` method.
type MError struct {
cap int
errors []error
overflow int
formatter FormatterFunc
}
// New returns a new instance of `MError` with no limit on the
// number of errors that can be appended.
func New() *MError {
me := &MError{}
me.errors = make([]error, 0, 10)
return me
}
// NewWithCap returns a new instance of `MError` with a maximum
// capacity of `cap` errors. If exceeded only the overflow counter
// will be incremented.
//
// A `cap` of zero of less means no cap and max size of a slice
// on the current platform is the upper bound.
func NewWithCap(cap int) *MError {
me := New()
me.cap = cap
return me
}
// Append adds an error to the aggregated error list.
func (me *MError) Append(err error) {
if err == nil {
return
}
if me.cap > 0 && len(me.errors) >= me.cap {
me.overflow++
} else {
me.errors = append(me.errors, err)
}
}
// Errors returns an array of the `error` instances that have been
// appended to this `MError`.
func (me *MError) Errors() []error {
return me.errors
}
// Len returns the number of errors that have been appended.
func (me *MError) Len() int {
return len(me.errors)
}
// Overflow returns the number of errors that have been truncated
// because maximum capacity was exceeded.
func (me *MError) Overflow() int {
return me.overflow
}
// SetFormatter sets the `FormatterFunc` to be used when `Error` is
// called. The previous `FormatterFunc` is returned.
func (me *MError) SetFormatter(f FormatterFunc) (old FormatterFunc) {
old = me.formatter
me.formatter = f
return
}
// ErrorOrNil returns nil if this `MError` contains no errors,
// otherwise this `MError` is returned.
func (me *MError) ErrorOrNil() error {
if me == nil || len(me.errors) == 0 {
return nil
}
return me
}
// Error returns a string representation of this MError.
// The output format depends on the `Formatter` set for this
// merror instance, or the global formatter if none set.
func (me *MError) Error() string {
f := me.formatter
if f == nil {
f = GlobalFormatter
}
return f(me)
}

1
vendor/github.com/wiggin77/srslog/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
.cover

15
vendor/github.com/wiggin77/srslog/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,15 @@
sudo: required
dist: trusty
group: edge
language: go
go:
- 1.5
before_install:
- pip install --user codecov
script:
- |
go get ./...
go test -v -coverprofile=coverage.txt -covermode=atomic
go vet
after_success:
- codecov

50
vendor/github.com/wiggin77/srslog/CODE_OF_CONDUCT.md generated vendored Normal file
View File

@ -0,0 +1,50 @@
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to
fairly and consistently applying these principles to every aspect of managing
this project. Project maintainers who do not follow or enforce the Code of
Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting a project maintainer at [sirsean@gmail.com]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. Maintainers are
obligated to maintain confidentiality with regard to the reporter of an
incident.
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/

27
vendor/github.com/wiggin77/srslog/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2015 Rackspace. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

147
vendor/github.com/wiggin77/srslog/README.md generated vendored Normal file
View File

@ -0,0 +1,147 @@
[![Build Status](https://travis-ci.org/RackSec/srslog.svg?branch=master)](https://travis-ci.org/RackSec/srslog)
# srslog
Go has a `syslog` package in the standard library, but it has the following
shortcomings:
1. It doesn't have TLS support
2. [According to bradfitz on the Go team, it is no longer being maintained.](https://github.com/golang/go/issues/13449#issuecomment-161204716)
I agree that it doesn't need to be in the standard library. So, I've
followed Brad's suggestion and have made a separate project to handle syslog.
This code was taken directly from the Go project as a base to start from.
However, this _does_ have TLS support.
# Usage
Basic usage retains the same interface as the original `syslog` package. We
only added to the interface where required to support new functionality.
Switch from the standard library:
```
import(
//"log/syslog"
syslog "github.com/RackSec/srslog"
)
```
You can still use it for local syslog:
```
w, err := syslog.Dial("", "", syslog.LOG_ERR, "testtag")
```
Or to unencrypted UDP:
```
w, err := syslog.Dial("udp", "192.168.0.50:514", syslog.LOG_ERR, "testtag")
```
Or to unencrypted TCP:
```
w, err := syslog.Dial("tcp", "192.168.0.51:514", syslog.LOG_ERR, "testtag")
```
But now you can also send messages via TLS-encrypted TCP:
```
w, err := syslog.DialWithTLSCertPath("tcp+tls", "192.168.0.52:514", syslog.LOG_ERR, "testtag", "/path/to/servercert.pem")
```
And if you need more control over your TLS configuration :
```
pool := x509.NewCertPool()
serverCert, err := ioutil.ReadFile("/path/to/servercert.pem")
if err != nil {
return nil, err
}
pool.AppendCertsFromPEM(serverCert)
config := tls.Config{
RootCAs: pool,
}
w, err := DialWithTLSConfig(network, raddr, priority, tag, &config)
```
(Note that in both TLS cases, this uses a self-signed certificate, where the
remote syslog server has the keypair and the client has only the public key.)
And then to write log messages, continue like so:
```
if err != nil {
log.Fatal("failed to connect to syslog:", err)
}
defer w.Close()
w.Alert("this is an alert")
w.Crit("this is critical")
w.Err("this is an error")
w.Warning("this is a warning")
w.Notice("this is a notice")
w.Info("this is info")
w.Debug("this is debug")
w.Write([]byte("these are some bytes"))
```
If you need further control over connection attempts, you can use the DialWithCustomDialer
function. To continue with the DialWithTLSConfig example:
```
netDialer := &net.Dialer{Timeout: time.Second*5} // easy timeouts
realNetwork := "tcp" // real network, other vars your dail func can close over
dial := func(network, addr string) (net.Conn, error) {
// cannot use "network" here as it'll simply be "custom" which will fail
return tls.DialWithDialer(netDialer, realNetwork, addr, &config)
}
w, err := DialWithCustomDialer("custom", "192.168.0.52:514", syslog.LOG_ERR, "testtag", dial)
```
Your custom dial func can set timeouts, proxy connections, and do whatever else it needs before returning a net.Conn.
# Generating TLS Certificates
We've provided a script that you can use to generate a self-signed keypair:
```
pip install cryptography
python script/gen-certs.py
```
That outputs the public key and private key to standard out. Put those into
`.pem` files. (And don't put them into any source control. The certificate in
the `test` directory is used by the unit tests, and please do not actually use
it anywhere else.)
# Running Tests
Run the tests as usual:
```
go test
```
But we've also provided a test coverage script that will show you which
lines of code are not covered:
```
script/coverage --html
```
That will open a new browser tab showing coverage information.
# License
This project uses the New BSD License, the same as the Go project itself.
# Code of Conduct
Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms.

68
vendor/github.com/wiggin77/srslog/constants.go generated vendored Normal file
View File

@ -0,0 +1,68 @@
package srslog
import (
"errors"
)
// Priority is a combination of the syslog facility and
// severity. For example, LOG_ALERT | LOG_FTP sends an alert severity
// message from the FTP facility. The default severity is LOG_EMERG;
// the default facility is LOG_KERN.
type Priority int
const severityMask = 0x07
const facilityMask = 0xf8
const (
// Severity.
// From /usr/include/sys/syslog.h.
// These are the same on Linux, BSD, and OS X.
LOG_EMERG Priority = iota
LOG_ALERT
LOG_CRIT
LOG_ERR
LOG_WARNING
LOG_NOTICE
LOG_INFO
LOG_DEBUG
)
const (
// Facility.
// From /usr/include/sys/syslog.h.
// These are the same up to LOG_FTP on Linux, BSD, and OS X.
LOG_KERN Priority = iota << 3
LOG_USER
LOG_MAIL
LOG_DAEMON
LOG_AUTH
LOG_SYSLOG
LOG_LPR
LOG_NEWS
LOG_UUCP
LOG_CRON
LOG_AUTHPRIV
LOG_FTP
_ // unused
_ // unused
_ // unused
_ // unused
LOG_LOCAL0
LOG_LOCAL1
LOG_LOCAL2
LOG_LOCAL3
LOG_LOCAL4
LOG_LOCAL5
LOG_LOCAL6
LOG_LOCAL7
)
func validatePriority(p Priority) error {
if p < 0 || p > LOG_LOCAL7|LOG_DEBUG {
return errors.New("log/syslog: invalid priority")
} else {
return nil
}
}

104
vendor/github.com/wiggin77/srslog/dialer.go generated vendored Normal file
View File

@ -0,0 +1,104 @@
package srslog
import (
"crypto/tls"
"net"
)
// dialerFunctionWrapper is a simple object that consists of a dialer function
// and its name. This is primarily for testing, so we can make sure that the
// getDialer method returns the correct dialer function. However, if you ever
// find that you need to check which dialer function you have, this would also
// be useful for you without having to use reflection.
type dialerFunctionWrapper struct {
Name string
Dialer func() (serverConn, string, error)
}
// Call the wrapped dialer function and return its return values.
func (df dialerFunctionWrapper) Call() (serverConn, string, error) {
return df.Dialer()
}
// getDialer returns a "dialer" function that can be called to connect to a
// syslog server.
//
// Each dialer function is responsible for dialing the remote host and returns
// a serverConn, the hostname (or a default if the Writer has not specified a
// hostname), and an error in case dialing fails.
//
// The reason for separate dialers is that different network types may need
// to dial their connection differently, yet still provide a net.Conn interface
// that you can use once they have dialed. Rather than an increasingly long
// conditional, we have a map of network -> dialer function (with a sane default
// value), and adding a new network type is as easy as writing the dialer
// function and adding it to the map.
func (w *Writer) getDialer() dialerFunctionWrapper {
dialers := map[string]dialerFunctionWrapper{
"": dialerFunctionWrapper{"unixDialer", w.unixDialer},
"tcp+tls": dialerFunctionWrapper{"tlsDialer", w.tlsDialer},
"custom": dialerFunctionWrapper{"customDialer", w.customDialer},
}
dialer, ok := dialers[w.network]
if !ok {
dialer = dialerFunctionWrapper{"basicDialer", w.basicDialer}
}
return dialer
}
// unixDialer uses the unixSyslog method to open a connection to the syslog
// daemon running on the local machine.
func (w *Writer) unixDialer() (serverConn, string, error) {
sc, err := unixSyslog()
hostname := w.hostname
if hostname == "" {
hostname = "localhost"
}
return sc, hostname, err
}
// tlsDialer connects to TLS over TCP, and is used for the "tcp+tls" network
// type.
func (w *Writer) tlsDialer() (serverConn, string, error) {
c, err := tls.Dial("tcp", w.raddr, w.tlsConfig)
var sc serverConn
hostname := w.hostname
if err == nil {
sc = newNetConn(c)
if hostname == "" {
hostname = c.LocalAddr().String()
}
}
return sc, hostname, err
}
// basicDialer is the most common dialer for syslog, and supports both TCP and
// UDP connections.
func (w *Writer) basicDialer() (serverConn, string, error) {
c, err := net.Dial(w.network, w.raddr)
var sc serverConn
hostname := w.hostname
if err == nil {
sc = newNetConn(c)
if hostname == "" {
hostname = c.LocalAddr().String()
}
}
return sc, hostname, err
}
// customDialer uses the custom dialer when the Writer was created
// giving developers total control over how connections are made and returned.
// Note it does not check if cdialer is nil, as it should only be referenced from getDialer.
func (w *Writer) customDialer() (serverConn, string, error) {
c, err := w.customDial(w.network, w.raddr)
var sc serverConn
hostname := w.hostname
if err == nil {
sc = newNetConn(c)
if hostname == "" {
hostname = c.LocalAddr().String()
}
}
return sc, hostname, err
}

58
vendor/github.com/wiggin77/srslog/formatter.go generated vendored Normal file
View File

@ -0,0 +1,58 @@
package srslog
import (
"fmt"
"os"
"time"
)
const appNameMaxLength = 48 // limit to 48 chars as per RFC5424
// Formatter is a type of function that takes the consituent parts of a
// syslog message and returns a formatted string. A different Formatter is
// defined for each different syslog protocol we support.
type Formatter func(p Priority, hostname, tag, content string) string
// DefaultFormatter is the original format supported by the Go syslog package,
// and is a non-compliant amalgamation of 3164 and 5424 that is intended to
// maximize compatibility.
func DefaultFormatter(p Priority, hostname, tag, content string) string {
timestamp := time.Now().Format(time.RFC3339)
msg := fmt.Sprintf("<%d> %s %s %s[%d]: %s",
p, timestamp, hostname, tag, os.Getpid(), content)
return msg
}
// UnixFormatter omits the hostname, because it is only used locally.
func UnixFormatter(p Priority, hostname, tag, content string) string {
timestamp := time.Now().Format(time.Stamp)
msg := fmt.Sprintf("<%d>%s %s[%d]: %s",
p, timestamp, tag, os.Getpid(), content)
return msg
}
// RFC3164Formatter provides an RFC 3164 compliant message.
func RFC3164Formatter(p Priority, hostname, tag, content string) string {
timestamp := time.Now().Format(time.Stamp)
msg := fmt.Sprintf("<%d>%s %s %s[%d]: %s",
p, timestamp, hostname, tag, os.Getpid(), content)
return msg
}
// if string's length is greater than max, then use the last part
func truncateStartStr(s string, max int) string {
if (len(s) > max) {
return s[len(s) - max:]
}
return s
}
// RFC5424Formatter provides an RFC 5424 compliant message.
func RFC5424Formatter(p Priority, hostname, tag, content string) string {
timestamp := time.Now().Format(time.RFC3339)
pid := os.Getpid()
appName := truncateStartStr(os.Args[0], appNameMaxLength)
msg := fmt.Sprintf("<%d>%d %s %s %s %d %s - %s",
p, 1, timestamp, hostname, appName, pid, tag, content)
return msg
}

24
vendor/github.com/wiggin77/srslog/framer.go generated vendored Normal file
View File

@ -0,0 +1,24 @@
package srslog
import (
"fmt"
)
// Framer is a type of function that takes an input string (typically an
// already-formatted syslog message) and applies "message framing" to it. We
// have different framers because different versions of the syslog protocol
// and its transport requirements define different framing behavior.
type Framer func(in string) string
// DefaultFramer does nothing, since there is no framing to apply. This is
// the original behavior of the Go syslog package, and is also typically used
// for UDP syslog.
func DefaultFramer(in string) string {
return in
}
// RFC5425MessageLengthFramer prepends the message length to the front of the
// provided message, as defined in RFC 5425.
func RFC5425MessageLengthFramer(in string) string {
return fmt.Sprintf("%d %s", len(in), in)
}

3
vendor/github.com/wiggin77/srslog/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/wiggin77/srslog
go 1.14

13
vendor/github.com/wiggin77/srslog/logger.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
package srslog
import (
"io/ioutil"
"log"
)
var Logger log.Logger
func init() {
Logger = log.Logger{}
Logger.SetOutput(ioutil.Discard)
}

76
vendor/github.com/wiggin77/srslog/net_conn.go generated vendored Normal file
View File

@ -0,0 +1,76 @@
package srslog
import (
"io"
"net"
"time"
)
// netConn has an internal net.Conn and adheres to the serverConn interface,
// allowing us to send syslog messages over the network.
type netConn struct {
conn net.Conn
done chan interface{}
}
// newNetConn creates a netConn instance that is monitored for unexpected socket closure.
func newNetConn(conn net.Conn) *netConn {
nc := &netConn{conn: conn, done: make(chan interface{})}
go monitor(nc.conn, nc.done)
return nc
}
// writeString formats syslog messages using time.RFC3339 and includes the
// hostname, and sends the message to the connection.
func (n *netConn) writeString(framer Framer, formatter Formatter, p Priority, hostname, tag, msg string) error {
if framer == nil {
framer = DefaultFramer
}
if formatter == nil {
formatter = DefaultFormatter
}
formattedMessage := framer(formatter(p, hostname, tag, msg))
_, err := n.conn.Write([]byte(formattedMessage))
return err
}
// close the network connection
func (n *netConn) close() error {
// signal monitor goroutine to exit
close(n.done)
// wake up monitor blocked on read (close usually is enough)
_ = n.conn.SetReadDeadline(time.Now())
// close the connection
return n.conn.Close()
}
// monitor continuously tries to read from the connection to detect socket close.
// This is needed because syslog server uses a write only socket and Linux systems
// take a long time to detect a loss of connectivity on a socket when only writing;
// the writes simply fail without an error returned.
func monitor(conn net.Conn, done chan interface{}) {
defer Logger.Println("monitor exit")
buf := make([]byte, 1)
for {
Logger.Println("monitor loop")
select {
case <-done:
return
case <-time.After(1 * time.Second):
}
err := conn.SetReadDeadline(time.Now().Add(time.Second * 30))
if err != nil {
continue
}
_, err = conn.Read(buf)
Logger.Println("monitor -- ", err)
if err == io.EOF {
Logger.Println("monitor close conn")
conn.Close()
}
}
}

125
vendor/github.com/wiggin77/srslog/srslog.go generated vendored Normal file
View File

@ -0,0 +1,125 @@
package srslog
import (
"crypto/tls"
"crypto/x509"
"errors"
"io/ioutil"
"log"
"net"
"os"
)
// This interface allows us to work with both local and network connections,
// and enables Solaris support (see syslog_unix.go).
type serverConn interface {
writeString(framer Framer, formatter Formatter, p Priority, hostname, tag, s string) error
close() error
}
// DialFunc is the function signature to be used for a custom dialer callback
// with DialWithCustomDialer
type DialFunc func(string, string) (net.Conn, error)
// New establishes a new connection to the system log daemon. Each
// write to the returned Writer sends a log message with the given
// priority and prefix.
func New(priority Priority, tag string) (w *Writer, err error) {
return Dial("", "", priority, tag)
}
// Dial establishes a connection to a log daemon by connecting to
// address raddr on the specified network. Each write to the returned
// Writer sends a log message with the given facility, severity and
// tag.
// If network is empty, Dial will connect to the local syslog server.
func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
return DialWithTLSConfig(network, raddr, priority, tag, nil)
}
// ErrNilDialFunc is returned from DialWithCustomDialer when a nil DialFunc is passed,
// avoiding a nil pointer deference panic.
var ErrNilDialFunc = errors.New("srslog: nil DialFunc passed to DialWithCustomDialer")
// DialWithCustomDialer establishes a connection by calling customDial.
// Each write to the returned Writer sends a log message with the given facility, severity and tag.
// Network must be "custom" in order for this package to use customDial.
// While network and raddr will be passed to customDial, it is allowed for customDial to ignore them.
// If customDial is nil, this function returns ErrNilDialFunc.
func DialWithCustomDialer(network, raddr string, priority Priority, tag string, customDial DialFunc) (*Writer, error) {
if customDial == nil {
return nil, ErrNilDialFunc
}
return dialAllParameters(network, raddr, priority, tag, nil, customDial)
}
// DialWithTLSCertPath establishes a secure connection to a log daemon by connecting to
// address raddr on the specified network. It uses certPath to load TLS certificates and configure
// the secure connection.
func DialWithTLSCertPath(network, raddr string, priority Priority, tag, certPath string) (*Writer, error) {
serverCert, err := ioutil.ReadFile(certPath)
if err != nil {
return nil, err
}
return DialWithTLSCert(network, raddr, priority, tag, serverCert)
}
// DialWIthTLSCert establishes a secure connection to a log daemon by connecting to
// address raddr on the specified network. It uses serverCert to load a TLS certificate
// and configure the secure connection.
func DialWithTLSCert(network, raddr string, priority Priority, tag string, serverCert []byte) (*Writer, error) {
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(serverCert)
config := tls.Config{
RootCAs: pool,
}
return DialWithTLSConfig(network, raddr, priority, tag, &config)
}
// DialWithTLSConfig establishes a secure connection to a log daemon by connecting to
// address raddr on the specified network. It uses tlsConfig to configure the secure connection.
func DialWithTLSConfig(network, raddr string, priority Priority, tag string, tlsConfig *tls.Config) (*Writer, error) {
return dialAllParameters(network, raddr, priority, tag, tlsConfig, nil)
}
// implementation of the various functions above
func dialAllParameters(network, raddr string, priority Priority, tag string, tlsConfig *tls.Config, customDial DialFunc) (*Writer, error) {
if err := validatePriority(priority); err != nil {
return nil, err
}
if tag == "" {
tag = os.Args[0]
}
hostname, _ := os.Hostname()
w := &Writer{
priority: priority,
tag: tag,
hostname: hostname,
network: network,
raddr: raddr,
tlsConfig: tlsConfig,
customDial: customDial,
}
_, err := w.connect()
if err != nil {
return nil, err
}
return w, err
}
// NewLogger creates a log.Logger whose output is written to
// the system log service with the specified priority. The logFlag
// argument is the flag set passed through to log.New to create
// the Logger.
func NewLogger(p Priority, logFlag int) (*log.Logger, error) {
s, err := New(p, "")
if err != nil {
return nil, err
}
return log.New(s, "", logFlag), nil
}

54
vendor/github.com/wiggin77/srslog/srslog_unix.go generated vendored Normal file
View File

@ -0,0 +1,54 @@
package srslog
import (
"errors"
"io"
"net"
)
// unixSyslog opens a connection to the syslog daemon running on the
// local machine using a Unix domain socket. This function exists because of
// Solaris support as implemented by gccgo. On Solaris you can not
// simply open a TCP connection to the syslog daemon. The gccgo
// sources have a syslog_solaris.go file that implements unixSyslog to
// return a type that satisfies the serverConn interface and simply calls the C
// library syslog function.
func unixSyslog() (conn serverConn, err error) {
logTypes := []string{"unixgram", "unix"}
logPaths := []string{"/dev/log", "/var/run/syslog", "/var/run/log"}
for _, network := range logTypes {
for _, path := range logPaths {
conn, err := net.Dial(network, path)
if err != nil {
continue
} else {
return &localConn{conn: conn}, nil
}
}
}
return nil, errors.New("Unix syslog delivery error")
}
// localConn adheres to the serverConn interface, allowing us to send syslog
// messages to the local syslog daemon over a Unix domain socket.
type localConn struct {
conn io.WriteCloser
}
// writeString formats syslog messages using time.Stamp instead of time.RFC3339,
// and omits the hostname (because it is expected to be used locally).
func (n *localConn) writeString(framer Framer, formatter Formatter, p Priority, hostname, tag, msg string) error {
if framer == nil {
framer = DefaultFramer
}
if formatter == nil {
formatter = UnixFormatter
}
_, err := n.conn.Write([]byte(framer(formatter(p, hostname, tag, msg))))
return err
}
// close the (local) network connection
func (n *localConn) close() error {
return n.conn.Close()
}

201
vendor/github.com/wiggin77/srslog/writer.go generated vendored Normal file
View File

@ -0,0 +1,201 @@
package srslog
import (
"crypto/tls"
"strings"
"sync"
)
// A Writer is a connection to a syslog server.
type Writer struct {
priority Priority
tag string
hostname string
network string
raddr string
tlsConfig *tls.Config
framer Framer
formatter Formatter
//non-nil if custom dialer set, used in getDialer
customDial DialFunc
mu sync.RWMutex // guards conn
conn serverConn
}
// getConn provides access to the internal conn, protected by a mutex. The
// conn is threadsafe, so it can be used while unlocked, but we want to avoid
// race conditions on grabbing a reference to it.
func (w *Writer) getConn() serverConn {
w.mu.RLock()
conn := w.conn
w.mu.RUnlock()
return conn
}
// setConn updates the internal conn, protected by a mutex.
func (w *Writer) setConn(c serverConn) {
w.mu.Lock()
w.conn = c
w.mu.Unlock()
}
// connect makes a connection to the syslog server.
func (w *Writer) connect() (serverConn, error) {
conn := w.getConn()
if conn != nil {
// ignore err from close, it makes sense to continue anyway
conn.close()
w.setConn(nil)
}
var hostname string
var err error
dialer := w.getDialer()
conn, hostname, err = dialer.Call()
if err == nil {
w.setConn(conn)
w.hostname = hostname
return conn, nil
} else {
return nil, err
}
}
// SetFormatter changes the formatter function for subsequent messages.
func (w *Writer) SetFormatter(f Formatter) {
w.formatter = f
}
// SetFramer changes the framer function for subsequent messages.
func (w *Writer) SetFramer(f Framer) {
w.framer = f
}
// SetHostname changes the hostname for syslog messages if needed.
func (w *Writer) SetHostname(hostname string) {
w.hostname = hostname
}
// Write sends a log message to the syslog daemon using the default priority
// passed into `srslog.New` or the `srslog.Dial*` functions.
func (w *Writer) Write(b []byte) (int, error) {
return w.writeAndRetry(w.priority, string(b))
}
// WriteWithPriority sends a log message with a custom priority.
func (w *Writer) WriteWithPriority(p Priority, b []byte) (int, error) {
return w.writeAndRetryWithPriority(p, string(b))
}
// Close closes a connection to the syslog daemon.
func (w *Writer) Close() error {
conn := w.getConn()
if conn != nil {
err := conn.close()
w.setConn(nil)
return err
}
return nil
}
// Emerg logs a message with severity LOG_EMERG; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Emerg(m string) (err error) {
_, err = w.writeAndRetry(LOG_EMERG, m)
return err
}
// Alert logs a message with severity LOG_ALERT; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Alert(m string) (err error) {
_, err = w.writeAndRetry(LOG_ALERT, m)
return err
}
// Crit logs a message with severity LOG_CRIT; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Crit(m string) (err error) {
_, err = w.writeAndRetry(LOG_CRIT, m)
return err
}
// Err logs a message with severity LOG_ERR; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Err(m string) (err error) {
_, err = w.writeAndRetry(LOG_ERR, m)
return err
}
// Warning logs a message with severity LOG_WARNING; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Warning(m string) (err error) {
_, err = w.writeAndRetry(LOG_WARNING, m)
return err
}
// Notice logs a message with severity LOG_NOTICE; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Notice(m string) (err error) {
_, err = w.writeAndRetry(LOG_NOTICE, m)
return err
}
// Info logs a message with severity LOG_INFO; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Info(m string) (err error) {
_, err = w.writeAndRetry(LOG_INFO, m)
return err
}
// Debug logs a message with severity LOG_DEBUG; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Debug(m string) (err error) {
_, err = w.writeAndRetry(LOG_DEBUG, m)
return err
}
// writeAndRetry takes a severity and the string to write. Any facility passed to
// it as part of the severity Priority will be ignored.
func (w *Writer) writeAndRetry(severity Priority, s string) (int, error) {
pr := (w.priority & facilityMask) | (severity & severityMask)
return w.writeAndRetryWithPriority(pr, s)
}
// writeAndRetryWithPriority differs from writeAndRetry in that it allows setting
// of both the facility and the severity.
func (w *Writer) writeAndRetryWithPriority(p Priority, s string) (int, error) {
conn := w.getConn()
if conn != nil {
if n, err := w.write(conn, p, s); err == nil {
return n, err
}
}
var err error
if conn, err = w.connect(); err != nil {
return 0, err
}
return w.write(conn, p, s)
}
// write generates and writes a syslog formatted string. It formats the
// message based on the current Formatter and Framer.
func (w *Writer) write(conn serverConn, p Priority, msg string) (int, error) {
// ensure it ends in a \n
if !strings.HasSuffix(msg, "\n") {
msg += "\n"
}
err := conn.writeString(w.framer, w.formatter, p, w.hostname, w.tag, msg)
if err != nil {
return 0, err
}
// Note: return the length of the input, not the number of
// bytes printed by Fprintf, because this must behave like
// an io.Writer.
return len(msg), nil
}