mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-27 19:41:11 +01:00
feat: support selfh.st icons, support homepage config overriding
This commit is contained in:
@@ -34,6 +34,7 @@ func NewHandler(cfg config.ConfigInstance) http.Handler {
|
||||
mux.HandleFunc("GET", "/v1/health/ws", auth.RequireAuth(useCfg(cfg, v1.HealthWS)))
|
||||
mux.HandleFunc("GET", "/v1/logs/ws", auth.RequireAuth(useCfg(cfg, v1.LogsWS())))
|
||||
mux.HandleFunc("GET", "/v1/favicon/{alias}", auth.RequireAuth(favicon.GetFavIcon))
|
||||
mux.HandleFunc("POST", "/v1/homepage/set", auth.RequireAuth(v1.SetHomePageOverrides))
|
||||
|
||||
defaultAuth := auth.GetDefaultAuth()
|
||||
if defaultAuth != nil {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -88,6 +89,8 @@ func GetFavIcon(w http.ResponseWriter, req *http.Request) {
|
||||
icon, status, errMsg = findIcon(r, req, hp.Icon.Value)
|
||||
case homepage.IconSourceWalkXCode:
|
||||
icon, status, errMsg = fetchWalkxcodeIcon(hp.Icon.Extra.FileType, hp.Icon.Extra.Name)
|
||||
case homepage.IconSourceSelfhSt:
|
||||
icon, status, errMsg = fetchSelfhStIcon(hp.Icon.Extra.FileType, hp.Icon.Extra.Name)
|
||||
}
|
||||
} else {
|
||||
// try extract from "link[rel=icon]"
|
||||
@@ -117,8 +120,8 @@ func ResetIconCache(route route.HTTPRoute) {
|
||||
|
||||
func loadIconCache(key string) (icon []byte, ok bool) {
|
||||
iconCacheMu.RLock()
|
||||
defer iconCacheMu.RUnlock()
|
||||
icon, ok = iconCache[key]
|
||||
iconCacheMu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -169,9 +172,9 @@ func sanitizeName(name string) string {
|
||||
return strings.ToLower(nameSanitizer.Replace(name))
|
||||
}
|
||||
|
||||
func fetchWalkxcodeIcon(filetype string, name string) ([]byte, int, string) {
|
||||
func fetchWalkxcodeIcon(filetype, name string) ([]byte, int, string) {
|
||||
// if icon isn't in the list, no need to fetch
|
||||
if !internal.HasIcon(name, filetype) {
|
||||
if !internal.HasWalkxCodeIcon(name, filetype) {
|
||||
logging.Debug().
|
||||
Str("filetype", filetype).
|
||||
Str("name", name).
|
||||
@@ -184,10 +187,39 @@ func fetchWalkxcodeIcon(filetype string, name string) ([]byte, int, string) {
|
||||
return icon, http.StatusOK, ""
|
||||
}
|
||||
|
||||
url := homepage.DashboardIconBaseURL + filetype + "/" + name + "." + filetype
|
||||
// url := homepage.DashboardIconBaseURL + filetype + "/" + name + "." + filetype
|
||||
url := fmt.Sprintf("https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/%s/%s.%s", filetype, name, filetype)
|
||||
return fetchIconAbsolute(url)
|
||||
}
|
||||
|
||||
func fetchSelfhStIcon(filetype, reference string) ([]byte, int, string) {
|
||||
// if icon isn't in the list, no need to fetch
|
||||
if !internal.HasSelfhstIcon(reference, filetype) {
|
||||
logging.Debug().
|
||||
Str("filetype", filetype).
|
||||
Str("reference", reference).
|
||||
Msg("icon not found")
|
||||
return nil, http.StatusNotFound, "icon not found"
|
||||
}
|
||||
|
||||
icon, ok := loadIconCache("selfh.st/" + filetype + "/" + reference)
|
||||
if ok {
|
||||
return icon, http.StatusOK, ""
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://cdn.jsdelivr.net/gh/selfhst/icons/%s/%s.%s", filetype, reference, filetype)
|
||||
return fetchIconAbsolute(url)
|
||||
}
|
||||
|
||||
func fetchIcon(filetype, filename string) (icon []byte, status int, errMsg string) {
|
||||
icon, status, errMsg = fetchSelfhStIcon(filetype, filename)
|
||||
if icon != nil {
|
||||
return
|
||||
}
|
||||
icon, status, errMsg = fetchWalkxcodeIcon(filetype, filename)
|
||||
return
|
||||
}
|
||||
|
||||
func findIcon(r route.HTTPRoute, req *http.Request, uri string) (icon []byte, status int, errMsg string) {
|
||||
key := r.TargetName()
|
||||
icon, ok := loadIconCache(key)
|
||||
@@ -198,10 +230,10 @@ func findIcon(r route.HTTPRoute, req *http.Request, uri string) (icon []byte, st
|
||||
return icon, http.StatusOK, ""
|
||||
}
|
||||
|
||||
icon, status, errMsg = fetchWalkxcodeIcon("png", sanitizeName(r.TargetName()))
|
||||
icon, status, errMsg = fetchIcon("png", sanitizeName(r.TargetName()))
|
||||
cont := r.RawEntry().Container
|
||||
if icon == nil && cont != nil {
|
||||
icon, status, errMsg = fetchWalkxcodeIcon("png", sanitizeName(cont.ImageName))
|
||||
icon, status, errMsg = fetchIcon("png", sanitizeName(cont.ImageName))
|
||||
}
|
||||
if icon == nil {
|
||||
// fallback to parse html
|
||||
@@ -213,7 +245,6 @@ func findIcon(r route.HTTPRoute, req *http.Request, uri string) (icon []byte, st
|
||||
}
|
||||
|
||||
func findIconSlow(r route.HTTPRoute, req *http.Request, uri string) (icon []byte, status int, errMsg string) {
|
||||
c := newContent()
|
||||
ctx, cancel := context.WithTimeoutCause(req.Context(), 3*time.Second, errors.New("favicon request timeout"))
|
||||
defer cancel()
|
||||
newReq := req.WithContext(ctx)
|
||||
@@ -233,6 +264,8 @@ func findIconSlow(r route.HTTPRoute, req *http.Request, uri string) (icon []byte
|
||||
newReq.URL.RawPath = u.RawPath
|
||||
newReq.URL.RawQuery = u.RawQuery
|
||||
newReq.RequestURI = u.String()
|
||||
|
||||
c := newContent()
|
||||
r.ServeHTTP(c, newReq)
|
||||
if c.status != http.StatusOK {
|
||||
switch c.status {
|
||||
|
||||
58
internal/api/v1/homepage_overrides.go
Normal file
58
internal/api/v1/homepage_overrides.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/api/v1/utils"
|
||||
"github.com/yusing/go-proxy/internal/homepage"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
)
|
||||
|
||||
const (
|
||||
HomepageOverrideDisplayname = "display_name"
|
||||
HomepageOverrideDisplayOrder = "display_order"
|
||||
HomepageOverrideDisplayCategory = "display_category"
|
||||
HomepageOverrideCategoryOrder = "category_order"
|
||||
HomepageOverrideCategoryName = "category_name"
|
||||
HomepageOverrideIcon = "icon"
|
||||
HomepageOverrideShow = "show"
|
||||
)
|
||||
|
||||
func SetHomePageOverrides(w http.ResponseWriter, r *http.Request) {
|
||||
what, which, value := r.FormValue("what"), r.FormValue("which"), r.FormValue("value")
|
||||
if what == "" || which == "" {
|
||||
http.Error(w, "missing what or which", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if value == "" {
|
||||
http.Error(w, "missing value", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
overrides := homepage.GetJSONConfig()
|
||||
switch what {
|
||||
case HomepageOverrideDisplayname:
|
||||
utils.RespondError(w, overrides.SetDisplayNameOverride(which, value))
|
||||
case HomepageOverrideDisplayCategory:
|
||||
utils.RespondError(w, overrides.SetDisplayCategoryOverride(which, value))
|
||||
case HomepageOverrideCategoryName:
|
||||
utils.RespondError(w, overrides.SetCategoryNameOverride(which, value))
|
||||
case HomepageOverrideIcon:
|
||||
utils.RespondError(w, overrides.SetIconOverride(which, value))
|
||||
case HomepageOverrideShow:
|
||||
utils.RespondError(w, overrides.SetShowItemOverride(which, strutils.ParseBool(value)))
|
||||
case HomepageOverrideDisplayOrder, HomepageOverrideCategoryOrder:
|
||||
v, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
http.Error(w, "invalid integer", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if what == HomepageOverrideDisplayOrder {
|
||||
utils.RespondError(w, overrides.SetDisplayOrder(which, v))
|
||||
} else {
|
||||
utils.RespondError(w, overrides.SetCategoryOrder(which, v))
|
||||
}
|
||||
default:
|
||||
http.Error(w, "invalid what", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/yusing/go-proxy/internal"
|
||||
U "github.com/yusing/go-proxy/internal/api/v1/utils"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
config "github.com/yusing/go-proxy/internal/config/types"
|
||||
@@ -24,6 +25,7 @@ const (
|
||||
ListHomepageConfig = "homepage_config"
|
||||
ListRouteProviders = "route_providers"
|
||||
ListHomepageCategories = "homepage_categories"
|
||||
ListIcons = "icons"
|
||||
ListTasks = "tasks"
|
||||
)
|
||||
|
||||
@@ -58,6 +60,13 @@ func List(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
|
||||
U.RespondJSON(w, r, cfg.RouteProviderList())
|
||||
case ListHomepageCategories:
|
||||
U.RespondJSON(w, r, routequery.HomepageCategories())
|
||||
case ListIcons:
|
||||
icons, err := internal.ListAvailableIcons()
|
||||
if err != nil {
|
||||
U.RespondError(w, err)
|
||||
return
|
||||
}
|
||||
U.RespondJSON(w, r, icons)
|
||||
case ListTasks:
|
||||
U.RespondJSON(w, r, task.DebugTaskList())
|
||||
default:
|
||||
@@ -80,7 +89,7 @@ func listRoute(which string) any {
|
||||
}
|
||||
|
||||
func listFiles(w http.ResponseWriter, r *http.Request) {
|
||||
files, err := utils.ListFiles(common.ConfigBasePath, 0)
|
||||
files, err := utils.ListFiles(common.ConfigBasePath, 0, true)
|
||||
if err != nil {
|
||||
U.HandleErr(w, r, err)
|
||||
return
|
||||
@@ -97,7 +106,7 @@ func listFiles(w http.ResponseWriter, r *http.Request) {
|
||||
resp[t] = append(resp[t], file)
|
||||
}
|
||||
|
||||
mids, err := utils.ListFiles(common.MiddlewareComposeBasePath, 0)
|
||||
mids, err := utils.ListFiles(common.MiddlewareComposeBasePath, 0, true)
|
||||
if err != nil {
|
||||
U.HandleErr(w, r, err)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user