package controller import ( "fmt" "net/http" "strings" "time" "github.com/TwinProduction/gatus/core" "github.com/TwinProduction/gatus/watchdog" "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}: group--service-.svg func badgeHandler(writer http.ResponseWriter, request *http.Request) { variables := mux.Vars(request) duration := variables["duration"] // group--service-.svg identifier := variables["identifier"] if duration != "7d" && duration != "24h" && duration != "1h" { writer.WriteHeader(http.StatusBadRequest) _, _ = writer.Write([]byte("Durations supported: 7d, 24h, 1h")) return } parts := strings.Split(identifier, "-service-") if len(parts) != 2 || !strings.HasPrefix(identifier, "group-") || !strings.HasSuffix(identifier, ".svg") { writer.WriteHeader(http.StatusBadRequest) _, _ = writer.Write([]byte("Invalid path: Pattern should look like /group--service-.svg")) return } groupName := strings.TrimPrefix(parts[0], "group-") serviceName := strings.TrimSuffix(parts[1], ".svg") uptime := watchdog.GetUptimeByServiceGroupAndName(groupName, serviceName) if uptime == nil { writer.WriteHeader(http.StatusNotFound) _, _ = writer.Write([]byte("Requested service not found")) 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, 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(` uptime %s uptime %s %s %s `, width, width, labelWidth, color, labelWidth, valueWidth, labelWidth, width, labelX, duration, labelX, duration, valueX, sanitizedValue, valueX, sanitizedValue)) return svg }