websocket.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package websocket
  2. import (
  3. "github.com/olahol/melody"
  4. "net/http"
  5. )
  6. const (
  7. groupIDKey = "group-id"
  8. connectionContextKey = "connection-context"
  9. )
  10. type HandleConnectFunc func(groupID string, context any)
  11. type HandleDisconnectFunc func(groupID string, context any)
  12. type HandleErrorFunc func(groupID string, err error, context any)
  13. type HandleCloseFunc func(groupID string, i int, s string, context any) error
  14. type HandlePongFunc func(groupID string, context any)
  15. type HandleMessageFunc func(groupID string, message []byte, context any)
  16. var managerInstance *Manager
  17. func Init() {
  18. if managerInstance == nil {
  19. melodyInstance := melody.New()
  20. melodyInstance.Upgrader.CheckOrigin = func(r *http.Request) bool { return true }
  21. managerInstance = &Manager{melodyInstance: melodyInstance}
  22. }
  23. }
  24. func Destroy() {
  25. if managerInstance != nil {
  26. err := managerInstance.melodyInstance.Close()
  27. if err != nil {
  28. panic(err)
  29. }
  30. }
  31. managerInstance = nil
  32. }
  33. func GetInstance() *Manager {
  34. return managerInstance
  35. }
  36. type Manager struct {
  37. melodyInstance *melody.Melody
  38. }
  39. func (m *Manager) HandleConnect(handleConnectFunc HandleConnectFunc) {
  40. m.melodyInstance.HandleConnect(func(session *melody.Session) {
  41. if handleConnectFunc != nil {
  42. handleConnectFunc(session.Keys[groupIDKey].(string), session.Keys[connectionContextKey])
  43. }
  44. })
  45. }
  46. func (m *Manager) HandleDisconnect(handleDisconnectFunc HandleDisconnectFunc) {
  47. m.melodyInstance.HandleDisconnect(func(session *melody.Session) {
  48. if handleDisconnectFunc != nil {
  49. handleDisconnectFunc(session.Keys[groupIDKey].(string), session.Keys[connectionContextKey])
  50. }
  51. })
  52. }
  53. func (m *Manager) HandleError(handleErrorFunc HandleErrorFunc) {
  54. m.melodyInstance.HandleError(func(session *melody.Session, err error) {
  55. if handleErrorFunc != nil {
  56. handleErrorFunc(session.Keys[groupIDKey].(string), err, session.Keys[connectionContextKey])
  57. }
  58. })
  59. }
  60. func (m *Manager) HandleClose(handleCloseFunc HandleCloseFunc) {
  61. m.melodyInstance.HandleClose(func(session *melody.Session, i int, s string) error {
  62. if handleCloseFunc != nil {
  63. err := handleCloseFunc(session.Keys[groupIDKey].(string), i, s, session.Keys[connectionContextKey])
  64. if err != nil {
  65. return err
  66. }
  67. }
  68. return nil
  69. })
  70. }
  71. func (m *Manager) HandlePong(handlePongFunc HandlePongFunc) {
  72. m.melodyInstance.HandlePong(func(session *melody.Session) {
  73. if handlePongFunc != nil {
  74. handlePongFunc(session.Keys[groupIDKey].(string), session.Keys[connectionContextKey])
  75. }
  76. })
  77. }
  78. func (m *Manager) HandleRequest(groupID string, w http.ResponseWriter, r *http.Request, opts ...ConnectionOption) error {
  79. sessionMap := map[string]interface{}{
  80. groupIDKey: groupID,
  81. }
  82. for _, opt := range opts {
  83. opt(sessionMap)
  84. }
  85. err := m.melodyInstance.HandleRequestWithKeys(w, r, sessionMap)
  86. if err != nil {
  87. return err
  88. }
  89. return nil
  90. }
  91. func (m *Manager) HandleMessage(handleMessageFunc HandleMessageFunc) {
  92. m.melodyInstance.HandleMessage(func(session *melody.Session, bytes []byte) {
  93. if handleMessageFunc != nil {
  94. handleMessageFunc(session.Keys[groupIDKey].(string), bytes, session.Keys[connectionContextKey])
  95. }
  96. })
  97. }
  98. func (m *Manager) BroadCast(groupID string, msg []byte) error {
  99. return m.melodyInstance.BroadcastFilter(msg, func(session *melody.Session) bool {
  100. if session.Keys[groupIDKey] != groupID {
  101. return false
  102. }
  103. return true
  104. })
  105. }
  106. type ConnectionOption func(sessionMap map[string]any)
  107. func WithConnectionContext(key string, context any) ConnectionOption {
  108. return func(sessionMap map[string]any) {
  109. sessionMap[connectionContextKey+"::"+key] = context
  110. }
  111. }