diff --git a/internal/api/v1/list.go b/internal/api/v1/list.go index 52fe91b..392b303 100644 --- a/internal/api/v1/list.go +++ b/internal/api/v1/list.go @@ -17,6 +17,7 @@ const ( ListMiddlewares = "middlewares" ListMiddlewareTrace = "middleware_trace" ListMatchDomains = "match_domains" + ListHomepageConfig = "homepage_config" ) func List(cfg *config.Config, w http.ResponseWriter, r *http.Request) { @@ -36,6 +37,8 @@ func List(cfg *config.Config, w http.ResponseWriter, r *http.Request) { listMiddlewareTrace(w, r) case ListMatchDomains: listMatchDomains(cfg, w, r) + case ListHomepageConfig: + listHomepageConfig(cfg, w, r) default: U.HandleErr(w, r, U.ErrInvalidKey("what"), http.StatusBadRequest) } @@ -78,3 +81,7 @@ func listMiddlewares(w http.ResponseWriter, r *http.Request) { func listMatchDomains(cfg *config.Config, w http.ResponseWriter, r *http.Request) { U.HandleErr(w, r, U.RespondJson(w, cfg.Value().MatchDomains)) } + +func listHomepageConfig(cfg *config.Config, w http.ResponseWriter, r *http.Request) { + U.HandleErr(w, r, U.RespondJson(w, cfg.HomepageConfig())) +} diff --git a/internal/config/query.go b/internal/config/query.go index cef4182..e61c36b 100644 --- a/internal/config/query.go +++ b/internal/config/query.go @@ -1,6 +1,7 @@ package config import ( + H "github.com/yusing/go-proxy/internal/homepage" M "github.com/yusing/go-proxy/internal/models" PR "github.com/yusing/go-proxy/internal/proxy/provider" R "github.com/yusing/go-proxy/internal/route" @@ -24,6 +25,17 @@ func (cfg *Config) DumpProviders() map[string]*PR.Provider { return entries } +func (cfg *Config) HomepageConfig() H.HomePageConfig { + hpCfg := H.NewHomePageConfig() + cfg.forEachRoute(func(alias string, r R.Route, p *PR.Provider) { + if !r.Started() { + return + } + hpCfg.Add(*r.Entry().Homepage) + }) + return hpCfg +} + func (cfg *Config) RoutesByAlias() map[string]U.SerializedObject { routes := make(map[string]U.SerializedObject) cfg.forEachRoute(func(alias string, r R.Route, p *PR.Provider) { diff --git a/internal/docker/homepage_label.go b/internal/docker/homepage_label.go deleted file mode 100644 index 4ad7146..0000000 --- a/internal/docker/homepage_label.go +++ /dev/null @@ -1,32 +0,0 @@ -package docker - -type ( - HomePageConfig struct{ m map[string]HomePageCategory } - HomePageCategory []HomePageItem - - HomePageItem struct { - Name string - Icon string - Category string - Description string - WidgetConfig map[string]any - } -) - -func NewHomePageConfig() *HomePageConfig { - return &HomePageConfig{m: make(map[string]HomePageCategory)} -} - -func NewHomePageItem() *HomePageItem { - return &HomePageItem{} -} - -func (c *HomePageConfig) Clear() { - c.m = make(map[string]HomePageCategory) -} - -func (c *HomePageConfig) Add(item HomePageItem) { - c.m[item.Category] = HomePageCategory{item} -} - -const NSHomePage = "homepage" diff --git a/internal/docker/labels.go b/internal/docker/labels.go index 8c78e79..10f0c9e 100644 --- a/internal/docker/labels.go +++ b/internal/docker/labels.go @@ -3,7 +3,8 @@ package docker const ( WildcardAlias = "*" - NSProxy = "proxy" + NSProxy = "proxy" + NSHomePage = "homepage" LabelAliases = NSProxy + ".aliases" LabelExclude = NSProxy + ".exclude" diff --git a/internal/homepage/homepage.go b/internal/homepage/homepage.go new file mode 100644 index 0000000..80f6c6c --- /dev/null +++ b/internal/homepage/homepage.go @@ -0,0 +1,37 @@ +package homepage + +type ( + HomePageConfig map[string]HomePageCategory + HomePageCategory []HomePageItem + + HomePageItem struct { + Name string `yaml:"name" json:"name"` + Icon string `yaml:"icon" json:"icon,omitempty"` // URL or unicodes + Category string `yaml:"category" json:"category"` + Description string `yaml:"description" json:"description,omitempty"` + WidgetConfig map[string]any `yaml:",flow" json:"widget_config,omitempty"` + } +) + +func NewHomePageConfig() HomePageConfig { + return HomePageConfig(make(map[string]HomePageCategory)) +} + +func HomePageItemDefault() *HomePageItem { + return &HomePageItem{ + Name: "Docker", + Category: "Uncategorized", + WidgetConfig: make(map[string]any), + } +} + +func (c *HomePageConfig) Clear() { + *c = make(HomePageConfig) +} + +func (c HomePageConfig) Add(item HomePageItem) { + if c[item.Category] == nil { + c[item.Category] = make(HomePageCategory, 0) + } + c[item.Category] = append(c[item.Category], item) +} diff --git a/internal/models/raw_entry.go b/internal/models/raw_entry.go index 34020d1..5386f59 100644 --- a/internal/models/raw_entry.go +++ b/internal/models/raw_entry.go @@ -7,6 +7,8 @@ import ( . "github.com/yusing/go-proxy/internal/common" D "github.com/yusing/go-proxy/internal/docker" + H "github.com/yusing/go-proxy/internal/homepage" + U "github.com/yusing/go-proxy/internal/utils" F "github.com/yusing/go-proxy/internal/utils/functional" ) @@ -18,9 +20,10 @@ type ( Scheme string `yaml:"scheme" json:"scheme"` Host string `yaml:"host" json:"host"` Port string `yaml:"port" json:"port"` - NoTLSVerify bool `yaml:"no_tls_verify" json:"no_tls_verify"` // https proxy only - PathPatterns []string `yaml:"path_patterns" json:"path_patterns"` // http(s) proxy only - Middlewares D.NestedLabelMap `yaml:"middlewares" json:"middlewares"` + 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 + Middlewares D.NestedLabelMap `yaml:"middlewares" json:"middlewares,omitempty"` + Homepage *H.HomePageItem `yaml:"homepage" json:"homepage"` /* Docker only */ *D.ProxyProperties `yaml:"-" json:"proxy_properties"` @@ -37,6 +40,11 @@ func (e *RawEntry) FillMissingFields() { e.ProxyProperties = &D.ProxyProperties{} } + if e.Homepage == nil { + e.Homepage = H.HomePageItemDefault() + e.Homepage.Name = U.Title(e.Alias) + } + lp, pp, extra := e.splitPorts() if port, ok := ServiceNamePortMapTCP[e.ImageName]; ok { diff --git a/internal/utils/string.go b/internal/utils/string.go index ccca361..ea2376c 100644 --- a/internal/utils/string.go +++ b/internal/utils/string.go @@ -5,9 +5,13 @@ import ( "strconv" "strings" - E "github.com/yusing/go-proxy/internal/error" + "golang.org/x/text/cases" + "golang.org/x/text/language" ) +// TODO: support other languages +var titleCaser = cases.Title(language.AmericanEnglish) + func CommaSeperatedList(s string) []string { res := strings.Split(s, ",") for i, part := range res { @@ -16,8 +20,8 @@ func CommaSeperatedList(s string) []string { return res } -func IntParser(value string) (int, E.NestedError) { - return E.Check(strconv.Atoi(value)) +func Title(s string) string { + return titleCaser.String(s) } func ExtractPort(fullURL string) (int, error) {