mirror of
https://github.com/therootcompany/golib.git
synced 2026-02-10 05:48:06 +00:00
119 lines
2.5 KiB
Go
119 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
_ "embed"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
//go:embed index.html
|
|
var indexHTML []byte
|
|
|
|
type Message struct {
|
|
Time string `json:"time"`
|
|
Nick string `json:"nick"`
|
|
Text string `json:"text"`
|
|
}
|
|
|
|
var sse = NewSSEChannel()
|
|
|
|
func main() {
|
|
mux := http.NewServeMux()
|
|
// Serve static HTML
|
|
//mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/" {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "text/html")
|
|
w.Write(indexHTML)
|
|
})
|
|
|
|
// SSE endpoint
|
|
mux.HandleFunc("GET /api/events", handleSSE)
|
|
|
|
// POST endpoint to send messages
|
|
mux.HandleFunc("POST /api/send", handleSend)
|
|
|
|
log.Println("Server running on :8080")
|
|
log.Fatal(http.ListenAndServe(":8080", mux))
|
|
}
|
|
|
|
func handleSSE(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.Header().Set("X-Accel-Buffering", "no") // helps nginx / some proxies
|
|
|
|
flusher, ok := w.(http.Flusher)
|
|
if !ok {
|
|
http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
sse.Subscribe(AddrStr(r.RemoteAddr))
|
|
defer sse.Unsubscribe(AddrStr(r.RemoteAddr))
|
|
|
|
fmt.Fprintf(w, "event: system\ndata: {\"time\":\"%s\",\"text\":\"You joined the room\"}\n\n", time.Now().Format("15:04"))
|
|
flusher.Flush()
|
|
|
|
// Forward messages to this client
|
|
for {
|
|
select {
|
|
case <-r.Context().Done():
|
|
return
|
|
case msg, ok := <-sse.Member(AddrStr(r.RemoteAddr)).C:
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
// SSE format: one data: line with the full JSON
|
|
if msg.Event != "" {
|
|
fmt.Fprintf(w, "event: %s\n", msg.Event)
|
|
}
|
|
fmt.Fprintf(w, "%s: %s\n\n", msg.Type, msg.Data)
|
|
flusher.Flush()
|
|
}
|
|
}
|
|
}
|
|
|
|
func handleSend(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
if err := r.ParseForm(); err != nil {
|
|
http.Error(w, "Bad form", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
nick := r.FormValue("nick")
|
|
text := r.FormValue("text")
|
|
if text == "" {
|
|
http.Error(w, "Message required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if nick == "" {
|
|
nick = "Anonymous"
|
|
}
|
|
|
|
// In the broadcast loop (handleSend)
|
|
msg := Message{
|
|
Time: time.Now().Format("15:04"),
|
|
Nick: nick,
|
|
Text: text,
|
|
}
|
|
payload, _ := json.Marshal(msg)
|
|
|
|
sse.Broadcast(payload)
|
|
|
|
w.WriteHeader(http.StatusAccepted)
|
|
}
|