package service import ( "hy2xs-admin/dao" "hy2xs-admin/model/vo" "strings" "time" ) func DashboardSummary() (vo.DashboardSummaryVo, error) { nowMs := time.Now().UnixMilli() summary := vo.DashboardSummaryVo{CollectedAt: nowMs} summary.Health.Collector = vo.DataHealthVo{Status: "stale", MessageKey: "dashboard.error.collectorStale"} summary.Health.Hysteria = vo.DataHealthVo{Status: "ok"} snapshot := DashboardSnapshot() if snapshot.CollectedAt > 0 { summary.CollectedAt = snapshot.CollectedAt summary.System = snapshot.System summary.Hysteria = snapshot.Hysteria summary.Peers.OnlinePeers = snapshot.OnlinePeers summary.Peers.OnlineDevices = snapshot.OnlineDevices summary.Health.Collector = snapshot.CollectorState summary.Health.Hysteria = snapshot.HysteriaState if nowMs-snapshot.CollectedAt > int64(90*time.Second/time.Millisecond) { summary.Health.Collector = vo.DataHealthVo{Status: "stale", MessageKey: "dashboard.error.collectorStale", LastSuccessAt: snapshot.CollectedAt} } } if peerSummary, err := dao.DashboardPeerSummary(nowMs); err == nil { summary.Peers.Total = peerSummary.Total summary.Peers.Enabled = peerSummary.Enabled summary.Peers.Disabled = peerSummary.Disabled summary.Peers.Expired = peerSummary.Expired } if trafficSummary, err := dao.DashboardTrafficSummary(); err == nil { summary.Traffic = trafficSummary } summary.SecurityRisks = DashboardSecurityRisks(summary) return summary, nil } func DashboardTimeseries(rangeKey string) (vo.DashboardTimeseriesVo, error) { nowMs := time.Now().UnixMilli() fromMs := nowMs - int64(24*time.Hour/time.Millisecond) r := strings.TrimSpace(rangeKey) if r == "1h" { fromMs = nowMs - int64(time.Hour/time.Millisecond) } else if r == "7d" { fromMs = nowMs - int64(7*24*time.Hour/time.Millisecond) } else if r == "30d" { fromMs = nowMs - int64(30*24*time.Hour/time.Millisecond) r = "30d" } else if r == "" { r = "24h" } traffic, err := dao.DashboardTrafficTimeseries(fromMs, nowMs) if err != nil { return vo.DashboardTimeseriesVo{}, err } systemRows, err := dao.DashboardSystemTimeseries(fromMs, nowMs) if err != nil { return vo.DashboardTimeseriesVo{}, err } return vo.DashboardTimeseriesVo{ Range: r, Traffic: traffic, System: systemRows, CollectedAt: nowMs, }, nil } func DashboardTopPeers(rangeKey string, limit int) ([]vo.DashboardTopPeerVo, error) { nowMs := time.Now().UnixMilli() fromMs := nowMs - int64(24*time.Hour/time.Millisecond) if strings.TrimSpace(rangeKey) == "7d" { fromMs = nowMs - int64(7*24*time.Hour/time.Millisecond) } else if strings.TrimSpace(rangeKey) == "30d" { fromMs = nowMs - int64(30*24*time.Hour/time.Millisecond) } return dao.DashboardTopPeers(fromMs, nowMs, limit) } func DashboardSecurity() ([]vo.SecurityRiskVo, error) { summary, err := DashboardSummary() if err != nil { return []vo.SecurityRiskVo{}, err } return summary.SecurityRisks, nil } func DashboardSecurityRisks(summary vo.DashboardSummaryVo) []vo.SecurityRiskVo { risks := make([]vo.SecurityRiskVo, 0) if !summary.Hysteria.Running { risks = append(risks, vo.SecurityRiskVo{Key: "dashboard.security.hysteriaStopped", Severity: "critical", Dismissible: false}) } if !summary.Hysteria.ApiReachable { risks = append(risks, vo.SecurityRiskVo{Key: "dashboard.security.trafficApiUnavailable", Severity: "warning", Dismissible: false}) } return risks }