summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/olahol/melody/melody.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/olahol/melody/melody.go')
-rw-r--r--vendor/github.com/olahol/melody/melody.go321
1 files changed, 321 insertions, 0 deletions
diff --git a/vendor/github.com/olahol/melody/melody.go b/vendor/github.com/olahol/melody/melody.go
new file mode 100644
index 00000000..ca2c5dd1
--- /dev/null
+++ b/vendor/github.com/olahol/melody/melody.go
@@ -0,0 +1,321 @@
+package melody
+
+import (
+ "net/http"
+ "sync"
+
+ "github.com/gorilla/websocket"
+)
+
+// Close codes defined in RFC 6455, section 11.7.
+// Duplicate of codes from gorilla/websocket for convenience.
+const (
+ CloseNormalClosure = 1000
+ CloseGoingAway = 1001
+ CloseProtocolError = 1002
+ CloseUnsupportedData = 1003
+ CloseNoStatusReceived = 1005
+ CloseAbnormalClosure = 1006
+ CloseInvalidFramePayloadData = 1007
+ ClosePolicyViolation = 1008
+ CloseMessageTooBig = 1009
+ CloseMandatoryExtension = 1010
+ CloseInternalServerErr = 1011
+ CloseServiceRestart = 1012
+ CloseTryAgainLater = 1013
+ CloseTLSHandshake = 1015
+)
+
+// Duplicate of codes from gorilla/websocket for convenience.
+var validReceivedCloseCodes = map[int]bool{
+ // see http://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number
+
+ CloseNormalClosure: true,
+ CloseGoingAway: true,
+ CloseProtocolError: true,
+ CloseUnsupportedData: true,
+ CloseNoStatusReceived: false,
+ CloseAbnormalClosure: false,
+ CloseInvalidFramePayloadData: true,
+ ClosePolicyViolation: true,
+ CloseMessageTooBig: true,
+ CloseMandatoryExtension: true,
+ CloseInternalServerErr: true,
+ CloseServiceRestart: true,
+ CloseTryAgainLater: true,
+ CloseTLSHandshake: false,
+}
+
+type handleMessageFunc func(*Session, []byte)
+type handleErrorFunc func(*Session, error)
+type handleCloseFunc func(*Session, int, string) error
+type handleSessionFunc func(*Session)
+type filterFunc func(*Session) bool
+
+// Melody implements a websocket manager.
+type Melody struct {
+ Config *Config
+ Upgrader *websocket.Upgrader
+ messageHandler handleMessageFunc
+ messageHandlerBinary handleMessageFunc
+ messageSentHandler handleMessageFunc
+ messageSentHandlerBinary handleMessageFunc
+ errorHandler handleErrorFunc
+ closeHandler handleCloseFunc
+ connectHandler handleSessionFunc
+ disconnectHandler handleSessionFunc
+ pongHandler handleSessionFunc
+ hub *hub
+}
+
+// New creates a new melody instance with default Upgrader and Config.
+func New() *Melody {
+ upgrader := &websocket.Upgrader{
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
+ CheckOrigin: func(r *http.Request) bool { return true },
+ }
+
+ hub := newHub()
+
+ go hub.run()
+
+ return &Melody{
+ Config: newConfig(),
+ Upgrader: upgrader,
+ messageHandler: func(*Session, []byte) {},
+ messageHandlerBinary: func(*Session, []byte) {},
+ messageSentHandler: func(*Session, []byte) {},
+ messageSentHandlerBinary: func(*Session, []byte) {},
+ errorHandler: func(*Session, error) {},
+ closeHandler: nil,
+ connectHandler: func(*Session) {},
+ disconnectHandler: func(*Session) {},
+ pongHandler: func(*Session) {},
+ hub: hub,
+ }
+}
+
+// HandleConnect fires fn when a session connects.
+func (m *Melody) HandleConnect(fn func(*Session)) {
+ m.connectHandler = fn
+}
+
+// HandleDisconnect fires fn when a session disconnects.
+func (m *Melody) HandleDisconnect(fn func(*Session)) {
+ m.disconnectHandler = fn
+}
+
+// HandlePong fires fn when a pong is received from a session.
+func (m *Melody) HandlePong(fn func(*Session)) {
+ m.pongHandler = fn
+}
+
+// HandleMessage fires fn when a text message comes in.
+func (m *Melody) HandleMessage(fn func(*Session, []byte)) {
+ m.messageHandler = fn
+}
+
+// HandleMessageBinary fires fn when a binary message comes in.
+func (m *Melody) HandleMessageBinary(fn func(*Session, []byte)) {
+ m.messageHandlerBinary = fn
+}
+
+// HandleSentMessage fires fn when a text message is successfully sent.
+func (m *Melody) HandleSentMessage(fn func(*Session, []byte)) {
+ m.messageSentHandler = fn
+}
+
+// HandleSentMessageBinary fires fn when a binary message is successfully sent.
+func (m *Melody) HandleSentMessageBinary(fn func(*Session, []byte)) {
+ m.messageSentHandlerBinary = fn
+}
+
+// HandleError fires fn when a session has an error.
+func (m *Melody) HandleError(fn func(*Session, error)) {
+ m.errorHandler = fn
+}
+
+// HandleClose sets the handler for close messages received from the session.
+// The code argument to h is the received close code or CloseNoStatusReceived
+// if the close message is empty. The default close handler sends a close frame
+// back to the session.
+//
+// The application must read the connection to process close messages as
+// described in the section on Control Frames above.
+//
+// The connection read methods return a CloseError when a close frame is
+// received. Most applications should handle close messages as part of their
+// normal error handling. Applications should only set a close handler when the
+// application must perform some action before sending a close frame back to
+// the session.
+func (m *Melody) HandleClose(fn func(*Session, int, string) error) {
+ if fn != nil {
+ m.closeHandler = fn
+ }
+}
+
+// HandleRequest upgrades http requests to websocket connections and dispatches them to be handled by the melody instance.
+func (m *Melody) HandleRequest(w http.ResponseWriter, r *http.Request) error {
+ return m.HandleRequestWithKeys(w, r, nil)
+}
+
+// HandleRequestWithKeys does the same as HandleRequest but populates session.Keys with keys.
+func (m *Melody) HandleRequestWithKeys(w http.ResponseWriter, r *http.Request, keys map[string]interface{}) error {
+ if m.hub.closed() {
+ return ErrClosed
+ }
+
+ conn, err := m.Upgrader.Upgrade(w, r, w.Header())
+
+ if err != nil {
+ return err
+ }
+
+ session := &Session{
+ Request: r,
+ Keys: keys,
+ conn: conn,
+ output: make(chan *envelope, m.Config.MessageBufferSize),
+ outputDone: make(chan struct{}),
+ melody: m,
+ open: true,
+ rwmutex: &sync.RWMutex{},
+ }
+
+ m.hub.register <- session
+
+ m.connectHandler(session)
+
+ go session.writePump()
+
+ session.readPump()
+
+ if !m.hub.closed() {
+ m.hub.unregister <- session
+ }
+
+ session.close()
+
+ m.disconnectHandler(session)
+
+ return nil
+}
+
+// Broadcast broadcasts a text message to all sessions.
+func (m *Melody) Broadcast(msg []byte) error {
+ if m.hub.closed() {
+ return ErrClosed
+ }
+
+ message := &envelope{t: websocket.TextMessage, msg: msg}
+ m.hub.broadcast <- message
+
+ return nil
+}
+
+// BroadcastFilter broadcasts a text message to all sessions that fn returns true for.
+func (m *Melody) BroadcastFilter(msg []byte, fn func(*Session) bool) error {
+ if m.hub.closed() {
+ return ErrClosed
+ }
+
+ message := &envelope{t: websocket.TextMessage, msg: msg, filter: fn}
+ m.hub.broadcast <- message
+
+ return nil
+}
+
+// BroadcastOthers broadcasts a text message to all sessions except session s.
+func (m *Melody) BroadcastOthers(msg []byte, s *Session) error {
+ return m.BroadcastFilter(msg, func(q *Session) bool {
+ return s != q
+ })
+}
+
+// BroadcastMultiple broadcasts a text message to multiple sessions given in the sessions slice.
+func (m *Melody) BroadcastMultiple(msg []byte, sessions []*Session) error {
+ for _, sess := range sessions {
+ if writeErr := sess.Write(msg); writeErr != nil {
+ return writeErr
+ }
+ }
+ return nil
+}
+
+// BroadcastBinary broadcasts a binary message to all sessions.
+func (m *Melody) BroadcastBinary(msg []byte) error {
+ if m.hub.closed() {
+ return ErrClosed
+ }
+
+ message := &envelope{t: websocket.BinaryMessage, msg: msg}
+ m.hub.broadcast <- message
+
+ return nil
+}
+
+// BroadcastBinaryFilter broadcasts a binary message to all sessions that fn returns true for.
+func (m *Melody) BroadcastBinaryFilter(msg []byte, fn func(*Session) bool) error {
+ if m.hub.closed() {
+ return ErrClosed
+ }
+
+ message := &envelope{t: websocket.BinaryMessage, msg: msg, filter: fn}
+ m.hub.broadcast <- message
+
+ return nil
+}
+
+// BroadcastBinaryOthers broadcasts a binary message to all sessions except session s.
+func (m *Melody) BroadcastBinaryOthers(msg []byte, s *Session) error {
+ return m.BroadcastBinaryFilter(msg, func(q *Session) bool {
+ return s != q
+ })
+}
+
+// Sessions returns all sessions. An error is returned if the melody session is closed.
+func (m *Melody) Sessions() ([]*Session, error) {
+ if m.hub.closed() {
+ return nil, ErrClosed
+ }
+ return m.hub.all(), nil
+}
+
+// Close closes the melody instance and all connected sessions.
+func (m *Melody) Close() error {
+ if m.hub.closed() {
+ return ErrClosed
+ }
+
+ m.hub.exit <- &envelope{t: websocket.CloseMessage, msg: []byte{}}
+
+ return nil
+}
+
+// CloseWithMsg closes the melody instance with the given close payload and all connected sessions.
+// Use the FormatCloseMessage function to format a proper close message payload.
+func (m *Melody) CloseWithMsg(msg []byte) error {
+ if m.hub.closed() {
+ return ErrClosed
+ }
+
+ m.hub.exit <- &envelope{t: websocket.CloseMessage, msg: msg}
+
+ return nil
+}
+
+// Len return the number of connected sessions.
+func (m *Melody) Len() int {
+ return m.hub.len()
+}
+
+// IsClosed returns the status of the melody instance.
+func (m *Melody) IsClosed() bool {
+ return m.hub.closed()
+}
+
+// FormatCloseMessage formats closeCode and text as a WebSocket close message.
+func FormatCloseMessage(closeCode int, text string) []byte {
+ return websocket.FormatCloseMessage(closeCode, text)
+}