README

melody

Build Status Coverage Status GoDoc

🎶 Minimalist websocket framework for Go.

Melody is websocket framework based on github.com/gorilla/websocket that abstracts away the tedious parts of handling websockets. It gets out of your way so you can write real-time apps. Features include:

  • Clear and easy interface similar to net/http or Gin.
  • A simple way to broadcast to all or selected connected sessions.
  • Message buffers making concurrent writing safe.
  • Automatic handling of ping/pong and session timeouts.
  • Store data on sessions.

Install

go get gopkg.in/olahol/melody.v1

Example: chat

Chat

Using Gin:

package main

import (
	"github.com/gin-gonic/gin"
	"gopkg.in/olahol/melody.v1"
	"net/http"
)

func main() {
	r := gin.Default()
	m := melody.New()

	r.GET("/", func(c *gin.Context) {
		http.ServeFile(c.Writer, c.Request, "index.html")
	})

	r.GET("/ws", func(c *gin.Context) {
		m.HandleRequest(c.Writer, c.Request)
	})

	m.HandleMessage(func(s *melody.Session, msg []byte) {
		m.Broadcast(msg)
	})

	r.Run(":5000")
}

Using Echo:

package main

import (
	"github.com/labstack/echo"
	"github.com/labstack/echo/engine/standard"
	"github.com/labstack/echo/middleware"
	"gopkg.in/olahol/melody.v1"
	"net/http"
)

func main() {
	e := echo.New()
	m := melody.New()

	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	e.GET("/", func(c echo.Context) error {
		http.ServeFile(c.Response().(*standard.Response).ResponseWriter, c.Request().(*standard.Request).Request, "index.html")
		return nil
	})

	e.GET("/ws", func(c echo.Context) error {
		m.HandleRequest(c.Response().(*standard.Response).ResponseWriter, c.Request().(*standard.Request).Request)
		return nil
	})

	m.HandleMessage(func(s *melody.Session, msg []byte) {
		m.Broadcast(msg)
	})

	e.Run(standard.New(":5000"))
}

Example: gophers

Gophers

package main

import (
	"github.com/gin-gonic/gin"
	"gopkg.in/olahol/melody.v1"
	"net/http"
	"strconv"
	"strings"
	"sync"
)

type GopherInfo struct {
	ID, X, Y string
}

func main() {
	router := gin.Default()
	mrouter := melody.New()
	gophers := make(map[*melody.Session]*GopherInfo)
	lock := new(sync.Mutex)
	counter := 0

	router.GET("/", func(c *gin.Context) {
		http.ServeFile(c.Writer, c.Request, "index.html")
	})

	router.GET("/ws", func(c *gin.Context) {
		mrouter.HandleRequest(c.Writer, c.Request)
	})

	mrouter.HandleConnect(func(s *melody.Session) {
		lock.Lock()
		for _, info := range gophers {
			s.Write([]byte("set " + info.ID + " " + info.X + " " + info.Y))
		}
		gophers[s] = &GopherInfo{strconv.Itoa(counter), "0", "0"}
		s.Write([]byte("iam " + gophers[s].ID))
		counter += 1
		lock.Unlock()
	})

	mrouter.HandleDisconnect(func(s *melody.Session) {
		lock.Lock()
		mrouter.BroadcastOthers([]byte("dis "+gophers[s].ID), s)
		delete(gophers, s)
		lock.Unlock()
	})

	mrouter.HandleMessage(func(s *melody.Session, msg []byte) {
		p := strings.Split(string(msg), " ")
		lock.Lock()
		info := gophers[s]
		if len(p) == 2 {
			info.X = p[0]
			info.Y = p[1]
			mrouter.BroadcastOthers([]byte("set "+info.ID+" "+info.X+" "+info.Y), s)
		}
		lock.Unlock()
	})

	router.Run(":5000")
}
More examples

Documentation

