Priority/sse/be/main.go

245 lines
4.7 KiB
Go
Raw Normal View History

2023-12-19 16:56:10 +01:00
package main
import (
2023-12-20 13:06:41 +01:00
"crypto/sha256"
"fmt"
2023-12-19 16:56:10 +01:00
"io"
2023-12-20 13:06:41 +01:00
"log"
2024-01-07 11:54:29 +00:00
"net/http"
2024-01-05 13:31:33 +00:00
"slices"
2023-12-19 16:56:10 +01:00
"strconv"
2023-12-20 13:06:41 +01:00
"strings"
2023-12-19 16:56:10 +01:00
"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"`
}
2023-12-20 13:06:41 +01:00
type ClientChan chan Message
type Client struct {
Id string `json:"id"`
Ip string `json:"ip"`
Chan ClientChan `json:"chan"`
Events []string `json:"events"`
2023-12-19 16:56:10 +01:00
}
2023-12-20 13:06:41 +01:00
type Event struct {
Clients []Client `json:"clients"`
Id int `json:"id"`
Events []string `json:"events"`
}
2023-12-19 16:56:10 +01:00
func main() {
r := gin.Default()
r.Use(cors.Default())
event := NewServer()
api := r.Group("/api")
2023-12-20 13:06:41 +01:00
// 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)
2023-12-19 16:56:10 +01:00
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 {
2023-12-20 13:06:41 +01:00
return &Event{
Clients: []Client{},
Id: 0,
Events: []string{
"ping",
"pong",
"msg",
"message",
},
2023-12-19 16:56:10 +01:00
}
}
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()
}
}
2023-12-20 13:06:41 +01:00
func (e *Event) Stream(c *gin.Context) {
client := &Client{
2023-12-20 13:31:38 +01:00
Ip: c.Request.RemoteAddr,
2023-12-20 13:06:41 +01:00
Chan: make(ClientChan),
2024-01-06 15:57:12 +00:00
Events: c.QueryArray("event"),
2023-12-20 13:06:41 +01:00
}
2023-12-19 16:56:10 +01:00
2023-12-20 13:06:41 +01:00
client.Id = Id(client.Ip, client.Events, 8)
2023-12-19 16:56:10 +01:00
2023-12-20 13:06:41 +01:00
log.Printf("Client: %+v", client)
2023-12-19 16:56:10 +01:00
2023-12-20 13:06:41 +01:00
e.Clients = append(e.Clients, *client)
2023-12-19 16:56:10 +01:00
2023-12-20 13:06:41 +01:00
defer func() {
e.Clients = remove(e.Clients, client)
close(client.Chan)
log.Printf("Client %s disconnected - tot: %d", client.Ip, len(e.Clients))
}()
2023-12-19 16:56:10 +01:00
2023-12-20 13:06:41 +01:00
log.Printf("Client %s connected - tot: %d", client.Ip, len(e.Clients))
2023-12-19 16:56:10 +01:00
2023-12-20 13:06:41 +01:00
c.Stream(func(w io.Writer) bool {
msg, ok := <-client.Chan
if ok {
c.SSEvent(msg.Event, msg)
2023-12-19 16:56:10 +01:00
}
2023-12-20 13:06:41 +01:00
return ok
})
}
2023-12-19 16:56:10 +01:00
2023-12-20 13:06:41 +01:00
func (e *Event) Send(msg Message) {
e.Id++
msg.Id = strconv.Itoa(e.Id)
for _, client := range e.Clients {
2024-01-05 13:31:33 +00:00
if slices.Contains(client.Events, msg.Event) || slices.Contains(client.Events, "*") {
client.Chan <- msg
}
2023-12-19 16:56:10 +01:00
}
}
2023-12-20 13:06:41 +01:00
func (e *Event) SendMessage(c *gin.Context) {
e.Send(Message{
Event: "message",
Data: "Ciao",
})
2024-01-07 11:54:29 +00:00
e.Send(Message{
Data: "Senza event",
})
2023-12-19 16:56:10 +01:00
}
2023-12-20 13:06:41 +01:00
func (e *Event) SendMsg(c *gin.Context) {
e.Send(Message{
Event: "msg",
Data: "hello",
})
2024-01-07 11:54:29 +00:00
c.JSON(http.StatusOK, gin.H{"status": "msg"})
2023-12-19 16:56:10 +01:00
}
2023-12-20 13:06:41 +01:00
func (e *Event) SendPing(c *gin.Context) {
e.Send(Message{
Event: "ping",
Data: "Ping",
})
2024-01-07 11:54:29 +00:00
c.JSON(http.StatusOK, gin.H{"status": "ping"})
2023-12-19 16:56:10 +01:00
}
2023-12-20 13:06:41 +01:00
func (e *Event) SendPong(c *gin.Context) {
e.Send(Message{
Event: "pong",
Data: "Pong",
})
2024-01-07 11:54:29 +00:00
c.JSON(http.StatusOK, gin.H{"status": "pong"})
2023-12-20 13:06:41 +01:00
}
func remove(slice []Client, s *Client) []Client {
for i, v := range slice {
if v.Id == s.Id {
return append(slice[:i], slice[i+1:]...)
}
2023-12-19 16:56:10 +01:00
}
2023-12-20 13:06:41 +01:00
return slice
2023-12-19 16:56:10 +01:00
}
2023-12-20 13:06:41 +01:00
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]
2023-12-19 16:56:10 +01:00
}
2023-12-20 13:06:41 +01:00
// 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
// }
// }
// }
// }