navidrome/server/server.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

114 lines
3.0 KiB
Go
Raw Normal View History

2020-01-13 23:06:47 +01:00
package server
import (
2021-05-24 17:55:39 +02:00
"fmt"
"net/http"
2020-04-03 23:50:42 +02:00
"path"
"time"
2021-05-11 23:21:18 +02:00
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/httprate"
2020-01-24 01:44:08 +01:00
"github.com/navidrome/navidrome/conf"
2020-04-03 23:50:42 +02:00
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/core/auth"
2020-01-24 01:44:08 +01:00
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/ui"
)
2020-01-13 23:06:47 +01:00
type Server struct {
2021-06-14 01:15:41 +02:00
router *chi.Mux
ds model.DataStore
appRoot string
}
func New(ds model.DataStore) *Server {
2021-06-14 01:15:41 +02:00
s := &Server{ds: ds}
initialSetup(ds)
2021-06-14 01:15:41 +02:00
s.initRoutes()
2020-10-06 23:24:16 +02:00
checkFfmpegInstallation()
checkExternalCredentials()
2021-06-14 01:15:41 +02:00
return s
}
2021-06-14 01:15:41 +02:00
func (s *Server) MountRouter(description, urlPath string, subRouter http.Handler) {
2020-04-03 23:50:42 +02:00
urlPath = path.Join(conf.Server.BaseURL, urlPath)
2021-05-24 17:55:39 +02:00
log.Info(fmt.Sprintf("Mounting %s routes", description), "path", urlPath)
2021-06-14 01:15:41 +02:00
s.router.Group(func(r chi.Router) {
2020-04-03 23:50:42 +02:00
r.Mount(urlPath, subRouter)
})
}
var startTime = time.Now()
2021-06-14 01:15:41 +02:00
func (s *Server) Run(addr string) error {
s.MountRouter("WebUI", consts.URLPathUI, s.frontendAssetsHandler())
log.Info("Navidrome server is ready!", "address", addr, "startupTime", time.Since(startTime))
server := &http.Server{
Addr: addr,
ReadHeaderTimeout: consts.ServerReadHeaderTimeout,
2022-09-27 22:53:40 +02:00
Handler: s.router,
}
return server.ListenAndServe()
}
2021-06-14 01:15:41 +02:00
func (s *Server) initRoutes() {
auth.Init(s.ds)
s.appRoot = path.Join(conf.Server.BaseURL, consts.URLPathUI)
r := chi.NewRouter()
r.Use(secureMiddleware())
r.Use(corsHandler())
r.Use(middleware.RequestID)
if conf.Server.ReverseProxyWhitelist == "" {
r.Use(middleware.RealIP)
}
r.Use(middleware.Recoverer)
2020-01-09 06:18:55 +01:00
r.Use(middleware.Compress(5, "application/xml", "application/json", "application/javascript"))
r.Use(middleware.Heartbeat("/ping"))
r.Use(clientUniqueIdAdder)
r.Use(loggerInjector)
r.Use(requestLogger)
2021-07-21 00:43:15 +02:00
r.Use(robotsTXT(ui.BuildAssets()))
r.Use(authHeaderMapper)
r.Use(jwtVerifier)
r.Route(path.Join(conf.Server.BaseURL, "/auth"), func(r chi.Router) {
if conf.Server.AuthRequestLimit > 0 {
log.Info("Login rate limit set", "requestLimit", conf.Server.AuthRequestLimit,
"windowLength", conf.Server.AuthWindowLength)
rateLimiter := httprate.LimitByIP(conf.Server.AuthRequestLimit, conf.Server.AuthWindowLength)
2021-06-14 01:15:41 +02:00
r.With(rateLimiter).Post("/login", login(s.ds))
} else {
log.Warn("Login rate limit is disabled! Consider enabling it to be protected against brute-force attacks")
2021-06-14 01:15:41 +02:00
r.Post("/login", login(s.ds))
}
2021-06-14 01:15:41 +02:00
r.Post("/createAdmin", createAdmin(s.ds))
})
2021-06-14 01:15:41 +02:00
// Redirect root to UI URL
r.Get("/*", func(w http.ResponseWriter, r *http.Request) {
2021-06-14 01:15:41 +02:00
http.Redirect(w, r, s.appRoot+"/", http.StatusFound)
})
2021-06-14 01:15:41 +02:00
r.Get(s.appRoot, func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, s.appRoot+"/", http.StatusFound)
})
2020-01-20 01:34:54 +01:00
2021-06-14 01:15:41 +02:00
s.router = r
}
// Serve UI app assets
func (s *Server) frontendAssetsHandler() http.Handler {
r := chi.NewRouter()
2021-07-21 00:43:15 +02:00
r.Handle("/", serveIndex(s.ds, ui.BuildAssets()))
r.Handle("/*", http.StripPrefix(s.appRoot, http.FileServer(http.FS(ui.BuildAssets()))))
2021-06-14 01:15:41 +02:00
return r
}