GPT generated - need to review
This commit is contained in:
parent
dfccac1752
commit
f23e0bc362
75
healthchecker.go
Normal file
75
healthchecker.go
Normal 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
42
main.go
@ -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
62
sse.go
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user