GPT generated - need to review

This commit is contained in:
kacarmichael 2025-05-26 01:40:02 -05:00
parent dfccac1752
commit f23e0bc362
5 changed files with 176 additions and 17 deletions

2
go.mod
View File

@ -1 +1,3 @@
module HealthCheckAPI module HealthCheckAPI
go 1.23.0

75
healthchecker.go Normal file
View File

@ -0,0 +1,75 @@
package main
import (
"encoding/json"
"log"
"net/http"
"sync"
"time"
)
var services = []string{
"https://git.aaronic.cc",
"https://portainer.aaronic.cc",
"https://jellyfin.aaronic.cc",
"https://dnd.aaronic.cc",
}
type HealthChecker struct {
status map[string]ServiceStatus
mu sync.RWMutex
client *http.Client
sse *SSEBroker
}
func NewHealthChecker() *HealthChecker {
return &HealthChecker{
status: make(map[string]ServiceStatus),
client: &http.Client{
Timeout: 5 * time.Second,
},
sse: NewSSEBroker(),
}
}
func (hc *HealthChecker) CheckAll() {
for _, service := range services {
go hc.checkService(service)
}
}
func (hc *HealthChecker) checkService(url string) {
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
}

42
main.go
View File

@ -1,25 +1,35 @@
package main package main
import ( import (
"fmt" "encoding/json"
"log"
"net/http"
"time"
) )
//TIP To run your code, right-click the code and select <b>Run</b>. Alternatively, click
// the <icon src="AllIcons.Actions.Execute"/> icon in the gutter and select the <b>Run</b> menu item from here.
func main() { func main() {
//TIP Press <shortcut actionId="ShowIntentionActions"/> when your caret is at the underlined or highlighted text sseBroker := NewSSEBroker()
// to see how GoLand suggests fixing it. checker := NewHealthChecker()
s := "gopher"
fmt.Println("Hello and welcome, %s!", s)
for i := 1; i <= 5; i++ { go func() {
//TIP You can try debugging your code. We have set one <icon src="AllIcons.Debugger.Db_set_breakpoint"/> breakpoint ticker := time.NewTicker(30 * time.Second)
// for you, but you can always add more by pressing <shortcut actionId="ToggleLineBreakpoint"/>. To start your debugging session, defer ticker.Stop()
// right-click your code in the editor and select the <b>Debug</b> option. for {
fmt.Println("i =", 100/i) checker.CheckAll()
} <-ticker.C
} }
}()
//TIP See GoLand help at <a href="https://www.jetbrains.com/help/go/">jetbrains.com/help/go/</a>. http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
// Also, you can try interactive lessons for GoLand by selecting 'Help | Learn IDE Features' from the main menu. statuses := checker.GetStatuses()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(statuses)
})
http.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
sseBroker.Handler(w, r)
})
log.Println("Serving on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}

62
sse.go Normal file
View File

@ -0,0 +1,62 @@
package main
import (
"fmt"
"net/http"
"sync"
)
type SSEBroker struct {
clients map[chan string]struct{}
lock sync.RWMutex
}
func NewSSEBroker() *SSEBroker {
return &SSEBroker{
clients: make(map[chan string]struct{}),
}
}
func (b *SSEBroker) AddClient(c chan string) {
b.lock.Lock()
defer b.lock.Unlock()
b.clients[c] = struct{}{}
}
func (b *SSEBroker) RemoveClient(c chan string) {
b.lock.Lock()
defer b.lock.Unlock()
delete(b.clients, c)
}
func (b *SSEBroker) Broadcast(msg string) {
b.lock.Lock()
defer b.lock.Unlock()
for c := range b.clients {
c <- msg
}
}
func (b *SSEBroker) Handler(w http.ResponseWriter, r *http.Request) {
flusher, ok := w.(http.Flusher)
if !ok {
http.Error(w, "Streaming not supported!", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
messageChannel := make(chan string)
b.AddClient(messageChannel)
defer b.RemoveClient(messageChannel)
for {
msg, open := <-messageChannel
if !open {
return
}
fmt.Fprintf(w, "data: %s\n\n", msg)
flusher.Flush()
}
}

10
types.go Normal file
View File

@ -0,0 +1,10 @@
package main
import "time"
type ServiceStatus struct {
URL string `json:"url"`
IsUp bool `json:"isUp"`
StatusCode int `json:"statusCode"`
CheckedAt time.Time `json:"checkedAt"`
}