webuiServer.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package httpservers
  2. import (
  3. "net/http"
  4. "os"
  5. "path"
  6. log "github.com/sirupsen/logrus"
  7. "github.com/jamesread/golure/pkg/dirs"
  8. config "github.com/OliveTin/OliveTin/internal/config"
  9. )
  10. type webUIServer struct {
  11. cfg *config.Config
  12. webuiDir string
  13. }
  14. var (
  15. customThemeCss []byte
  16. customThemeCssRead = false
  17. )
  18. func NewWebUIServer(cfg *config.Config) *webUIServer {
  19. s := &webUIServer{
  20. cfg: cfg,
  21. }
  22. s.webuiDir = s.findWebuiDir()
  23. s.setupCustomWebuiDir()
  24. return s
  25. }
  26. func (s *webUIServer) handleWebui(w http.ResponseWriter, r *http.Request) {
  27. // dirName := path.Dir(r.URL.Path)
  28. // Mangle requests for any path like /logs or /config to load the webui index.html
  29. if path.Ext(r.URL.Path) == "" && r.URL.Path != "/" {
  30. log.Debugf("Mangling request for %s to /index.html", r.URL.Path)
  31. http.ServeFile(w, r, path.Join(s.webuiDir, "index.html"))
  32. } else {
  33. log.Tracef("Serving webui from %s for %s", s.webuiDir, r.URL.Path)
  34. http.ServeFile(w, r, path.Join(s.webuiDir, r.URL.Path))
  35. // http.StripPrefix(dirName, http.FileServer(http.Dir(s.webuiDir))).ServeHTTP(w, r)
  36. }
  37. }
  38. func (s *webUIServer) findWebuiDir() string {
  39. directoriesToSearch := []string{
  40. s.cfg.WebUIDir,
  41. "../frontend/dist/",
  42. "../webui/",
  43. "../frontend/",
  44. "/usr/share/OliveTin/frontend/",
  45. "/usr/share/OliveTin/webui/",
  46. "/var/www/OliveTin/",
  47. "/var/www/olivetin/",
  48. "/etc/OliveTin/frontend/",
  49. }
  50. dir, err := dirs.GetFirstExistingDirectory("webui", directoriesToSearch)
  51. if err != nil {
  52. log.Warnf("Did not find the webui directory, you will probably get 404 errors.")
  53. return "./webui" // Should not exist
  54. }
  55. log.Infof("Using webui directory: %s", dir)
  56. return dir
  57. }
  58. func (s *webUIServer) findCustomWebuiDir() string {
  59. dir := path.Join(s.cfg.GetDir(), "custom-webui")
  60. return dir
  61. }
  62. func (s *webUIServer) setupCustomWebuiDir() {
  63. dir := s.findCustomWebuiDir()
  64. err := os.MkdirAll(path.Join(dir, "themes/"), 0775)
  65. if err != nil {
  66. log.Warnf("Could not create themes directory: %v", err)
  67. }
  68. }
  69. func shouldReloadThemeCss() bool {
  70. return !customThemeCssRead
  71. }
  72. func loadThemeCssFromFile(filename string) []byte {
  73. _, err := os.Stat(filename)
  74. if err == nil {
  75. css, err := os.ReadFile(filename)
  76. if err != nil {
  77. log.Tracef("Theme CSS file not read: %s", filename)
  78. return nil
  79. }
  80. return css
  81. }
  82. log.Tracef("Theme CSS file not found: %s", filename)
  83. return nil
  84. }
  85. func (s *webUIServer) generateThemeCss(w http.ResponseWriter, r *http.Request) {
  86. themeCssFilename := path.Join(s.findCustomWebuiDir(), "themes", s.cfg.ThemeName, "theme.css")
  87. if shouldReloadThemeCss() || s.cfg.ThemeCacheDisabled {
  88. customThemeCssRead = true
  89. customThemeCss = loadThemeCssFromFile(themeCssFilename)
  90. }
  91. w.Header().Add("Content-Type", "text/css")
  92. _, err := w.Write(customThemeCss)
  93. if err != nil {
  94. log.WithFields(log.Fields{
  95. "error": err,
  96. }).Warnf("Failed to write theme CSS")
  97. }
  98. }
  99. func (s *webUIServer) handleCustomWebui() http.Handler {
  100. return http.StripPrefix("/custom-webui/", http.FileServer(http.Dir(s.findCustomWebuiDir())))
  101. }