mirror of
https://github.com/yusing/godoxy.git
synced 2025-06-09 04:52:35 +02:00
api: add /v1/health/ws for health bubbles on dashboard
This commit is contained in:
parent
fe7740f1b0
commit
1adba05065
13 changed files with 89 additions and 23 deletions
|
@ -37,6 +37,7 @@ func NewHandler(cfg config.ConfigInstance) http.Handler {
|
|||
mux.HandleFunc("GET", "/v1/schema/{filename...}", v1.GetSchemaFile)
|
||||
mux.HandleFunc("GET", "/v1/stats", useCfg(cfg, v1.Stats))
|
||||
mux.HandleFunc("GET", "/v1/stats/ws", useCfg(cfg, v1.StatsWS))
|
||||
mux.HandleFunc("GET", "/v1/health/ws", useCfg(cfg, v1.HealthWS))
|
||||
mux.HandleFunc("GET", "/v1/favicon/{alias}", auth.RequireAuth(favicon.GetFavIcon))
|
||||
return mux
|
||||
}
|
||||
|
|
18
internal/api/v1/health.go
Normal file
18
internal/api/v1/health.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/coder/websocket"
|
||||
"github.com/coder/websocket/wsjson"
|
||||
U "github.com/yusing/go-proxy/internal/api/v1/utils"
|
||||
config "github.com/yusing/go-proxy/internal/config/types"
|
||||
"github.com/yusing/go-proxy/internal/route/routes"
|
||||
)
|
||||
|
||||
func HealthWS(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
|
||||
U.PeriodicWS(cfg, w, r, 1*time.Second, func(conn *websocket.Conn) error {
|
||||
return wsjson.Write(r.Context(), conn, routes.HealthMap())
|
||||
})
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -146,6 +147,10 @@ func (cfg *Config) Task() *task.Task {
|
|||
return cfg.task
|
||||
}
|
||||
|
||||
func (cfg *Config) Context() context.Context {
|
||||
return cfg.task.Context()
|
||||
}
|
||||
|
||||
func (cfg *Config) Start() {
|
||||
cfg.StartAutoCert()
|
||||
cfg.StartProxyProviders()
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/net/http/accesslog"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
|
||||
|
@ -31,6 +33,7 @@ type (
|
|||
Value() *Config
|
||||
Reload() E.Error
|
||||
Statistics() map[string]any
|
||||
Context() context.Context
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -117,6 +117,11 @@ func (w *Watcher) Uptime() time.Duration {
|
|||
return 0
|
||||
}
|
||||
|
||||
// Latency implements health.HealthMonitor.
|
||||
func (w *Watcher) Latency() time.Duration {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Status implements health.HealthMonitor.
|
||||
func (w *Watcher) Status() health.Status {
|
||||
status := w.getStatusUpdateReady()
|
||||
|
|
|
@ -28,7 +28,7 @@ type (
|
|||
Name() string
|
||||
URL() types.URL
|
||||
Weight() Weight
|
||||
SetWeight(Weight)
|
||||
SetWeight(weight Weight)
|
||||
TryWake() error
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ type (
|
|||
HealthMon health.HealthMonitor `json:"health,omitempty"`
|
||||
|
||||
loadBalancer *loadbalancer.LoadBalancer
|
||||
server *loadbalancer.Server
|
||||
server loadbalancer.Server
|
||||
handler http.Handler
|
||||
rp *reverseproxy.ReverseProxy
|
||||
|
||||
|
@ -180,11 +180,8 @@ func (r *HTTPRoute) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
r.handler.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
func (r *HTTPRoute) Health() health.Status {
|
||||
if r.HealthMon != nil {
|
||||
return r.HealthMon.Status()
|
||||
}
|
||||
return health.StatusUnknown
|
||||
func (r *HTTPRoute) HealthMonitor() health.HealthMonitor {
|
||||
return r.HealthMon
|
||||
}
|
||||
|
||||
func (r *HTTPRoute) addToLoadBalancer(parent task.Parent) {
|
||||
|
|
|
@ -26,7 +26,12 @@ type (
|
|||
|
||||
func (stats *RouteStats) Add(r *R.Route) {
|
||||
stats.Total++
|
||||
switch r.Health() {
|
||||
mon := r.HealthMonitor()
|
||||
if mon == nil {
|
||||
stats.NumUnknown++
|
||||
return
|
||||
}
|
||||
switch mon.Status() {
|
||||
case health.StatusHealthy:
|
||||
stats.NumHealthy++
|
||||
case health.StatusUnhealthy:
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"github.com/yusing/go-proxy/internal/task"
|
||||
U "github.com/yusing/go-proxy/internal/utils"
|
||||
F "github.com/yusing/go-proxy/internal/utils/functional"
|
||||
"github.com/yusing/go-proxy/internal/watcher/health"
|
||||
)
|
||||
|
||||
type (
|
||||
|
@ -24,12 +23,11 @@ type (
|
|||
Routes = F.Map[string, *Route]
|
||||
|
||||
impl interface {
|
||||
entry.Entry
|
||||
types.Route
|
||||
task.TaskStarter
|
||||
task.TaskFinisher
|
||||
String() string
|
||||
TargetURL() url.URL
|
||||
Health() health.Status
|
||||
}
|
||||
RawEntry = types.RawEntry
|
||||
RawEntries = types.RawEntries
|
||||
|
|
|
@ -2,6 +2,7 @@ package routes
|
|||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/homepage"
|
||||
"github.com/yusing/go-proxy/internal/route/entry"
|
||||
|
@ -10,6 +11,33 @@ import (
|
|||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
)
|
||||
|
||||
func getHealthInfo(r route.Route) map[string]string {
|
||||
mon := r.HealthMonitor()
|
||||
if mon == nil {
|
||||
return map[string]string{
|
||||
"status": "unknown",
|
||||
"uptime": "n/a",
|
||||
"latency": "n/a",
|
||||
}
|
||||
}
|
||||
return map[string]string{
|
||||
"status": mon.Status().String(),
|
||||
"uptime": mon.Uptime().Round(time.Second).String(),
|
||||
"latency": mon.Latency().Round(time.Microsecond).String(),
|
||||
}
|
||||
}
|
||||
|
||||
func HealthMap() map[string]map[string]string {
|
||||
healthMap := make(map[string]map[string]string)
|
||||
httpRoutes.RangeAll(func(alias string, r route.HTTPRoute) {
|
||||
healthMap[alias] = getHealthInfo(r)
|
||||
})
|
||||
streamRoutes.RangeAll(func(alias string, r route.StreamRoute) {
|
||||
healthMap[alias] = getHealthInfo(r)
|
||||
})
|
||||
return healthMap
|
||||
}
|
||||
|
||||
func HomepageConfig(useDefaultCategories bool) homepage.Config {
|
||||
hpCfg := homepage.NewHomePageConfig()
|
||||
GetHTTPRoutes().RangeAll(func(alias string, r route.HTTPRoute) {
|
||||
|
@ -77,8 +105,8 @@ func HomepageConfig(useDefaultCategories bool) homepage.Config {
|
|||
return hpCfg
|
||||
}
|
||||
|
||||
func RoutesByAlias(typeFilter ...route.RouteType) map[string]any {
|
||||
rts := make(map[string]any)
|
||||
func RoutesByAlias(typeFilter ...route.RouteType) map[string]route.Route {
|
||||
rts := make(map[string]route.Route)
|
||||
if len(typeFilter) == 0 || typeFilter[0] == "" {
|
||||
typeFilter = []route.RouteType{route.RouteTypeReverseProxy, route.RouteTypeStream}
|
||||
}
|
||||
|
|
|
@ -116,12 +116,8 @@ func (r *StreamRoute) Finish(reason any) {
|
|||
r.task.Finish(reason)
|
||||
}
|
||||
|
||||
|
||||
func (r *StreamRoute) Health() health.Status {
|
||||
if r.HealthMon != nil {
|
||||
return r.HealthMon.Status()
|
||||
}
|
||||
return health.StatusUnknown
|
||||
func (r *StreamRoute) HealthMonitor() health.HealthMonitor {
|
||||
return r.HealthMon
|
||||
}
|
||||
|
||||
func (r *StreamRoute) acceptConnections() {
|
||||
|
|
|
@ -8,14 +8,16 @@ import (
|
|||
)
|
||||
|
||||
type (
|
||||
HTTPRoute interface {
|
||||
Route interface {
|
||||
Entry
|
||||
HealthMonitor() health.HealthMonitor
|
||||
}
|
||||
HTTPRoute interface {
|
||||
Route
|
||||
http.Handler
|
||||
Health() health.Status
|
||||
}
|
||||
StreamRoute interface {
|
||||
Entry
|
||||
Route
|
||||
net.Stream
|
||||
Health() health.Status
|
||||
}
|
||||
)
|
||||
|
|
|
@ -142,6 +142,14 @@ func (mon *monitor) Uptime() time.Duration {
|
|||
return time.Since(mon.startTime)
|
||||
}
|
||||
|
||||
// Latency implements HealthMonitor.
|
||||
func (mon *monitor) Latency() time.Duration {
|
||||
if mon.lastResult == nil {
|
||||
return 0
|
||||
}
|
||||
return mon.lastResult.Latency
|
||||
}
|
||||
|
||||
// Name implements HealthMonitor.
|
||||
func (mon *monitor) Name() string {
|
||||
parts := strutils.SplitRune(mon.service, '/')
|
||||
|
|
Loading…
Add table
Reference in a new issue