mirror of
https://github.com/TwiN/gatus.git
synced 2024-12-22 23:02:22 +01:00
107 lines
3.3 KiB
Go
107 lines
3.3 KiB
Go
package controller
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/TwinProduction/gatus/core"
|
|
"github.com/TwinProduction/gatus/storage"
|
|
"github.com/TwinProduction/gatus/storage/store/paging"
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
// badgeHandler handles the automatic generation of badge based on the group name and service name passed.
|
|
//
|
|
// Valid values for {duration}: 7d, 24h, 1h
|
|
// Pattern for {identifier}: <KEY>.svg
|
|
func badgeHandler(writer http.ResponseWriter, request *http.Request) {
|
|
variables := mux.Vars(request)
|
|
duration := variables["duration"]
|
|
if duration != "7d" && duration != "24h" && duration != "1h" {
|
|
writer.WriteHeader(http.StatusBadRequest)
|
|
_, _ = writer.Write([]byte("Durations supported: 7d, 24h, 1h"))
|
|
return
|
|
}
|
|
identifier := variables["identifier"]
|
|
key := strings.TrimSuffix(identifier, ".svg")
|
|
serviceStatus := storage.Get().GetServiceStatusByKey(key, paging.NewServiceStatusParams().WithUptime())
|
|
if serviceStatus == nil {
|
|
writer.WriteHeader(http.StatusNotFound)
|
|
_, _ = writer.Write([]byte("Requested service not found"))
|
|
return
|
|
}
|
|
if serviceStatus.Uptime == nil {
|
|
writer.WriteHeader(http.StatusInternalServerError)
|
|
_, _ = writer.Write([]byte("Failed to compute uptime"))
|
|
return
|
|
}
|
|
formattedDate := time.Now().Format(http.TimeFormat)
|
|
writer.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
|
writer.Header().Set("Date", formattedDate)
|
|
writer.Header().Set("Expires", formattedDate)
|
|
writer.Header().Set("Content-Type", "image/svg+xml")
|
|
_, _ = writer.Write(generateSVG(duration, serviceStatus.Uptime))
|
|
}
|
|
|
|
func generateSVG(duration string, uptime *core.Uptime) []byte {
|
|
var labelWidth, valueWidth, valueWidthAdjustment int
|
|
var color string
|
|
var value float64
|
|
switch duration {
|
|
case "7d":
|
|
labelWidth = 65
|
|
value = uptime.LastSevenDays
|
|
case "24h":
|
|
labelWidth = 70
|
|
value = uptime.LastTwentyFourHours
|
|
case "1h":
|
|
labelWidth = 65
|
|
value = uptime.LastHour
|
|
default:
|
|
}
|
|
if value >= 0.8 {
|
|
color = "#40cc11"
|
|
} else {
|
|
color = "#c7130a"
|
|
}
|
|
sanitizedValue := strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", value*100), "0"), ".") + "%"
|
|
if strings.Contains(sanitizedValue, ".") {
|
|
valueWidthAdjustment = -10
|
|
}
|
|
valueWidth = (len(sanitizedValue) * 11) + valueWidthAdjustment
|
|
width := labelWidth + valueWidth
|
|
labelX := labelWidth / 2
|
|
valueX := labelWidth + (valueWidth / 2)
|
|
svg := []byte(fmt.Sprintf(`<svg xmlns="http://www.w3.org/2000/svg" width="%d" height="20">
|
|
<linearGradient id="b" x2="0" y2="100%%">
|
|
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
|
<stop offset="1" stop-opacity=".1"/>
|
|
</linearGradient>
|
|
<mask id="a">
|
|
<rect width="%d" height="20" rx="3" fill="#fff"/>
|
|
</mask>
|
|
<g mask="url(#a)">
|
|
<path fill="#555" d="M0 0h%dv20H0z"/>
|
|
<path fill="%s" d="M%d 0h%dv20H%dz"/>
|
|
<path fill="url(#b)" d="M0 0h%dv20H0z"/>
|
|
</g>
|
|
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
|
<text x="%d" y="15" fill="#010101" fill-opacity=".3">
|
|
uptime %s
|
|
</text>
|
|
<text x="%d" y="14">
|
|
uptime %s
|
|
</text>
|
|
<text x="%d" y="15" fill="#010101" fill-opacity=".3">
|
|
%s
|
|
</text>
|
|
<text x="%d" y="14">
|
|
%s
|
|
</text>
|
|
</g>
|
|
</svg>`, width, width, labelWidth, color, labelWidth, valueWidth, labelWidth, width, labelX, duration, labelX, duration, valueX, sanitizedValue, valueX, sanitizedValue))
|
|
return svg
|
|
}
|