Maintenance: improve error wrapping
This commit is contained in:
@@ -10,6 +10,7 @@ issues:
|
|||||||
linters:
|
linters:
|
||||||
- dupl
|
- dupl
|
||||||
- maligned
|
- maligned
|
||||||
|
- goerr113
|
||||||
- path: internal/server/
|
- path: internal/server/
|
||||||
linters:
|
linters:
|
||||||
- dupl
|
- dupl
|
||||||
@@ -40,7 +41,7 @@ linters:
|
|||||||
- gomnd
|
- gomnd
|
||||||
- goprintffuncname
|
- goprintffuncname
|
||||||
- gosec
|
- gosec
|
||||||
# - goerr113
|
- goerr113
|
||||||
- gosimple
|
- gosimple
|
||||||
- govet
|
- govet
|
||||||
- importas
|
- importas
|
||||||
|
|||||||
@@ -106,6 +106,10 @@ func main() {
|
|||||||
nativeos.Exit(1)
|
nativeos.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errCommandUnknown = errors.New("command is unknown")
|
||||||
|
)
|
||||||
|
|
||||||
//nolint:gocognit,gocyclo
|
//nolint:gocognit,gocyclo
|
||||||
func _main(ctx context.Context, buildInfo models.BuildInformation,
|
func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||||
args []string, logger logging.ParentLogger, os os.OS,
|
args []string, logger logging.ParentLogger, os os.OS,
|
||||||
@@ -121,7 +125,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
case "update":
|
case "update":
|
||||||
return cli.Update(ctx, args[2:], os, logger)
|
return cli.Update(ctx, args[2:], os, logger)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("command %q is unknown", args[1])
|
return fmt.Errorf("%w: %s", errCommandUnknown, args[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +433,7 @@ func routeReadyEvents(ctx context.Context, done chan<- struct{}, buildInfo model
|
|||||||
first = false
|
first = false
|
||||||
message, err := versionpkg.GetMessage(ctx, buildInfo, httpClient)
|
message, err := versionpkg.GetMessage(ctx, buildInfo, httpClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error("cannot get version information: " + err.Error())
|
||||||
} else {
|
} else {
|
||||||
logger.Info(message)
|
logger.Info(message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -15,6 +16,13 @@ import (
|
|||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNoFileOrStdoutFlag = errors.New("at least one of -file or -stdout must be specified")
|
||||||
|
ErrSyncServers = errors.New("cannot sync hardcoded and persisted servers")
|
||||||
|
ErrUpdateServerInformation = errors.New("cannot update server information")
|
||||||
|
ErrWriteToFile = errors.New("cannot write updated information to file")
|
||||||
|
)
|
||||||
|
|
||||||
func (c *cli) Update(ctx context.Context, args []string, os os.OS, logger logging.Logger) error {
|
func (c *cli) Update(ctx context.Context, args []string, os os.OS, logger logging.Logger) error {
|
||||||
options := configuration.Updater{CLI: true}
|
options := configuration.Updater{CLI: true}
|
||||||
var flushToFile bool
|
var flushToFile bool
|
||||||
@@ -40,7 +48,7 @@ func (c *cli) Update(ctx context.Context, args []string, os os.OS, logger loggin
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !flushToFile && !options.Stdout {
|
if !flushToFile && !options.Stdout {
|
||||||
return fmt.Errorf("at least one of -file or -stdout must be specified")
|
return ErrNoFileOrStdoutFlag
|
||||||
}
|
}
|
||||||
|
|
||||||
const clientTimeout = 10 * time.Second
|
const clientTimeout = 10 * time.Second
|
||||||
@@ -48,16 +56,16 @@ func (c *cli) Update(ctx context.Context, args []string, os os.OS, logger loggin
|
|||||||
storage := storage.New(logger, os, constants.ServersData)
|
storage := storage.New(logger, os, constants.ServersData)
|
||||||
currentServers, err := storage.SyncServers(constants.GetAllServers())
|
currentServers, err := storage.SyncServers(constants.GetAllServers())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot update servers: %w", err)
|
return fmt.Errorf("%w: %s", ErrSyncServers, err)
|
||||||
}
|
}
|
||||||
updater := updater.New(options, httpClient, currentServers, logger)
|
updater := updater.New(options, httpClient, currentServers, logger)
|
||||||
allServers, err := updater.UpdateServers(ctx)
|
allServers, err := updater.UpdateServers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("%w: %s", ErrUpdateServerInformation, err)
|
||||||
}
|
}
|
||||||
if flushToFile {
|
if flushToFile {
|
||||||
if err := storage.FlushToFile(allServers); err != nil {
|
if err := storage.FlushToFile(allServers); err != nil {
|
||||||
return fmt.Errorf("cannot update servers: %w", err)
|
return fmt.Errorf("%w: %s", ErrWriteToFile, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package configuration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
@@ -81,10 +81,12 @@ func readCyberghostClientKey(r reader) (clientKey string, err error) {
|
|||||||
return extractClientKey(b)
|
return extractClientKey(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errDecodePEMBlockClientKey = errors.New("cannot decode PEM block from client key")
|
||||||
|
|
||||||
func extractClientKey(b []byte) (key string, err error) {
|
func extractClientKey(b []byte) (key string, err error) {
|
||||||
pemBlock, _ := pem.Decode(b)
|
pemBlock, _ := pem.Decode(b)
|
||||||
if pemBlock == nil {
|
if pemBlock == nil {
|
||||||
return "", fmt.Errorf("cannot decode PEM block from client key")
|
return "", errDecodePEMBlockClientKey
|
||||||
}
|
}
|
||||||
parsedBytes := pem.EncodeToMemory(pemBlock)
|
parsedBytes := pem.EncodeToMemory(pemBlock)
|
||||||
s := string(parsedBytes)
|
s := string(parsedBytes)
|
||||||
@@ -102,10 +104,12 @@ func readCyberghostClientCertificate(r reader) (clientCertificate string, err er
|
|||||||
return extractClientCertificate(b)
|
return extractClientCertificate(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errDecodePEMBlockClientCert = errors.New("cannot decode PEM block from client certificate")
|
||||||
|
|
||||||
func extractClientCertificate(b []byte) (certificate string, err error) {
|
func extractClientCertificate(b []byte) (certificate string, err error) {
|
||||||
pemBlock, _ := pem.Decode(b)
|
pemBlock, _ := pem.Decode(b)
|
||||||
if pemBlock == nil {
|
if pemBlock == nil {
|
||||||
return "", fmt.Errorf("cannot decode PEM block from client certificate")
|
return "", errDecodePEMBlockClientCert
|
||||||
}
|
}
|
||||||
parsedBytes := pem.EncodeToMemory(pemBlock)
|
parsedBytes := pem.EncodeToMemory(pemBlock)
|
||||||
s := string(parsedBytes)
|
s := string(parsedBytes)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package configuration
|
package configuration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -71,11 +70,11 @@ zZjrL52saevO25cigVl+hxcnY8DTpbk=
|
|||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
"no input": {
|
"no input": {
|
||||||
err: fmt.Errorf("cannot decode PEM block from client key"),
|
err: errDecodePEMBlockClientKey,
|
||||||
},
|
},
|
||||||
"bad input": {
|
"bad input": {
|
||||||
b: []byte{1, 2, 3},
|
b: []byte{1, 2, 3},
|
||||||
err: fmt.Errorf("cannot decode PEM block from client key"),
|
err: errDecodePEMBlockClientKey,
|
||||||
},
|
},
|
||||||
"valid key": {
|
"valid key": {
|
||||||
b: []byte(validPEM),
|
b: []byte(validPEM),
|
||||||
@@ -147,11 +146,11 @@ iOCYTbretAFZRhh6ycUN5hBeN8GMQxiMreMtDV4PEIQ=
|
|||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
"no input": {
|
"no input": {
|
||||||
err: fmt.Errorf("cannot decode PEM block from client certificate"),
|
err: errDecodePEMBlockClientCert,
|
||||||
},
|
},
|
||||||
"bad input": {
|
"bad input": {
|
||||||
b: []byte{1, 2, 3},
|
b: []byte{1, 2, 3},
|
||||||
err: fmt.Errorf("cannot decode PEM block from client certificate"),
|
err: errDecodePEMBlockClientCert,
|
||||||
},
|
},
|
||||||
"valid key": {
|
"valid key": {
|
||||||
b: []byte(validPEM),
|
b: []byte(validPEM),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -29,6 +30,8 @@ func (l *looper) GetStatus() (status models.LoopStatus) {
|
|||||||
return l.state.status
|
return l.state.status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrInvalidStatus = errors.New("invalid status")
|
||||||
|
|
||||||
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
||||||
l.state.statusMu.Lock()
|
l.state.statusMu.Lock()
|
||||||
defer l.state.statusMu.Unlock()
|
defer l.state.statusMu.Unlock()
|
||||||
@@ -64,8 +67,8 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
l.state.status = constants.Stopped
|
l.state.status = constants.Stopped
|
||||||
return status.String(), nil
|
return status.String(), nil
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("status %q can only be %q or %q",
|
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
|
||||||
status, constants.Running, constants.Stopped)
|
ErrInvalidStatus, status, constants.Running, constants.Stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,16 +41,18 @@ func (c *configurator) runIP6tablesInstruction(ctx context.Context, instruction
|
|||||||
}
|
}
|
||||||
flags := strings.Fields(instruction)
|
flags := strings.Fields(instruction)
|
||||||
if output, err := c.commander.Run(ctx, "ip6tables", flags...); err != nil {
|
if output, err := c.commander.Run(ctx, "ip6tables", flags...); err != nil {
|
||||||
return fmt.Errorf("%w \"ip6tables %s\": %s: %s", ErrIP6Tables, instruction, output, err)
|
return fmt.Errorf("%w: \"ip6tables %s\": %s: %s", ErrIP6Tables, instruction, output, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errPolicyNotValid = errors.New("policy is not valid")
|
||||||
|
|
||||||
func (c *configurator) setIPv6AllPolicies(ctx context.Context, policy string) error {
|
func (c *configurator) setIPv6AllPolicies(ctx context.Context, policy string) error {
|
||||||
switch policy {
|
switch policy {
|
||||||
case "ACCEPT", "DROP":
|
case "ACCEPT", "DROP":
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("policy %q not recognized", policy)
|
return fmt.Errorf("%w: %s", errPolicyNotValid, policy)
|
||||||
}
|
}
|
||||||
return c.runIP6tablesInstructions(ctx, []string{
|
return c.runIP6tablesInstructions(ctx, []string{
|
||||||
"--policy INPUT " + policy,
|
"--policy INPUT " + policy,
|
||||||
|
|||||||
@@ -2,11 +2,16 @@ package healthcheck
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrHTTPStatusNotOK = errors.New("HTTP response status is not OK")
|
||||||
|
)
|
||||||
|
|
||||||
type Checker interface {
|
type Checker interface {
|
||||||
Check(ctx context.Context, url string) error
|
Check(ctx context.Context, url string) error
|
||||||
}
|
}
|
||||||
@@ -38,5 +43,5 @@ func (h *checker) Check(ctx context.Context, url string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return fmt.Errorf("%s: %s", response.Status, string(b))
|
return fmt.Errorf("%w: %s: %s", ErrHTTPStatusNotOK, response.Status, string(b))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package httpproxy
|
package httpproxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -29,6 +30,8 @@ func (l *looper) GetStatus() (status models.LoopStatus) {
|
|||||||
return l.state.status
|
return l.state.status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrInvalidStatus = errors.New("invalid status")
|
||||||
|
|
||||||
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
||||||
l.state.statusMu.Lock()
|
l.state.statusMu.Lock()
|
||||||
defer l.state.statusMu.Unlock()
|
defer l.state.statusMu.Unlock()
|
||||||
@@ -64,8 +67,8 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
l.state.status = status
|
l.state.status = status
|
||||||
return status.String(), nil
|
return status.String(), nil
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("status %q can only be %q or %q",
|
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
|
||||||
status, constants.Running, constants.Stopped)
|
ErrInvalidStatus, status, constants.Running, constants.Stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package openvpn
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -14,6 +15,8 @@ func (c *configurator) Start(ctx context.Context) (
|
|||||||
return c.commander.Start(ctx, "openvpn", "--config", constants.OpenVPNConf)
|
return c.commander.Start(ctx, "openvpn", "--config", constants.OpenVPNConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrVersionTooShort = errors.New("version output is too short")
|
||||||
|
|
||||||
func (c *configurator) Version(ctx context.Context) (string, error) {
|
func (c *configurator) Version(ctx context.Context) (string, error) {
|
||||||
output, err := c.commander.Run(ctx, "openvpn", "--version")
|
output, err := c.commander.Run(ctx, "openvpn", "--version")
|
||||||
if err != nil && err.Error() != "exit status 1" {
|
if err != nil && err.Error() != "exit status 1" {
|
||||||
@@ -23,7 +26,7 @@ func (c *configurator) Version(ctx context.Context) (string, error) {
|
|||||||
words := strings.Fields(firstLine)
|
words := strings.Fields(firstLine)
|
||||||
const minWords = 2
|
const minWords = 2
|
||||||
if len(words) < minWords {
|
if len(words) < minWords {
|
||||||
return "", fmt.Errorf("openvpn --version: first line is too short: %q", firstLine)
|
return "", fmt.Errorf("%w: %s", ErrVersionTooShort, firstLine)
|
||||||
}
|
}
|
||||||
return words[1], nil
|
return words[1], nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package openvpn
|
package openvpn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -43,6 +44,8 @@ func (l *looper) GetStatus() (status models.LoopStatus) {
|
|||||||
return l.state.status
|
return l.state.status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrInvalidStatus = errors.New("invalid status")
|
||||||
|
|
||||||
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
||||||
l.state.statusMu.Lock()
|
l.state.statusMu.Lock()
|
||||||
defer l.state.statusMu.Unlock()
|
defer l.state.statusMu.Unlock()
|
||||||
@@ -78,8 +81,8 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
l.state.status = constants.Stopped
|
l.state.status = constants.Stopped
|
||||||
return status.String(), nil
|
return status.String(), nil
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("status %q can only be %q or %q",
|
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
|
||||||
status, constants.Running, constants.Stopped)
|
ErrInvalidStatus, status, constants.Running, constants.Stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -478,7 +478,7 @@ func writePortForwardedToFile(openFile os.OpenFileFunc,
|
|||||||
// replaceInErr is used to remove sensitive information from errors.
|
// replaceInErr is used to remove sensitive information from errors.
|
||||||
func replaceInErr(err error, substitutions map[string]string) error {
|
func replaceInErr(err error, substitutions map[string]string) error {
|
||||||
s := replaceInString(err.Error(), substitutions)
|
s := replaceInString(err.Error(), substitutions)
|
||||||
return errors.New(s)
|
return errors.New(s) //nolint:goerr113
|
||||||
}
|
}
|
||||||
|
|
||||||
// replaceInString is used to remove sensitive information.
|
// replaceInString is used to remove sensitive information.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package publicip
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@@ -27,6 +28,8 @@ func NewIPGetter(client *http.Client) IPGetter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrParseIP = errors.New("cannot parse IP address")
|
||||||
|
|
||||||
func (i *ipGetter) Get(ctx context.Context) (ip net.IP, err error) {
|
func (i *ipGetter) Get(ctx context.Context) (ip net.IP, err error) {
|
||||||
urls := []string{
|
urls := []string{
|
||||||
"https://ifconfig.me/ip",
|
"https://ifconfig.me/ip",
|
||||||
@@ -63,7 +66,7 @@ func (i *ipGetter) Get(ctx context.Context) (ip net.IP, err error) {
|
|||||||
s := strings.ReplaceAll(string(content), "\n", "")
|
s := strings.ReplaceAll(string(content), "\n", "")
|
||||||
ip = net.ParseIP(s)
|
ip = net.ParseIP(s)
|
||||||
if ip == nil {
|
if ip == nil {
|
||||||
return nil, fmt.Errorf("cannot parse IP address from %q", s)
|
return nil, fmt.Errorf("%w: %s", ErrParseIP, s)
|
||||||
}
|
}
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package publicip
|
package publicip
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -32,6 +33,8 @@ func (l *looper) GetStatus() (status models.LoopStatus) {
|
|||||||
return l.state.status
|
return l.state.status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrInvalidStatus = errors.New("invalid status")
|
||||||
|
|
||||||
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
||||||
l.state.statusMu.Lock()
|
l.state.statusMu.Lock()
|
||||||
defer l.state.statusMu.Unlock()
|
defer l.state.statusMu.Unlock()
|
||||||
@@ -67,8 +70,8 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
l.state.status = status
|
l.state.status = status
|
||||||
return status.String(), nil
|
return status.String(), nil
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("status %q can only be %q or %q",
|
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
|
||||||
status, constants.Running, constants.Stopped)
|
ErrInvalidStatus, status, constants.Running, constants.Stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ func (s *server) Run(ctx context.Context, done chan<- struct{}) {
|
|||||||
}()
|
}()
|
||||||
s.logger.Info("listening on %s", s.address)
|
s.logger.Info("listening on %s", s.address)
|
||||||
err := server.ListenAndServe()
|
err := server.ListenAndServe()
|
||||||
if err != nil && ctx.Err() != context.Canceled {
|
if err != nil && errors.Is(ctx.Err(), context.Canceled) {
|
||||||
s.logger.Error(err)
|
s.logger.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
@@ -11,15 +12,16 @@ type statusWrapper struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errInvalidStatus = errors.New("invalid status")
|
||||||
|
|
||||||
func (sw *statusWrapper) getStatus() (status models.LoopStatus, err error) {
|
func (sw *statusWrapper) getStatus() (status models.LoopStatus, err error) {
|
||||||
status = models.LoopStatus(sw.Status)
|
status = models.LoopStatus(sw.Status)
|
||||||
switch status {
|
switch status {
|
||||||
case constants.Stopped, constants.Running:
|
case constants.Stopped, constants.Running:
|
||||||
return status, nil
|
return status, nil
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf(
|
return "", fmt.Errorf("%w: %s: possible values are: %s, %s",
|
||||||
"invalid status %q: possible values are: %s, %s",
|
errInvalidStatus, sw.Status, constants.Stopped, constants.Running)
|
||||||
sw.Status, constants.Stopped, constants.Running)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package shadowsocks
|
package shadowsocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -29,6 +30,8 @@ func (l *looper) GetStatus() (status models.LoopStatus) {
|
|||||||
return l.state.status
|
return l.state.status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrInvalidStatus = errors.New("invalid status")
|
||||||
|
|
||||||
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
||||||
l.state.statusMu.Lock()
|
l.state.statusMu.Lock()
|
||||||
defer l.state.statusMu.Unlock()
|
defer l.state.statusMu.Unlock()
|
||||||
@@ -64,8 +67,8 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
l.state.status = status
|
l.state.status = status
|
||||||
return status.String(), nil
|
return status.String(), nil
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("status %q can only be %q or %q",
|
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
|
||||||
status, constants.Running, constants.Stopped)
|
ErrInvalidStatus, status, constants.Running, constants.Stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package updater
|
package updater
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -29,6 +30,8 @@ func (l *looper) GetStatus() (status models.LoopStatus) {
|
|||||||
return l.state.status
|
return l.state.status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrInvalidStatus = errors.New("invalid status")
|
||||||
|
|
||||||
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
|
||||||
l.state.statusMu.Lock()
|
l.state.statusMu.Lock()
|
||||||
defer l.state.statusMu.Unlock()
|
defer l.state.statusMu.Unlock()
|
||||||
@@ -64,8 +67,8 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
l.state.status = status
|
l.state.status = status
|
||||||
return status.String(), nil
|
return status.String(), nil
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("status %q can only be %q or %q",
|
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
|
||||||
status, constants.Running, constants.Stopped)
|
ErrInvalidStatus, status, constants.Running, constants.Stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package version
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
@@ -20,7 +21,7 @@ func GetMessage(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
// Find # of commits between current commit and latest commit
|
// Find # of commits between current commit and latest commit
|
||||||
commitsSince, err := getCommitsSince(ctx, client, buildInfo.Commit)
|
commitsSince, err := getCommitsSince(ctx, client, buildInfo.Commit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("cannot get version information: %w", err)
|
return "", err
|
||||||
} else if commitsSince == 0 {
|
} else if commitsSince == 0 {
|
||||||
return fmt.Sprintf("You are running on the bleeding edge of %s!", buildInfo.Version), nil
|
return fmt.Sprintf("You are running on the bleeding edge of %s!", buildInfo.Version), nil
|
||||||
}
|
}
|
||||||
@@ -32,7 +33,7 @@ func GetMessage(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
}
|
}
|
||||||
tagName, name, releaseTime, err := getLatestRelease(ctx, client)
|
tagName, name, releaseTime, err := getLatestRelease(ctx, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("cannot get version information: %w", err)
|
return "", err
|
||||||
}
|
}
|
||||||
if tagName == buildInfo.Version {
|
if tagName == buildInfo.Version {
|
||||||
return fmt.Sprintf("You are running the latest release %s", buildInfo.Version), nil
|
return fmt.Sprintf("You are running the latest release %s", buildInfo.Version), nil
|
||||||
@@ -43,6 +44,8 @@ func GetMessage(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errReleaseNotFound = errors.New("release not found")
|
||||||
|
|
||||||
func getLatestRelease(ctx context.Context, client *http.Client) (tagName, name string, time time.Time, err error) {
|
func getLatestRelease(ctx context.Context, client *http.Client) (tagName, name string, time time.Time, err error) {
|
||||||
releases, err := getGithubReleases(ctx, client)
|
releases, err := getGithubReleases(ctx, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -54,9 +57,11 @@ func getLatestRelease(ctx context.Context, client *http.Client) (tagName, name s
|
|||||||
}
|
}
|
||||||
return release.TagName, release.Name, release.PublishedAt, nil
|
return release.TagName, release.Name, release.PublishedAt, nil
|
||||||
}
|
}
|
||||||
return "", "", time, fmt.Errorf("no releases found")
|
return "", "", time, errReleaseNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errCommitNotFound = errors.New("commit not found")
|
||||||
|
|
||||||
func getCommitsSince(ctx context.Context, client *http.Client, commitShort string) (n int, err error) {
|
func getCommitsSince(ctx context.Context, client *http.Client, commitShort string) (n int, err error) {
|
||||||
commits, err := getGithubCommits(ctx, client)
|
commits, err := getGithubCommits(ctx, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -68,5 +73,5 @@ func getCommitsSince(ctx context.Context, client *http.Client, commitShort strin
|
|||||||
}
|
}
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
return 0, fmt.Errorf("no commit matching %q was found", commitShort)
|
return 0, fmt.Errorf("%w: %s", errCommitNotFound, commitShort)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user