Compare commits

...

4 Commits

Author SHA1 Message Date
yusing
8ef8015a7f feat: improved icon and category lookup mechanism 2025-05-04 09:37:15 +08:00
yusing
5fce4b445b fix: error formatting 2025-05-04 07:12:28 +08:00
yusing
7552a706a7 chore: deps upgrade 2025-05-04 06:33:08 +08:00
yusing
e1bc6d1f44 fix: nil panic when formatting error 2025-05-04 06:33:00 +08:00
10 changed files with 97 additions and 85 deletions

View File

@@ -9,7 +9,7 @@ require (
github.com/docker/docker v28.1.1+incompatible
github.com/rs/zerolog v1.34.0
github.com/stretchr/testify v1.10.0
github.com/yusing/go-proxy v0.11.9
github.com/yusing/go-proxy v0.12.0
)
replace github.com/docker/docker => github.com/godoxy-app/docker v0.0.0-20250425105916-b2ad800de7a1

10
go.mod
View File

@@ -41,8 +41,8 @@ require (
github.com/samber/slog-zerolog/v2 v2.7.3
github.com/spf13/afero v1.14.0
github.com/stretchr/testify v1.10.0
github.com/yusing/go-proxy/agent v0.0.0-20250501215534-7fa7b55b1889
github.com/yusing/go-proxy/internal/dnsproviders v0.0.0-20250501215534-7fa7b55b1889
github.com/yusing/go-proxy/agent v0.0.0-20250503173201-5f780f490224
github.com/yusing/go-proxy/internal/dnsproviders v0.0.0-20250503173201-5f780f490224
go.uber.org/atomic v1.11.0
)
@@ -205,7 +205,7 @@ require (
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
github.com/sony/gobreaker v1.0.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/cast v1.8.0 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/spf13/viper v1.20.1 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
@@ -243,12 +243,12 @@ require (
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/ns1/ns1-go.v2 v2.14.2 // indirect
gopkg.in/ns1/ns1-go.v2 v2.14.3 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/api v0.33.0 // indirect
k8s.io/apimachinery v0.33.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect
k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect

12
go.sum
View File

@@ -1572,8 +1572,8 @@ github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZ
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cast v1.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk=
github.com/spf13/cast v1.8.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
@@ -2523,8 +2523,8 @@ gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/ns1/ns1-go.v2 v2.14.2 h1:wz/toj9U20wBrmYxW4vTz7sZWED+JJVRjUBBJ7CKrzI=
gopkg.in/ns1/ns1-go.v2 v2.14.2/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc=
gopkg.in/ns1/ns1-go.v2 v2.14.3 h1:Yn72GgB6AA9I4602AsLMtbC1ZKT5EUrKiG+IPS+Ovr0=
gopkg.in/ns1/ns1-go.v2 v2.14.3/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -2560,8 +2560,8 @@ k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ=
k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97RvvF3a8J3fP/Lg=
k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=

View File

@@ -14,6 +14,9 @@ func Multiline() *MultilineError {
}
func (m *MultilineError) add(err error) {
if err == nil {
return
}
m.Extras = append(m.Extras, err)
}

View File

@@ -68,75 +68,58 @@ func (err *nestedError) Is(other error) bool {
var nilError = newError("<nil>")
var bulletPrefix = []byte("• ")
var markdownBulletPrefix = []byte("- ")
var spaces = []byte(" ")
var spaces = []byte(" ")
type appendLineFunc func(buf []byte, err error, level int) []byte
func (err *nestedError) Error() string {
func (err *nestedError) fmtError(appendLine appendLineFunc) []byte {
if err == nil {
return nilError.Error()
return appendLine(nil, nilError, 0)
}
buf := appendLineNormal(nil, err.Err, 0)
if len(err.Extras) > 0 {
if err.Err != nil {
buf := appendLine(nil, err.Err, 0)
buf = append(buf, '\n')
buf = appendLines(buf, err.Extras, 1, appendLineNormal)
buf = appendLines(buf, err.Extras, 1, appendLine)
return buf
}
return string(buf)
return appendLines(nil, err.Extras, 0, appendLine)
}
func (err *nestedError) Error() string {
return string(err.fmtError(appendLineNormal))
}
func (err *nestedError) Plain() []byte {
if err == nil {
return appendLinePlain(nil, nilError, 0)
}
buf := appendLinePlain(nil, err.Err, 0)
if len(err.Extras) > 0 {
buf = append(buf, '\n')
buf = appendLines(buf, err.Extras, 1, appendLinePlain)
}
return buf
return err.fmtError(appendLinePlain)
}
func (err *nestedError) Markdown() []byte {
if err == nil {
return appendLineMd(nil, nilError, 0)
}
return err.fmtError(appendLineMd)
}
buf := appendLineMd(nil, err.Err, 0)
if len(err.Extras) > 0 {
buf = append(buf, '\n')
buf = appendLines(buf, err.Extras, 1, appendLineMd)
func appendLine(buf []byte, err error, level int, prefix []byte, format func(err error) []byte) []byte {
if err == nil {
return appendLine(buf, nilError, level, prefix, format)
}
if level == 0 {
return append(buf, format(err)...)
}
buf = append(buf, spaces[:2*level]...)
buf = append(buf, prefix...)
buf = append(buf, format(err)...)
return buf
}
func appendLineNormal(buf []byte, err error, level int) []byte {
if level == 0 {
return append(buf, err.Error()...)
}
buf = append(buf, spaces[:2*level]...)
buf = append(buf, bulletPrefix...)
buf = append(buf, err.Error()...)
return buf
return appendLine(buf, err, level, bulletPrefix, Normal)
}
func appendLinePlain(buf []byte, err error, level int) []byte {
if level == 0 {
return append(buf, Plain(err)...)
}
buf = append(buf, spaces[:2*level]...)
buf = append(buf, bulletPrefix...)
buf = append(buf, Plain(err)...)
return buf
return appendLine(buf, err, level, bulletPrefix, Plain)
}
func appendLineMd(buf []byte, err error, level int) []byte {
if level == 0 {
return append(buf, Markdown(err)...)
}
buf = append(buf, spaces[:2*level]...)
buf = append(buf, markdownBulletPrefix...)
buf = append(buf, Markdown(err)...)
return buf
return appendLine(buf, err, level, markdownBulletPrefix, Markdown)
}
func appendLines(buf []byte, errs []error, level int, appendLine appendLineFunc) []byte {
@@ -154,6 +137,9 @@ func appendLines(buf []byte, errs []error, level int, appendLine appendLineFunc)
buf = appendLines(buf, err.Extras, level, appendLine)
}
default:
if err == nil {
continue
}
buf = appendLine(buf, err, level)
buf = append(buf, '\n')
}

View File

@@ -91,6 +91,13 @@ func Collect[T any, Err error, Arg any, Func func(Arg) (T, Err)](eb *Builder, fn
return result
}
func Normal(err error) []byte {
if err == nil {
return nil
}
return []byte(err.Error())
}
func Plain(err error) []byte {
if err == nil {
return nil

View File

@@ -114,12 +114,18 @@ func fetchKnownIcon(ctx context.Context, url *IconURL) *FetchResult {
return fetchIconAbsolute(ctx, url.URL())
}
func fetchIcon(ctx context.Context, filetype, filename string) *FetchResult {
result := fetchKnownIcon(ctx, NewSelfhStIconURL(filename, filetype))
if result.OK() {
return result
func fetchIcon(ctx context.Context, filename string) *FetchResult {
for _, fileType := range []string{"svg", "webp", "png"} {
result := fetchKnownIcon(ctx, NewSelfhStIconURL(filename, fileType))
if result.OK() {
return result
}
result = fetchKnownIcon(ctx, NewWalkXCodeIconURL(filename, fileType))
if result.OK() {
return result
}
}
return fetchKnownIcon(ctx, NewWalkXCodeIconURL(filename, filetype))
return &FetchResult{StatusCode: http.StatusNotFound, ErrMsg: "no icon found"}
}
func FindIcon(ctx context.Context, r route, uri string) *FetchResult {
@@ -127,17 +133,18 @@ func FindIcon(ctx context.Context, r route, uri string) *FetchResult {
return result
}
result := fetchIcon(ctx, "png", sanitizeName(r.Reference()))
if !result.OK() {
if r, ok := r.(httpRoute); ok {
// fallback to parse html
result = findIconSlow(ctx, r, uri, nil)
for _, ref := range r.References() {
result := fetchIcon(ctx, sanitizeName(ref))
if result.OK() {
storeIconCache(r.Key(), result)
return result
}
}
if result.OK() {
storeIconCache(r.Key(), result)
if r, ok := r.(httpRoute); ok {
// fallback to parse html
return findIconSlow(ctx, r, uri, nil)
}
return result
return &FetchResult{StatusCode: http.StatusNotFound, ErrMsg: "no icon found"}
}
func findIconSlow(ctx context.Context, r httpRoute, uri string, stack []string) *FetchResult {

View File

@@ -10,7 +10,7 @@ import (
type route interface {
pool.Object
ProviderName() string
Reference() string
References() []string
TargetURL() *gpnet.URL
}

View File

@@ -243,11 +243,14 @@ func (r *Route) TargetURL() *net.URL {
return r.ProxyURL
}
func (r *Route) Reference() string {
func (r *Route) References() []string {
if r.Container != nil {
return r.Container.Image.Name
if r.Container.ContainerName != r.Alias {
return []string{r.Container.Image.Name, r.Container.ContainerName, r.Alias, r.Container.Image.Author}
}
return []string{r.Container.Image.Name, r.Alias, r.Container.Image.Author}
}
return r.Alias
return []string{r.Alias}
}
// Name implements pool.Object.
@@ -476,21 +479,24 @@ func (r *Route) FinalizeHomepageConfig() {
r.Homepage = r.Homepage.GetOverride(r.Alias)
hp := r.Homepage
ref := r.Reference()
meta, ok := homepage.GetHomepageMeta(ref)
if ok {
if hp.Name == "" {
hp.Name = meta.DisplayName
}
if hp.Category == "" {
hp.Category = meta.Tag
refs := r.References()
for _, ref := range refs {
meta, ok := homepage.GetHomepageMeta(ref)
if ok {
if hp.Name == "" {
hp.Name = meta.DisplayName
}
if hp.Category == "" {
hp.Category = meta.Tag
}
break
}
}
if hp.Name == "" {
hp.Name = strutils.Title(
strings.ReplaceAll(
strings.ReplaceAll(ref, "-", " "),
strings.ReplaceAll(refs[0], "-", " "),
"_", " ",
),
)
@@ -498,8 +504,11 @@ func (r *Route) FinalizeHomepageConfig() {
if hp.Category == "" {
if config.GetInstance().Value().Homepage.UseDefaultCategories {
if category, ok := homepage.PredefinedCategories[ref]; ok {
hp.Category = category
for _, ref := range refs {
if category, ok := homepage.PredefinedCategories[ref]; ok {
hp.Category = category
break
}
}
}

View File

@@ -25,7 +25,7 @@ type (
ProviderName() string
TargetURL() *net.URL
HealthMonitor() health.HealthMonitor
Reference() string
References() []string
Started() bool