diff --git a/README.md b/README.md index 094889d..a992ecf 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,15 @@ -# melody +# melody [![Build Status](https://travis-ci.org/olahol/melody.svg)](https://travis-ci.org/olahol/melody) [![GoDoc](https://godoc.org/github.com/olahol/melody?status.svg)](https://godoc.org/github.com/olahol/melody) -[![GoDoc](https://godoc.org/github.com/olahol/melody?status.svg)](https://godoc.org/github.com/olahol/melody) -[![Build Status](https://travis-ci.org/olahol/melody.svg)](https://travis-ci.org/olahol/melody) - -> :notes: Simple websocket framework for Go +> :notes: Minimalist websocket framework for Go. Melody is websocket framework based on [github.com/gorilla/websocket](https://github.com/gorilla/websocket) -that abstracts away the more tedious parts of handling websockets. Features include: +that abstracts away the tedious parts of handling websockets. It gets out of +your way so you can write real-time apps. Features include: -* [x] Timeouts for write and read. -* [x] Built-in ping/pong handling. -* [x] Message buffer for connections making concurrent writing easy. -* [x] Simple broadcasting to all or selected sessions. +* [x] Clear and easy interface similar to `net/http` or Gin. +* [x] A simple way to broadcast to all or selected connected sessions. +* [x] Message buffers making concurrent writing safe. +* [x] Automatic handling of ping/pong and session timeouts. ## Install @@ -21,10 +19,10 @@ go get github.com/olahol/melody ## [Example](https://github.com/olahol/melody/tree/master/examples) -[Simple broadcasting chat server](https://github.com/olahol/melody/tree/master/examples/chat), +[Multi channel chat server](https://github.com/olahol/melody/tree/master/examples/multichat), error handling left as en exercise for the developer. -[![Chat demo](https://cdn.rawgit.com/olahol/melody/master/examples/chat/demo.gif "Demo")](https://github.com/olahol/melody/tree/master/examples/chat) +[![Chat demo](https://cdn.rawgit.com/olahol/melody/master/examples/chat/demo.gif "Demo")](https://github.com/olahol/melody/tree/master/examples/multichat) ```go package main @@ -43,16 +41,24 @@ func main() { http.ServeFile(c.Writer, c.Request, "index.html") }) - r.GET("/ws", func(c *gin.Context) { + r.GET("/channel/:name", func(c *gin.Context) { + http.ServeFile(c.Writer, c.Request, "chan.html") + }) + + r.GET("/channel/:name/ws", func(c *gin.Context) { m.HandleRequest(c.Writer, c.Request) }) m.HandleMessage(func(s *melody.Session, msg []byte) { - m.Broadcast(msg) + m.BroadcastFilter(msg, func(q *melody.Session) bool { + return q.Request.URL.Path == s.Request.URL.Path + }) }) r.Run(":5000") } ``` -### [Documentation](https://godoc.org/github.com/olahol/melody) +### [More examples](https://github.com/olahol/melody/tree/master/examples) + +## [Documentation](https://godoc.org/github.com/olahol/melody) diff --git a/examples/multichat/chan.html b/examples/multichat/chan.html new file mode 100644 index 0000000..4ea76ba --- /dev/null +++ b/examples/multichat/chan.html @@ -0,0 +1,53 @@ + + + Melody example: chatting + + + + + +
+

+

+      
+    
+ + + + diff --git a/examples/multichat/demo.gif b/examples/multichat/demo.gif new file mode 100644 index 0000000..0bd7afe Binary files /dev/null and b/examples/multichat/demo.gif differ diff --git a/examples/multichat/index.html b/examples/multichat/index.html new file mode 100644 index 0000000..c93fd66 --- /dev/null +++ b/examples/multichat/index.html @@ -0,0 +1,34 @@ + + + Melody example: chatting + + + + + +
+

Join a channel

+ +
+ + + + diff --git a/examples/multichat/main.go b/examples/multichat/main.go new file mode 100644 index 0000000..20c4acd --- /dev/null +++ b/examples/multichat/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "../../" + "github.com/gin-gonic/gin" + "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("/channel/:name", func(c *gin.Context) { + http.ServeFile(c.Writer, c.Request, "chan.html") + }) + + r.GET("/channel/:name/ws", func(c *gin.Context) { + m.HandleRequest(c.Writer, c.Request) + }) + + m.HandleMessage(func(s *melody.Session, msg []byte) { + m.BroadcastFilter(msg, func(q *melody.Session) bool { + return q.Request.URL.Path == s.Request.URL.Path + }) + }) + + r.Run(":5000") +} diff --git a/melody.go b/melody.go index 0b4b982..21a1da7 100644 --- a/melody.go +++ b/melody.go @@ -63,14 +63,14 @@ func (m *Melody) HandleError(fn func(*Session, error)) { } // Handles a http request and upgrades it to a websocket. -func (m *Melody) HandleRequest(w http.ResponseWriter, r *http.Request) error { +func (m *Melody) HandleRequest(w http.ResponseWriter, r *http.Request) { conn, err := m.upgrader.Upgrade(w, r, nil) if err != nil { - return err + return } - session := newSession(m.Config, conn) + session := newSession(m.Config, conn, r) m.hub.register <- session @@ -83,8 +83,6 @@ func (m *Melody) HandleRequest(w http.ResponseWriter, r *http.Request) error { m.hub.unregister <- session go m.disconnectHandler(session) - - return nil } // Broadcasts a message to all sessions. @@ -94,7 +92,7 @@ func (m *Melody) Broadcast(msg []byte) { } // Broadcasts a message to all sessions that fn returns true for. -func (m *Melody) BroadcastFilter(fn func(*Session) bool, msg []byte) { +func (m *Melody) BroadcastFilter(msg []byte, fn func(*Session) bool) { message := &envelope{t: websocket.TextMessage, msg: msg, filter: fn} m.hub.broadcast <- message } diff --git a/session.go b/session.go index 7090ac8..3f4e471 100644 --- a/session.go +++ b/session.go @@ -2,21 +2,24 @@ package melody import ( "github.com/gorilla/websocket" + "net/http" "time" ) // A melody session. type Session struct { - conn *websocket.Conn - output chan *envelope - config *Config + Request *http.Request + conn *websocket.Conn + output chan *envelope + config *Config } -func newSession(config *Config, conn *websocket.Conn) *Session { +func newSession(config *Config, conn *websocket.Conn, req *http.Request) *Session { return &Session{ - conn: conn, - output: make(chan *envelope, config.MessageBufferSize), - config: config, + Request: req, + conn: conn, + output: make(chan *envelope, config.MessageBufferSize), + config: config, } }