conn.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. // Copyright 2013 Gary Burd. 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. // connection is an middleman between the websocket connection and the hub.
  22. type connection struct {
  23. // The websocket connection.
  24. ws *websocket.Conn
  25. // Buffered channel of outbound messages.
  26. send chan []byte
  27. }
  28. // readPump pumps messages from the websocket connection to the hub.
  29. func (c *connection) readPump() {
  30. defer func() {
  31. h.unregister <- c
  32. c.ws.Close()
  33. }()
  34. c.ws.SetReadLimit(maxMessageSize)
  35. c.ws.SetReadDeadline(time.Now().Add(pongWait))
  36. c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
  37. for {
  38. _, message, err := c.ws.ReadMessage()
  39. if err != nil {
  40. break
  41. }
  42. h.broadcast <- message
  43. }
  44. }
  45. // write writes a message with the given message type and payload.
  46. func (c *connection) write(mt int, payload []byte) error {
  47. c.ws.SetWriteDeadline(time.Now().Add(writeWait))
  48. return c.ws.WriteMessage(mt, payload)
  49. }
  50. // writePump pumps messages from the hub to the websocket connection.
  51. func (c *connection) writePump() {
  52. ticker := time.NewTicker(pingPeriod)
  53. defer func() {
  54. ticker.Stop()
  55. c.ws.Close()
  56. }()
  57. for {
  58. select {
  59. case message, ok := <-c.send:
  60. if !ok {
  61. c.write(websocket.CloseMessage, []byte{})
  62. return
  63. }
  64. if err := c.write(websocket.TextMessage, message); err != nil {
  65. return
  66. }
  67. case <-ticker.C:
  68. if err := c.write(websocket.PingMessage, []byte{}); err != nil {
  69. return
  70. }
  71. }
  72. }
  73. }
  74. // serverWs handles webocket requests from the peer.
  75. func serveWs(w http.ResponseWriter, r *http.Request) {
  76. if r.Method != "GET" {
  77. http.Error(w, "Method not allowed", 405)
  78. return
  79. }
  80. if r.Header.Get("Origin") != "http://"+r.Host {
  81. http.Error(w, "Origin not allowed", 403)
  82. return
  83. }
  84. ws, err := websocket.Upgrade(w, r, nil, 1024, 1024)
  85. if _, ok := err.(websocket.HandshakeError); ok {
  86. http.Error(w, "Not a websocket handshake", 400)
  87. return
  88. } else if err != nil {
  89. log.Println(err)
  90. return
  91. }
  92. c := &connection{send: make(chan []byte, 256), ws: ws}
  93. h.register <- c
  94. go c.writePump()
  95. c.readPump()
  96. }