Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d62d0aa11c | ||
|
|
b78c92b2df | ||
|
|
037a131b66 | ||
|
|
970c0d0430 | ||
|
|
fb99e88487 | ||
|
|
1a827e04f4 | ||
|
|
1f663e1fd5 | ||
|
|
6606956d68 | ||
|
|
ade07f7450 | ||
|
|
ab4d896efc | ||
|
|
c2b3d19a51 | ||
|
|
de57fbd262 |
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
@@ -19,15 +19,42 @@ jobs:
|
||||
goarch: s390x
|
||||
- goos: linux
|
||||
goarch: arm64
|
||||
|
||||
|
||||
name: Build artifacts
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: goreleaser/goreleaser-cross:v1.23
|
||||
steps:
|
||||
- run: git config --global --add safe.directory /__w/nezha/nezha
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: robinraju/release-downloader@v1
|
||||
with:
|
||||
repository: nezhahq/admin-frontend
|
||||
tag: v1.0.4
|
||||
fileName: dist.zip
|
||||
latest: true
|
||||
extract: true
|
||||
|
||||
- name: prepare admin-frontend dists
|
||||
run: |
|
||||
rm -rf cmd/dashboard/admin-dist
|
||||
mv dist cmd/dashboard/admin-dist
|
||||
|
||||
- uses: robinraju/release-downloader@v1
|
||||
with:
|
||||
repository: nezhahq/user-frontend
|
||||
tag: v1.0.3
|
||||
fileName: dist.zip
|
||||
latest: true
|
||||
extract: true
|
||||
|
||||
- name: prepare admin-frontend dists
|
||||
run: |
|
||||
rm -rf cmd/dashboard/user-dist
|
||||
mv dist cmd/dashboard/user-dist
|
||||
|
||||
- name: Fetch IPInfo GeoIP Database
|
||||
env:
|
||||
IPINFO_TOKEN: ${{ secrets.IPINFO_TOKEN }}
|
||||
@@ -44,7 +71,7 @@ jobs:
|
||||
run: |
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
swag init --pd -d . -g ./cmd/dashboard/main.go -o ./cmd/dashboard/docs --parseGoList=false
|
||||
|
||||
|
||||
- name: Build with tag
|
||||
if: contains(github.ref, 'refs/tags/')
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
@@ -54,7 +81,7 @@ jobs:
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: '~> v2'
|
||||
version: "~> v2"
|
||||
args: build --single-target --clean --skip=validate
|
||||
|
||||
- name: Build snapshot
|
||||
@@ -66,7 +93,7 @@ jobs:
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: '~> v2'
|
||||
version: "~> v2"
|
||||
args: build --single-target --clean --skip=validate --snapshot
|
||||
|
||||
- name: Upload artifacts
|
||||
@@ -89,12 +116,11 @@ jobs:
|
||||
|
||||
- name: Archive and compress binaries
|
||||
run: |
|
||||
for file in assets/*/*/*; do
|
||||
if [ -f "$file" ]; then
|
||||
chmod +x "$file"
|
||||
export fileWithoutExt=${file%.*}
|
||||
zip -jr "$fileWithoutExt.zip" "$file"
|
||||
fi
|
||||
find assets/*/*/* -type f | while read -r file; do
|
||||
dir=$(dirname "$file")
|
||||
filename=$(basename "$file")
|
||||
fileWithoutExt="${filename%.*}"
|
||||
zip -jr "$dir/$fileWithoutExt.zip" "$file"
|
||||
done
|
||||
|
||||
- name: Release
|
||||
@@ -131,30 +157,6 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: robinraju/release-downloader@v1
|
||||
with:
|
||||
repository: nezhahq/admin-frontend
|
||||
tag: v1.0.3
|
||||
fileName: dist.zip
|
||||
latest: true
|
||||
extract: true
|
||||
|
||||
- name: prepare admin-frontend dists
|
||||
run: |
|
||||
mv dist admin-dist
|
||||
|
||||
- uses: robinraju/release-downloader@v1
|
||||
with:
|
||||
repository: nezhahq/user-frontend
|
||||
tag: v1.0.2
|
||||
fileName: dist.zip
|
||||
latest: true
|
||||
extract: true
|
||||
|
||||
- name: prepare admin-frontend dists
|
||||
run: |
|
||||
mv dist user-dist
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -201,7 +203,7 @@ jobs:
|
||||
run: |
|
||||
GHCR_IMAGE_NAME=$(echo "ghcr.io/${{ github.repository_owner }}/nezha" | tr '[:upper:]' '[:lower:]')
|
||||
if [ ${{ github.repository_owner }} = "nezhahq" ]
|
||||
then ALI_IMAGE_NAME=$(echo "registry.cn-shanghai.aliyuncs.com/nezhahq/nezha-dashboard")
|
||||
then ALI_IMAGE_NAME=$(echo "registry.cn-shanghai.aliyuncs.com/naibahq/nezha-dashboard")
|
||||
else ALI_IMAGE_NAME=$(echo "registry.cn-shanghai.aliyuncs.com/${{ github.repository_owner }}/nezha-dashboard" | tr '[:upper:]' '[:lower:]')
|
||||
fi
|
||||
echo "GHCR_IMAGE_NAME=$GHCR_IMAGE_NAME" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -13,4 +13,4 @@ jobs:
|
||||
with:
|
||||
destination_repository: [email protected]:naibahq/nezha.git
|
||||
destination_branch_name: master
|
||||
destination_ssh_key: ${{ secrets.GITLAB_SSH_KEY }}
|
||||
destination_ssh_key: ${{ secrets.GITEE_SSH_KEY }}
|
||||
|
||||
@@ -6,6 +6,7 @@ on:
|
||||
jobs:
|
||||
sync-release-to-gitee:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
GITEE_TOKEN: ${{ secrets.GITEE_TOKEN }}
|
||||
steps:
|
||||
|
||||
@@ -32,6 +32,8 @@ jobs:
|
||||
- name: generate swagger docs
|
||||
run: |
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
touch ./cmd/dashboard/user-dist/a
|
||||
touch ./cmd/dashboard/admin-dist/a
|
||||
swag init --pd -d . -g ./cmd/dashboard/main.go -o ./cmd/dashboard/docs --parseGoList=false
|
||||
|
||||
- name: Unit test
|
||||
|
||||
+4
-2
@@ -17,8 +17,10 @@
|
||||
.DS_Store
|
||||
/cmd/dashboard/data
|
||||
/cmd/dashboard/main
|
||||
/cmd/dashboard/admin-dist
|
||||
/cmd/dashboard/user-dist
|
||||
/cmd/dashboard/admin-dist/*
|
||||
/cmd/dashboard/user-dist/*
|
||||
!/cmd/dashboard/admin-dist/.gitkeep
|
||||
!/cmd/dashboard/user-dist/.gitkeep
|
||||
/config.yml
|
||||
/resource/template/theme-custom
|
||||
/resource/static/custom
|
||||
|
||||
@@ -7,8 +7,6 @@ ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
||||
COPY --from=certs /etc/ssl/certs /etc/ssl/certs
|
||||
COPY ./admin-dist /dashboard/admin-dist
|
||||
COPY ./user-dist /dashboard/user-dist
|
||||
COPY ./script/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div align="center">
|
||||
<br>
|
||||
<img width="360" style="max-width:80%" src="resource/static/brand.svg" title="哪吒监控 Nezha Monitoring">
|
||||
<img width="360" style="max-width:80%" src=".github/brand.svg" title="哪吒监控 Nezha Monitoring">
|
||||
<br>
|
||||
<small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
|
||||
<br><br>
|
||||
@@ -24,11 +24,10 @@
|
||||
|
||||
## Screenshots
|
||||
|
||||
| Default Theme | DayNight [@JackieSung](https://github.com/JackieSung4ev) | hotaru |
|
||||
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
|
||||
|  | <img src="resource/template/theme-daynight/screenshot.png" width="3000px"/> | <img src="resource/template/theme-hotaru/screenshot.png" width="1500px" /> |
|
||||
| <div align="center"><b>Neko Mdui <a href="https://github.com/MikoyChinese">@MikoyChinese</a></b></div> | <div align="center"><b>AngelKanade <a href="https://github.com/adminsama">@adminsama</a></b></div> |<div align="center"><b>ServerStatus <a href="https://github.com/unclezs">@unclezs</a></b></div> |
|
||||
|  |  |  |
|
||||
| 用户前台 [@hamster1963](https://github.com/hamster1963) | 管理后台 [@uubulb](https://github.com/uubulb) |
|
||||
|---|---|
|
||||
|  |  |
|
||||
| [hamster1963/nezha-dash-react](https://github.com/hamster1963/nezha-dash-react) | [nezhahq/admin-frontend](https://github.com/nezhahq/admin-frontend) |
|
||||
|
||||
## Supported Languages
|
||||
|
||||
@@ -41,9 +40,9 @@ You can change the dashboard language in the settings page (`/setting`) after th
|
||||
## Contributors
|
||||
|
||||
<!--GAMFC_DELIMITER--><a href="https://github.com/naiba" title="naiba"><img src="https://avatars.githubusercontent.com/u/29243953?v=4" width="50;" alt="naiba"/></a>
|
||||
<a href="https://github.com/uubulb" title="UUBulb"><img src="https://avatars.githubusercontent.com/u/35923940?v=4" width="50;" alt="UUBulb"/></a>
|
||||
<a href="https://github.com/AkkiaS7" title="Akkia"><img src="https://avatars.githubusercontent.com/u/68485070?v=4" width="50;" alt="Akkia"/></a>
|
||||
<a href="https://github.com/Erope" title="卖女孩的小火柴"><img src="https://avatars.githubusercontent.com/u/44471469?v=4" width="50;" alt="卖女孩的小火柴"/></a>
|
||||
<a href="https://github.com/uubulb" title="UUBulb"><img src="https://avatars.githubusercontent.com/u/35923940?v=4" width="50;" alt="UUBulb"/></a>
|
||||
<a href="https://github.com/nap0o" title="nap0o"><img src="https://avatars.githubusercontent.com/u/144927971?v=4" width="50;" alt="nap0o"/></a>
|
||||
<a href="https://github.com/dysf888" title="黑歌"><img src="https://avatars.githubusercontent.com/u/47450409?v=4" width="50;" alt="黑歌"/></a>
|
||||
<a href="https://github.com/xykt" title="xykt"><img src="https://avatars.githubusercontent.com/u/152045469?v=4" width="50;" alt="xykt"/></a>
|
||||
@@ -87,7 +86,6 @@ You can change the dashboard language in the settings page (`/setting`) after th
|
||||
<a href="https://github.com/Moraxyc" title="Moraxyc"><img src="https://avatars.githubusercontent.com/u/69713071?v=4" width="50;" alt="Moraxyc"/></a>
|
||||
<a href="https://github.com/silver-ymz" title="Mingzhuo Yin"><img src="https://avatars.githubusercontent.com/u/78400701?v=4" width="50;" alt="Mingzhuo Yin"/></a>
|
||||
<a href="https://github.com/MartijnLindeman" title="Martijn Lindeman"><img src="https://avatars.githubusercontent.com/u/78365708?v=4" width="50;" alt="Martijn Lindeman"/></a>
|
||||
<a href="https://github.com/xrgzs" title="MadDogOwner"><img src="https://avatars.githubusercontent.com/u/26499123?v=4" width="50;" alt="MadDogOwner"/></a>
|
||||
<a href="https://github.com/funnyzak" title="Leon"><img src="https://avatars.githubusercontent.com/u/2562087?v=4" width="50;" alt="Leon"/></a>
|
||||
<a href="https://github.com/KorenKrita" title="KorenKrita"><img src="https://avatars.githubusercontent.com/u/22239339?v=4" width="50;" alt="KorenKrita"/></a>
|
||||
<a href="https://github.com/techotaku" title="Ian Li"><img src="https://avatars.githubusercontent.com/u/1948179?v=4" width="50;" alt="Ian Li"/></a>
|
||||
|
||||
@@ -3,6 +3,8 @@ package controller
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -21,7 +23,7 @@ import (
|
||||
"github.com/nezhahq/nezha/service/singleton"
|
||||
)
|
||||
|
||||
func ServeWeb() http.Handler {
|
||||
func ServeWeb(adminFrontend, userFrontend fs.FS) http.Handler {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.Default()
|
||||
|
||||
@@ -37,12 +39,13 @@ func ServeWeb() http.Handler {
|
||||
r.Use(waf.RealIp)
|
||||
r.Use(waf.Waf)
|
||||
r.Use(recordPath)
|
||||
routers(r)
|
||||
|
||||
routers(r, adminFrontend, userFrontend)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func routers(r *gin.Engine) {
|
||||
func routers(r *gin.Engine, adminFrontend, userFrontend fs.FS) {
|
||||
authMiddleware, err := jwt.New(initParams())
|
||||
if err != nil {
|
||||
log.Fatal("JWT Error:" + err.Error())
|
||||
@@ -129,7 +132,7 @@ func routers(r *gin.Engine) {
|
||||
|
||||
auth.PATCH("/setting", commonHandler(updateConfig))
|
||||
|
||||
r.NoRoute(fallbackToFrontend)
|
||||
r.NoRoute(fallbackToFrontend(adminFrontend, userFrontend))
|
||||
}
|
||||
|
||||
func recordPath(c *gin.Context) {
|
||||
@@ -208,25 +211,49 @@ func commonHandler[T any](handler handlerFunc[T]) func(*gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func fallbackToFrontend(c *gin.Context) {
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/api") {
|
||||
c.JSON(http.StatusOK, newErrorResponse(errors.New("404 Not Found")))
|
||||
return
|
||||
func fallbackToFrontend(adminFrontend, userFrontend fs.FS) func(*gin.Context) {
|
||||
checkLocalFileOrFs := func(c *gin.Context, fs fs.FS, path string) bool {
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
c.File(path)
|
||||
return true
|
||||
}
|
||||
f, err := fs.Open(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
fileStat, err := f.Stat()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if fileStat.IsDir() {
|
||||
return false
|
||||
}
|
||||
http.ServeContent(c.Writer, c.Request, path, fileStat.ModTime(), f.(io.ReadSeeker))
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/dashboard") {
|
||||
stripPath := strings.TrimPrefix(c.Request.URL.Path, "/dashboard")
|
||||
localFilePath := filepath.Join("./admin-dist", stripPath)
|
||||
if _, err := os.Stat(localFilePath); err == nil {
|
||||
c.File(localFilePath)
|
||||
return func(c *gin.Context) {
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/api") {
|
||||
c.JSON(http.StatusOK, newErrorResponse(errors.New("404 Not Found")))
|
||||
return
|
||||
}
|
||||
c.File("admin-dist/index.html")
|
||||
return
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/dashboard") {
|
||||
stripPath := strings.TrimPrefix(c.Request.URL.Path, "/dashboard")
|
||||
localFilePath := filepath.Join("admin-dist", stripPath)
|
||||
if checkLocalFileOrFs(c, adminFrontend, localFilePath) {
|
||||
return
|
||||
}
|
||||
if !checkLocalFileOrFs(c, adminFrontend, "admin-dist/index.html") {
|
||||
c.JSON(http.StatusOK, newErrorResponse(errors.New("404 Not Found")))
|
||||
}
|
||||
return
|
||||
}
|
||||
localFilePath := filepath.Join("user-dist", c.Request.URL.Path)
|
||||
if checkLocalFileOrFs(c, userFrontend, localFilePath) {
|
||||
return
|
||||
}
|
||||
if !checkLocalFileOrFs(c, userFrontend, "user-dist/index.html") {
|
||||
c.JSON(http.StatusOK, newErrorResponse(errors.New("404 Not Found")))
|
||||
}
|
||||
}
|
||||
localFilePath := filepath.Join("user-dist", c.Request.URL.Path)
|
||||
if _, err := os.Stat(localFilePath); err == nil {
|
||||
c.File(localFilePath)
|
||||
return
|
||||
}
|
||||
c.File("user-dist/index.html")
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
_ "embed"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -32,6 +34,10 @@ type DashboardCliParam struct {
|
||||
|
||||
var (
|
||||
dashboardCliParam DashboardCliParam
|
||||
//go:embed admin-dist
|
||||
adminFrontend embed.FS
|
||||
//go:embed user-dist
|
||||
userFrontend embed.FS
|
||||
)
|
||||
|
||||
func initSystem() {
|
||||
@@ -119,7 +125,7 @@ func main() {
|
||||
singleton.NewServiceSentinel(serviceSentinelDispatchBus)
|
||||
|
||||
grpcHandler := rpc.ServeRPC()
|
||||
httpHandler := controller.ServeWeb()
|
||||
httpHandler := controller.ServeWeb(adminFrontend, userFrontend)
|
||||
controller.InitUpgrader()
|
||||
|
||||
muxHandler := newHTTPandGRPCMux(httpHandler, grpcHandler)
|
||||
|
||||
@@ -28,7 +28,6 @@ require (
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/swaggo/files v1.0.1
|
||||
github.com/swaggo/gin-swagger v1.6.0
|
||||
github.com/swaggo/swag v1.16.4
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
golang.org/x/crypto v0.28.0
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
|
||||
@@ -62,7 +61,7 @@ require (
|
||||
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
@@ -80,6 +79,7 @@ require (
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/swaggo/swag v1.16.4 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
|
||||
@@ -66,8 +66,8 @@ github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlnd
|
||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
touch ./cmd/dashboard/user-dist/a
|
||||
touch ./cmd/dashboard/admin-dist/a
|
||||
swag init --pd -d . -g ./cmd/dashboard/main.go -o ./cmd/dashboard/docs --requiredByDefault
|
||||
protoc --go-grpc_out="require_unimplemented_servers=false:." --go_out="." proto/*.proto
|
||||
rm -rf ../agent/proto
|
||||
|
||||
Reference in New Issue
Block a user