websocket 增加多分组 fork https://github.com/olahol/melody
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

255 lines
6.9 KiB

10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package melody
  2. import (
  3. "errors"
  4. "net/http"
  5. "sync"
  6. "github.com/gorilla/websocket"
  7. )
  8. // Close codes defined in RFC 6455, section 11.7.
  9. // Duplicate of codes from gorilla/websocket for convenience.
  10. const (
  11. CloseNormalClosure = 1000
  12. CloseGoingAway = 1001
  13. CloseProtocolError = 1002
  14. CloseUnsupportedData = 1003
  15. CloseNoStatusReceived = 1005
  16. CloseAbnormalClosure = 1006
  17. CloseInvalidFramePayloadData = 1007
  18. ClosePolicyViolation = 1008
  19. CloseMessageTooBig = 1009
  20. CloseMandatoryExtension = 1010
  21. CloseInternalServerErr = 1011
  22. CloseServiceRestart = 1012
  23. CloseTryAgainLater = 1013
  24. CloseTLSHandshake = 1015
  25. )
  26. type handleMessageFunc func(*Session, []byte)
  27. type handleErrorFunc func(*Session, error)
  28. type handleSessionFunc func(*Session)
  29. type filterFunc func(*Session) bool
  30. // Melody implements a websocket manager.
  31. type Melody struct {
  32. Config *Config
  33. Upgrader *websocket.Upgrader
  34. messageHandler handleMessageFunc
  35. messageHandlerBinary handleMessageFunc
  36. messageSentHandler handleMessageFunc
  37. messageSentHandlerBinary handleMessageFunc
  38. errorHandler handleErrorFunc
  39. connectHandler handleSessionFunc
  40. disconnectHandler handleSessionFunc
  41. pongHandler handleSessionFunc
  42. hub *hub
  43. }
  44. // New creates a new melody instance with default Upgrader and Config.
  45. func New() *Melody {
  46. upgrader := &websocket.Upgrader{
  47. ReadBufferSize: 1024,
  48. WriteBufferSize: 1024,
  49. }
  50. hub := newHub()
  51. go hub.run()
  52. return &Melody{
  53. Config: newConfig(),
  54. Upgrader: upgrader,
  55. messageHandler: func(*Session, []byte) {},
  56. messageHandlerBinary: func(*Session, []byte) {},
  57. messageSentHandler: func(*Session, []byte) {},
  58. messageSentHandlerBinary: func(*Session, []byte) {},
  59. errorHandler: func(*Session, error) {},
  60. connectHandler: func(*Session) {},
  61. disconnectHandler: func(*Session) {},
  62. pongHandler: func(*Session) {},
  63. hub: hub,
  64. }
  65. }
  66. // HandleConnect fires fn when a session connects.
  67. func (m *Melody) HandleConnect(fn func(*Session)) {
  68. m.connectHandler = fn
  69. }
  70. // HandleDisconnect fires fn when a session disconnects.
  71. func (m *Melody) HandleDisconnect(fn func(*Session)) {
  72. m.disconnectHandler = fn
  73. }
  74. // HandlePong fires fn when a pong is received from a session.
  75. func (m *Melody) HandlePong(fn func(*Session)) {
  76. m.pongHandler = fn
  77. }
  78. // HandleMessage fires fn when a text message comes in.
  79. func (m *Melody) HandleMessage(fn func(*Session, []byte)) {
  80. m.messageHandler = fn
  81. }
  82. // HandleMessageBinary fires fn when a binary message comes in.
  83. func (m *Melody) HandleMessageBinary(fn func(*Session, []byte)) {
  84. m.messageHandlerBinary = fn
  85. }
  86. // HandleSentMessage fires fn when a text message is successfully sent.
  87. func (m *Melody) HandleSentMessage(fn func(*Session, []byte)) {
  88. m.messageSentHandler = fn
  89. }
  90. // HandleSentMessageBinary fires fn when a binary message is successfully sent.
  91. func (m *Melody) HandleSentMessageBinary(fn func(*Session, []byte)) {
  92. m.messageSentHandler = fn
  93. }
  94. // HandleError fires fn when a session has an error.
  95. func (m *Melody) HandleError(fn func(*Session, error)) {
  96. m.errorHandler = fn
  97. }
  98. // HandleRequest upgrades http requests to websocket connections and dispatches them to be handled by the melody instance.
  99. func (m *Melody) HandleRequest(w http.ResponseWriter, r *http.Request) error {
  100. return m.HandleRequestWithKeys(w, r, nil)
  101. }
  102. // HandleRequestWithKeys does the same as HandleRequest but populates session.Keys with keys.
  103. func (m *Melody) HandleRequestWithKeys(w http.ResponseWriter, r *http.Request, keys map[string]interface{}) error {
  104. if m.hub.closed() {
  105. return errors.New("Melody instance is closed.")
  106. }
  107. conn, err := m.Upgrader.Upgrade(w, r, nil)
  108. if err != nil {
  109. return err
  110. }
  111. session := &Session{
  112. Request: r,
  113. Keys: keys,
  114. conn: conn,
  115. output: make(chan *envelope, m.Config.MessageBufferSize),
  116. melody: m,
  117. open: true,
  118. rwmutex: &sync.RWMutex{},
  119. }
  120. m.hub.register <- session
  121. m.connectHandler(session)
  122. go session.writePump()
  123. session.readPump()
  124. if !m.hub.closed() {
  125. m.hub.unregister <- session
  126. }
  127. session.close()
  128. m.disconnectHandler(session)
  129. return nil
  130. }
  131. // Broadcast broadcasts a text message to all sessions.
  132. func (m *Melody) Broadcast(msg []byte) error {
  133. if m.hub.closed() {
  134. return errors.New("Melody instance is closed.")
  135. }
  136. message := &envelope{t: websocket.TextMessage, msg: msg}
  137. m.hub.broadcast <- message
  138. return nil
  139. }
  140. // BroadcastFilter broadcasts a text message to all sessions that fn returns true for.
  141. func (m *Melody) BroadcastFilter(msg []byte, fn func(*Session) bool) error {
  142. if m.hub.closed() {
  143. return errors.New("Melody instance is closed.")
  144. }
  145. message := &envelope{t: websocket.TextMessage, msg: msg, filter: fn}
  146. m.hub.broadcast <- message
  147. return nil
  148. }
  149. // BroadcastOthers broadcasts a text message to all sessions except session s.
  150. func (m *Melody) BroadcastOthers(msg []byte, s *Session) error {
  151. return m.BroadcastFilter(msg, func(q *Session) bool {
  152. return s != q
  153. })
  154. }
  155. // BroadcastBinary broadcasts a binary message to all sessions.
  156. func (m *Melody) BroadcastBinary(msg []byte) error {
  157. if m.hub.closed() {
  158. return errors.New("Melody instance is closed.")
  159. }
  160. message := &envelope{t: websocket.BinaryMessage, msg: msg}
  161. m.hub.broadcast <- message
  162. return nil
  163. }
  164. // BroadcastBinaryFilter broadcasts a binary message to all sessions that fn returns true for.
  165. func (m *Melody) BroadcastBinaryFilter(msg []byte, fn func(*Session) bool) error {
  166. if m.hub.closed() {
  167. return errors.New("Melody instance is closed.")
  168. }
  169. message := &envelope{t: websocket.BinaryMessage, msg: msg, filter: fn}
  170. m.hub.broadcast <- message
  171. return nil
  172. }
  173. // BroadcastBinaryOthers broadcasts a binary message to all sessions except session s.
  174. func (m *Melody) BroadcastBinaryOthers(msg []byte, s *Session) error {
  175. return m.BroadcastBinaryFilter(msg, func(q *Session) bool {
  176. return s != q
  177. })
  178. }
  179. // Close closes the melody instance and all connected sessions.
  180. func (m *Melody) Close() error {
  181. if m.hub.closed() {
  182. return errors.New("Melody instance is already closed.")
  183. }
  184. m.hub.exit <- &envelope{t: websocket.CloseMessage, msg: []byte{}}
  185. return nil
  186. }
  187. // CloseWithMsg closes the melody instance with the given close payload and all connected sessions.
  188. // Use the FormatCloseMessage function to format a proper close message payload.
  189. func (m *Melody) CloseWithMsg(msg []byte) error {
  190. if m.hub.closed() {
  191. return errors.New("Melody instance is already closed.")
  192. }
  193. m.hub.exit <- &envelope{t: websocket.CloseMessage, msg: msg}
  194. return nil
  195. }
  196. // Len return the number of connected sessions.
  197. func (m *Melody) Len() int {
  198. return m.hub.len()
  199. }
  200. // FormatCloseMessage formats closeCode and text as a WebSocket close message.
  201. func FormatCloseMessage(closeCode int, text string) []byte {
  202. return websocket.FormatCloseMessage(closeCode, text)
  203. }