// Package api wires the monitoring endpoints onto an HTTP router. // // api.RegisterRoutes(http.NewServeMux(), 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 SummaryResponse = proxy.SummaryResponse type HashrateResponse = proxy.HashrateResponse type MinersCountResponse = proxy.MinersCountResponse type UpstreamResponse = proxy.UpstreamResponse type ResultsResponse = proxy.ResultsResponse // RegisterRoutes mounts the monitoring endpoints on any router with HandleFunc. // // 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) }