Skip to content

Commit

Permalink
feat: Support configurable base path for server (#714)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrishoage authored Nov 18, 2024
1 parent 6ce3fdd commit 444c452
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 10 deletions.
2 changes: 2 additions & 0 deletions docs/source/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Server Configuration
~~~~~~~~~~~~~~~~~~
- ``DAGU_HOST`` (``127.0.0.1``): Server binding host
- ``DAGU_PORT`` (``8080``): Server binding port
- ``DAGU_BASE_PATH`` (``""``): Base path to serve the application
- ``DAGU_TZ`` (``""``): Server timezone (default: system timezone)
- ``DAGU_CERT_FILE``: SSL certificate file path
- ``DAGU_KEY_FILE``: SSL key file path
Expand Down Expand Up @@ -59,6 +60,7 @@ Create ``admin.yaml`` in ``$HOME/.config/dagu/`` to override default settings. B
# Server Configuration
host: "127.0.0.1" # Web UI hostname
port: 8080 # Web UI port
basePath: "" # Base path to serve the application
tz: "Asia/Tokyo" # Timezone (e.g., "America/New_York")
# Directory Configuration
Expand Down
16 changes: 16 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"
"log"
"os"
"path"
"path/filepath"
"strconv"
"strings"
Expand Down Expand Up @@ -52,6 +53,7 @@ type Config struct {
IsAuthToken bool // Enable auth token for API
AuthToken string // Auth token for API
LatestStatusToday bool // Show latest status today or the latest status
BasePath string // Base path for the server
APIBaseURL string // Base URL for API
Debug bool // Enable debug mode (verbose logging)
LogFormat string // Log format
Expand Down Expand Up @@ -118,6 +120,18 @@ func Load() (*Config, error) {
cfg.Location = time.Local
}

if cfg.BasePath != "" {
cfg.BasePath = path.Clean(cfg.BasePath)

if !path.IsAbs(cfg.BasePath) {
cfg.BasePath = path.Join("/", cfg.BasePath)
}

if cfg.BasePath == "/" {
cfg.BasePath = ""
}
}

return &cfg, nil
}

Expand Down Expand Up @@ -168,6 +182,7 @@ func setupViper() error {
viper.SetDefault("host", "127.0.0.1")
viper.SetDefault("port", "8080")
viper.SetDefault("navbarTitle", "Dagu")
viper.SetDefault("basePath", "")
viper.SetDefault("apiBaseURL", "/api/v1")

// Set executable path
Expand Down Expand Up @@ -198,6 +213,7 @@ func bindEnvs() {
_ = viper.BindEnv("logEncodingCharset", "DAGU_LOG_ENCODING_CHARSET")
_ = viper.BindEnv("navbarColor", "DAGU_NAVBAR_COLOR")
_ = viper.BindEnv("navbarTitle", "DAGU_NAVBAR_TITLE")
_ = viper.BindEnv("basePath", "DAGU_BASE_PATH")
_ = viper.BindEnv("apiBaseURL", "DAGU_API_BASE_URL")
_ = viper.BindEnv("tz", "DAGU_TZ")

Expand Down
1 change: 1 addition & 0 deletions internal/frontend/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func New(cfg *config.Config, lg logger.Logger, cli client.Client) *server.Server
AssetsFS: assetsFS,
NavbarColor: cfg.NavbarColor,
NavbarTitle: cfg.NavbarTitle,
BasePath: cfg.BasePath,
APIBaseURL: cfg.APIBaseURL,
TimeZone: cfg.TZ,
}
Expand Down
18 changes: 14 additions & 4 deletions internal/frontend/middleware/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,15 @@ var (
authBasic *AuthBasic
authToken *AuthToken
appLogger logger.Logger
basePath string
)

type Options struct {
Handler http.Handler
AuthBasic *AuthBasic
AuthToken *AuthToken
Logger logger.Logger
BasePath string
}

type AuthBasic struct {
Expand All @@ -95,16 +97,24 @@ func Setup(opts *Options) {
authBasic = opts.AuthBasic
authToken = opts.AuthToken
appLogger = opts.Logger
basePath = opts.BasePath
}

func prefixChecker(next http.Handler) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api") {
next.ServeHTTP(w, r)
} else {
defaultHandler.ServeHTTP(w, r)
if basePath != "" && r.URL.Path == "/" {
http.Redirect(w, r, basePath, http.StatusSeeOther)
return
}

http.StripPrefix(basePath, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api") {
next.ServeHTTP(w, r)
} else {
defaultHandler.ServeHTTP(w, r)
}
})).ServeHTTP(w, r)
})
}

Expand Down
7 changes: 5 additions & 2 deletions internal/frontend/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type NewServerArgs struct {
// Configuration for the frontend
NavbarColor string
NavbarTitle string
BasePath string
APIBaseURL string
TimeZone string
}
Expand Down Expand Up @@ -92,6 +93,7 @@ func New(params NewServerArgs) *Server {
funcsConfig: funcsConfig{
NavbarColor: params.NavbarColor,
NavbarTitle: params.NavbarTitle,
BasePath: params.BasePath,
APIBaseURL: params.APIBaseURL,
TZ: params.TimeZone,
},
Expand All @@ -110,8 +112,9 @@ func (svr *Server) Shutdown() {

func (svr *Server) Serve(ctx context.Context) (err error) {
middlewareOptions := &pkgmiddleware.Options{
Handler: svr.defaultRoutes(chi.NewRouter()),
Logger: svr.logger,
Handler: svr.defaultRoutes(chi.NewRouter()),
Logger: svr.logger,
BasePath: svr.funcsConfig.BasePath,
}
if svr.authToken != nil {
middlewareOptions.AuthToken = &pkgmiddleware.AuthToken{
Expand Down
7 changes: 6 additions & 1 deletion internal/frontend/server/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"bytes"
"io"
"net/http"
"path"
"path/filepath"
"text/template"

Expand Down Expand Up @@ -56,6 +57,7 @@ func (srv *Server) useTemplate(
type funcsConfig struct {
NavbarColor string
NavbarTitle string
BasePath string
APIBaseURL string
TZ string
}
Expand All @@ -78,8 +80,11 @@ func defaultFunctions(cfg funcsConfig) template.FuncMap {
"navbarTitle": func() string {
return cfg.NavbarTitle
},
"basePath": func() string {
return cfg.BasePath
},
"apiURL": func() string {
return cfg.APIBaseURL
return path.Join(cfg.BasePath, cfg.APIBaseURL)
},
"tz": func() string {
return cfg.TZ
Expand Down
3 changes: 2 additions & 1 deletion internal/frontend/templates/base.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
function getConfig() {
return {
apiURL: "{{ apiURL }}",
basePath: "{{ basePath }}",
title: "{{ navbarTitle }}",
navbarColor: "{{ navbarColor }}",
version: "{{ version }}",
tz: "{{ tz }}",
};
}
</script>
<script defer="defer" src="/assets/bundle.js?v={{ version }}"></script>
<script defer="defer" src="{{ basePath }}/assets/bundle.js?v={{ version }}"></script>
</head>
<body>
{{template "content" .}}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function App({ config }: Props) {
>
<ConfigContext.Provider value={config}>
<UserPreferencesProvider>
<BrowserRouter>
<BrowserRouter basename={config.basePath}>
<Layout {...config}>
<Routes>
<Route path="/" element={<Dashboard />} />
Expand Down
1 change: 1 addition & 0 deletions ui/src/contexts/ConfigContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createContext, useContext } from 'react';

export type Config = {
apiURL: string;
basePath: string;
title: string;
navbarColor: string;
tz: string;
Expand Down
2 changes: 1 addition & 1 deletion ui/webpack.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module.exports = merge(common, {
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/assets/',
publicPath: 'auto',
clean: true,
},
});

0 comments on commit 444c452

Please sign in to comment.