handleLatency 返回所有节点在指定时间范围内的延迟采样。 GET /v1/nodes/latency?from=RFC3339&to=RFC3339 默认 from = 1小时前,to = 现在。
(w http.ResponseWriter, r *http.Request)
| 12 | // GET /v1/nodes/latency?from=RFC3339&to=RFC3339 |
| 13 | // 默认 from = 1小时前,to = 现在。 |
| 14 | func (a *API) handleLatency(w http.ResponseWriter, r *http.Request) { |
| 15 | if r.Method != http.MethodGet { |
| 16 | writeMethodNotAllowed(w, http.MethodGet) |
| 17 | return |
| 18 | } |
| 19 | |
| 20 | now := time.Now().UTC() |
| 21 | from := now.Add(-1 * time.Hour) |
| 22 | to := now |
| 23 | |
| 24 | if s := r.URL.Query().Get("from"); s != "" { |
| 25 | t, err := time.Parse(time.RFC3339, s) |
| 26 | if err != nil { |
| 27 | writeJSON(w, http.StatusBadRequest, map[string]any{"error": "invalid from: " + err.Error()}) |
| 28 | return |
| 29 | } |
| 30 | from = t |
| 31 | } |
| 32 | if s := r.URL.Query().Get("to"); s != "" { |
| 33 | t, err := time.Parse(time.RFC3339, s) |
| 34 | if err != nil { |
| 35 | writeJSON(w, http.StatusBadRequest, map[string]any{"error": "invalid to: " + err.Error()}) |
| 36 | return |
| 37 | } |
| 38 | to = t |
| 39 | } |
| 40 | if !from.Before(to) { |
| 41 | writeJSON(w, http.StatusBadRequest, map[string]any{"error": "from must be before to"}) |
| 42 | return |
| 43 | } |
| 44 | |
| 45 | allNodes, err := a.store.List() |
| 46 | if err != nil { |
| 47 | internalError(w, r, err) |
| 48 | return |
| 49 | } |
| 50 | nodeIDs := make([]string, 0, len(allNodes)) |
| 51 | nameMap := make(map[string]string, len(allNodes)) |
| 52 | for _, n := range allNodes { |
| 53 | nodeIDs = append(nodeIDs, n.ID) |
| 54 | nameMap[n.ID] = n.Name |
| 55 | } |
| 56 | |
| 57 | samples, err := a.store.QueryLatencySamples(nodeIDs, from, to) |
| 58 | if err != nil { |
| 59 | internalError(w, r, err) |
| 60 | return |
| 61 | } |
| 62 | if samples == nil { |
| 63 | samples = []nodes.LatencySample{} |
| 64 | } |
| 65 | |
| 66 | type sampleResp struct { |
| 67 | NodeID string `json:"node_id"` |
| 68 | NodeName string `json:"node_name"` |
| 69 | ISP string `json:"isp"` |
| 70 | RttMs *int `json:"rtt_ms"` |
| 71 | SampledAt time.Time `json:"sampled_at"` |
nothing calls this directly
no test coverage detected