experimental homepage labels support

This commit is contained in:
yusing 2024-10-03 10:10:14 +08:00
parent 90bababd38
commit e6b4630ce9
7 changed files with 43 additions and 24 deletions

View file

@ -35,10 +35,10 @@ func (cfg *Config) HomepageConfig() H.HomePageConfig {
cert, _ := cfg.autocertProvider.GetCert(nil) cert, _ := cfg.autocertProvider.GetCert(nil)
if cert != nil { if cert != nil {
proto = "https" proto = "https"
port = common.ProxyHTTPPort port = common.ProxyHTTPSPort
} else { } else {
proto = "http" proto = "http"
port = common.ProxyHTTPSPort port = common.ProxyHTTPPort
} }
hpCfg := H.NewHomePageConfig() hpCfg := H.NewHomePageConfig()
@ -49,8 +49,13 @@ func (cfg *Config) HomepageConfig() H.HomePageConfig {
entry := r.Entry() entry := r.Entry()
item := entry.Homepage item := entry.Homepage
if item == nil {
item = &H.HomePageItem{} if !item.Initialized {
item.Show = r.Entry().IsExplicit || !p.IsExplicitOnly()
}
if !item.Show || r.Type() != R.RouteTypeReverseProxy {
return
} }
if item.Name == "" { if item.Name == "" {
@ -61,20 +66,27 @@ func (cfg *Config) HomepageConfig() H.HomePageConfig {
if item.Category == "" { if item.Category == "" {
item.Category = "Docker" item.Category = "Docker"
} }
if item.Icon == "" {
item.Icon = "🐳"
}
item.SourceType = string(PR.ProviderTypeDocker) item.SourceType = string(PR.ProviderTypeDocker)
} else if p.GetType() == PR.ProviderTypeFile { } else if p.GetType() == PR.ProviderTypeFile {
if item.Category == "" { if item.Category == "" {
item.Category = "Others" item.Category = "Others"
} }
if item.Icon == "" {
item.Icon = "🔗"
}
item.SourceType = string(PR.ProviderTypeFile) item.SourceType = string(PR.ProviderTypeFile)
} }
if item.URL == "" && r.Type() == R.RouteTypeReverseProxy { if item.URL == "" {
if len(domains) > 0 { if len(domains) > 0 {
item.URL = fmt.Sprintf("%s://%s.%s:%s", proto, strings.ToLower(alias), domains[0], port) item.URL = fmt.Sprintf("%s://%s.%s:%s", proto, strings.ToLower(alias), domains[0], port)
} }
} }
hpCfg.Add(item)
hpCfg.Add(&item)
}) })
return hpCfg return hpCfg
} }

View file

