CodeSection1

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"io"
)

type MsgH struct {
	MID string `json:"id"`
}

type MsgC struct {
	MID string `json:"id"`
}

type MID uuid.UUID
type UID uuid.UUID
type SID uuid.UUID
type SSEHandle struct {
	UID    UID
	SID    SID
	handle chan any
}

type SSEExit struct {
	UID UID
	SID SID
}

func main() {
	r := gin.Default()

	var stream = make(chan any, 2)
	var handles = make(chan *SSEHandle, 8)
	var exitSignal = make(chan *SSEExit, 1)

	go func() {
		var handleContainer = make(map[UID]map[SID]chan any)

		for {
			select {
			case handle, ok := <-handles:
				if !ok {
					return
				}
				if _, ok := handleContainer[handle.UID]; !ok {
					handleContainer[handle.UID] = make(map[SID]chan any)
				}
				handleContainer[handle.UID][handle.SID] = handle.handle
			case msg, ok := <-stream:
				if !ok {
					return
				}
				for _, m := range handleContainer {
					for _, handle := range m {
						handle <- msg
					}
				}
			case exit, ok := <-exitSignal:
				if !ok {
					if _, ok := handleContainer[exit.UID]; ok {
						close(handleContainer[exit.UID][exit.SID])
						delete(handleContainer[exit.UID], exit.SID)
					}
				}
			}
		}
	}()

	r.GET("/sse", func(c *gin.Context) {
		var query = &struct {
			Id string `form:"id"`
		}{}

		err := c.ShouldBind(query)
		if err != nil {
			return
		}

		uid, err := uuid.Parse(query.Id)
		if err != nil {
			return
		}

		c.SSEvent("message", "hello world")
		c.Writer.Flush()

		var handle = make(chan any, 1)
		var sid = SID(uuid.New())
		handles <- &SSEHandle{
			UID:    UID(uid),
			SID:    sid,
			handle: handle,
		}

		c.Stream(func(w io.Writer) bool {
			msg, ok := <-handle
			if ok {
				c.SSEvent("message", msg)
				c.Writer.Flush()
			}
			return ok
		})

		exitSignal <- &SSEExit{
			UID: UID(uid),
			SID: sid,
		}
	})

	r.POST("/H", func(context *gin.Context) {
		var msg = new(MsgH)
		err := context.BindJSON(&msg)
		if err != nil {
			return
		}
		stream <- msg
	})

	r.POST("/C", func(context *gin.Context) {
		var msg = new(MsgC)
		err := context.BindJSON(&msg)
		if err != nil {
			return
		}
		stream <- msg
	})

	_ = r.Run()
}