package routes import ( "math" "time" "github.com/bytedance/sonic" "github.com/yusing/godoxy/internal/types" ) type HealthInfo struct { Status types.HealthStatus `json:"status" swaggertype:"string" enums:"healthy,unhealthy,napping,starting,error,unknown"` Uptime time.Duration `json:"uptime" swaggertype:"number"` // uptime in milliseconds Latency time.Duration `json:"latency" swaggertype:"number"` // latency in microseconds Detail string `json:"detail"` } func (info *HealthInfo) MarshalJSON() ([]byte, error) { return sonic.Marshal(map[string]any{ "status": info.Status.String(), "latency": info.Latency.Microseconds(), "uptime": info.Uptime.Milliseconds(), "detail": info.Detail, }) } func (info *HealthInfo) UnmarshalJSON(data []byte) error { var v struct { Status string `json:"status"` Latency int64 `json:"latency"` Uptime int64 `json:"uptime"` Detail string `json:"detail"` } if err := sonic.Unmarshal(data, &v); err != nil { return err } // overflow check // Check if latency (in microseconds) would overflow when converted to nanoseconds if v.Latency > math.MaxInt64/int64(time.Microsecond) { v.Latency = 0 } // Check if uptime (in milliseconds) would overflow when converted to nanoseconds if v.Uptime > math.MaxInt64/int64(time.Millisecond) { v.Uptime = 0 } info.Status = types.NewHealthStatusFromString(v.Status) info.Latency = time.Duration(v.Latency) * time.Microsecond info.Uptime = time.Duration(v.Uptime) * time.Millisecond info.Detail = v.Detail return nil } func GetHealthInfo() map[string]HealthInfo { healthMap := make(map[string]HealthInfo, NumRoutes()) for r := range Iter { healthMap[r.Name()] = getHealthInfo(r) } return healthMap } func getHealthInfo(r types.Route) HealthInfo { mon := r.HealthMonitor() if mon == nil { return HealthInfo{ Status: types.StatusUnknown, Detail: "n/a", } } return HealthInfo{ Status: mon.Status(), Uptime: mon.Uptime(), Latency: mon.Latency(), Detail: mon.Detail(), } } func ByProvider() map[string][]types.Route { rts := make(map[string][]types.Route) for r := range Iter { rts[r.ProviderName()] = append(rts[r.ProviderName()], r) } return rts }