dashboard.go 3.3 KB

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