gui.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package main
  2. import (
  3. "encoding/json"
  4. "io/ioutil"
  5. "log"
  6. "net/http"
  7. "runtime"
  8. "sync"
  9. "time"
  10. "github.com/codegangsta/martini"
  11. )
  12. type guiError struct {
  13. Time time.Time
  14. Error string
  15. }
  16. var (
  17. configInSync = true
  18. guiErrors = []guiError{}
  19. guiErrorsMut sync.Mutex
  20. )
  21. func startGUI(addr string, m *Model) {
  22. router := martini.NewRouter()
  23. router.Get("/", getRoot)
  24. router.Get("/rest/version", restGetVersion)
  25. router.Get("/rest/model", restGetModel)
  26. router.Get("/rest/connections", restGetConnections)
  27. router.Get("/rest/config", restGetConfig)
  28. router.Get("/rest/config/sync", restGetConfigInSync)
  29. router.Get("/rest/need", restGetNeed)
  30. router.Get("/rest/system", restGetSystem)
  31. router.Get("/rest/errors", restGetErrors)
  32. router.Post("/rest/config", restPostConfig)
  33. router.Post("/rest/restart", restPostRestart)
  34. router.Post("/rest/error", restPostError)
  35. go func() {
  36. mr := martini.New()
  37. mr.Use(embeddedStatic())
  38. mr.Use(martini.Recovery())
  39. mr.Action(router.Handle)
  40. mr.Map(m)
  41. err := http.ListenAndServe(addr, mr)
  42. if err != nil {
  43. warnln("GUI not possible:", err)
  44. }
  45. }()
  46. }
  47. func getRoot(w http.ResponseWriter, r *http.Request) {
  48. http.Redirect(w, r, "/index.html", 302)
  49. }
  50. func restGetVersion() string {
  51. return Version
  52. }
  53. func restGetModel(m *Model, w http.ResponseWriter) {
  54. var res = make(map[string]interface{})
  55. globalFiles, globalDeleted, globalBytes := m.GlobalSize()
  56. res["globalFiles"], res["globalDeleted"], res["globalBytes"] = globalFiles, globalDeleted, globalBytes
  57. localFiles, localDeleted, localBytes := m.LocalSize()
  58. res["localFiles"], res["localDeleted"], res["localBytes"] = localFiles, localDeleted, localBytes
  59. inSyncFiles, inSyncBytes := m.InSyncSize()
  60. res["inSyncFiles"], res["inSyncBytes"] = inSyncFiles, inSyncBytes
  61. files, total := m.NeedFiles()
  62. res["needFiles"], res["needBytes"] = len(files), total
  63. w.Header().Set("Content-Type", "application/json")
  64. json.NewEncoder(w).Encode(res)
  65. }
  66. func restGetConnections(m *Model, w http.ResponseWriter) {
  67. var res = m.ConnectionStats()
  68. w.Header().Set("Content-Type", "application/json")
  69. json.NewEncoder(w).Encode(res)
  70. }
  71. func restGetConfig(w http.ResponseWriter) {
  72. json.NewEncoder(w).Encode(cfg)
  73. }
  74. func restPostConfig(req *http.Request) {
  75. err := json.NewDecoder(req.Body).Decode(&cfg)
  76. if err != nil {
  77. log.Println(err)
  78. } else {
  79. saveConfig()
  80. configInSync = false
  81. }
  82. }
  83. func restGetConfigInSync(w http.ResponseWriter) {
  84. json.NewEncoder(w).Encode(map[string]bool{"configInSync": configInSync})
  85. }
  86. func restPostRestart(req *http.Request) {
  87. restart()
  88. }
  89. type guiFile File
  90. func (f guiFile) MarshalJSON() ([]byte, error) {
  91. type t struct {
  92. Name string
  93. Size int
  94. }
  95. return json.Marshal(t{
  96. Name: f.Name,
  97. Size: File(f).Size(),
  98. })
  99. }
  100. func restGetNeed(m *Model, w http.ResponseWriter) {
  101. files, _ := m.NeedFiles()
  102. gfs := make([]guiFile, len(files))
  103. for i, f := range files {
  104. gfs[i] = guiFile(f)
  105. }
  106. w.Header().Set("Content-Type", "application/json")
  107. json.NewEncoder(w).Encode(gfs)
  108. }
  109. var cpuUsagePercent float64
  110. var cpuUsageLock sync.RWMutex
  111. func restGetSystem(w http.ResponseWriter) {
  112. var m runtime.MemStats
  113. runtime.ReadMemStats(&m)
  114. res := make(map[string]interface{})
  115. res["myID"] = myID
  116. res["goroutines"] = runtime.NumGoroutine()
  117. res["alloc"] = m.Alloc
  118. res["sys"] = m.Sys
  119. cpuUsageLock.RLock()
  120. res["cpuPercent"] = cpuUsagePercent
  121. cpuUsageLock.RUnlock()
  122. w.Header().Set("Content-Type", "application/json")
  123. json.NewEncoder(w).Encode(res)
  124. }
  125. func restGetErrors(w http.ResponseWriter) {
  126. guiErrorsMut.Lock()
  127. json.NewEncoder(w).Encode(guiErrors)
  128. guiErrorsMut.Unlock()
  129. }
  130. func restPostError(req *http.Request) {
  131. bs, _ := ioutil.ReadAll(req.Body)
  132. req.Body.Close()
  133. showGuiError(string(bs))
  134. }
  135. func showGuiError(err string) {
  136. guiErrorsMut.Lock()
  137. guiErrors = append(guiErrors, guiError{time.Now(), err})
  138. if len(guiErrors) > 5 {
  139. guiErrors = guiErrors[len(guiErrors)-5:]
  140. }
  141. guiErrorsMut.Unlock()
  142. }