zdravko/internal/server/handlers/index.go

182 lines
4.4 KiB
Go
Raw Normal View History

package handlers
import (
2024-02-22 16:29:17 +00:00
"context"
"net/http"
2024-02-22 16:29:17 +00:00
"time"
"github.com/labstack/echo/v4"
"github.com/mentos1386/zdravko/database/models"
"github.com/mentos1386/zdravko/internal/server/services"
"github.com/mentos1386/zdravko/web/templates/components"
)
type IndexData struct {
*components.Base
Targets map[string]TargetsAndStatus
TargetsLength int
TimeRange string
Status models.TargetStatus
}
type Target struct {
Name string
Visibility models.TargetVisibility
Group string
Status models.TargetStatus
History *History
}
2024-03-04 13:20:01 +00:00
type HistoryItem struct {
Status models.TargetStatus
2024-03-04 13:20:01 +00:00
Date time.Time
}
2024-02-22 16:29:17 +00:00
type History struct {
2024-03-04 13:20:01 +00:00
List []HistoryItem
2024-05-17 19:54:14 +00:00
Uptime float64
2024-02-22 16:29:17 +00:00
}
type TargetsAndStatus struct {
Status models.TargetStatus
Targets []*Target
2024-03-04 13:20:01 +00:00
}
func getDateString(date time.Time) string {
2024-02-29 22:57:23 +00:00
return date.UTC().Format("2006-01-02T15:04:05")
2024-02-22 16:29:17 +00:00
}
func getHistory(history []*services.TargetHistory, period time.Duration, buckets int) *History {
historyMap := map[string]models.TargetStatus{}
2024-05-17 19:54:14 +00:00
numOfSuccess := 0.0
numTotal := 0.0
2024-02-22 16:29:17 +00:00
2024-02-29 22:42:56 +00:00
for i := 0; i < buckets; i++ {
2024-03-04 13:20:01 +00:00
dateString := getDateString(time.Now().Add(period * time.Duration(-i)).Truncate(period))
historyMap[dateString] = models.TargetStatusUnknown
2024-02-22 16:29:17 +00:00
}
for _, _history := range history {
2024-03-04 13:20:01 +00:00
dateString := getDateString(_history.CreatedAt.Time.Truncate(period))
2024-02-22 16:29:17 +00:00
2024-02-29 22:42:56 +00:00
// Skip if not part of the "buckets"
2024-03-04 13:20:01 +00:00
if _, ok := historyMap[dateString]; !ok {
2024-02-22 16:29:17 +00:00
continue
}
numTotal++
if _history.Status == models.TargetStatusSuccess {
2024-02-22 16:29:17 +00:00
numOfSuccess++
}
2024-02-29 22:42:56 +00:00
// skip if it is already set to failure
if historyMap[dateString] == models.TargetStatusFailure {
2024-02-22 16:29:17 +00:00
continue
}
// FIXME: This is wrong! As we can have multiple targets in dateString.
2024-03-04 13:20:01 +00:00
// We should look at only the newest one.
historyMap[dateString] = _history.Status
2024-02-22 16:29:17 +00:00
}
2024-03-04 13:20:01 +00:00
historyItems := make([]HistoryItem, buckets)
2024-02-29 22:42:56 +00:00
for i := 0; i < buckets; i++ {
2024-03-04 13:20:01 +00:00
date := time.Now().Add(period * time.Duration(-buckets+i+1)).Truncate(period)
datestring := getDateString(date)
historyItems[i] = HistoryItem{
Status: historyMap[datestring],
Date: date,
}
2024-02-22 16:29:17 +00:00
}
2024-05-17 19:54:14 +00:00
uptime := 0.0
2024-02-22 19:20:34 +00:00
if numTotal > 0 {
2024-05-17 19:54:14 +00:00
uptime = 100.0 * numOfSuccess / numTotal
2024-02-22 19:20:34 +00:00
}
2024-02-22 16:29:17 +00:00
return &History{
2024-03-04 13:20:01 +00:00
List: historyItems,
2024-02-29 22:42:56 +00:00
Uptime: uptime,
}
}
func (h *BaseHandler) Index(c echo.Context) error {
2024-02-22 16:29:17 +00:00
ctx := context.Background()
targets, err := services.GetTargets(ctx, h.db)
2024-02-22 16:29:17 +00:00
if err != nil {
return err
}
timeRange := c.QueryParam("time-range")
2024-02-29 22:42:56 +00:00
if timeRange != "48hours" && timeRange != "90days" && timeRange != "90minutes" {
2024-02-22 16:29:17 +00:00
timeRange = "90days"
}
overallStatus := models.TargetStatusUnknown
statusByGroup := make(map[string]models.TargetStatus)
2024-02-22 16:29:17 +00:00
targetsWithHistory := make([]*Target, len(targets))
for i, target := range targets {
history, err := services.GetTargetHistoryForTarget(ctx, h.db, target.Id)
2024-02-27 11:04:05 +00:00
if err != nil {
return err
}
2024-02-29 22:42:56 +00:00
var historyResult *History
switch timeRange {
case "48hours":
historyResult = getHistory(history, time.Hour, 48)
case "90days":
historyResult = getHistory(history, time.Hour*24, 90)
case "90minutes":
historyResult = getHistory(history, time.Minute, 90)
}
2024-02-22 16:29:17 +00:00
if statusByGroup[target.Group] == "" {
statusByGroup[target.Group] = models.TargetStatusUnknown
2024-03-04 13:20:01 +00:00
}
2024-02-29 22:42:56 +00:00
status := historyResult.List[len(historyResult.List)-1]
if status.Status == models.TargetStatusSuccess {
if overallStatus == models.TargetStatusUnknown {
2024-03-04 13:20:01 +00:00
overallStatus = status.Status
}
if statusByGroup[target.Group] == models.TargetStatusUnknown {
statusByGroup[target.Group] = status.Status
2024-03-04 13:20:01 +00:00
}
}
if status.Status != models.TargetStatusSuccess && status.Status != models.TargetStatusUnknown {
2024-03-04 13:20:01 +00:00
overallStatus = status.Status
statusByGroup[target.Group] = status.Status
2024-02-22 16:29:17 +00:00
}
targetsWithHistory[i] = &Target{
Name: target.Name,
Visibility: target.Visibility,
Group: target.Group,
Status: status.Status,
History: historyResult,
2024-02-22 16:29:17 +00:00
}
}
targetsByGroup := map[string]TargetsAndStatus{}
for _, target := range targetsWithHistory {
targetsByGroup[target.Group] = TargetsAndStatus{
Status: statusByGroup[target.Group],
Targets: append(targetsByGroup[target.Group].Targets, target),
2024-03-04 13:20:01 +00:00
}
2024-03-03 14:28:25 +00:00
}
c.Response().Header().Set("Cache-Control", "max-age=10")
return c.Render(http.StatusOK, "index.tmpl", &IndexData{
Base: &components.Base{
NavbarActive: GetPageByTitle(Pages, "Status"),
Navbar: Pages,
},
Targets: targetsByGroup,
2024-03-03 14:28:25 +00:00
TimeRange: timeRange,
Status: overallStatus,
})
}