Contributors

  • Ola Holmström (@olahol)
  • Shogo Iwano (@shiwano)
  • Matt Caldwell (@mattcaldwell)
  • Heikki Uljas (@huljas)
  • Robbie Trencheny (@robbiet480)
  • yangjinecho (@yangjinecho)

FAQ

If you are getting a 403 when trying to connect to your websocket you can change allow all origin hosts:

m := melody.New()
m.Upgrader.CheckOrigin = func(r *http.Request) bool { return true }
Expand ▾ Collapse ▴

Documentation

Overview

Package melody implements a framework for dealing with WebSockets.

Example

A broadcasting echo server:

func main() {
	r := gin.Default()
	m := melody.New()
	r.GET("/ws", func(c *gin.Context) {
		m.HandleRequest(c.Writer, c.Request)
	})
	m.HandleMessage(func(s *melody.Session, msg []byte) {
		m.Broadcast(msg)
	})
	r.Run(":5000")
}

Index

Constants

View Source
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
)

    Close codes defined in RFC 6455, section 11.7. Duplicate of codes from gorilla/websocket for convenience.

    Variables

    This section is empty.

    Functions

    func FormatCloseMessage

    func FormatCloseMessage(closeCode int, text string) []byte

      FormatCloseMessage formats closeCode and text as a WebSocket close message.

      Types

      type Config

      type Config struct {
      	WriteWait         time.Duration // Milliseconds until write times out.
      	PongWait          time.Duration // Timeout for waiting on pong.
      	PingPeriod        time.Duration // Milliseconds between pings.
      	MaxMessageSize    int64         // Maximum size in bytes of a message.
      	MessageBufferSize int           // The max amount of messages that can be in a sessions buffer before it starts dropping them.
      }

        Config melody configuration struct.

        type Melody

        type Melody struct {
        	Config   *Config
        	Upgrader *websocket.Upgrader
        	// contains filtered or unexported fields
        }

          Melody implements a websocket manager.

          func New

          func New() *Melody

            New creates a new melody instance with default Upgrader and Config.

            func (*Melody) Broadcast

            func (m *Melody) Broadcast(msg []byte) error

              Broadcast broadcasts a text message to all sessions.

              func (*Melody) BroadcastBinary

              func (m *Melody) BroadcastBinary(msg []byte) error

                BroadcastBinary broadcasts a binary message to all sessions.

                func (*Melody) BroadcastBinaryFilter

                func (m *Melody) BroadcastBinaryFilter(msg []byte, fn func(*Session) bool) error

                  BroadcastBinaryFilter broadcasts a binary message to all sessions that fn returns true for.

                  func (*Melody) BroadcastBinaryOthers

                  func (m *Melody) BroadcastBinaryOthers(msg []byte, s *Session) error

                    BroadcastBinaryOthers broadcasts a binary message to all sessions except session s.

                    func (*Melody) BroadcastFilter

                    func (m *Melody) BroadcastFilter(msg []byte, fn func(*Session) bool) error

                      BroadcastFilter broadcasts a text message to all sessions that fn returns true for.

                      func (*Melody) BroadcastMultiple

                      func (m *Melody) BroadcastMultiple(msg []byte, sessions []*Session) error

                        BroadcastMultiple broadcasts a text message to multiple sessions given in the sessions slice.

                        func (*Melody) BroadcastOthers

                        func (m *Melody) BroadcastOthers(msg []byte, s *Session) error

                          BroadcastOthers broadcasts a text message to all sessions except session s.

                          func (*Melody) Close

                          func (m *Melody) Close() error

                            Close closes the melody instance and all connected sessions.

                            func (*Melody) CloseWithMsg

                            func (m *Melody) CloseWithMsg(msg []byte) error

                              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 (*Melody) HandleClose

                              func (m *Melody) HandleClose(fn func(*Session, int, string) error)

                                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 (*Melody) HandleConnect

                                func (m *Melody) HandleConnect(fn func(*Session))

                                  HandleConnect fires fn when a session connects.

                                  func (*Melody) HandleDisconnect

                                  func (m *Melody) HandleDisconnect(fn func(*Session))

                                    HandleDisconnect fires fn when a session disconnects.

                                    func (*Melody) HandleError

                                    func (m *Melody) HandleError(fn func(*Session, error))

                                      HandleError fires fn when a session has an error.

                                      func (*Melody) HandleMessage

                                      func (m *Melody) HandleMessage(fn func(*Session, []byte))

                                        HandleMessage fires fn when a text message comes in.

                                        func (*Melody) HandleMessageBinary

                                        func (m *Melody) HandleMessageBinary(fn func(*Session, []byte))

                                          HandleMessageBinary fires fn when a binary message comes in.

                                          func (*Melody) HandlePong

                                          func (m *Melody) HandlePong(fn func(*Session))

                                            HandlePong fires fn when a pong is received from a session.

                                            func (*Melody) HandleRequest

                                            func (m *Melody) HandleRequest(w http.ResponseWriter, r *http.Request) error

                                              HandleRequest upgrades http requests to websocket connections and dispatches them to be handled by the melody instance.

                                              func (*Melody) HandleRequestWithKeys

                                              func (m *Melody) HandleRequestWithKeys(w http.ResponseWriter, r *http.Request, keys map[string]interface{}) error

                                                HandleRequestWithKeys does the same as HandleRequest but populates session.Keys with keys.

                                                func (*Melody) HandleSentMessage

                                                func (m *Melody) HandleSentMessage(fn func(*Session, []byte))

                                                  HandleSentMessage fires fn when a text message is successfully sent.

                                                  func (*Melody) HandleSentMessageBinary

                                                  func (m *Melody) HandleSentMessageBinary(fn func(*Session, []byte))

                                                    HandleSentMessageBinary fires fn when a binary message is successfully sent.

                                                    func (*Melody) IsClosed

                                                    func (m *Melody) IsClosed() bool

                                                      IsClosed returns the status of the melody instance.

                                                      func (*Melody) Len

                                                      func (m *Melody) Len() int

                                                        Len return the number of connected sessions.

                                                        type Session

                                                        type Session struct {
                                                        	Request *http.Request
                                                        	Keys    map[string]interface{}
                                                        	// contains filtered or unexported fields
                                                        }

                                                          Session wrapper around websocket connections.

                                                          func (*Session) Close

                                                          func (s *Session) Close() error

                                                            Close closes session.

                                                            func (*Session) CloseWithMsg

                                                            func (s *Session) CloseWithMsg(msg []byte) error

                                                              CloseWithMsg closes the session with the provided payload. Use the FormatCloseMessage function to format a proper close message payload.

                                                              func (*Session) Get

                                                              func (s *Session) Get(key string) (value interface{}, exists bool)

                                                                Get returns the value for the given key, ie: (value, true). If the value does not exists it returns (nil, false)

                                                                func (*Session) IsClosed

                                                                func (s *Session) IsClosed() bool

                                                                  IsClosed returns the status of the connection.

                                                                  func (*Session) MustGet

                                                                  func (s *Session) MustGet(key string) interface{}

                                                                    MustGet returns the value for the given key if it exists, otherwise it panics.

                                                                    func (*Session) Set

                                                                    func (s *Session) Set(key string, value interface{})

                                                                      Set is used to store a new key/value pair exclusivelly for this session. It also lazy initializes s.Keys if it was not used previously.

                                                                      func (*Session) Write

                                                                      func (s *Session) Write(msg []byte) error

                                                                        Write writes message to session.

                                                                        func (*Session) WriteBinary

                                                                        func (s *Session) WriteBinary(msg []byte) error

                                                                          WriteBinary writes a binary message to session.

                                                                          Directories

                                                                          Path Synopsis
                                                                          examples