@ -58,7 +58,7 @@ func ApplyLabel[T any](obj *T, l *Label) E.NestedError {
} }
dst, ok := field.Interface().(NestedLabelMap) dst, ok := field.Interface().(NestedLabelMap)
if !ok { if !ok {
return E.Invalid("type", field.Type()) return U.Deserialize(U.SerializedObject{nestedLabel.Namespace: nestedLabel.Value}, field.Addr().Interface())
} }
if dst == nil { if dst == nil {
field.Set(reflect.MakeMap(reflect.TypeFor[NestedLabelMap]())) field.Set(reflect.MakeMap(reflect.TypeFor[NestedLabelMap]()))

View file

@ -5,13 +5,16 @@ type (
HomePageCategory []*HomePageItem HomePageCategory []*HomePageItem
HomePageItem struct { HomePageItem struct {
Show bool `yaml:"show" json:"show"`
Name string `yaml:"name" json:"name"` Name string `yaml:"name" json:"name"`
Icon string `yaml:"icon" json:"icon,omitempty"` Icon string `yaml:"icon" json:"icon"`
URL string `yaml:"url" json:"url,omitempty"` // URL or unicodes URL string `yaml:"url" json:"url"` // URL or unicodes
Category string `yaml:"category" json:"category"` Category string `yaml:"category" json:"category"`
SourceType string `yaml:"source_type" json:"source_type,omitempty"` SourceType string `yaml:"source_type" json:"source_type"`
Description string `yaml:"description" json:"description,omitempty"` Description string `yaml:"description" json:"description"`
WidgetConfig map[string]any `yaml:",flow" json:"widget_config,omitempty"` WidgetConfig map[string]any `yaml:",flow" json:"widget_config"`
Initialized bool `yaml:"-" json:"-"`
} }
) )

View file

@ -22,7 +22,7 @@ type (
NoTLSVerify bool `yaml:"no_tls_verify" json:"no_tls_verify,omitempty"` // https proxy only NoTLSVerify bool `yaml:"no_tls_verify" json:"no_tls_verify,omitempty"` // https proxy only
PathPatterns []string `yaml:"path_patterns" json:"path_patterns,omitempty"` // http(s) proxy only PathPatterns []string `yaml:"path_patterns" json:"path_patterns,omitempty"` // http(s) proxy only
Middlewares D.NestedLabelMap `yaml:"middlewares" json:"middlewares,omitempty"` Middlewares D.NestedLabelMap `yaml:"middlewares" json:"middlewares,omitempty"`
Homepage *H.HomePageItem `yaml:"homepage" json:"homepage"` Homepage H.HomePageItem `yaml:"homepage" json:"homepage"`
/* Docker only */ /* Docker only */
*D.ProxyProperties `yaml:"-" json:"proxy_properties"` *D.ProxyProperties `yaml:"-" json:"proxy_properties"`

View file

@ -9,7 +9,6 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
D "github.com/yusing/go-proxy/internal/docker" D "github.com/yusing/go-proxy/internal/docker"
E "github.com/yusing/go-proxy/internal/error" E "github.com/yusing/go-proxy/internal/error"
H "github.com/yusing/go-proxy/internal/homepage"
M "github.com/yusing/go-proxy/internal/models" M "github.com/yusing/go-proxy/internal/models"
R "github.com/yusing/go-proxy/internal/route" R "github.com/yusing/go-proxy/internal/route"
W "github.com/yusing/go-proxy/internal/watcher" W "github.com/yusing/go-proxy/internal/watcher"
@ -185,7 +184,6 @@ func (p *DockerProvider) entriesFromContainerLabels(container D.Container) (entr
Alias: a, Alias: a,
Host: p.hostname, Host: p.hostname,
ProxyProperties: container.ProxyProperties, ProxyProperties: container.ProxyProperties,
Homepage: &H.HomePageItem{},
}) })
} }

View file

@ -77,14 +77,9 @@ func NewDockerProvider(name string, dockerHost string) (p *Provider, err E.Neste
if name == "" { if name == "" {
return nil, E.Invalid("provider name", "empty") return nil, E.Invalid("provider name", "empty")
} }
explicitOnly := false
if name[len(name)-1] == '!' {
explicitOnly = true
name = name[:len(name)-1]
}
p = newProvider(name, ProviderTypeDocker) p = newProvider(name, ProviderTypeDocker)
p.ProviderImpl, err = DockerProviderImpl(dockerHost, explicitOnly) p.ProviderImpl, err = DockerProviderImpl(dockerHost, p.IsExplicitOnly())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -92,6 +87,10 @@ func NewDockerProvider(name string, dockerHost string) (p *Provider, err E.Neste
return return
} }
func (p *Provider) IsExplicitOnly() bool {
return p.name[len(p.name)-1] == '!'
}
func (p *Provider) GetName() string { func (p *Provider) GetName() string {
return p.name return p.name
} }

View file

@ -122,14 +122,21 @@ func Serialize(data any) (SerializedObject, E.NestedError) {
// //
// The function returns an error if the target value is not a struct or a map[string]any, or if there is an error during deserialization. // The function returns an error if the target value is not a struct or a map[string]any, or if there is an error during deserialization.
func Deserialize(src SerializedObject, dst any) E.NestedError { func Deserialize(src SerializedObject, dst any) E.NestedError {
if src == nil || dst == nil { if src == nil {
return nil return E.Invalid("src", "nil")
}
if dst == nil {
return E.Invalid("nil dst", fmt.Sprintf("type: %T", dst))
} }
dstV := reflect.ValueOf(dst) dstV := reflect.ValueOf(dst)
dstT := dstV.Type() dstT := dstV.Type()
if dstV.Kind() == reflect.Ptr { if dstV.Kind() == reflect.Ptr {
if dstV.IsNil() {
return E.Invalid("nil dst", fmt.Sprintf("type: %T", dst))
}
dstV = dstV.Elem() dstV = dstV.Elem()
dstT = dstV.Type() dstT = dstV.Type()
} }
@ -153,7 +160,7 @@ func Deserialize(src SerializedObject, dst any) E.NestedError {
return err.Subject(k) return err.Subject(k)
} }
} else { } else {
return E.Unexpected("field", k) return E.Unexpected("field", k).Subjectf("%T", dst)
} }
} }
} else if dstV.Kind() == reflect.Map && dstT.Key().Kind() == reflect.String { } else if dstV.Kind() == reflect.Map && dstT.Key().Kind() == reflect.String {