package main import ( "fmt" "html/template" "log" "net/http" "time" ) type handler = func(http.ResponseWriter, *http.Request) func generateHandler(file string, handler func(), data func() any) handler { tmpl := template.Must(template.ParseFiles(fmt.Sprintf("templates/%s", file))) return func(w http.ResponseWriter, r *http.Request) { handler() w.Header().Set("Content-Type", "text/html; charset=utf-8") tmpl.Execute(w, data()) } } func generateClick() handler { var clicks uint = 0 return generateHandler( "click.html", func() { clicks++ }, func() any { return clicks }, ) } func generateSseHandler(handler func(http.ResponseWriter, *http.Request)) handler { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") w.WriteHeader(http.StatusOK) handler(w, r) } } func generateCounter() handler { return generateSseHandler(func(w http.ResponseWriter, r *http.Request) { tick := time.Tick(500 * time.Millisecond) ctx := r.Context() outer: for i := 0; ; i++ { select { case <-ctx.Done(): break outer case <-tick: fmt.Fprintf(w, "event: count\ndata:
%d
\n\n", i) w.(http.Flusher).Flush() } } }) } func main() { http.Handle("/", http.FileServer(http.Dir("static"))) http.HandleFunc("/api/click1", generateClick()) http.HandleFunc("/api/click2", generateClick()) http.HandleFunc("/api/click3", generateClick()) http.HandleFunc("/api/counter", generateCounter()) log.Fatal(http.ListenAndServe(":3333", nil)) }