FILE / ScuroNeko/mtg

config/config.go

Исходный файл и его история в репозитории.
FILE 386522ba22b83537ab547a1dcb8f76a98a28293f
Files
mtg/config/config.go
T

275 lines
6.0 KiB
Go

package config
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"net"
"strconv"
"time"
"go.uber.org/zap"
statsd "gopkg.in/alexcesaro/statsd.v2"
)
type SecretMode uint8
func (s SecretMode) String() string {
switch s {
case SecretModeSimple:
return "simple"
case SecretModeSecured:
return "secured"
}
return "tls"
}
const (
SecretModeSimple SecretMode = iota
SecretModeSecured
SecretModeTLS
)
const SimpleSecretLength = 16
type OptionType uint8
const (
OptionTypeDebug OptionType = iota
OptionTypeVerbose
OptionTypeBindIP
OptionTypeBindPort
OptionTypePublicIPv4
OptionTypePublicIPv4Port
OptionTypePublicIPv6
OptionTypePublicIPv6Port
OptionTypeStatsIP
OptionTypeStatsPort
OptionTypeStatsdIP
OptionTypeStatsdPort
OptionTypeStatsdNetwork
OptionTypeStatsdPrefix
OptionTypeStatsdTagsFormat
OptionTypeStatsdTags
OptionTypePrometheusPrefix
OptionTypeWriteBufferSize
OptionTypeReadBufferSize
OptionTypeAntiReplayMaxSize
OptionTypeAntiReplayEvictionTime
OptionTypeSecret
OptionTypeAdtag
)
type BufferSize struct {
Read int `json:"read"`
Write int `json:"write"`
}
type AntiReplay struct {
MaxSize int `json:"max_size"`
EvictionTime time.Duration `json:"duration"`
}
type Stats struct {
Prefix string `json:"prefix"`
}
type StatsdStats struct {
Stats
Addr Addr `json:"addr"`
Tags map[string]string `json:"tags"`
TagsFormat statsd.TagFormat `json:"format"`
}
type PrometheusStats struct {
Stats
}
type Addr struct {
IP net.IP `json:"ip"`
Port int `json:"port"`
net string
}
func (a Addr) Network() string {
if a.net == "" {
return "tcp"
}
return a.net
}
func (a Addr) String() string {
return net.JoinHostPort(a.IP.String(), strconv.Itoa(a.Port))
}
func (a Addr) MarshalJSON() ([]byte, error) {
data := map[string]string{
"network": a.Network(),
"addr": a.String(),
}
return json.Marshal(data)
}
type Config struct {
BufferSize BufferSize `json:"buffer_size"`
AntiReplay AntiReplay `json:"anti_replay"`
ListenAddr Addr `json:"listen_addr"`
PublicIPv4Addr Addr `json:"public_ipv4_addr"`
PublicIPv6Addr Addr `json:"public_ipv6_addr"`
StatsAddr Addr `json:"stats_addr"`
StatsdStats StatsdStats `json:"stats_statsd"`
PrometheusStats PrometheusStats `json:"stats_prometheus"`
Debug bool `json:"debug"`
Verbose bool `json:"verbose"`
SecretMode SecretMode `json:"secret_mode"`
Secret []byte `json:"secret"`
AdTag []byte `json:"adtag"`
}
func (c Config) Printable() interface{} {
data, err := json.Marshal(c)
if err != nil {
panic(err)
}
rv := map[string]interface{}{}
if err := json.Unmarshal(data, &rv); err != nil {
panic(err)
}
return rv
}
func (c Config) String() string {
data, _ := json.Marshal(c)
return string(data)
}
type Opt struct {
Option OptionType
Value interface{}
}
var C = Config{}
func Init(options ...Opt) error { // nolint: gocyclo
for _, opt := range options {
switch opt.Option {
case OptionTypeDebug:
C.Debug = opt.Value.(bool)
case OptionTypeVerbose:
C.Verbose = opt.Value.(bool)
case OptionTypeBindIP:
C.ListenAddr.IP = opt.Value.(net.IP)
case OptionTypeBindPort:
C.ListenAddr.Port = int(opt.Value.(uint16))
case OptionTypePublicIPv4:
C.PublicIPv4Addr.IP = opt.Value.(net.IP)
case OptionTypePublicIPv4Port:
C.PublicIPv4Addr.Port = int(opt.Value.(uint16))
case OptionTypePublicIPv6:
C.PublicIPv6Addr.IP = opt.Value.(net.IP)
case OptionTypePublicIPv6Port:
C.PublicIPv6Addr.Port = int(opt.Value.(uint16))
case OptionTypeStatsIP:
C.StatsAddr.IP = opt.Value.(net.IP)
case OptionTypeStatsPort:
C.StatsAddr.Port = int(opt.Value.(uint16))
case OptionTypeStatsdIP:
C.StatsdStats.Addr.IP = opt.Value.(net.IP)
case OptionTypeStatsdPort:
C.StatsdStats.Addr.Port = int(opt.Value.(uint16))
case OptionTypeStatsdNetwork:
C.StatsdStats.Addr.net = opt.Value.(string)
case OptionTypeStatsdPrefix:
C.StatsdStats.Prefix = opt.Value.(string)
case OptionTypeStatsdTagsFormat:
value := opt.Value.(string)
switch value {
case "datadog":
C.StatsdStats.TagsFormat = statsd.Datadog
case "influxdb":
C.StatsdStats.TagsFormat = statsd.InfluxDB
default:
return fmt.Errorf("Incorrect statsd tag %s", value)
}
case OptionTypeStatsdTags:
C.StatsdStats.Tags = opt.Value.(map[string]string)
case OptionTypePrometheusPrefix:
C.PrometheusStats.Prefix = opt.Value.(string)
case OptionTypeWriteBufferSize:
C.BufferSize.Write = int(opt.Value.(uint32))
case OptionTypeReadBufferSize:
C.BufferSize.Read = int(opt.Value.(uint32))
case OptionTypeAntiReplayMaxSize:
C.AntiReplay.MaxSize = opt.Value.(int)
case OptionTypeAntiReplayEvictionTime:
C.AntiReplay.EvictionTime = opt.Value.(time.Duration)
case OptionTypeSecret:
C.Secret = opt.Value.([]byte)
case OptionTypeAdtag:
C.AdTag = opt.Value.([]byte)
default:
return fmt.Errorf("Unknown tag %v", opt.Option)
}
}
switch {
case len(C.Secret) == 1+SimpleSecretLength && bytes.HasPrefix(C.Secret, []byte{0xdd}):
C.SecretMode = SecretModeSecured
C.Secret = bytes.TrimPrefix(C.Secret, []byte{0xdd})
case len(C.Secret) == SimpleSecretLength:
C.SecretMode = SecretModeSimple
default:
return errors.New("Incorrect secret")
}
return nil
}
func InitPublicAddress(ctx context.Context) error {
if C.PublicIPv4Addr.Port == 0 {
C.PublicIPv4Addr.Port = C.ListenAddr.Port
}
if C.PublicIPv6Addr.Port == 0 {
C.PublicIPv6Addr.Port = C.ListenAddr.Port
}
foundAddress := C.PublicIPv4Addr.IP != nil || C.PublicIPv6Addr.IP != nil
if C.PublicIPv4Addr.IP == nil {
ip, err := getGlobalIPv4(ctx)
if err != nil {
zap.S().Warnw("Cannot resolve public address", "error", err)
} else {
C.PublicIPv4Addr.IP = ip
foundAddress = true
}
}
if C.PublicIPv6Addr.IP == nil {
ip, err := getGlobalIPv6(ctx)
if err != nil {
zap.S().Warnw("Cannot resolve public address", "error", err)
} else {
C.PublicIPv6Addr.IP = ip
foundAddress = true
}
}
if !foundAddress {
return errors.New("Cannot resolve any public address")
}
return nil
}