Priority/sse/be/main.go
2024-01-07 11:54:29 +00:00

244 lines
4.7 KiB
Go

package main
import (
"crypto/sha256"
"fmt"
"io"
"log"
"net/http"
"slices"
"strconv"
"strings"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
type Message struct {
Event string `json:"event"`
Data string `json:"data"`
Id string `json:"id"`
}
type ClientChan chan Message
type Client struct {
Id string `json:"id"`
Ip string `json:"ip"`
Chan ClientChan `json:"chan"`
Events []string `json:"events"`
}
type Event struct {
Clients []Client `json:"clients"`
Id int `json:"id"`
Events []string `json:"events"`
}
func main() {
r := gin.Default()
r.Use(cors.Default())
event := NewServer()
api := r.Group("/api")
// api.GET("/sse", HeadersMiddleware(), event.serveHTTP(), event.retvalSSE())
api.GET("/sse", HeadersMiddleware(), event.Stream)
api.GET("/msg", event.SendMsg)
api.GET("/message", event.SendMessage)
api.GET("/ping", event.SendPing)
api.GET("/pong", event.SendPong)
sse := r.Group("/sse")
sse.Static("/", "./static/sse")
app := r.Group("/_app")
app.Static("/", "./static/_app")
static := r.Group("/static")
static.Static("/", "./static/static")
r.StaticFile("/", "./static/index.html")
r.StaticFile("/favicon.png", "./static/favicon.png")
r.ForwardedByClientIP = true
r.SetTrustedProxies([]string{"127.0.0.1"})
r.Run(":8888")
}
func NewServer() *Event {
return &Event{
Clients: []Client{},
Id: 0,
Events: []string{
"ping",
"pong",
"msg",
"message",
},
}
}
func HeadersMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
headers := c.Writer.Header()
headers.Set("Content-Type", "text/event-stream")
headers.Set("Cache-Control", "no-cache")
headers.Set("Connection", "keep-alive")
headers.Set("Transfer-Encoding", "chunked")
c.Next()
}
}
func (e *Event) Stream(c *gin.Context) {
client := &Client{
Ip: c.Request.RemoteAddr,
Chan: make(ClientChan),
Events: c.QueryArray("event"),
}
client.Id = Id(client.Ip, client.Events, 8)
log.Printf("Client: %+v", client)
e.Clients = append(e.Clients, *client)
defer func() {
e.Clients = remove(e.Clients, client)
close(client.Chan)
log.Printf("Client %s disconnected - tot: %d", client.Ip, len(e.Clients))
}()
log.Printf("Client %s connected - tot: %d", client.Ip, len(e.Clients))
c.Stream(func(w io.Writer) bool {
msg, ok := <-client.Chan
if ok {
c.SSEvent(msg.Event, msg)
}
return ok
})
}
func (e *Event) Send(msg Message) {
e.Id++
msg.Id = strconv.Itoa(e.Id)
for _, client := range e.Clients {
if slices.Contains(client.Events, msg.Event) || slices.Contains(client.Events, "*") {
client.Chan <- msg
}
}
}
func (e *Event) SendMessage(c *gin.Context) {
e.Send(Message{
Event: "message",
Data: "Ciao",
})
e.Send(Message{
Data: "Senza event",
})
}
func (e *Event) SendMsg(c *gin.Context) {
e.Send(Message{
Event: "msg",
Data: "hello",
})
c.JSON(http.StatusOK, gin.H{"status": "msg"})
}
func (e *Event) SendPing(c *gin.Context) {
e.Send(Message{
Event: "ping",
Data: "Ping",
})
c.JSON(http.StatusOK, gin.H{"status": "ping"})
}
func (e *Event) SendPong(c *gin.Context) {
e.Send(Message{
Event: "pong",
Data: "Pong",
})
c.JSON(http.StatusOK, gin.H{"status": "pong"})
}
func remove(slice []Client, s *Client) []Client {
for i, v := range slice {
if v.Id == s.Id {
return append(slice[:i], slice[i+1:]...)
}
}
return slice
}
func Id(ip string, events []string, len int) string {
str := ip + strings.Join(events, "|")
id := sha256.Sum256([]byte(str))
return fmt.Sprintf("%X", id)[0:len]
}
// func (e *Event) serveHTTP() gin.HandlerFunc {
// return func(c *gin.Context) {
// // Initialize client channel
// clientChan := make(ClientChan)
// // Send new connection to event server
// e.NewClient <- clientChan
// defer func() {
// // Send closed connection to event server
// e.ClosedClient <- clientChan
// }()
// c.Set("clientChan", clientChan)
// c.Next()
// }
// }
// func (e *Event) retvalSSE() gin.HandlerFunc {
// return func(c *gin.Context) {
// v, ok := c.Get("clientChan")
// if !ok {
// return
// }
// clientChan, ok := v.(ClientChan)
// if !ok {
// return
// }
// c.Stream(func(w io.Writer) bool {
// msg, ok := <-clientChan
// if ok {
// c.SSEvent("message", msg)
// }
// return ok
// })
// }
// }
// func (e *Event) Broadcast() {
// id := 0
// for {
// select {
// case client := <-e.NewClient:
// e.TotalClients[client] = true
// case client := <-e.ClosedClient:
// delete(e.TotalClients, client)
// close(client)
// case message := <-e.Message:
// id++
// for client := range e.TotalClients {
// // msg, _ := json.Marshal(message)
// // client <- string(msg)
// client <- message
// }
// }
// }
// }