package main import ( "encoding/json" "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"}, } 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 resp.Body.Close() 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 }