session.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package dashboard
  2. import (
  3. "math/rand"
  4. "time"
  5. log "github.com/Sirupsen/logrus"
  6. "github.com/gorilla/websocket"
  7. )
  8. const (
  9. maxMessageSize = 1024
  10. writeWait = 5 * time.Second
  11. pongWait = 60 * time.Second
  12. pingPeriod = 50 * time.Second
  13. )
  14. var idCharset = []byte("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890")
  15. // Represents an active session with a client
  16. type session struct {
  17. id string
  18. ws *websocket.Conn
  19. // Messages to send over the websocket are received on this channel
  20. send <-chan *message
  21. }
  22. // Receives messages from the websocket connection associated with a session
  23. func (s *session) receive() {
  24. defer s.ws.Close()
  25. s.ws.SetReadLimit(maxMessageSize)
  26. s.ws.SetReadDeadline(time.Now().Add(pongWait))
  27. s.ws.SetPongHandler(func(string) error {
  28. s.ws.SetReadDeadline(time.Now().Add(pongWait))
  29. return nil
  30. })
  31. for {
  32. _, message, err := s.ws.ReadMessage()
  33. if err != nil {
  34. if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
  35. log.WithError(err).Error("Websocket closed unexpectedly")
  36. }
  37. break
  38. }
  39. log.Infof("Message: %s", string(message))
  40. }
  41. }
  42. // Transmits messages to the websocket connection associated with a session
  43. func (s *session) transmit() {
  44. ticker := time.NewTicker(pingPeriod)
  45. defer s.ws.Close()
  46. defer ticker.Stop()
  47. // Label for loop to allow breaking from within switch statement
  48. transmit:
  49. for {
  50. select {
  51. case p, ok := <-s.send:
  52. s.ws.SetWriteDeadline(time.Now().Add(writeWait))
  53. if !ok {
  54. s.ws.WriteMessage(websocket.CloseMessage, []byte{})
  55. break transmit
  56. }
  57. err := s.ws.WriteJSON(p)
  58. if err != nil {
  59. log.WithError(err).Debug("Failed to write next websocket message. Closing connection")
  60. break transmit
  61. }
  62. case <-ticker.C:
  63. s.ws.SetWriteDeadline(time.Now().Add(writeWait))
  64. if err := s.ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
  65. log.WithError(err).Debug("Failed to write next websocket message. Closing connection")
  66. break transmit
  67. }
  68. }
  69. }
  70. }
  71. // Returns a random alphanumeric 10-character ID
  72. func newSessionID() string {
  73. mask := int64(63)
  74. gen := rand.Int63()
  75. out := []byte{}
  76. for i := 0; i < 10; i++ {
  77. out = append(out, idCharset[int(gen&mask)%58])
  78. gen = gen >> 6
  79. }
  80. return string(out)
  81. }