dashboard.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package dashboard
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "net/http"
  6. "time"
  7. log "github.com/Sirupsen/logrus"
  8. // "github.com/flashmob/go-guerrilla/dashboard/statik"
  9. "github.com/gorilla/mux"
  10. "github.com/gorilla/websocket"
  11. "github.com/rakyll/statik/fs"
  12. )
  13. var (
  14. config *Config
  15. sessions map[string]*session
  16. )
  17. var upgrader = websocket.Upgrader{
  18. ReadBufferSize: 1024,
  19. WriteBufferSize: 1024,
  20. // TODO below for testing w/ webpack only, change before merging
  21. CheckOrigin: func(r *http.Request) bool { return true },
  22. }
  23. type Config struct {
  24. Enabled bool `json:"is_enabled"`
  25. ListenInterface string `json:"listen_interface"`
  26. // Interval at which we send measure and send dataframe to frontend
  27. TickInterval string `json:"tick_interval"`
  28. // Maximum interval for which we store data
  29. MaxWindow string `json:"max_window"`
  30. // Granularity for which rankings are aggregated
  31. RankingUpdateInterval string `json:"ranking_aggregation_interval"`
  32. // Determines at which ratio of unique HELOs to unique connections we
  33. // will stop collecting data to prevent memory exhaustion attack.
  34. // Number between 0-1, set to >1 if you never want to stop collecting data.
  35. // Default is 0.8
  36. UniqueHeloRatioMax float64 `json:"unique_helo_ratio"`
  37. }
  38. // Begin collecting data and listening for dashboard clients
  39. func Run(c *Config) {
  40. statikFS, _ := fs.New()
  41. applyConfig(c)
  42. sessions = map[string]*session{}
  43. r := mux.NewRouter()
  44. r.HandleFunc("/ws", webSocketHandler)
  45. r.PathPrefix("/").Handler(http.FileServer(statikFS))
  46. rand.Seed(time.Now().UnixNano())
  47. go dataListener(tickInterval)
  48. go store.rankingManager()
  49. err := http.ListenAndServe(c.ListenInterface, r)
  50. log.WithError(err).Error("Dashboard server failed to start")
  51. }
  52. // Parses options in config and applies to global variables
  53. func applyConfig(c *Config) {
  54. config = c
  55. if len(config.MaxWindow) > 0 {
  56. mw, err := time.ParseDuration(config.MaxWindow)
  57. if err == nil {
  58. maxWindow = mw
  59. }
  60. }
  61. if len(config.RankingUpdateInterval) > 0 {
  62. rui, err := time.ParseDuration(config.RankingUpdateInterval)
  63. if err == nil {
  64. rankingUpdateInterval = rui
  65. }
  66. }
  67. if len(config.TickInterval) > 0 {
  68. ti, err := time.ParseDuration(config.TickInterval)
  69. if err == nil {
  70. tickInterval = ti
  71. }
  72. }
  73. if config.UniqueHeloRatioMax > 0 {
  74. uniqueHeloRatioMax = config.UniqueHeloRatioMax
  75. }
  76. maxTicks = int(maxWindow * tickInterval)
  77. nRankingBuffers = int(maxWindow / rankingUpdateInterval)
  78. }
  79. func webSocketHandler(w http.ResponseWriter, r *http.Request) {
  80. var sess *session
  81. cookie, err := r.Cookie("SID")
  82. fmt.Println("cookie", cookie, err.Error())
  83. if err != nil {
  84. // Haven't set this cookie yet.
  85. sess = startSession(w, r)
  86. } else {
  87. var sidExists bool
  88. sess, sidExists = sessions[cookie.Value]
  89. if !sidExists {
  90. // No SID cookie in our store, start a new session
  91. sess = startSession(w, r)
  92. }
  93. }
  94. conn, err := upgrader.Upgrade(w, r, nil)
  95. if err != nil {
  96. w.WriteHeader(http.StatusInternalServerError)
  97. return
  98. }
  99. sess.ws = conn
  100. c := make(chan *message)
  101. sess.send = c
  102. store.subscribe(sess.id, c)
  103. go sess.receive()
  104. go sess.transmit()
  105. go store.initSession(sess)
  106. }
  107. func startSession(w http.ResponseWriter, r *http.Request) *session {
  108. sessionID := newSessionID()
  109. cookie := &http.Cookie{
  110. Name: "SID",
  111. Value: sessionID,
  112. Path: "/",
  113. // Secure: true, // TODO re-add this when TLS is set up
  114. }
  115. sess := &session{
  116. id: sessionID,
  117. }
  118. http.SetCookie(w, cookie)
  119. sessions[sessionID] = sess
  120. return sess
  121. }