session.go 2.2 KB

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