gui.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "log"
  7. "mime"
  8. "net/http"
  9. "path/filepath"
  10. "bitbucket.org/tebeka/nrsc"
  11. "github.com/codegangsta/martini"
  12. )
  13. func startGUI(addr string, m *Model) {
  14. router := martini.NewRouter()
  15. router.Get("/", getRoot)
  16. router.Get("/rest/version", restGetVersion)
  17. router.Get("/rest/model", restGetModel)
  18. router.Get("/rest/connections", restGetConnections)
  19. router.Get("/rest/config", restGetConfig)
  20. router.Get("/rest/need", restGetNeed)
  21. go func() {
  22. mr := martini.New()
  23. mr.Use(nrscStatic("gui"))
  24. mr.Use(martini.Recovery())
  25. mr.Action(router.Handle)
  26. mr.Map(m)
  27. http.ListenAndServe(addr, mr)
  28. }()
  29. }
  30. func getRoot(w http.ResponseWriter, r *http.Request) {
  31. http.Redirect(w, r, "/index.html", 302)
  32. }
  33. func restGetVersion() string {
  34. return Version
  35. }
  36. func restGetModel(m *Model, w http.ResponseWriter) {
  37. var res = make(map[string]interface{})
  38. globalFiles, globalDeleted, globalBytes := m.GlobalSize()
  39. res["globalFiles"], res["globalDeleted"], res["globalBytes"] = globalFiles, globalDeleted, globalBytes
  40. localFiles, localDeleted, localBytes := m.LocalSize()
  41. res["localFiles"], res["localDeleted"], res["localBytes"] = localFiles, localDeleted, localBytes
  42. files, total := m.NeedFiles()
  43. res["needFiles"], res["needBytes"] = len(files), total
  44. w.Header().Set("Content-Type", "application/json")
  45. json.NewEncoder(w).Encode(res)
  46. }
  47. func restGetConnections(m *Model, w http.ResponseWriter) {
  48. var res = m.ConnectionStats()
  49. w.Header().Set("Content-Type", "application/json")
  50. json.NewEncoder(w).Encode(res)
  51. }
  52. func restGetConfig(w http.ResponseWriter) {
  53. var res = make(map[string]interface{})
  54. res["repository"] = config.OptionMap("repository")
  55. res["nodes"] = config.OptionMap("nodes")
  56. w.Header().Set("Content-Type", "application/json")
  57. json.NewEncoder(w).Encode(res)
  58. }
  59. func restGetNeed(m *Model, w http.ResponseWriter) {
  60. files, _ := m.NeedFiles()
  61. if files == nil {
  62. // We don't want the empty list to serialize as "null\n"
  63. files = make([]FileInfo, 0)
  64. }
  65. w.Header().Set("Content-Type", "application/json")
  66. json.NewEncoder(w).Encode(files)
  67. }
  68. func nrscStatic(path string) interface{} {
  69. if err := nrsc.Initialize(); err != nil {
  70. panic("Unable to initialize nrsc: " + err.Error())
  71. }
  72. return func(res http.ResponseWriter, req *http.Request, log *log.Logger) {
  73. file := req.URL.Path
  74. // nrsc expects there not to be a leading slash
  75. if file[0] == '/' {
  76. file = file[1:]
  77. }
  78. f := nrsc.Get(file)
  79. if f == nil {
  80. return
  81. }
  82. rdr, err := f.Open()
  83. if err != nil {
  84. http.Error(res, "Internal Server Error", http.StatusInternalServerError)
  85. }
  86. defer rdr.Close()
  87. mtype := mime.TypeByExtension(filepath.Ext(req.URL.Path))
  88. if len(mtype) != 0 {
  89. res.Header().Set("Content-Type", mtype)
  90. }
  91. res.Header().Set("Content-Size", fmt.Sprintf("%d", f.Size()))
  92. res.Header().Set("Last-Modified", f.ModTime().UTC().Format(http.TimeFormat))
  93. io.Copy(res, rdr)
  94. }
  95. }