server.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package sse
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "io"
  5. "net/http"
  6. "sync"
  7. "sync/atomic"
  8. )
  9. var _ Server = (*event)(nil)
  10. type Server interface {
  11. HandlerFunc(auth func(c *gin.Context) (string, error)) gin.HandlerFunc
  12. Push(user, name, msg string) bool
  13. Broadcast(name, msg string)
  14. }
  15. type clientChan struct {
  16. User string
  17. Chan chan msgChan
  18. }
  19. type msgChan struct {
  20. Name string
  21. Message string
  22. }
  23. type event struct {
  24. SessionList sync.Map
  25. Count atomic.Int32
  26. Register chan clientChan
  27. Unregister chan string
  28. }
  29. func NewServer() Server {
  30. e := &event{
  31. SessionList: sync.Map{},
  32. Count: atomic.Int32{},
  33. Register: make(chan clientChan),
  34. Unregister: make(chan string),
  35. }
  36. go e.listen()
  37. return e
  38. }
  39. func (stream *event) listen() {
  40. for {
  41. select {
  42. case client := <-stream.Register:
  43. stream.SessionList.Store(client.User, client.Chan)
  44. stream.Count.Add(1)
  45. case user := <-stream.Unregister:
  46. value, ok := stream.SessionList.Load(user)
  47. if ok {
  48. event := value.(chan msgChan)
  49. close(event)
  50. stream.SessionList.Delete(user)
  51. stream.Count.Add(-1)
  52. }
  53. }
  54. }
  55. }
  56. func (stream *event) HandlerFunc(auth func(c *gin.Context) (string, error)) gin.HandlerFunc {
  57. return func(c *gin.Context) {
  58. user, err := auth(c)
  59. if err != nil {
  60. c.AbortWithStatus(http.StatusBadRequest)
  61. return
  62. }
  63. e := make(chan msgChan)
  64. client := clientChan{
  65. User: user,
  66. Chan: e,
  67. }
  68. stream.Register <- client
  69. defer func() {
  70. stream.Unregister <- user
  71. }()
  72. c.Writer.Header().Set("Content-Type", "text/event-stream")
  73. c.Writer.Header().Set("Cache-Control", "no-cache")
  74. c.Writer.Header().Set("Connection", "keep-alive")
  75. c.Writer.Header().Set("Transfer-Encoding", "chunked")
  76. c.Stream(func(w io.Writer) bool {
  77. if msg, ok := <-e; ok {
  78. c.SSEvent(msg.Name, msg.Message)
  79. return true
  80. }
  81. return false
  82. })
  83. c.Next()
  84. }
  85. }
  86. func (stream *event) Push(user, name, msg string) bool {
  87. value, ok := stream.SessionList.Load(user)
  88. if ok {
  89. val := value.(chan msgChan)
  90. val <- msgChan{Name: name, Message: msg}
  91. }
  92. return false
  93. }
  94. func (stream *event) Broadcast(name, msg string) {
  95. stream.SessionList.Range(func(user, value any) bool {
  96. val := value.(chan msgChan)
  97. val <- msgChan{Name: name, Message: msg}
  98. return true
  99. })
  100. }