refactor(api): share monitoring route registration
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
140e66ac64
commit
e523fd0740
4 changed files with 27 additions and 158 deletions
156
api/router.go
156
api/router.go
|
|
@ -1,23 +1,15 @@
|
|||
// Package api wires the monitoring endpoints onto an HTTP router.
|
||||
//
|
||||
// api.RegisterRoutes(http.NewServeMux(), p)
|
||||
// mux := http.NewServeMux()
|
||||
// api.RegisterRoutes(mux, p)
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"dappco.re/go/core/proxy"
|
||||
)
|
||||
|
||||
// Router is the minimal route-registration surface used by RegisterRoutes.
|
||||
//
|
||||
// mux := http.NewServeMux()
|
||||
// api.RegisterRoutes(mux, p)
|
||||
type Router interface {
|
||||
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
||||
}
|
||||
type Router = proxy.RouteRegistrar
|
||||
|
||||
type SummaryResponse = proxy.SummaryResponse
|
||||
type HashrateResponse = proxy.HashrateResponse
|
||||
|
|
@ -30,145 +22,5 @@ type ResultsResponse = proxy.ResultsResponse
|
|||
// mux := http.NewServeMux()
|
||||
// api.RegisterRoutes(mux, p)
|
||||
func RegisterRoutes(router Router, proxyValue *proxy.Proxy) {
|
||||
if router == nil || proxyValue == nil {
|
||||
return
|
||||
}
|
||||
|
||||
router.HandleFunc("/1/summary", func(writer http.ResponseWriter, request *http.Request) {
|
||||
if !allowRequest(writer, request, proxyValue.HTTPConfig()) {
|
||||
return
|
||||
}
|
||||
summary := proxyValue.Summary()
|
||||
response := SummaryResponse{
|
||||
Version: "1.0.0",
|
||||
Mode: proxyValue.Mode(),
|
||||
Hashrate: HashrateResponse{
|
||||
Total: summary.Hashrate,
|
||||
},
|
||||
Miners: MinersCountResponse{
|
||||
Now: proxyValue.CurrentMiners(),
|
||||
Max: proxyValue.MaxMiners(),
|
||||
},
|
||||
Workers: uint64(len(proxyValue.Workers())),
|
||||
Upstreams: func() UpstreamResponse {
|
||||
upstreams := proxyValue.Upstreams()
|
||||
ratio := 0.0
|
||||
if upstreams.Total > 0 {
|
||||
ratio = float64(proxyValue.CurrentMiners()) / float64(upstreams.Total)
|
||||
}
|
||||
return UpstreamResponse{
|
||||
Active: upstreams.Active,
|
||||
Sleep: upstreams.Sleep,
|
||||
Error: upstreams.Error,
|
||||
Total: upstreams.Total,
|
||||
Ratio: ratio,
|
||||
}
|
||||
}(),
|
||||
Results: ResultsResponse{
|
||||
Accepted: summary.Accepted,
|
||||
Rejected: summary.Rejected,
|
||||
Invalid: summary.Invalid,
|
||||
Expired: summary.Expired,
|
||||
AvgTime: summary.AvgTime,
|
||||
Latency: summary.AvgLatency,
|
||||
HashesTotal: summary.Hashes,
|
||||
Best: summary.TopDiff,
|
||||
},
|
||||
}
|
||||
writeJSON(writer, response)
|
||||
})
|
||||
|
||||
router.HandleFunc("/1/workers", func(writer http.ResponseWriter, request *http.Request) {
|
||||
if !allowRequest(writer, request, proxyValue.HTTPConfig()) {
|
||||
return
|
||||
}
|
||||
type responseBody struct {
|
||||
Mode string `json:"mode"`
|
||||
Workers [][]interface{} `json:"workers"`
|
||||
}
|
||||
|
||||
records := proxyValue.Workers()
|
||||
rows := make([][]interface{}, 0, len(records))
|
||||
for _, record := range records {
|
||||
rows = append(rows, []interface{}{
|
||||
record.Name,
|
||||
record.LastIP,
|
||||
record.Connections,
|
||||
record.Accepted,
|
||||
record.Rejected,
|
||||
record.Invalid,
|
||||
record.Hashes,
|
||||
record.LastHashAt.Unix(),
|
||||
record.Hashrate(60),
|
||||
record.Hashrate(600),
|
||||
record.Hashrate(3600),
|
||||
record.Hashrate(43200),
|
||||
record.Hashrate(86400),
|
||||
})
|
||||
}
|
||||
|
||||
writeJSON(writer, responseBody{
|
||||
Mode: proxyValue.WorkersMode(),
|
||||
Workers: rows,
|
||||
})
|
||||
})
|
||||
|
||||
router.HandleFunc("/1/miners", func(writer http.ResponseWriter, request *http.Request) {
|
||||
if !allowRequest(writer, request, proxyValue.HTTPConfig()) {
|
||||
return
|
||||
}
|
||||
miners := proxyValue.Miners()
|
||||
rows := make([][]interface{}, 0, len(miners))
|
||||
for _, miner := range miners {
|
||||
ip := ""
|
||||
if remote := miner.RemoteAddr(); remote != nil {
|
||||
ip = remote.String()
|
||||
}
|
||||
rows = append(rows, []interface{}{
|
||||
miner.ID(),
|
||||
ip,
|
||||
miner.TX(),
|
||||
miner.RX(),
|
||||
miner.State(),
|
||||
miner.Diff(),
|
||||
miner.User(),
|
||||
"********",
|
||||
miner.RigID(),
|
||||
miner.Agent(),
|
||||
})
|
||||
}
|
||||
|
||||
writeJSON(writer, map[string]interface{}{
|
||||
"format": []string{"id", "ip", "tx", "rx", "state", "diff", "user", "password", "rig_id", "agent"},
|
||||
"miners": rows,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func allowRequest(writer http.ResponseWriter, request *http.Request, config proxy.HTTPConfig) bool {
|
||||
if request == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if config.AccessToken != "" {
|
||||
header := request.Header.Get("Authorization")
|
||||
prefix := "Bearer "
|
||||
if !strings.HasPrefix(header, prefix) || strings.TrimSpace(strings.TrimPrefix(header, prefix)) != config.AccessToken {
|
||||
writer.Header().Set("WWW-Authenticate", "Bearer")
|
||||
http.Error(writer, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if config.Restricted && request.Method != http.MethodGet {
|
||||
http.Error(writer, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func writeJSON(writer http.ResponseWriter, value interface{}) {
|
||||
writer.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(writer).Encode(value)
|
||||
proxy.RegisterMonitoringRoutes(router, proxyValue)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,10 @@ func LoadConfig(path string) (*Config, error) {
|
|||
|
||||
// Validate checks that `bind` and `pools` are present and every enabled pool has a URL.
|
||||
//
|
||||
// cfg := &proxy.Config{Bind: []proxy.BindAddr{{Host: "127.0.0.1", Port: 3333}}, Pools: []proxy.PoolConfig{{URL: "pool-a:3333", Enabled: true}}}
|
||||
// cfg := &proxy.Config{
|
||||
// Bind: []proxy.BindAddr{{Host: "127.0.0.1", Port: 3333}},
|
||||
// Pools: []proxy.PoolConfig{{URL: "pool-a:3333", Enabled: true}},
|
||||
// }
|
||||
// if errorValue := cfg.Validate(); errorValue != nil {
|
||||
// return
|
||||
// }
|
||||
|
|
@ -61,7 +64,9 @@ func (c *Config) Validate() error {
|
|||
|
||||
// NewConfigWatcher watches a config file and reloads the proxy on modification.
|
||||
//
|
||||
// w := proxy.NewConfigWatcher("config.json", func(cfg *proxy.Config) { p.Reload(cfg) })
|
||||
// w := proxy.NewConfigWatcher("config.json", func(cfg *proxy.Config) {
|
||||
// p.Reload(cfg)
|
||||
// })
|
||||
func NewConfigWatcher(path string, onChange func(*Config)) *ConfigWatcher {
|
||||
return newConfigWatcher(path, onChange, true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,14 @@ import (
|
|||
|
||||
const proxyAPIVersion = "1.0.0"
|
||||
|
||||
// RouteRegistrar is the minimal route-registration surface used by RegisterMonitoringRoutes.
|
||||
//
|
||||
// mux := http.NewServeMux()
|
||||
// RegisterMonitoringRoutes(mux, p)
|
||||
type RouteRegistrar interface {
|
||||
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
||||
}
|
||||
|
||||
// SummaryResponse is the /1/summary JSON body.
|
||||
type SummaryResponse struct {
|
||||
Version string `json:"version"`
|
||||
|
|
@ -61,7 +69,7 @@ func startHTTPServer(p *Proxy) {
|
|||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
registerMonitoringRoutes(mux, p)
|
||||
RegisterMonitoringRoutes(mux, p)
|
||||
|
||||
address := net.JoinHostPort(p.config.HTTP.Host, strconv.Itoa(int(p.config.HTTP.Port)))
|
||||
listener, errorValue := net.Listen("tcp", address)
|
||||
|
|
@ -92,7 +100,11 @@ func stopHTTPServer(p *Proxy) {
|
|||
_ = server.Shutdown(shutdownContext)
|
||||
}
|
||||
|
||||
func registerMonitoringRoutes(router *http.ServeMux, proxyValue *Proxy) {
|
||||
// RegisterMonitoringRoutes mounts the monitoring endpoints on any router with HandleFunc.
|
||||
//
|
||||
// mux := http.NewServeMux()
|
||||
// RegisterMonitoringRoutes(mux, p)
|
||||
func RegisterMonitoringRoutes(router RouteRegistrar, proxyValue *Proxy) {
|
||||
if router == nil || proxyValue == nil {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
// NewRateLimiter creates a per-IP limiter, for example:
|
||||
//
|
||||
// rl := proxy.NewRateLimiter(cfg.RateLimit)
|
||||
// rl := proxy.NewRateLimiter(proxy.RateLimit{MaxConnectionsPerMinute: 30, BanDurationSeconds: 300})
|
||||
func NewRateLimiter(config RateLimit) *RateLimiter {
|
||||
return &RateLimiter{
|
||||
limitConfig: config,
|
||||
|
|
@ -17,7 +17,7 @@ func NewRateLimiter(config RateLimit) *RateLimiter {
|
|||
}
|
||||
}
|
||||
|
||||
// SetConfig swaps in a live reload value such as `proxy.RateLimit{MaxConnectionsPerMinute: 30}`.
|
||||
// SetConfig swaps in a live reload value such as:
|
||||
//
|
||||
// rl.SetConfig(proxy.RateLimit{MaxConnectionsPerMinute: 30, BanDurationSeconds: 300})
|
||||
func (rateLimiter *RateLimiter) SetConfig(config RateLimit) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue