ベースパスを指定できるようにした

This commit is contained in:
yaoresugi 2025-10-20 22:52:36 +09:00
parent ca9f644bcc
commit 4d69c29bbe
17 changed files with 71 additions and 31 deletions

View file

@ -3,6 +3,7 @@ package api
import (
"net/http"
"strconv"
"strings"
"github.com/gin-gonic/gin"
@ -20,6 +21,9 @@ func saveConfigHandler(c *gin.Context) {
conf.AppConfig.NodePath = c.PostForm("node")
conf.AppConfig.ShoutURL = c.PostForm("shout")
basePath := c.PostForm("basepath")
conf.AppConfig.BasePath = strings.TrimRight(basePath, "/")
conf.Write(conf.AppConfig)
c.Redirect(http.StatusFound, c.Request.Referer())

View file

@ -8,7 +8,7 @@ import (
)
// Routes - start API routes
func Routes(router *gin.Engine) {
func Routes(router gin.IRouter) {
r0 := router.Group("/api")
{

View file

@ -13,6 +13,7 @@ func read(path string) (config models.Conf) {
viper.SetDefault("HOST", "0.0.0.0")
viper.SetDefault("PORT", "8840")
viper.SetDefault("BASE_PATH", "")
viper.SetDefault("THEME", "sand")
viper.SetDefault("COLOR", "dark")
viper.SetDefault("NODEPATH", "")
@ -40,6 +41,7 @@ func read(path string) (config models.Conf) {
config.Host = viper.Get("HOST").(string)
config.Port = viper.Get("PORT").(string)
config.BasePath = strings.Trim(viper.GetString("BASE_PATH"), "/")
config.Theme = viper.Get("THEME").(string)
config.Color = viper.Get("COLOR").(string)
config.NodePath = viper.Get("NODEPATH").(string)

View file

@ -19,6 +19,7 @@ func Write(config models.Conf) {
viper.Set("HOST", config.Host)
viper.Set("PORT", config.Port)
viper.Set("BASE_PATH", "") // Can be set only with ENV
viper.Set("THEME", config.Theme)
viper.Set("COLOR", config.Color)
viper.Set("NODEPATH", config.NodePath)

View file

@ -4,6 +4,7 @@ package models
type Conf struct {
Host string
Port string
BasePath string
Theme string
Color string
DirPath string

View file

@ -3,10 +3,19 @@ package web
import (
"net/http"
"github.com/aceberg/WatchYourLAN/internal/conf"
"github.com/gin-gonic/gin"
)
func indexHandler(c *gin.Context) {
basePath := ""
if conf.AppConfig.BasePath != "" {
basePath = "/" + conf.AppConfig.BasePath
}
c.HTML(http.StatusOK, "index.html", true)
data := gin.H{
"BasePath": basePath,
}
c.HTML(http.StatusOK, "index.html", data)
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -5,11 +5,17 @@
<title>WatchYourLAN</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Template data injection -->
<script>
window.appConfig = {
basePath: "{{ .BasePath }}",
};
</script>
<!--Favicon-->
<link rel="icon" type="image/x-icon" href="/fs/public/favicon.png">
<link rel="icon" type="image/x-icon" href="{{ .BasePath }}/fs/public/favicon.png">
<!-- JS & CSS -->
<script type="module" crossorigin src="/fs/public/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/fs/public/assets/index.css">
<script type="module" crossorigin src="{{ .BasePath }}/fs/public/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="{{ .BasePath }}/fs/public/assets/index.css">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View file

@ -41,7 +41,7 @@ func Gui() {
"\n Config dir: " + conf.AppConfig.DirPath +
"\n Default DB: " + conf.AppConfig.UseDB +
"\n Log level: " + conf.AppConfig.LogLevel +
"\n Web GUI: http://" + address +
"\n Web GUI: http://" + address + "/" + conf.AppConfig.BasePath +
"\n=================================== " + colorReset)
gin.SetMode(gin.ReleaseMode)
@ -51,15 +51,21 @@ func Gui() {
templ := template.Must(template.New("").ParseFS(templFS, "templates/*"))
router.SetHTMLTemplate(templ) // templates
router.StaticFS("/fs/", http.FS(pubFS)) // public
var routerGroup gin.IRouter = router
router.GET("/", indexHandler) // index.go
router.GET("/config", indexHandler) // index.go
router.GET("/history", indexHandler) // index.go
router.GET("/host/*any", indexHandler) // index.go
router.GET("/metrics", prometheus.Handler())
if conf.AppConfig.BasePath != "" {
routerGroup = router.Group(conf.AppConfig.BasePath)
}
api.Routes(router)
routerGroup.StaticFS("/fs/", http.FS(pubFS))
routerGroup.GET("/", indexHandler)
routerGroup.GET("/config", indexHandler)
routerGroup.GET("/history", indexHandler)
routerGroup.GET("/host/*any", indexHandler)
routerGroup.GET("/metrics", prometheus.Handler())
api.Routes(routerGroup)
err = router.Run(address)
check.IfError(err)

View file

@ -2,7 +2,7 @@ version: "3"
services:
wyl:
image: aceberg/watchyourlan
network_mode: "host"
network_mode: "host"
restart: unless-stopped
volumes:
- ~/.dockerdata/wyl:/data/WatchYourLAN
@ -11,6 +11,7 @@ services:
IFACES: "enp4s0 wlxf4ec3892dd51" # required: 1 or more interface
HOST: "0.0.0.0" # optional, default: 0.0.0.0
PORT: "8840" # optional, default: 8840
BASE_PATH: "" # optional
TIMEOUT: "120" # optional, time in seconds, default: 120
SHOUTRRR_URL: "" # optional, set url to notify
THEME: "sand" # optional
@ -19,7 +20,7 @@ services:
# WARNING! WYL needs 'host' network mode to work. So, WYL port will be exposed in this setup. You need to limit access to it with firewall or other measures
forauth:
image: aceberg/forauth
image: aceberg/forauth
restart: unless-stopped
ports:
- 8800:8800 # Proxy port
@ -28,10 +29,10 @@ services:
- ~/.dockerdata/forauth:/data/ForAuth
environment:
TZ: Asia/Novosibirsk # required: needs your TZ for correct time
FA_TARGET: "YOUR_IP:8840" # optional: path to wyl host:port
FA_TARGET: "YOUR_IP:8840" # optional: path to wyl host:port
FA_AUTH: "true" # optional: true - enabled, default: false
FA_AUTH_EXPIRE: 7d # optional: expiration time, default: 7d
FA_AUTH_PASSWORD: "$$2a$$10$$wGLUHXh2cRN1257uGg1s5eZvYgnjw8wB9vAcfcHqqqrxm5hvBqAzK"
FA_AUTH_PASSWORD: "$$2a$$10$$wGLUHXh2cRN1257uGg1s5eZvYgnjw8wB9vAcfcHqqqrxm5hvBqAzK"
# WARNING! If password is set as environment variable, every '$' character must be escaped with another '$', like this '$$'
# optional: password encrypted with bcrypt, how-to: https://github.com/aceberg/ForAuth/blob/main/docs/BCRYPT.md (In this example FA_AUTH_PASSWORD=pw)
FA_AUTH_USER: user # optional: username

View file

@ -9,7 +9,7 @@ services:
wyl:
image: aceberg/watchyourlan # dockerhub
# image: ghcr.io/aceberg/watchyourlan # or github
network_mode: "host"
network_mode: "host"
restart: unless-stopped
# uncomment those if you are using local node-bootstrap:
# command: "-n http://YOUR_IP:8850" # put your server IP or DNS name here
@ -22,6 +22,7 @@ services:
IFACES: "enp4s0 wlxf4ec3892dd51" # required: 1 or more interface
# HOST: "0.0.0.0" # optional, default: 0.0.0.0
# PORT: "8840" # optional, default: 8840
# BASE_PATH: "" # optional, default: "" (empty)
# TIMEOUT: "120" # optional, time in seconds, default: 120
# SHOUTRRR_URL: "" # optional, set url to notify
# THEME: "sand" # optional

View file

@ -1,12 +1,12 @@
{
"name": "watchyourlan",
"version": "2.1.3",
"version": "2.1.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "watchyourlan",
"version": "2.1.3",
"version": "2.1.4",
"dependencies": {
"@solid-primitives/scheduled": "^1.5.2",
"@solidjs/router": "^0.15.3",

View file

@ -22,7 +22,7 @@ function App() {
<div class="container-lg">
<div class="row">
<div class="col-md mt-4 mb-4">
<Router>
<Router base={window.appConfig?.basePath || ""}>
<Route path="/" component={Body}/>
<Route path="/config" component={Config}/>
<Route path="/history" component={History}/>

View file

@ -6,13 +6,13 @@ function Header() {
const [themePath, setThemePath] = createSignal('');
const [iconsPath, setIconsPath] = createSignal('');
const setCurrentTheme = async () => {
setAppConfig(await apiGetConfig());
const theme = appConfig().Theme?appConfig().Theme:"sand";
const color = appConfig().Color?appConfig().Color:"dark";
if (appConfig().NodePath == '') {
setThemePath("https://cdn.jsdelivr.net/npm/aceberg-bootswatch-fork@v5.3.3-2/dist/"+theme+"/bootstrap.min.css");
setIconsPath("https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css");
@ -35,17 +35,17 @@ function Header() {
<nav class="navbar navbar-expand-md navbar-dark bg-primary">
<div class="container-lg">
<a class="navbar-brand" href="/">
<img src="/fs/public/favicon.png" style="width: 2em"/>
<img src={window.appConfig?.basePath + "/fs/public/favicon.png"} style="width: 2em"/>
</a>
<ul class="navbar-nav me-auto mb-2 mb-md-0">
<li class="nav-item">
<a class="nav-link active" href="/" title="Home">Home</a>
<a class="nav-link active" href={window.appConfig?.basePath + "/"} title="Home">Home</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="/config/" title="Config">Config</a>
<a class="nav-link active" href={window.appConfig?.basePath + "/config/"} title="Config">Config</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="/history/" title="History">History</a>
<a class="nav-link active" href={window.appConfig?.basePath + "/history/"} title="History">History</a>
</li>
</ul>
<ul class="navbar-nav">

View file

@ -1,4 +1,4 @@
export const apiPath = 'http://0.0.0.0:8840';
export const apiPath = 'http://0.0.0.0:8840'+(window.appConfig?.basePath ?? '');
export const apiGetAllHosts = async () => {
const url = apiPath+'/api/all';

View file

@ -1 +1,10 @@
/// <reference types="vite/client" />
export {};
declare global {
interface Window {
appConfig: {
basePath: string;
};
}
}