mirror of
https://github.com/yusing/godoxy.git
synced 2026-01-11 22:30:47 +01:00
perf(mem): replace Scheme and ExcludedReason string with uint8 type to reduce mem usage
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
. "github.com/yusing/godoxy/internal/entrypoint"
|
||||
"github.com/yusing/godoxy/internal/route"
|
||||
"github.com/yusing/godoxy/internal/route/routes"
|
||||
routeTypes "github.com/yusing/godoxy/internal/route/types"
|
||||
"github.com/yusing/godoxy/internal/types"
|
||||
"github.com/yusing/goutils/task"
|
||||
)
|
||||
@@ -78,7 +79,7 @@ func BenchmarkEntrypointReal(b *testing.B) {
|
||||
|
||||
r := &route.Route{
|
||||
Alias: "test",
|
||||
Scheme: "http",
|
||||
Scheme: routeTypes.SchemeHTTP,
|
||||
Host: host,
|
||||
Port: route.Port{Proxy: portInt},
|
||||
HealthCheck: &types.HealthCheckConfig{Disable: true},
|
||||
@@ -119,7 +120,7 @@ func BenchmarkEntrypoint(b *testing.B) {
|
||||
|
||||
r := &route.Route{
|
||||
Alias: "test",
|
||||
Scheme: "http",
|
||||
Scheme: routeTypes.SchemeHTTP,
|
||||
Host: "localhost",
|
||||
Port: route.Port{
|
||||
Proxy: 8080,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package route
|
||||
|
||||
import route "github.com/yusing/godoxy/internal/route/types"
|
||||
|
||||
var (
|
||||
ImageNamePortMapTCP = map[string]int{
|
||||
"mssql": 1433,
|
||||
@@ -57,25 +59,25 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func getSchemePortByImageName(imageName string) (scheme string, port int, ok bool) {
|
||||
func getSchemePortByImageName(imageName string) (scheme route.Scheme, port int, ok bool) {
|
||||
if port, ok := ImageNamePortMapHTTP[imageName]; ok {
|
||||
return "http", port, true
|
||||
return route.SchemeHTTP, port, true
|
||||
}
|
||||
if port, ok := ImageNamePortMapHTTPS[imageName]; ok {
|
||||
return "https", port, true
|
||||
return route.SchemeHTTPS, port, true
|
||||
}
|
||||
if port, ok := ImageNamePortMapTCP[imageName]; ok {
|
||||
return "tcp", port, true
|
||||
return route.SchemeTCP, port, true
|
||||
}
|
||||
return scheme, port, ok
|
||||
}
|
||||
|
||||
func getSchemePortByAlias(alias string) (scheme string, port int, ok bool) {
|
||||
func getSchemePortByAlias(alias string) (scheme route.Scheme, port int, ok bool) {
|
||||
if port, ok := AliasPortMapHTTP[alias]; ok {
|
||||
return "http", port, true
|
||||
return route.SchemeHTTP, port, true
|
||||
}
|
||||
if port, ok := AliasPortMapHTTPS[alias]; ok {
|
||||
return "https", port, true
|
||||
return route.SchemeHTTPS, port, true
|
||||
}
|
||||
return scheme, port, ok
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/docker/docker/client"
|
||||
D "github.com/yusing/godoxy/internal/docker"
|
||||
"github.com/yusing/godoxy/internal/route"
|
||||
T "github.com/yusing/godoxy/internal/route/types"
|
||||
routeTypes "github.com/yusing/godoxy/internal/route/types"
|
||||
expect "github.com/yusing/goutils/testing"
|
||||
)
|
||||
|
||||
@@ -91,8 +91,8 @@ func TestApplyLabel(t *testing.T) {
|
||||
b, ok := entries["b"]
|
||||
expect.True(t, ok)
|
||||
|
||||
expect.Equal(t, a.Scheme, "https")
|
||||
expect.Equal(t, b.Scheme, "https")
|
||||
expect.Equal(t, a.Scheme, routeTypes.SchemeHTTPS)
|
||||
expect.Equal(t, b.Scheme, routeTypes.SchemeHTTPS)
|
||||
|
||||
expect.Equal(t, a.Host, "app")
|
||||
expect.Equal(t, b.Host, "app")
|
||||
@@ -152,12 +152,12 @@ func TestApplyLabelWithAlias(t *testing.T) {
|
||||
c, ok := entries["c"]
|
||||
expect.True(t, ok)
|
||||
|
||||
expect.Equal(t, a.Scheme, "http")
|
||||
expect.Equal(t, a.Scheme, routeTypes.SchemeHTTP)
|
||||
expect.Equal(t, a.Port.Proxy, 3333)
|
||||
expect.Equal(t, a.NoTLSVerify, true)
|
||||
expect.Equal(t, b.Scheme, "http")
|
||||
expect.Equal(t, b.Scheme, routeTypes.SchemeHTTP)
|
||||
expect.Equal(t, b.Port.Proxy, 1234)
|
||||
expect.Equal(t, c.Scheme, "https")
|
||||
expect.Equal(t, c.Scheme, routeTypes.SchemeHTTPS)
|
||||
}
|
||||
|
||||
func TestApplyLabelWithRef(t *testing.T) {
|
||||
@@ -180,11 +180,11 @@ func TestApplyLabelWithRef(t *testing.T) {
|
||||
c, ok := entries["c"]
|
||||
expect.True(t, ok)
|
||||
|
||||
expect.Equal(t, a.Scheme, "http")
|
||||
expect.Equal(t, a.Scheme, routeTypes.SchemeHTTP)
|
||||
expect.Equal(t, a.Host, "localhost")
|
||||
expect.Equal(t, a.Port.Proxy, 4444)
|
||||
expect.Equal(t, b.Port.Proxy, 9999)
|
||||
expect.Equal(t, c.Scheme, "https")
|
||||
expect.Equal(t, c.Scheme, routeTypes.SchemeHTTPS)
|
||||
expect.Equal(t, c.Port.Proxy, 1111)
|
||||
}
|
||||
|
||||
@@ -229,12 +229,12 @@ func TestDynamicAliases(t *testing.T) {
|
||||
|
||||
r, ok := entries["app1"]
|
||||
expect.True(t, ok)
|
||||
expect.Equal(t, r.Scheme, "http")
|
||||
expect.Equal(t, r.Scheme, routeTypes.SchemeHTTP)
|
||||
expect.Equal(t, r.Port.Proxy, 1234)
|
||||
|
||||
r, ok = entries["app1_backend"]
|
||||
expect.True(t, ok)
|
||||
expect.Equal(t, r.Scheme, "http")
|
||||
expect.Equal(t, r.Scheme, routeTypes.SchemeHTTP)
|
||||
expect.Equal(t, r.Port.Proxy, 5678)
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ func TestStreamDefaultValues(t *testing.T) {
|
||||
r, ok := makeRoutes(cont)["a"]
|
||||
expect.True(t, ok)
|
||||
expect.NoError(t, r.Validate())
|
||||
expect.Equal(t, r.Scheme, T.Scheme("udp"))
|
||||
expect.Equal(t, r.Scheme, routeTypes.SchemeUDP)
|
||||
expect.Equal(t, r.TargetURL().Hostname(), privIP)
|
||||
expect.Equal(t, r.Port.Listening, 0)
|
||||
expect.Equal(t, r.Port.Proxy, int(privPort))
|
||||
@@ -337,7 +337,7 @@ func TestStreamDefaultValues(t *testing.T) {
|
||||
r, ok := makeRoutes(cont, testIP)["a"]
|
||||
expect.True(t, ok)
|
||||
expect.NoError(t, r.Validate())
|
||||
expect.Equal(t, r.Scheme, T.Scheme("udp"))
|
||||
expect.Equal(t, r.Scheme, routeTypes.SchemeUDP)
|
||||
expect.Equal(t, r.TargetURL().Hostname(), testIP)
|
||||
expect.Equal(t, r.Port.Listening, 0)
|
||||
expect.Equal(t, r.Port.Proxy, int(pubPort))
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -40,7 +41,7 @@ type (
|
||||
_ utils.NoCopy
|
||||
|
||||
Alias string `json:"alias"`
|
||||
Scheme route.Scheme `json:"scheme,omitempty"`
|
||||
Scheme route.Scheme `json:"scheme,omitempty" swaggertype:"string"`
|
||||
Host string `json:"host,omitempty"`
|
||||
Port route.Port `json:"port"`
|
||||
Root string `json:"root,omitempty"`
|
||||
@@ -71,8 +72,8 @@ type (
|
||||
LisURL *nettypes.URL `json:"lurl,omitempty" swaggertype:"string" extensions:"x-nullable"`
|
||||
ProxyURL *nettypes.URL `json:"purl,omitempty" swaggertype:"string"`
|
||||
|
||||
Excluded bool `json:"excluded,omitempty" extensions:"x-nullable"`
|
||||
ExcludedReason string `json:"excluded_reason,omitempty" extensions:"x-nullable"`
|
||||
Excluded bool `json:"excluded,omitempty" extensions:"x-nullable"`
|
||||
ExcludedReason ExcludedReason `json:"excluded_reason,omitempty" extensions:"x-nullable"`
|
||||
|
||||
HealthMon types.HealthMonitor `json:"health,omitempty" swaggerignore:"true"`
|
||||
// for swagger
|
||||
@@ -272,7 +273,7 @@ func (r *Route) Validate() gperr.Error {
|
||||
r.impl = impl
|
||||
r.Excluded = r.ShouldExclude()
|
||||
if r.Excluded {
|
||||
r.ExcludedReason = r.GetExcludedReason()
|
||||
r.ExcludedReason = r.findExcludedReason()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -518,31 +519,73 @@ func (r *Route) ShouldExclude() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *Route) GetExcludedReason() string {
|
||||
if r.lastError != nil {
|
||||
return string(gperr.Plain(r.lastError))
|
||||
type ExcludedReason uint8
|
||||
|
||||
const (
|
||||
ExcludedReasonNone ExcludedReason = iota
|
||||
ExcludedReasonError
|
||||
ExcludedReasonManual
|
||||
ExcludedReasonNoPortContainer
|
||||
ExcludedReasonNoPortSpecified
|
||||
ExcludedReasonBlacklisted
|
||||
ExcludedReasonBuildx
|
||||
ExcludedReasonOld
|
||||
)
|
||||
|
||||
func (re ExcludedReason) String() string {
|
||||
switch re {
|
||||
case ExcludedReasonNone:
|
||||
return ""
|
||||
case ExcludedReasonError:
|
||||
return "Error"
|
||||
case ExcludedReasonManual:
|
||||
return "Manual exclusion"
|
||||
case ExcludedReasonNoPortContainer:
|
||||
return "No port exposed in container"
|
||||
case ExcludedReasonNoPortSpecified:
|
||||
return "No port specified"
|
||||
case ExcludedReasonBlacklisted:
|
||||
return "Blacklisted (backend service or database)"
|
||||
case ExcludedReasonBuildx:
|
||||
return "Buildx"
|
||||
case ExcludedReasonOld:
|
||||
return "Container renaming intermediate state"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
if r.ExcludedReason != "" {
|
||||
}
|
||||
|
||||
func (re ExcludedReason) MarshalJSON() ([]byte, error) {
|
||||
return strconv.AppendQuote(nil, re.String()), nil
|
||||
}
|
||||
|
||||
// no need to unmarshal json because we don't store this
|
||||
|
||||
func (r *Route) findExcludedReason() ExcludedReason {
|
||||
if r.lastError != nil {
|
||||
return ExcludedReasonError
|
||||
}
|
||||
if r.ExcludedReason != ExcludedReasonNone {
|
||||
return r.ExcludedReason
|
||||
}
|
||||
if r.Container != nil {
|
||||
switch {
|
||||
case r.Container.IsExcluded:
|
||||
return "Manual exclusion"
|
||||
return ExcludedReasonManual
|
||||
case r.IsZeroPort() && !r.UseIdleWatcher():
|
||||
return "No port exposed in container"
|
||||
return ExcludedReasonNoPortContainer
|
||||
case !r.Container.IsExplicit && docker.IsBlacklisted(r.Container):
|
||||
return "Blacklisted (backend service or database)"
|
||||
return ExcludedReasonBlacklisted
|
||||
case strings.HasPrefix(r.Container.ContainerName, "buildx_"):
|
||||
return "Buildx"
|
||||
return ExcludedReasonBuildx
|
||||
}
|
||||
} else if r.IsZeroPort() && r.Scheme != route.SchemeFileServer {
|
||||
return "No port specified"
|
||||
return ExcludedReasonNoPortSpecified
|
||||
}
|
||||
if strings.HasSuffix(r.Alias, "-old") {
|
||||
return "Container renaming intermediate state"
|
||||
return ExcludedReasonOld
|
||||
}
|
||||
return ""
|
||||
return ExcludedReasonNone
|
||||
}
|
||||
|
||||
func (r *Route) UseLoadBalance() bool {
|
||||
@@ -594,8 +637,8 @@ func (r *Route) Finalize() {
|
||||
if isDocker {
|
||||
scheme, port, ok := getSchemePortByImageName(cont.Image.Name)
|
||||
if ok {
|
||||
if r.Scheme == "" {
|
||||
r.Scheme = route.Scheme(scheme)
|
||||
if r.Scheme == route.SchemeNone {
|
||||
r.Scheme = scheme
|
||||
}
|
||||
if pp == 0 {
|
||||
pp = port
|
||||
@@ -604,8 +647,8 @@ func (r *Route) Finalize() {
|
||||
}
|
||||
|
||||
if scheme, port, ok := getSchemePortByAlias(r.Alias); ok {
|
||||
if r.Scheme == "" {
|
||||
r.Scheme = route.Scheme(scheme)
|
||||
if r.Scheme == route.SchemeNone {
|
||||
r.Scheme = scheme
|
||||
}
|
||||
if pp == 0 {
|
||||
pp = port
|
||||
@@ -620,7 +663,7 @@ func (r *Route) Finalize() {
|
||||
} else {
|
||||
pp = preferredPort(cont.PrivatePortMapping)
|
||||
}
|
||||
case r.Scheme == "https":
|
||||
case r.Scheme == route.SchemeHTTPS:
|
||||
pp = 443
|
||||
default:
|
||||
pp = 80
|
||||
@@ -628,10 +671,10 @@ func (r *Route) Finalize() {
|
||||
}
|
||||
|
||||
if isDocker {
|
||||
if r.Scheme == "" {
|
||||
if r.Scheme == route.SchemeNone {
|
||||
for _, p := range cont.PublicPortMapping {
|
||||
if int(p.PrivatePort) == pp && p.Type == "udp" {
|
||||
r.Scheme = "udp"
|
||||
r.Scheme = route.SchemeUDP
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -649,14 +692,14 @@ func (r *Route) Finalize() {
|
||||
}
|
||||
}
|
||||
|
||||
if r.Scheme == "" {
|
||||
if r.Scheme == route.SchemeNone {
|
||||
switch {
|
||||
case lp != 0:
|
||||
r.Scheme = "tcp"
|
||||
r.Scheme = route.SchemeTCP
|
||||
case pp%1000 == 443:
|
||||
r.Scheme = "https"
|
||||
r.Scheme = route.SchemeHTTPS
|
||||
default: // assume its http
|
||||
r.Scheme = "http"
|
||||
r.Scheme = route.SchemeHTTP
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ func TestRouteValidate(t *testing.T) {
|
||||
t.Run("InvalidScheme", func(t *testing.T) {
|
||||
r := &Route{
|
||||
Alias: "test",
|
||||
Scheme: "invalid",
|
||||
Scheme: 123,
|
||||
Host: "example.com",
|
||||
Port: route.Port{Proxy: 80},
|
||||
}
|
||||
|
||||
@@ -1,29 +1,82 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
gperr "github.com/yusing/goutils/errs"
|
||||
)
|
||||
|
||||
type Scheme string
|
||||
type Scheme uint8
|
||||
|
||||
var ErrInvalidScheme = gperr.New("invalid scheme")
|
||||
|
||||
const (
|
||||
SchemeHTTP Scheme = "http"
|
||||
SchemeHTTPS Scheme = "https"
|
||||
SchemeTCP Scheme = "tcp"
|
||||
SchemeUDP Scheme = "udp"
|
||||
SchemeFileServer Scheme = "fileserver"
|
||||
SchemeHTTP Scheme = 1 << iota
|
||||
SchemeHTTPS
|
||||
SchemeTCP
|
||||
SchemeUDP
|
||||
SchemeFileServer
|
||||
SchemeNone Scheme = 0
|
||||
|
||||
schemeReverseProxy = SchemeHTTP | SchemeHTTPS
|
||||
schemeStream = SchemeTCP | SchemeUDP
|
||||
|
||||
schemeStrHTTP = "http"
|
||||
schemeStrHTTPS = "https"
|
||||
schemeStrTCP = "tcp"
|
||||
schemeStrUDP = "udp"
|
||||
schemeStrFileServer = "fileserver"
|
||||
schemeStrUnknown = "unknown"
|
||||
)
|
||||
|
||||
func (s Scheme) Validate() gperr.Error {
|
||||
func (s Scheme) String() string {
|
||||
switch s {
|
||||
case SchemeHTTP, SchemeHTTPS,
|
||||
SchemeTCP, SchemeUDP, SchemeFileServer:
|
||||
return nil
|
||||
case SchemeHTTP:
|
||||
return schemeStrHTTP
|
||||
case SchemeHTTPS:
|
||||
return schemeStrHTTPS
|
||||
case SchemeTCP:
|
||||
return schemeStrTCP
|
||||
case SchemeUDP:
|
||||
return schemeStrUDP
|
||||
case SchemeFileServer:
|
||||
return schemeStrFileServer
|
||||
default:
|
||||
return schemeStrUnknown
|
||||
}
|
||||
return ErrInvalidScheme.Subject(string(s))
|
||||
}
|
||||
|
||||
func (s Scheme) IsReverseProxy() bool { return s == SchemeHTTP || s == SchemeHTTPS }
|
||||
func (s Scheme) IsStream() bool { return s == SchemeTCP || s == SchemeUDP }
|
||||
func (s Scheme) MarshalJSON() ([]byte, error) {
|
||||
return strconv.AppendQuote(nil, s.String()), nil
|
||||
}
|
||||
|
||||
func (s *Scheme) UnmarshalJSON(data []byte) error {
|
||||
var v string
|
||||
if err := sonic.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Parse(v)
|
||||
}
|
||||
|
||||
// Parse implements strutils.Parser
|
||||
func (s *Scheme) Parse(v string) error {
|
||||
switch v {
|
||||
case schemeStrHTTP:
|
||||
*s = SchemeHTTP
|
||||
case schemeStrHTTPS:
|
||||
*s = SchemeHTTPS
|
||||
case schemeStrTCP:
|
||||
*s = SchemeTCP
|
||||
case schemeStrUDP:
|
||||
*s = SchemeUDP
|
||||
case schemeStrFileServer:
|
||||
*s = SchemeFileServer
|
||||
default:
|
||||
return ErrInvalidScheme.Subject(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Scheme) IsReverseProxy() bool { return s&schemeReverseProxy != 0 }
|
||||
func (s Scheme) IsStream() bool { return s&schemeStream != 0 }
|
||||
|
||||
Reference in New Issue
Block a user