migrated from logrus to zerolog, improved error formatting, fixed concurrent map write, fixed crash on rapid page refresh for idle containers, fixed infinite recursion on gotfiy error, fixed websocket connection problem when using idlewatcher

This commit is contained in:
yusing
2024-10-29 11:34:58 +08:00
parent cfa74d69ae
commit e5bbb18414
137 changed files with 2640 additions and 2348 deletions

View File

@@ -1,6 +1,3 @@
package fields
type (
Alias string
NewAlias = Alias
)
type Alias string

View File

@@ -1,14 +1,10 @@
package fields
import (
E "github.com/yusing/go-proxy/internal/error"
)
type (
Host string
Subdomain = Alias
)
func ValidateHost[String ~string](s String) (Host, E.Error) {
func ValidateHost[String ~string](s String) (Host, error) {
return Host(s), nil
}

View File

@@ -1,6 +1,8 @@
package fields
import (
"errors"
"fmt"
"regexp"
E "github.com/yusing/go-proxy/internal/error"
@@ -13,12 +15,17 @@ type (
var pathPattern = regexp.MustCompile(`^(/[-\w./]*({\$\})?|((GET|POST|DELETE|PUT|HEAD|OPTION) /[-\w./]*({\$\})?))$`)
func ValidatePathPattern(s string) (PathPattern, E.Error) {
var (
ErrEmptyPathPattern = errors.New("path must not be empty")
ErrInvalidPathPattern = errors.New("invalid path pattern")
)
func ValidatePathPattern(s string) (PathPattern, error) {
if len(s) == 0 {
return "", E.Invalid("path", "must not be empty")
return "", ErrEmptyPathPattern
}
if !pathPattern.MatchString(s) {
return "", E.Invalid("path pattern", s)
return "", fmt.Errorf("%w %q", ErrInvalidPathPattern, s)
}
return PathPattern(s), nil
}
@@ -27,13 +34,15 @@ func ValidatePathPatterns(s []string) (PathPatterns, E.Error) {
if len(s) == 0 {
return []PathPattern{"/"}, nil
}
errs := E.NewBuilder("invalid path patterns")
pp := make(PathPatterns, len(s))
for i, v := range s {
pattern, err := ValidatePathPattern(v)
if err != nil {
return nil, err
errs.Add(err)
} else {
pp[i] = pattern
}
pp[i] = pattern
}
return pp, nil
return pp, errs.Error()
}

View File

@@ -1,9 +1,9 @@
package fields
import (
"errors"
"testing"
E "github.com/yusing/go-proxy/internal/error"
U "github.com/yusing/go-proxy/internal/utils/testing"
)
@@ -38,10 +38,10 @@ var invalidPatterns = []string{
func TestPathPatternRegex(t *testing.T) {
for _, pattern := range validPatterns {
_, err := ValidatePathPattern(pattern)
U.ExpectNoError(t, err.Error())
U.ExpectNoError(t, err)
}
for _, pattern := range invalidPatterns {
_, err := ValidatePathPattern(pattern)
U.ExpectError2(t, pattern, E.ErrInvalid, err.Error())
U.ExpectTrue(t, errors.Is(err, ErrInvalidPathPattern))
}
}

View File

@@ -4,22 +4,25 @@ import (
"strconv"
E "github.com/yusing/go-proxy/internal/error"
"github.com/yusing/go-proxy/internal/utils/strutils"
)
type Port int
func ValidatePort[String ~string](v String) (Port, E.Error) {
p, err := strconv.Atoi(string(v))
var ErrPortOutOfRange = E.New("port out of range")
func ValidatePort[String ~string](v String) (Port, error) {
p, err := strutils.Atoi(string(v))
if err != nil {
return ErrPort, E.Invalid("port number", v).With(err)
return ErrPort, err
}
return ValidatePortInt(p)
}
func ValidatePortInt[Int int | uint16](v Int) (Port, E.Error) {
func ValidatePortInt[Int int | uint16](v Int) (Port, error) {
p := Port(v)
if !p.inBound() {
return ErrPort, E.OutOfRange("port", p)
return ErrPort, ErrPortOutOfRange.Subject(strconv.Itoa(int(p)))
}
return p, nil
}

View File

@@ -6,12 +6,14 @@ import (
type Scheme string
func NewScheme[String ~string](s String) (Scheme, E.Error) {
var ErrInvalidScheme = E.New("invalid scheme")
func NewScheme(s string) (Scheme, error) {
switch s {
case "http", "https", "tcp", "udp":
return Scheme(s), nil
}
return "", E.Invalid("scheme", s)
return "", ErrInvalidScheme.Subject(s)
}
func (s Scheme) IsHTTP() bool { return s == "http" }

View File

@@ -3,7 +3,6 @@ package fields
import (
"strings"
"github.com/yusing/go-proxy/internal/common"
E "github.com/yusing/go-proxy/internal/error"
)
@@ -12,7 +11,9 @@ type StreamPort struct {
ProxyPort Port `json:"proxy"`
}
func ValidateStreamPort(p string) (_ StreamPort, err E.Error) {
var ErrStreamPortTooManyColons = E.New("too many colons")
func ValidateStreamPort(p string) (StreamPort, error) {
split := strings.Split(p, ":")
switch len(split) {
@@ -21,36 +22,14 @@ func ValidateStreamPort(p string) (_ StreamPort, err E.Error) {
case 2:
break
default:
err = E.Invalid("stream port", p).With("too many colons")
return
return StreamPort{}, ErrStreamPortTooManyColons.Subject(p)
}
listeningPort, err := ValidatePort(split[0])
if err != nil {
err = err.Subject("listening port")
return
}
proxyPort, err := ValidatePort(split[1])
if err.Is(E.ErrOutOfRange) {
err = err.Subject("proxy port")
return
} else if err != nil {
proxyPort, err = parseNameToPort(split[1])
if err != nil {
err = E.Invalid("proxy port", proxyPort)
return
}
listeningPort, lErr := ValidatePort(split[0])
proxyPort, pErr := ValidatePort(split[1])
if err := E.Join(lErr, pErr); err != nil {
return StreamPort{}, err
}
return StreamPort{listeningPort, proxyPort}, nil
}
func parseNameToPort(name string) (Port, E.Error) {
port, ok := common.ServiceNamePortMapTCP[name]
if !ok {
return ErrPort, E.Invalid("service", name)
}
return Port(port), nil
}

View File

@@ -1,9 +1,9 @@
package fields
import (
"strconv"
"testing"
E "github.com/yusing/go-proxy/internal/error"
. "github.com/yusing/go-proxy/internal/utils/testing"
)
@@ -11,7 +11,6 @@ var validPorts = []string{
"1234:5678",
"0:2345",
"2345",
"1234:postgres",
}
var invalidPorts = []string{
@@ -19,7 +18,6 @@ var invalidPorts = []string{
"123:",
"0:",
":1234",
"1234:1234:1234",
"qwerty",
"asdfgh:asdfgh",
"1234:asdfgh",
@@ -32,17 +30,25 @@ var outOfRangePorts = []string{
"0:65536",
}
var tooManyColonsPorts = []string{
"1234:1234:1234",
}
func TestStreamPort(t *testing.T) {
for _, port := range validPorts {
_, err := ValidateStreamPort(port)
ExpectNoError(t, err.Error())
ExpectNoError(t, err)
}
for _, port := range invalidPorts {
_, err := ValidateStreamPort(port)
ExpectError2(t, port, E.ErrInvalid, err.Error())
ExpectError2(t, port, strconv.ErrSyntax, err)
}
for _, port := range outOfRangePorts {
_, err := ValidateStreamPort(port)
ExpectError2(t, port, E.ErrOutOfRange, err.Error())
ExpectError2(t, port, ErrPortOutOfRange, err)
}
for _, port := range tooManyColonsPorts {
_, err := ValidateStreamPort(port)
ExpectError2(t, port, ErrStreamPortTooManyColons, err)
}
}

View File

@@ -12,22 +12,23 @@ type StreamScheme struct {
ProxyScheme Scheme `json:"proxy"`
}
func ValidateStreamScheme(s string) (ss *StreamScheme, err E.Error) {
ss = &StreamScheme{}
func ValidateStreamScheme(s string) (*StreamScheme, error) {
ss := &StreamScheme{}
parts := strings.Split(s, ":")
if len(parts) == 1 {
parts = []string{s, s}
} else if len(parts) != 2 {
return nil, E.Invalid("stream scheme", s)
return nil, ErrInvalidScheme.Subject(s)
}
ss.ListeningScheme, err = NewScheme(parts[0])
if err.HasError() {
return nil, err
}
ss.ProxyScheme, err = NewScheme(parts[1])
if err.HasError() {
var lErr, pErr error
ss.ListeningScheme, lErr = NewScheme(parts[0])
ss.ProxyScheme, pErr = NewScheme(parts[1])
if err := E.Join(lErr, pErr); err != nil {
return nil, err
}
return ss, nil
}

View File

@@ -0,0 +1,37 @@
package fields
import (
"testing"
. "github.com/yusing/go-proxy/internal/utils/testing"
)
var (
validStreamSchemes = []string{
"tcp:tcp",
"tcp:udp",
"udp:tcp",
"udp:udp",
"tcp",
"udp",
}
invalidStreamSchemes = []string{
"tcp:tcp:",
"tcp:",
":udp:",
":udp",
"top",
}
)
func TestNewStreamScheme(t *testing.T) {
for _, s := range validStreamSchemes {
_, err := ValidateStreamScheme(s)
ExpectNoError(t, err)
}
for _, s := range invalidStreamSchemes {
_, err := ValidateStreamScheme(s)
ExpectError(t, ErrInvalidScheme, err)
}
}