main.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. package main
  2. import (
  3. "encoding/json"
  4. "flag"
  5. "fmt"
  6. "io"
  7. "log"
  8. "net/http"
  9. "os"
  10. "path"
  11. "path/filepath"
  12. "sort"
  13. "sync"
  14. "time"
  15. )
  16. var (
  17. keyFile = flag.String("key", "", "Key file")
  18. certFile = flag.String("cert", "", "Certificate file")
  19. dbDir = flag.String("db", "", "Database directory")
  20. port = flag.Int("port", 8443, "Listen port")
  21. )
  22. func main() {
  23. flag.Parse()
  24. log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
  25. http.HandleFunc("/newdata", newDataHandler)
  26. http.HandleFunc("/report", reportHandler)
  27. http.Handle("/", http.FileServer(http.Dir("static")))
  28. err := http.ListenAndServeTLS(fmt.Sprintf(":%d", *port), *certFile, *keyFile, nil)
  29. if err != nil {
  30. log.Fatal(err)
  31. }
  32. }
  33. func newDataHandler(w http.ResponseWriter, r *http.Request) {
  34. today := time.Now().Format("20060102")
  35. dir := filepath.Join(*dbDir, today)
  36. ensureDir(dir, 0700)
  37. var m map[string]interface{}
  38. lr := &io.LimitedReader{R: r.Body, N: 10240}
  39. err := json.NewDecoder(lr).Decode(&m)
  40. if err != nil {
  41. log.Println(err)
  42. http.Error(w, err.Error(), 500)
  43. return
  44. }
  45. id, ok := m["uniqueID"]
  46. if ok {
  47. idStr, ok := id.(string)
  48. if !ok {
  49. if err != nil {
  50. log.Println("No ID")
  51. http.Error(w, "No ID", 500)
  52. return
  53. }
  54. }
  55. f, err := os.Create(path.Join(dir, idStr+".json"))
  56. if err != nil {
  57. log.Println(err)
  58. http.Error(w, err.Error(), 500)
  59. return
  60. }
  61. json.NewEncoder(f).Encode(m)
  62. f.Close()
  63. } else {
  64. log.Println("No ID")
  65. http.Error(w, "No ID", 500)
  66. return
  67. }
  68. }
  69. type report struct {
  70. UniqueID string
  71. Version string
  72. Platform string
  73. NumRepos int
  74. NumNodes int
  75. TotFiles int
  76. RepoMaxFiles int
  77. TotMiB int
  78. RepoMaxMiB int
  79. MemoryUsageMiB int
  80. SHA256Perf float64
  81. MemorySize int
  82. }
  83. var cache map[string]interface{}
  84. var cacheDate string
  85. var cacheMut sync.Mutex
  86. func reportHandler(w http.ResponseWriter, r *http.Request) {
  87. yesterday := time.Now().Add(-24 * time.Hour).Format("20060102")
  88. cacheMut.Lock()
  89. cacheMut.Unlock()
  90. if cacheDate != yesterday {
  91. cache = make(map[string]interface{})
  92. dir := filepath.Join(*dbDir, yesterday)
  93. files, err := filepath.Glob(filepath.Join(dir, "*.json"))
  94. if err != nil {
  95. http.Error(w, "Glob error", 500)
  96. return
  97. }
  98. nodes := 0
  99. versions := make(map[string]int)
  100. platforms := make(map[string]int)
  101. var numRepos []int
  102. var numNodes []int
  103. var totFiles []int
  104. var maxFiles []int
  105. var totMiB []int
  106. var maxMiB []int
  107. var memoryUsage []int
  108. var sha256Perf []float64
  109. var memorySize []int
  110. for _, fn := range files {
  111. f, err := os.Open(fn)
  112. if err != nil {
  113. continue
  114. }
  115. var rep report
  116. err = json.NewDecoder(f).Decode(&rep)
  117. if err != nil {
  118. continue
  119. }
  120. f.Close()
  121. nodes++
  122. versions[rep.Version]++
  123. platforms[rep.Platform]++
  124. numRepos = append(numRepos, rep.NumRepos)
  125. numNodes = append(numNodes, rep.NumNodes)
  126. totFiles = append(totFiles, rep.TotFiles)
  127. maxFiles = append(maxFiles, rep.RepoMaxFiles)
  128. totMiB = append(totMiB, rep.TotMiB)
  129. maxMiB = append(maxMiB, rep.RepoMaxMiB)
  130. memoryUsage = append(memoryUsage, rep.MemoryUsageMiB)
  131. sha256Perf = append(sha256Perf, rep.SHA256Perf)
  132. if rep.MemorySize > 0 {
  133. memorySize = append(memorySize, rep.MemorySize)
  134. }
  135. }
  136. cache = make(map[string]interface{})
  137. cache["nodes"] = nodes
  138. cache["versions"] = versions
  139. cache["platforms"] = platforms
  140. cache["numRepos"] = statsForInts(numRepos)
  141. cache["numNodes"] = statsForInts(numNodes)
  142. cache["totFiles"] = statsForInts(totFiles)
  143. cache["maxFiles"] = statsForInts(maxFiles)
  144. cache["totMiB"] = statsForInts(totMiB)
  145. cache["maxMiB"] = statsForInts(maxMiB)
  146. cache["memoryUsage"] = statsForInts(memoryUsage)
  147. cache["sha256Perf"] = statsForFloats(sha256Perf)
  148. cache["memorySize"] = statsForInts(memorySize)
  149. }
  150. w.Header().Set("Content-Type", "application/json")
  151. json.NewEncoder(w).Encode(cache)
  152. }
  153. func statsForInts(data []int) map[string]int {
  154. sort.Ints(data)
  155. res := make(map[string]int, 4)
  156. res["min"] = data[0]
  157. res["med"] = data[len(data)/2]
  158. res["nfp"] = data[int(float64(len(data))*0.95)]
  159. res["max"] = data[len(data)-1]
  160. return res
  161. }
  162. func statsForFloats(data []float64) map[string]float64 {
  163. sort.Float64s(data)
  164. res := make(map[string]float64, 4)
  165. res["min"] = data[0]
  166. res["med"] = data[len(data)/2]
  167. res["nfp"] = data[int(float64(len(data))*0.95)]
  168. res["max"] = data[len(data)-1]
  169. return res
  170. }
  171. func ensureDir(dir string, mode int) {
  172. fi, err := os.Stat(dir)
  173. if os.IsNotExist(err) {
  174. os.MkdirAll(dir, 0700)
  175. } else if mode >= 0 && err == nil && int(fi.Mode()&0777) != mode {
  176. os.Chmod(dir, os.FileMode(mode))
  177. }
  178. }