HealthCheckAPI/healthchecker.go

97 lines
2.1 KiB
Go

package main
import (
"encoding/json"
"io"
"log"
"net/http"
"sync"
"time"
)
type Domain struct {
Name string
Protocol string
}
var ServiceItems = map[string]Domain{
"git": {Name: "git.aaronic.cc", Protocol: "https"},
"jellyfin": {Name: "jellyfin.aaronic.cc", Protocol: "https"},
"dnd": {Name: "dnd.aaronic.cc", Protocol: "https"},
"portainer": {Name: "portainer.aaronic.cc", Protocol: "https"},
"code": {Name: "code.aaronic.cc", Protocol: "https"},
}
type HealthChecker struct {
status map[string]ServiceStatus
mu sync.RWMutex
client *http.Client
sse *SSEBroker
}
func NewHealthChecker(broker *SSEBroker) *HealthChecker {
return &HealthChecker{
status: make(map[string]ServiceStatus),
client: &http.Client{
Timeout: 5 * time.Second,
},
sse: broker,
}
}
func (hc *HealthChecker) CheckAll() {
for _, service := range ServiceItems {
go hc.checkService(service.Protocol + "://" + service.Name)
}
}
func (hc *HealthChecker) checkService(url string) {
//var url = ServiceItems[service].Protocol + "://" + ServiceItems[service].Name
resp, err := hc.client.Get(url)
status := ServiceStatus{
URL: url,
CheckedAt: time.Now(),
}
if err != nil {
log.Printf("Error checking %s: %s", url, err)
status.IsUp = false
} else {
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
log.Printf("Error closing %s: %s", url, err)
}
}(resp.Body)
status.StatusCode = resp.StatusCode
status.IsUp = resp.StatusCode >= 200 && resp.StatusCode < 300
log.Printf("%s: %d", url, resp.StatusCode)
}
hc.mu.Lock()
hc.status[url] = status
hc.mu.Unlock()
data, _ := json.Marshal(status)
hc.sse.Broadcast(string(data))
}
func (hc *HealthChecker) GetStatuses() []ServiceStatus {
hc.mu.RLock()
defer hc.mu.RUnlock()
results := make([]ServiceStatus, 0, len(hc.status))
for _, status := range hc.status {
results = append(results, status)
}
return results
}
func (hc *HealthChecker) GetStatus(url string) (ServiceStatus, bool) {
hc.mu.RLock()
defer hc.mu.RUnlock()
status, ok := hc.status[url]
return status, ok
}