conn.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package main
  5. import (
  6. "github.com/gorilla/websocket"
  7. "log"
  8. "net/http"
  9. "time"
  10. )
  11. const (
  12. // Time allowed to write a message to the peer.
  13. writeWait = 10 * time.Second
  14. // Time allowed to read the next pong message from the peer.
  15. pongWait = 60 * time.Second
  16. // Send pings to peer with this period. Must be less than pongWait.
  17. pingPeriod = (pongWait * 9) / 10
  18. // Maximum message size allowed from peer.
  19. maxMessageSize = 512
  20. )
  21. var upgrader = websocket.Upgrader{
  22. ReadBufferSize: 1024,
  23. WriteBufferSize: 1024,
  24. }
  25. // connection is an middleman between the websocket connection and the hub.
  26. type connection struct {
  27. // The websocket connection.
  28. ws *websocket.Conn
  29. // Buffered channel of outbound messages.
  30. send chan []byte
  31. }
  32. // readPump pumps messages from the websocket connection to the hub.
  33. func (conn *connection) readPump() {
  34. defer func() {
  35. mainHub.unregister <- conn
  36. conn.ws.Close()
  37. }()
  38. conn.ws.SetReadLimit(maxMessageSize)
  39. conn.ws.SetReadDeadline(time.Now().Add(pongWait))
  40. conn.ws.SetPongHandler(func(string) error { conn.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
  41. for {
  42. _, message, err := conn.ws.ReadMessage()
  43. if err != nil {
  44. if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
  45. log.Printf("error: %v", err)
  46. }
  47. break
  48. }
  49. mainHub.broadcast <- message
  50. }
  51. }
  52. // write writes a message with the given message type and payload.
  53. func (conn *connection) write(mt int, payload []byte) error {
  54. conn.ws.SetWriteDeadline(time.Now().Add(writeWait))
  55. return conn.ws.WriteMessage(mt, payload)
  56. }
  57. // writePump pumps messages from the hub to the websocket connection.
  58. func (conn *connection) writePump() {
  59. ticker := time.NewTicker(pingPeriod)
  60. defer func() {
  61. ticker.Stop()
  62. conn.ws.Close()
  63. }()
  64. for {
  65. select {
  66. case message, ok := <-conn.send:
  67. if !ok {
  68. conn.write(websocket.CloseMessage, []byte{})
  69. return
  70. }
  71. if err := conn.write(websocket.TextMessage, message); err != nil {
  72. return
  73. }
  74. case <-ticker.C:
  75. if err := conn.write(websocket.PingMessage, []byte{}); err != nil {
  76. return
  77. }
  78. }
  79. }
  80. }
  81. // serveWs handles websocket requests from the peer.
  82. func serveWs(w http.ResponseWriter, r *http.Request) {
  83. ws, err := upgrader.Upgrade(w, r, nil)
  84. if err != nil {
  85. log.Println(err)
  86. return
  87. }
  88. conn := &connection{send: make(chan []byte, 256), ws: ws}
  89. mainHub.register <- conn
  90. go conn.writePump()
  91. conn.readPump()
  92. }