- drop qdm12/govalid dependency - upgrade qdm12/ss-server to v0.6.0 - do not unset sensitive config settings (makes no sense to me)
139 lines
3.9 KiB
Go
139 lines
3.9 KiB
Go
package settings
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/qdm12/gluetun/internal/publicip/api"
|
|
"github.com/qdm12/gosettings"
|
|
"github.com/qdm12/gosettings/reader"
|
|
"github.com/qdm12/gotree"
|
|
)
|
|
|
|
// PublicIP contains settings for port forwarding.
|
|
type PublicIP struct {
|
|
// Period is the period to get the public IP address.
|
|
// It can be set to 0 to disable periodic checking.
|
|
// It cannot be nil for the internal state.
|
|
// TODO change to value and add enabled field
|
|
Period *time.Duration
|
|
// IPFilepath is the public IP address status file path
|
|
// to use. It can be the empty string to indicate not
|
|
// to write to a file. It cannot be nil for the
|
|
// internal state
|
|
IPFilepath *string
|
|
// API is the API name to use to fetch public IP information.
|
|
// It can be ipinfo or ip2location. It defaults to ipinfo.
|
|
API string
|
|
// APIToken is the token to use for the IP data service
|
|
// such as ipinfo.io. It can be the empty string to
|
|
// indicate not to use a token. It cannot be nil for the
|
|
// internal state.
|
|
APIToken *string
|
|
}
|
|
|
|
// UpdateWith deep copies the receiving settings, overrides the copy with
|
|
// fields set in the partialUpdate argument, validates the new settings
|
|
// and returns them if they are valid, or returns an error otherwise.
|
|
// In all cases, the receiving settings are unmodified.
|
|
func (p PublicIP) UpdateWith(partialUpdate PublicIP) (updatedSettings PublicIP, err error) {
|
|
updatedSettings = p.copy()
|
|
updatedSettings.overrideWith(partialUpdate)
|
|
err = updatedSettings.validate()
|
|
if err != nil {
|
|
return updatedSettings, fmt.Errorf("validating updated settings: %w", err)
|
|
}
|
|
return updatedSettings, nil
|
|
}
|
|
|
|
func (p PublicIP) validate() (err error) {
|
|
const minPeriod = 5 * time.Second
|
|
if *p.Period < minPeriod {
|
|
return fmt.Errorf("%w: %s must be at least %s",
|
|
ErrPublicIPPeriodTooShort, p.Period, minPeriod)
|
|
}
|
|
|
|
if *p.IPFilepath != "" { // optional
|
|
_, err := filepath.Abs(*p.IPFilepath)
|
|
if err != nil {
|
|
return fmt.Errorf("filepath is not valid: %w", err)
|
|
}
|
|
}
|
|
|
|
_, err = api.ParseProvider(p.API)
|
|
if err != nil {
|
|
return fmt.Errorf("API name: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *PublicIP) copy() (copied PublicIP) {
|
|
return PublicIP{
|
|
Period: gosettings.CopyPointer(p.Period),
|
|
IPFilepath: gosettings.CopyPointer(p.IPFilepath),
|
|
API: p.API,
|
|
APIToken: gosettings.CopyPointer(p.APIToken),
|
|
}
|
|
}
|
|
|
|
func (p *PublicIP) overrideWith(other PublicIP) {
|
|
p.Period = gosettings.OverrideWithPointer(p.Period, other.Period)
|
|
p.IPFilepath = gosettings.OverrideWithPointer(p.IPFilepath, other.IPFilepath)
|
|
p.API = gosettings.OverrideWithComparable(p.API, other.API)
|
|
p.APIToken = gosettings.OverrideWithPointer(p.APIToken, other.APIToken)
|
|
}
|
|
|
|
func (p *PublicIP) setDefaults() {
|
|
const defaultPeriod = 12 * time.Hour
|
|
p.Period = gosettings.DefaultPointer(p.Period, defaultPeriod)
|
|
p.IPFilepath = gosettings.DefaultPointer(p.IPFilepath, "/tmp/gluetun/ip")
|
|
p.API = gosettings.DefaultComparable(p.API, "ipinfo")
|
|
p.APIToken = gosettings.DefaultPointer(p.APIToken, "")
|
|
}
|
|
|
|
func (p PublicIP) String() string {
|
|
return p.toLinesNode().String()
|
|
}
|
|
|
|
func (p PublicIP) toLinesNode() (node *gotree.Node) {
|
|
node = gotree.New("Public IP settings:")
|
|
|
|
if *p.Period == 0 {
|
|
node.Appendf("Enabled: no")
|
|
return node
|
|
}
|
|
|
|
updatePeriod := "disabled"
|
|
if *p.Period > 0 {
|
|
updatePeriod = "every " + p.Period.String()
|
|
}
|
|
node.Appendf("Fetching: %s", updatePeriod)
|
|
|
|
if *p.IPFilepath != "" {
|
|
node.Appendf("IP file path: %s", *p.IPFilepath)
|
|
}
|
|
|
|
node.Appendf("Public IP data API: %s", p.API)
|
|
|
|
if *p.APIToken != "" {
|
|
node.Appendf("API token: %s", gosettings.ObfuscateKey(*p.APIToken))
|
|
}
|
|
|
|
return node
|
|
}
|
|
|
|
func (p *PublicIP) read(r *reader.Reader) (err error) {
|
|
p.Period, err = r.DurationPtr("PUBLICIP_PERIOD")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
p.IPFilepath = r.Get("PUBLICIP_FILE",
|
|
reader.ForceLowercase(false), reader.RetroKeys("IP_STATUS_FILE"))
|
|
p.API = r.String("PUBLICIP_API")
|
|
p.APIToken = r.Get("PUBLICIP_API_TOKEN")
|
|
return nil
|
|
}
|