Add BaseURL configuration (fixes #103)

This commit is contained in:
Deluan 2020-04-03 17:50:42 -04:00
parent b8eb22d162
commit 75cd21da1f
17 changed files with 61 additions and 25 deletions

View File

@ -100,6 +100,7 @@ services:
ND_PORT: 4533
ND_TRANSCODINGCACHESIZE: 100MB
ND_SESSIONTIMEOUT: 30m
ND_BASEURL: ""
volumes:
- "./data:/data"
- "/path/to/your/music/folder:/music:ro"

View File

@ -20,6 +20,7 @@ type nd struct {
DbPath string ``
LogLevel string `default:"info"`
SessionTimeout string `default:"30m"`
BaseURL string `default:""`
IgnoredArticles string `default:"The El La Los Las Le Les Os As O A"`
IndexGroups string `default:"A B C D E F G H I J K L M N O P Q R S T U V W X-Z(XYZ) [Unknown]([)"`

View File

@ -27,6 +27,9 @@ const (
DevInitialUserName = "admin"
DevInitialName = "Dev Admin"
URLPathUI = "/app"
URLPathSubsonicAPI = "/rest"
)
var (

View File

@ -15,6 +15,7 @@ services:
ND_PORT: 4533
ND_TRANSCODINGCACHESIZE: 100MB
ND_SESSIONTIMEOUT: 30m
ND_BASEURL: ""
volumes:
- "./data:/data"
- "./music:/music"

View File

@ -19,7 +19,7 @@ func main() {
panic(fmt.Sprintf("Could not create the Subsonic API router. Aborting! err=%v", err))
}
a := CreateServer(conf.Server.MusicFolder)
a.MountRouter("/rest", subsonic)
a.MountRouter("/app", CreateAppRouter("/app"))
a.MountRouter(consts.URLPathSubsonicAPI, subsonic)
a.MountRouter(consts.URLPathUI, CreateAppRouter())
a.Run(":" + conf.Server.Port)
}

View File

@ -15,22 +15,23 @@ import (
)
type Router struct {
ds model.DataStore
mux http.Handler
path string
ds model.DataStore
mux http.Handler
}
func New(ds model.DataStore, path string) *Router {
r := &Router{ds: ds, path: path}
r.mux = r.routes()
return r
func New(ds model.DataStore) *Router {
return &Router{ds: ds}
}
func (app *Router) Setup(path string) {
app.mux = app.routes(path)
}
func (app *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
app.mux.ServeHTTP(w, r)
}
func (app *Router) routes() http.Handler {
func (app *Router) routes(path string) http.Handler {
r := chi.NewRouter()
r.Post("/login", Login(app.ds))
@ -52,7 +53,7 @@ func (app *Router) routes() http.Handler {
// Serve UI app assets
r.Handle("/", ServeIndex(app.ds))
r.Handle("/*", http.StripPrefix(app.path, http.FileServer(assets.AssetFile())))
r.Handle("/*", http.StripPrefix(path, http.FileServer(assets.AssetFile())))
return r
}

View File

@ -5,8 +5,10 @@ import (
"html/template"
"io/ioutil"
"net/http"
"strings"
"github.com/deluan/navidrome/assets"
"github.com/deluan/navidrome/conf"
"github.com/deluan/navidrome/consts"
"github.com/deluan/navidrome/log"
"github.com/deluan/navidrome/model"
@ -31,6 +33,7 @@ func ServeIndex(ds model.DataStore) http.HandlerFunc {
t, _ = t.Parse(string(indexStr))
appConfig := map[string]interface{}{
"firstTime": firstTime,
"baseURL": strings.TrimSuffix(conf.Server.BaseURL, "/"),
}
j, _ := json.Marshal(appConfig)
data := map[string]interface{}{

View File

@ -3,10 +3,12 @@ package server
import (
"net/http"
"os"
"path"
"path/filepath"
"time"
"github.com/deluan/navidrome/conf"
"github.com/deluan/navidrome/consts"
"github.com/deluan/navidrome/log"
"github.com/deluan/navidrome/model"
"github.com/deluan/navidrome/scanner"
@ -15,6 +17,11 @@ import (
"github.com/go-chi/cors"
)
type Handler interface {
http.Handler
Setup(path string)
}
type Server struct {
Scanner *scanner.Scanner
router *chi.Mux
@ -29,11 +36,13 @@ func New(scanner *scanner.Scanner, ds model.DataStore) *Server {
return a
}
func (a *Server) MountRouter(path string, subRouter http.Handler) {
log.Info("Mounting routes", "path", path)
func (a *Server) MountRouter(urlPath string, subRouter Handler) {
urlPath = path.Join(conf.Server.BaseURL, urlPath)
log.Info("Mounting routes", "path", urlPath)
subRouter.Setup(urlPath)
a.router.Group(func(r chi.Router) {
r.Use(RequestLogger)
r.Mount(path, subRouter)
r.Mount(urlPath, subRouter)
})
}
@ -53,8 +62,9 @@ func (a *Server) initRoutes() {
r.Use(middleware.Heartbeat("/ping"))
r.Use(InjectLogger)
indexHtml := path.Join(conf.Server.BaseURL, consts.URLPathUI, "index.html")
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/app", 302)
http.Redirect(w, r, indexHtml, 302)
})
workDir, _ := os.Getwd()

View File

@ -42,6 +42,8 @@ func New(browser engine.Browser, cover engine.Cover, listGenerator engine.ListGe
return r
}
func (api *Router) Setup(path string) {}
func (api *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
api.mux.ServeHTTP(w, r)
}

View File

@ -25,7 +25,7 @@
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"homepage": "https://localhost/app/",
"homepage": ".",
"proxy": "http://localhost:4633/",
"eslintConfig": {
"extends": "react-app"

View File

@ -34,6 +34,7 @@ const App = () => {
if (appConfig.firstTime) {
localStorage.setItem('initialAccountCreation', 'true')
}
localStorage.setItem('baseURL', appConfig.baseURL)
} catch (e) {}
return (

View File

@ -1,11 +1,12 @@
import jwtDecode from 'jwt-decode'
import md5 from 'md5-hex'
import baseUrl from './utils/baseUrl'
const authProvider = {
login: ({ username, password }) => {
let url = '/app/login'
let url = baseUrl('/app/login')
if (localStorage.getItem('initialAccountCreation')) {
url = '/app/createAdmin'
url = baseUrl('/app/createAdmin')
}
const request = new Request(url, {
method: 'POST',

View File

@ -1,10 +1,12 @@
import { fetchUtils } from 'react-admin'
import jsonServerProvider from 'ra-data-json-server'
import baseUrl from './utils/baseUrl'
const baseUrl = '/app/api'
const restUrl = '/app/api'
const httpClient = (url, options = {}) => {
url = url.replace(baseUrl + '/albumSong', baseUrl + '/song')
url = baseUrl(url)
url = url.replace(restUrl + '/albumSong', restUrl + '/song')
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' })
}
@ -22,6 +24,6 @@ const httpClient = (url, options = {}) => {
})
}
const dataProvider = jsonServerProvider(baseUrl, httpClient)
const dataProvider = jsonServerProvider(restUrl, httpClient)
export default dataProvider

View File

@ -1,4 +1,5 @@
import { fetchUtils } from 'react-admin'
import baseUrl from "../utils/baseUrl"
const url = (command, id, options) => {
const params = new URLSearchParams()
@ -18,7 +19,8 @@ const url = (command, id, options) => {
params.append(k, options[k])
})
}
return `rest/${command}?${params.toString()}`
const url = `/rest/${command}?${params.toString()}`
return baseUrl(url)
}
const scrobble = (id, submit) => {

8
ui/src/utils/baseUrl.js Normal file
View File

@ -0,0 +1,8 @@
const baseUrl = (path) => {
const base = localStorage.getItem('baseURL') || ''
const parts = [base]
parts.push(path.replace(/^\//, ''))
return parts.join('/')
}
export default baseUrl

View File

@ -25,9 +25,9 @@ func CreateServer(musicFolder string) *server.Server {
return serverServer
}
func CreateAppRouter(path string) *app.Router {
func CreateAppRouter() *app.Router {
dataStore := persistence.New()
router := app.New(dataStore, path)
router := app.New(dataStore)
return router
}

View File

@ -27,7 +27,7 @@ func CreateServer(musicFolder string) *server.Server {
))
}
func CreateAppRouter(path string) *app.Router {
func CreateAppRouter() *app.Router {
panic(wire.Build(allProviders))
}