mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-19 20:32:35 +02:00
refactor, fix metrics and upgrade go to 1.24.0
This commit is contained in:
parent
c807b30c8f
commit
82042e0b99
19 changed files with 157 additions and 104 deletions
|
@ -1,5 +1,5 @@
|
|||
# Stage 1: Builder
|
||||
FROM golang:1.23.6-alpine AS builder
|
||||
FROM golang:1.24.0-alpine AS builder
|
||||
HEALTHCHECK NONE
|
||||
|
||||
# package version does not matter
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
E "github.com/yusing/go-proxy/internal/error"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
"github.com/yusing/go-proxy/pkg"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
@ -69,5 +68,5 @@ Tips:
|
|||
|
||||
server.StartAgentServer(t, opts)
|
||||
|
||||
utils.WaitExit(3)
|
||||
task.WaitExit(3)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package handler
|
||||
package handler_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -10,6 +10,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
||||
"github.com/yusing/go-proxy/agent/pkg/handler"
|
||||
. "github.com/yusing/go-proxy/internal/utils/testing"
|
||||
"github.com/yusing/go-proxy/internal/watcher/health"
|
||||
)
|
||||
|
@ -75,7 +76,7 @@ func TestCheckHealthHTTP(t *testing.T) {
|
|||
query.Set(key, value)
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, agent.APIEndpointBase+agent.EndpointHealth+"?"+query.Encode(), nil)
|
||||
CheckHealth(recorder, request)
|
||||
handler.CheckHealth(recorder, request)
|
||||
|
||||
ExpectEqual(t, recorder.Code, tt.expectedStatus)
|
||||
|
||||
|
@ -120,7 +121,7 @@ func TestCheckHealthFileServer(t *testing.T) {
|
|||
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, agent.APIEndpointBase+agent.EndpointHealth+"?"+query.Encode(), nil)
|
||||
CheckHealth(recorder, request)
|
||||
handler.CheckHealth(recorder, request)
|
||||
|
||||
ExpectEqual(t, recorder.Code, tt.expectedStatus)
|
||||
|
||||
|
@ -203,7 +204,7 @@ func TestCheckHealthTCPUDP(t *testing.T) {
|
|||
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, agent.APIEndpointBase+agent.EndpointHealth+"?"+query.Encode(), nil)
|
||||
CheckHealth(recorder, request)
|
||||
handler.CheckHealth(recorder, request)
|
||||
|
||||
ExpectEqual(t, recorder.Code, tt.expectedStatus)
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/net/http/middleware"
|
||||
"github.com/yusing/go-proxy/internal/route/routes/routequery"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/pkg"
|
||||
)
|
||||
|
||||
|
@ -129,7 +129,7 @@ func main() {
|
|||
|
||||
config.WatchChanges()
|
||||
|
||||
utils.WaitExit(cfg.Value().TimeoutShutdown)
|
||||
task.WaitExit(cfg.Value().TimeoutShutdown)
|
||||
}
|
||||
|
||||
func prepareDirectory(dir string) {
|
||||
|
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
|||
module github.com/yusing/go-proxy
|
||||
|
||||
go 1.23.6
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.10.1
|
||||
|
|
|
@ -37,13 +37,13 @@ func NewHandler(cfg config.ConfigInstance) http.Handler {
|
|||
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", auth.RequireAuth(useCfg(cfg, v1.HealthWS)))
|
||||
mux.HandleFunc("GET", "/v1/logs/ws", auth.RequireAuth(memlogger.LogsWS(cfg)))
|
||||
mux.HandleFunc("GET", "/v1/logs/ws", auth.RequireAuth(memlogger.LogsWS(cfg.Value().MatchDomains)))
|
||||
mux.HandleFunc("GET", "/v1/favicon", auth.RequireAuth(favicon.GetFavIcon))
|
||||
mux.HandleFunc("POST", "/v1/homepage/set", auth.RequireAuth(v1.SetHomePageOverrides))
|
||||
mux.HandleFunc("GET", "/v1/metrics/system_info", auth.RequireAuth(useCfg(cfg, v1.SystemInfo)))
|
||||
mux.HandleFunc("GET", "/v1/metrics/system_info/ws", auth.RequireAuth(useCfg(cfg, v1.SystemInfo)))
|
||||
mux.HandleFunc("GET", "/v1/metrics/uptime", auth.RequireAuth(uptime.Poller.ServeHTTP))
|
||||
mux.HandleFunc("GET", "/v1/metrics/uptime/ws", auth.RequireAuth(useCfg(cfg, uptime.Poller.ServeWS)))
|
||||
mux.HandleFunc("GET", "/v1/metrics/uptime/ws", auth.RequireAuth(useWS(cfg, uptime.Poller.ServeWS)))
|
||||
|
||||
if common.PrometheusEnabled {
|
||||
mux.Handle("GET /v1/metrics", promhttp.Handler())
|
||||
|
@ -74,3 +74,9 @@ func useCfg(cfg config.ConfigInstance, handler func(cfg config.ConfigInstance, w
|
|||
handler(cfg, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func useWS(cfg config.ConfigInstance, handler func(allowedDomains []string, w http.ResponseWriter, r *http.Request)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
handler(cfg.Value().MatchDomains, w, r)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
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.Value().MatchDomains, w, r, 1*time.Second, func(conn *websocket.Conn) error {
|
||||
return wsjson.Write(r.Context(), conn, routequery.HealthMap())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ func Stats(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func StatsWS(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.Value().MatchDomains, w, r, 1*time.Second, func(conn *websocket.Conn) error {
|
||||
return wsjson.Write(r.Context(), conn, getStats(cfg))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ func SystemInfo(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Reques
|
|||
agentName := r.URL.Query().Get("agent_name")
|
||||
if agentName == "" {
|
||||
if isWS {
|
||||
systeminfo.Poller.ServeWS(cfg, w, r)
|
||||
systeminfo.Poller.ServeWS(cfg.Value().MatchDomains, w, r)
|
||||
} else {
|
||||
systeminfo.Poller.ServeHTTP(w, r)
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func SystemInfo(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Reques
|
|||
}
|
||||
U.WriteBody(w, respData)
|
||||
} else {
|
||||
clientConn, err := U.InitiateWS(cfg, w, r)
|
||||
clientConn, err := U.InitiateWS(cfg.Value().MatchDomains, w, r)
|
||||
if err != nil {
|
||||
U.HandleErr(w, r, err)
|
||||
return
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"syscall"
|
||||
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils/ansi"
|
||||
|
@ -16,10 +17,11 @@ import (
|
|||
//
|
||||
// The error is only logged but not returned to the client.
|
||||
func HandleErr(w http.ResponseWriter, r *http.Request, err error, code ...int) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if errors.Is(err, context.Canceled) {
|
||||
switch {
|
||||
case err == nil,
|
||||
errors.Is(err, context.Canceled),
|
||||
errors.Is(err, syscall.EPIPE),
|
||||
errors.Is(err, syscall.ECONNRESET):
|
||||
return
|
||||
}
|
||||
LogError(r).Msg(err.Error())
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
|
||||
"github.com/coder/websocket"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
config "github.com/yusing/go-proxy/internal/config/types"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
)
|
||||
|
||||
|
@ -17,45 +16,49 @@ func warnNoMatchDomains() {
|
|||
|
||||
var warnNoMatchDomainOnce sync.Once
|
||||
|
||||
func InitiateWS(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) (*websocket.Conn, error) {
|
||||
func InitiateWS(allowedDomains []string, w http.ResponseWriter, r *http.Request) (*websocket.Conn, error) {
|
||||
var originPats []string
|
||||
|
||||
localAddresses := []string{"127.0.0.1", "10.0.*.*", "172.16.*.*", "192.168.*.*"}
|
||||
|
||||
if cfg == nil || len(cfg.Value().MatchDomains) == 0 {
|
||||
if len(allowedDomains) == 0 || common.IsDebug {
|
||||
warnNoMatchDomainOnce.Do(warnNoMatchDomains)
|
||||
originPats = []string{"*"}
|
||||
} else {
|
||||
originPats = make([]string, len(cfg.Value().MatchDomains))
|
||||
for i, domain := range cfg.Value().MatchDomains {
|
||||
originPats[i] = "*" + domain
|
||||
originPats = make([]string, len(allowedDomains))
|
||||
for i, domain := range allowedDomains {
|
||||
if domain[0] != '.' {
|
||||
originPats[i] = "*." + domain
|
||||
} else {
|
||||
originPats[i] = "*" + domain
|
||||
}
|
||||
}
|
||||
originPats = append(originPats, localAddresses...)
|
||||
}
|
||||
if common.IsDebug {
|
||||
originPats = []string{"*"}
|
||||
}
|
||||
return websocket.Accept(w, r, &websocket.AcceptOptions{
|
||||
OriginPatterns: originPats,
|
||||
})
|
||||
}
|
||||
|
||||
func PeriodicWS(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request, interval time.Duration, do func(conn *websocket.Conn) error) {
|
||||
conn, err := InitiateWS(cfg, w, r)
|
||||
func PeriodicWS(allowedDomains []string, w http.ResponseWriter, r *http.Request, interval time.Duration, do func(conn *websocket.Conn) error) {
|
||||
conn, err := InitiateWS(allowedDomains, w, r)
|
||||
if err != nil {
|
||||
HandleErr(w, r, err)
|
||||
return
|
||||
}
|
||||
/* trunk-ignore(golangci-lint/errcheck) */
|
||||
//nolint:errcheck
|
||||
defer conn.CloseNow()
|
||||
|
||||
if err := do(conn); err != nil {
|
||||
HandleErr(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(interval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-cfg.Context().Done():
|
||||
return
|
||||
case <-r.Context().Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/rs/zerolog"
|
||||
"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"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
F "github.com/yusing/go-proxy/internal/utils/functional"
|
||||
|
@ -81,9 +80,9 @@ func init() {
|
|||
logging.InitLogger(zerolog.MultiLevelWriter(os.Stderr, memLoggerInstance))
|
||||
}
|
||||
|
||||
func LogsWS(config config.ConfigInstance) http.HandlerFunc {
|
||||
func LogsWS(allowedDomains []string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
memLoggerInstance.ServeHTTP(config, w, r)
|
||||
memLoggerInstance.ServeHTTP(allowedDomains, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,8 +150,8 @@ func (m *memLogger) Write(p []byte) (n int, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (m *memLogger) ServeHTTP(config config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := utils.InitiateWS(config, w, r)
|
||||
func (m *memLogger) ServeHTTP(allowedDomains []string, w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := utils.InitiateWS(allowedDomains, w, r)
|
||||
if err != nil {
|
||||
utils.HandleErr(w, r, err)
|
||||
return
|
||||
|
@ -161,7 +160,6 @@ func (m *memLogger) ServeHTTP(config config.ConfigInstance, w http.ResponseWrite
|
|||
logCh := make(chan *logEntryRange)
|
||||
m.connChans.Store(logCh, struct{}{})
|
||||
|
||||
/* trunk-ignore(golangci-lint/errcheck) */
|
||||
defer func() {
|
||||
_ = conn.CloseNow()
|
||||
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
package period
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Entries[T any] struct {
|
||||
entries [maxEntries]*T
|
||||
index int
|
||||
count int
|
||||
interval int64
|
||||
lastAdd int64
|
||||
interval time.Duration
|
||||
lastAdd time.Time
|
||||
}
|
||||
|
||||
const maxEntries = 500
|
||||
const maxEntries = 200
|
||||
|
||||
func newEntries[T any](interval int64) *Entries[T] {
|
||||
func newEntries[T any](duration time.Duration) *Entries[T] {
|
||||
return &Entries[T]{
|
||||
interval: interval,
|
||||
lastAdd: time.Now().Unix(),
|
||||
interval: duration / maxEntries,
|
||||
lastAdd: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Entries[T]) Add(now int64, info *T) {
|
||||
if now-e.lastAdd < e.interval {
|
||||
func (e *Entries[T]) Add(now time.Time, info *T) {
|
||||
if now.Sub(e.lastAdd) < e.interval {
|
||||
return
|
||||
}
|
||||
e.entries[e.index] = info
|
||||
|
|
|
@ -2,11 +2,11 @@ package period
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/coder/websocket"
|
||||
"github.com/coder/websocket/wsjson"
|
||||
"github.com/yusing/go-proxy/internal/api/v1/utils"
|
||||
config "github.com/yusing/go-proxy/internal/config/types"
|
||||
)
|
||||
|
||||
func (p *Poller[T, AggregateT]) lastResultHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -42,8 +42,35 @@ func (p *Poller[T, AggregateT]) ServeHTTP(w http.ResponseWriter, r *http.Request
|
|||
}
|
||||
}
|
||||
|
||||
func (p *Poller[T, AggregateT]) ServeWS(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
|
||||
utils.PeriodicWS(cfg, w, r, p.interval, func(conn *websocket.Conn) error {
|
||||
return wsjson.Write(r.Context(), conn, p.GetLastResult())
|
||||
})
|
||||
func (p *Poller[T, AggregateT]) ServeWS(allowedDomains []string, w http.ResponseWriter, r *http.Request) {
|
||||
query := r.URL.Query()
|
||||
period := query.Get("period")
|
||||
intervalStr := query.Get("interval")
|
||||
interval, err := time.ParseDuration(intervalStr)
|
||||
|
||||
minInterval := p.interval()
|
||||
if err != nil || interval < minInterval {
|
||||
interval = minInterval
|
||||
}
|
||||
|
||||
if period == "" {
|
||||
utils.PeriodicWS(allowedDomains, w, r, interval, func(conn *websocket.Conn) error {
|
||||
return wsjson.Write(r.Context(), conn, p.GetLastResult())
|
||||
})
|
||||
} else {
|
||||
periodFilter := Filter(period)
|
||||
if !periodFilter.IsValid() {
|
||||
http.Error(w, "invalid period", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if p.aggregator != nil {
|
||||
utils.PeriodicWS(allowedDomains, w, r, interval, func(conn *websocket.Conn) error {
|
||||
return wsjson.Write(r.Context(), conn, p.aggregator(p.Get(periodFilter)...))
|
||||
})
|
||||
} else {
|
||||
utils.PeriodicWS(allowedDomains, w, r, interval, func(conn *websocket.Conn) error {
|
||||
return wsjson.Write(r.Context(), conn, p.Get(periodFilter))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,17 +24,17 @@ const (
|
|||
|
||||
func NewPeriod[T any]() *Period[T] {
|
||||
return &Period[T]{
|
||||
FifteenMinutes: newEntries[T](15 * 60 / maxEntries),
|
||||
OneHour: newEntries[T](60 * 60 / maxEntries),
|
||||
OneDay: newEntries[T](24 * 60 * 60 / maxEntries),
|
||||
OneMonth: newEntries[T](30 * 24 * 60 * 60 / maxEntries),
|
||||
FifteenMinutes: newEntries[T](15 * time.Minute),
|
||||
OneHour: newEntries[T](1 * time.Hour),
|
||||
OneDay: newEntries[T](24 * time.Hour),
|
||||
OneMonth: newEntries[T](30 * 24 * time.Hour),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Period[T]) Add(info *T) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
now := time.Now().Unix()
|
||||
now := time.Now()
|
||||
p.FifteenMinutes.Add(now, info)
|
||||
p.OneHour.Add(now, info)
|
||||
p.OneDay.Add(now, info)
|
||||
|
|
|
@ -18,7 +18,6 @@ type (
|
|||
poll PollFunc[T]
|
||||
aggregator AggregateFunc[T, AggregateT]
|
||||
period *Period[T]
|
||||
interval time.Duration
|
||||
lastResult *T
|
||||
errs []pollErr
|
||||
}
|
||||
|
@ -36,10 +35,9 @@ func NewPoller[T any](
|
|||
poll PollFunc[T],
|
||||
) *Poller[T, T] {
|
||||
return &Poller[T, T]{
|
||||
name: name,
|
||||
poll: poll,
|
||||
period: NewPeriod[T](),
|
||||
interval: interval,
|
||||
name: name,
|
||||
poll: poll,
|
||||
period: NewPeriod[T](),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,10 +52,13 @@ func NewPollerWithAggregator[T, AggregateT any](
|
|||
poll: poll,
|
||||
aggregator: aggregator,
|
||||
period: NewPeriod[T](),
|
||||
interval: interval,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Poller[T, AggregateT]) interval() time.Duration {
|
||||
return p.period.FifteenMinutes.interval
|
||||
}
|
||||
|
||||
func (p *Poller[T, AggregateT]) appendErr(err error) {
|
||||
if len(p.errs) == 0 {
|
||||
p.errs = []pollErr{
|
||||
|
@ -87,32 +88,36 @@ func (p *Poller[T, AggregateT]) gatherErrs() (string, bool) {
|
|||
return strings.Join(errs, "\n"), true
|
||||
}
|
||||
|
||||
func (p *Poller[T, AggregateT]) pollWithTimeout(ctx context.Context) (*T, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, p.interval)
|
||||
func (p *Poller[T, AggregateT]) pollWithTimeout(ctx context.Context) {
|
||||
ctx, cancel := context.WithTimeout(ctx, p.interval())
|
||||
defer cancel()
|
||||
return p.poll(ctx)
|
||||
data, err := p.poll(ctx)
|
||||
if err != nil {
|
||||
p.appendErr(err)
|
||||
return
|
||||
}
|
||||
p.period.Add(data)
|
||||
p.lastResult = data
|
||||
}
|
||||
|
||||
func (p *Poller[T, AggregateT]) Start() {
|
||||
go func() {
|
||||
ctx := task.RootContext()
|
||||
ticker := time.NewTicker(p.interval)
|
||||
ticker := time.NewTicker(p.interval())
|
||||
gatherErrsTicker := time.NewTicker(gatherErrsInterval)
|
||||
defer ticker.Stop()
|
||||
defer gatherErrsTicker.Stop()
|
||||
|
||||
logging.Debug().Msgf("Starting poller %s with interval %s", p.name, p.interval())
|
||||
|
||||
p.pollWithTimeout(ctx)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
data, err := p.pollWithTimeout(ctx)
|
||||
if err != nil {
|
||||
p.appendErr(err)
|
||||
continue
|
||||
}
|
||||
p.period.Add(data)
|
||||
p.lastResult = data
|
||||
p.pollWithTimeout(ctx)
|
||||
case <-gatherErrsTicker.C:
|
||||
errs, ok := p.gatherErrs()
|
||||
if ok {
|
||||
|
|
|
@ -2,21 +2,23 @@ package uptime
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/metrics/period"
|
||||
"github.com/yusing/go-proxy/internal/route/routes/routequery"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
"github.com/yusing/go-proxy/internal/watcher/health"
|
||||
)
|
||||
|
||||
type (
|
||||
Statuses struct {
|
||||
Statuses map[string]health.Status
|
||||
Timestamp int64
|
||||
Timestamp time.Time
|
||||
}
|
||||
Status struct {
|
||||
Status health.Status
|
||||
Timestamp int64
|
||||
Timestamp time.Time
|
||||
}
|
||||
Aggregated map[string][]Status
|
||||
)
|
||||
|
@ -30,7 +32,7 @@ func init() {
|
|||
func getStatuses(ctx context.Context) (*Statuses, error) {
|
||||
return &Statuses{
|
||||
Statuses: routequery.HealthStatuses(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
Timestamp: time.Now(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -71,3 +73,19 @@ func (a Aggregated) finalize() map[string]map[string]interface{} {
|
|||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *Status) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"status": s.Status.String(),
|
||||
"timestamp": s.Timestamp.Unix(),
|
||||
"tooltip": strutils.FormatTime(s.Timestamp),
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Statuses) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"statuses": s.Statuses,
|
||||
"timestamp": s.Timestamp.Unix(),
|
||||
"tooltip": strutils.FormatTime(s.Timestamp),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
|
@ -73,3 +76,17 @@ func GracefulShutdown(timeout time.Duration) (err error) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WaitExit(shutdownTimeout int) {
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, syscall.SIGINT)
|
||||
signal.Notify(sig, syscall.SIGTERM)
|
||||
signal.Notify(sig, syscall.SIGHUP)
|
||||
|
||||
// wait for signal
|
||||
<-sig
|
||||
|
||||
// gracefully shutdown
|
||||
logging.Info().Msg("shutting down")
|
||||
_ = GracefulShutdown(time.Second * time.Duration(shutdownTimeout))
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
)
|
||||
|
||||
func WaitExit(shutdownTimeout int) {
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, syscall.SIGINT)
|
||||
signal.Notify(sig, syscall.SIGTERM)
|
||||
signal.Notify(sig, syscall.SIGHUP)
|
||||
|
||||
// wait for signal
|
||||
<-sig
|
||||
|
||||
// gracefully shutdown
|
||||
logging.Info().Msg("shutting down")
|
||||
_ = task.GracefulShutdown(time.Second * time.Duration(shutdownTimeout))
|
||||
}
|
Loading…
Add table
Reference in a new issue