api: added some endpoints for dashboard filter to work

This commit is contained in:
yusing 2025-01-20 06:17:18 +08:00
parent bcc7faa8e5
commit 68771ce399
13 changed files with 82 additions and 34 deletions

View file

@ -18,7 +18,7 @@ import (
E "github.com/yusing/go-proxy/internal/error" E "github.com/yusing/go-proxy/internal/error"
"github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/logging"
"github.com/yusing/go-proxy/internal/net/http/middleware" "github.com/yusing/go-proxy/internal/net/http/middleware"
"github.com/yusing/go-proxy/internal/route/routes" "github.com/yusing/go-proxy/internal/route/routes/routequery"
"github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/internal/task"
"github.com/yusing/go-proxy/pkg" "github.com/yusing/go-proxy/pkg"
) )
@ -104,7 +104,7 @@ func main() {
switch args.Command { switch args.Command {
case common.CommandListRoutes: case common.CommandListRoutes:
cfg.StartProxyProviders() cfg.StartProxyProviders()
printJSON(routes.RoutesByAlias()) printJSON(routequery.RoutesByAlias())
return return
case common.CommandListConfigs: case common.CommandListConfigs:
printJSON(cfg.Value()) printJSON(cfg.Value())
@ -113,7 +113,7 @@ func main() {
printJSON(cfg.DumpEntries()) printJSON(cfg.DumpEntries())
return return
case common.CommandDebugListProviders: case common.CommandDebugListProviders:
printJSON(cfg.DumpProviders()) printJSON(cfg.DumpRouteProviders())
return return
} }

View file

@ -8,11 +8,11 @@ import (
"github.com/coder/websocket/wsjson" "github.com/coder/websocket/wsjson"
U "github.com/yusing/go-proxy/internal/api/v1/utils" U "github.com/yusing/go-proxy/internal/api/v1/utils"
config "github.com/yusing/go-proxy/internal/config/types" config "github.com/yusing/go-proxy/internal/config/types"
"github.com/yusing/go-proxy/internal/route/routes" "github.com/yusing/go-proxy/internal/route/routes/routequery"
) )
func HealthWS(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) { func HealthWS(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
U.PeriodicWS(cfg, w, r, 1*time.Second, func(conn *websocket.Conn) error { U.PeriodicWS(cfg, w, r, 1*time.Second, func(conn *websocket.Conn) error {
return wsjson.Write(r.Context(), conn, routes.HealthMap()) return wsjson.Write(r.Context(), conn, routequery.HealthMap())
}) })
} }

View file

@ -8,21 +8,23 @@ import (
"github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/common"
config "github.com/yusing/go-proxy/internal/config/types" config "github.com/yusing/go-proxy/internal/config/types"
"github.com/yusing/go-proxy/internal/net/http/middleware" "github.com/yusing/go-proxy/internal/net/http/middleware"
"github.com/yusing/go-proxy/internal/route/routes" "github.com/yusing/go-proxy/internal/route/routes/routequery"
route "github.com/yusing/go-proxy/internal/route/types" route "github.com/yusing/go-proxy/internal/route/types"
"github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/internal/task"
"github.com/yusing/go-proxy/internal/utils" "github.com/yusing/go-proxy/internal/utils"
) )
const ( const (
ListRoute = "route" ListRoute = "route"
ListRoutes = "routes" ListRoutes = "routes"
ListFiles = "files" ListFiles = "files"
ListMiddlewares = "middlewares" ListMiddlewares = "middlewares"
ListMiddlewareTraces = "middleware_trace" ListMiddlewareTraces = "middleware_trace"
ListMatchDomains = "match_domains" ListMatchDomains = "match_domains"
ListHomepageConfig = "homepage_config" ListHomepageConfig = "homepage_config"
ListTasks = "tasks" ListRouteProviders = "route_providers"
ListHomepageCategories = "homepage_categories"
ListTasks = "tasks"
) )
func List(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) { func List(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
@ -41,7 +43,7 @@ func List(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
U.RespondJSON(w, r, route) U.RespondJSON(w, r, route)
} }
case ListRoutes: case ListRoutes:
U.RespondJSON(w, r, routes.RoutesByAlias(route.RouteType(r.FormValue("type")))) U.RespondJSON(w, r, routequery.RoutesByAlias(route.RouteType(r.FormValue("type"))))
case ListFiles: case ListFiles:
listFiles(w, r) listFiles(w, r)
case ListMiddlewares: case ListMiddlewares:
@ -51,7 +53,11 @@ func List(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
case ListMatchDomains: case ListMatchDomains:
U.RespondJSON(w, r, cfg.Value().MatchDomains) U.RespondJSON(w, r, cfg.Value().MatchDomains)
case ListHomepageConfig: case ListHomepageConfig:
U.RespondJSON(w, r, routes.HomepageConfig(cfg.Value().Homepage.UseDefaultCategories)) U.RespondJSON(w, r, routequery.HomepageConfig(cfg.Value().Homepage.UseDefaultCategories, r.FormValue("category"), r.FormValue("provider")))
case ListRouteProviders:
U.RespondJSON(w, r, cfg.RouteProviderList())
case ListHomepageCategories:
U.RespondJSON(w, r, routequery.HomepageCategories())
case ListTasks: case ListTasks:
U.RespondJSON(w, r, task.DebugTaskList()) U.RespondJSON(w, r, task.DebugTaskList())
default: default:
@ -63,9 +69,9 @@ func List(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
// otherwise, return a single Route with alias which or nil if not found. // otherwise, return a single Route with alias which or nil if not found.
func listRoute(which string) any { func listRoute(which string) any {
if which == "" || which == "all" { if which == "" || which == "all" {
return routes.RoutesByAlias() return routequery.RoutesByAlias()
} }
routes := routes.RoutesByAlias() routes := routequery.RoutesByAlias()
route, ok := routes[which] route, ok := routes[which]
if !ok { if !ok {
return nil return nil

View file

@ -16,7 +16,7 @@ func (cfg *Config) DumpEntries() map[string]*types.RawEntry {
return entries return entries
} }
func (cfg *Config) DumpProviders() map[string]*provider.Provider { func (cfg *Config) DumpRouteProviders() map[string]*provider.Provider {
entries := make(map[string]*provider.Provider) entries := make(map[string]*provider.Provider)
cfg.providers.RangeAll(func(_ string, p *provider.Provider) { cfg.providers.RangeAll(func(_ string, p *provider.Provider) {
entries[p.ShortName()] = p entries[p.ShortName()] = p
@ -24,6 +24,14 @@ func (cfg *Config) DumpProviders() map[string]*provider.Provider {
return entries return entries
} }
func (cfg *Config) RouteProviderList() []string {
var list []string
cfg.providers.RangeAll(func(_ string, p *provider.Provider) {
list = append(list, p.ShortName())
})
return list
}
func (cfg *Config) Statistics() map[string]any { func (cfg *Config) Statistics() map[string]any {
var rps, streams provider.RouteStats var rps, streams provider.RouteStats
var total uint16 var total uint16

View file

@ -33,6 +33,7 @@ type (
Value() *Config Value() *Config
Reload() E.Error Reload() E.Error
Statistics() map[string]any Statistics() map[string]any
RouteProviderList() []string
Context() context.Context Context() context.Context
} }
) )

View file

@ -33,7 +33,6 @@ var PredefinedCategories = map[string]string{
"changedetection": "Monitoring", "changedetection": "Monitoring",
"influxdb": "Monitoring", "influxdb": "Monitoring",
"influx": "Monitoring", "influx": "Monitoring",
"dozzle": "Monitoring",
"adguardhome": "Networking", "adguardhome": "Networking",
"adgh": "Networking", "adgh": "Networking",
@ -47,6 +46,8 @@ var PredefinedCategories = map[string]string{
"dockge": "Container Management", "dockge": "Container Management",
"portainer-ce": "Container Management", "portainer-ce": "Container Management",
"portainer-be": "Container Management", "portainer-be": "Container Management",
"logs": "Container Management",
"dozzle": "Container Management",
"rss": "RSS", "rss": "RSS",
"rsshub": "RSS", "rsshub": "RSS",
@ -57,6 +58,7 @@ var PredefinedCategories = map[string]string{
"paperless": "Documents", "paperless": "Documents",
"paperless-ngx": "Documents", "paperless-ngx": "Documents",
"s-pdf": "Documents", "s-pdf": "Documents",
"stirling-pdf": "Documents",
"minio": "Storage", "minio": "Storage",
"filebrowser": "Storage", "filebrowser": "Storage",

View file

@ -17,6 +17,7 @@ type (
Alias string `json:"alias"` // proxy alias Alias string `json:"alias"` // proxy alias
SourceType string `json:"source_type"` SourceType string `json:"source_type"`
AltURL string `json:"alt_url"` // original proxy target AltURL string `json:"alt_url"` // original proxy target
Provider string `json:"provider"`
} }
) )

View file

@ -90,7 +90,7 @@ func (p *DockerProvider) loadRoutesImpl() (route.Routes, E.Error) {
}) })
} }
routes, err = route.FromEntries(entries) routes, err = route.FromEntries(p.ShortName(), entries)
errs.Add(err) errs.Add(err)
return routes, errs.Error() return routes, errs.Error()

View file

@ -32,16 +32,16 @@ func FileProviderImpl(filename string) (ProviderImpl, error) {
return impl, nil return impl, nil
} }
func validate(data []byte) (route.Routes, E.Error) { func validate(provider string, data []byte) (route.Routes, E.Error) {
entries, err := utils.DeserializeYAMLMap[*route.RawEntry](data) entries, err := utils.DeserializeYAMLMap[*route.RawEntry](data)
if err != nil { if err != nil {
return route.NewRoutes(), err return route.NewRoutes(), err
} }
return route.FromEntries(entries) return route.FromEntries(provider, entries)
} }
func Validate(data []byte) (err E.Error) { func Validate(data []byte) (err E.Error) {
_, err = validate(data) _, err = validate("", data)
return return
} }
@ -69,7 +69,7 @@ func (p *FileProvider) loadRoutesImpl() (route.Routes, E.Error) {
return routes, E.From(err) return routes, E.From(err)
} }
return validate(data) return validate(p.ShortName(), data)
} }
func (p *FileProvider) NewWatcher() W.Watcher { func (p *FileProvider) NewWatcher() W.Watcher {

View file

@ -12,6 +12,6 @@ import (
var testAllFieldsYAML []byte var testAllFieldsYAML []byte
func TestFile(t *testing.T) { func TestFile(t *testing.T) {
_, err := validate(testAllFieldsYAML) _, err := validate("", testAllFieldsYAML)
ExpectNoError(t, err) ExpectNoError(t, err)
} }

View file

@ -76,7 +76,7 @@ func NewRoute(raw *RawEntry) (*Route, E.Error) {
}, nil }, nil
} }
func FromEntries(entries RawEntries) (Routes, E.Error) { func FromEntries(provider string, entries RawEntries) (Routes, E.Error) {
b := E.NewBuilder("errors in routes") b := E.NewBuilder("errors in routes")
routes := NewRoutes() routes := NewRoutes()
@ -85,6 +85,7 @@ func FromEntries(entries RawEntries) (Routes, E.Error) {
en = new(RawEntry) en = new(RawEntry)
} }
en.Alias = alias en.Alias = alias
en.Provider = provider
if strings.HasPrefix(alias, "x-") { // x properties if strings.HasPrefix(alias, "x-") { // x properties
return return
} }

View file

@ -1,4 +1,4 @@
package routes package routequery
import ( import (
"strings" "strings"
@ -7,6 +7,7 @@ import (
"github.com/yusing/go-proxy/internal/homepage" "github.com/yusing/go-proxy/internal/homepage"
"github.com/yusing/go-proxy/internal/route/entry" "github.com/yusing/go-proxy/internal/route/entry"
provider "github.com/yusing/go-proxy/internal/route/provider/types" provider "github.com/yusing/go-proxy/internal/route/provider/types"
"github.com/yusing/go-proxy/internal/route/routes"
route "github.com/yusing/go-proxy/internal/route/types" route "github.com/yusing/go-proxy/internal/route/types"
"github.com/yusing/go-proxy/internal/utils/strutils" "github.com/yusing/go-proxy/internal/utils/strutils"
) )
@ -29,18 +30,36 @@ func getHealthInfo(r route.Route) map[string]string {
func HealthMap() map[string]map[string]string { func HealthMap() map[string]map[string]string {
healthMap := make(map[string]map[string]string) healthMap := make(map[string]map[string]string)
httpRoutes.RangeAll(func(alias string, r route.HTTPRoute) { routes.GetHTTPRoutes().RangeAll(func(alias string, r route.HTTPRoute) {
healthMap[alias] = getHealthInfo(r) healthMap[alias] = getHealthInfo(r)
}) })
streamRoutes.RangeAll(func(alias string, r route.StreamRoute) { routes.GetStreamRoutes().RangeAll(func(alias string, r route.StreamRoute) {
healthMap[alias] = getHealthInfo(r) healthMap[alias] = getHealthInfo(r)
}) })
return healthMap return healthMap
} }
func HomepageConfig(useDefaultCategories bool) homepage.Config { func HomepageCategories() []string {
check := make(map[string]struct{})
categories := make([]string, 0)
routes.GetHTTPRoutes().RangeAll(func(alias string, r route.HTTPRoute) {
en := r.RawEntry()
if en.Homepage == nil || en.Homepage.Category == "" {
return
}
if _, ok := check[en.Homepage.Category]; ok {
return
}
check[en.Homepage.Category] = struct{}{}
categories = append(categories, en.Homepage.Category)
})
return categories
}
func HomepageConfig(useDefaultCategories bool, categoryFilter, providerFilter string) homepage.Config {
hpCfg := homepage.NewHomePageConfig() hpCfg := homepage.NewHomePageConfig()
GetHTTPRoutes().RangeAll(func(alias string, r route.HTTPRoute) {
routes.GetHTTPRoutes().RangeAll(func(alias string, r route.HTTPRoute) {
en := r.RawEntry() en := r.RawEntry()
item := en.Homepage item := en.Homepage
if item == nil { if item == nil {
@ -57,6 +76,11 @@ func HomepageConfig(useDefaultCategories bool) homepage.Config {
} }
item.Alias = alias item.Alias = alias
item.Provider = r.RawEntry().Provider
if providerFilter != "" && item.Provider != providerFilter {
return
}
if item.Name == "" { if item.Name == "" {
item.Name = strutils.Title( item.Name = strutils.Title(
@ -81,6 +105,10 @@ func HomepageConfig(useDefaultCategories bool) homepage.Config {
} }
} }
if categoryFilter != "" && item.Category != categoryFilter {
return
}
switch { switch {
case entry.IsDocker(r): case entry.IsDocker(r):
if item.Category == "" { if item.Category == "" {
@ -113,11 +141,11 @@ func RoutesByAlias(typeFilter ...route.RouteType) map[string]route.Route {
for _, t := range typeFilter { for _, t := range typeFilter {
switch t { switch t {
case route.RouteTypeReverseProxy: case route.RouteTypeReverseProxy:
GetHTTPRoutes().RangeAll(func(alias string, r route.HTTPRoute) { routes.GetHTTPRoutes().RangeAll(func(alias string, r route.HTTPRoute) {
rts[alias] = r rts[alias] = r
}) })
case route.RouteTypeStream: case route.RouteTypeStream:
GetStreamRoutes().RangeAll(func(alias string, r route.StreamRoute) { routes.GetStreamRoutes().RangeAll(func(alias string, r route.StreamRoute) {
rts[alias] = r rts[alias] = r
}) })
} }

View file

@ -40,6 +40,7 @@ type (
/* Docker only */ /* Docker only */
Container *docker.Container `json:"container,omitempty"` Container *docker.Container `json:"container,omitempty"`
Provider string `json:"provider,omitempty"`
finalized bool finalized bool
} }