Compare commits

...
24 Commits
Author SHA1 Message Date
naiba 60bfb4cb65 fix: config persistence 2024-11-14 20:21:02 +08:00
github-actions[bot] 9e730cc2cb update contributors[no ci] 2024-11-13 15:18:13 +00:00
naiba 08d9d14161 fix: remove debug code 2024-11-13 23:17:52 +08:00
Chotow 9b6d8ad0f2 feat(config): reading from env variables (#474)
* chore(config): remove agent config

* feat(config): support env variables

* refactor(config): ordinal priority
2024-11-13 23:12:48 +08:00
github-actions[bot] bd0d355bd6 update contributors[no ci] 2024-11-13 15:03:51 +00:00
006lp 40ae067f99 为Hotaru和DayNight主题添加南极洲地区图片 (#473)
* 为Hotaru主题上传南极洲地区图片

发现Hotaru主题不能显示南极洲服务器的图片,
![我的服务器状态](https://pan.006lp.top:5245/d/temp/nezha-AQ/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE%202024-11-09%20165621.png?sign=XIRYPIJ5Q_QXmD588OC2Hszy1TS9XyQ3Xw3mOf49X8w=:0)
于是索性自己做了一张图片。
[原图](https://pan.006lp.top:5245/temp/nezha-AQ/aq.svg)已存档于我的网盘,由于是640*480分辨率,与主题文件夹下其他图片70*47不同,于是我通过PS先扩展成710*480分辨率再通过二次立方重新采样成70*47分辨率。

* 为daynight主题添加南极洲地区图片

由原图640*480扩展成700*480,再经过二次立方重新采样成35*24分辨率
2024-11-13 23:03:28 +08:00
github-actions[bot] 11c29d14ad update contributors[no ci] 2024-11-06 15:38:33 +00:00
Tao Chen f4b7483807 Add API to register server (#472) 2024-11-06 23:38:15 +08:00
UUBulb 3d6edd602c ci: fix permission when packaging; move installer to another repository (#470)
* installer: fix permission & move to another repository

* update gitee url

* update resource

* ci: fix permission
2024-11-06 16:44:31 +08:00
UUBulb 2590815a6c ci: fix arm64 path parsing (#468) 2024-11-05 22:54:02 +08:00
nap0o c20dfdc7a3 improve: status-server主题日常优化 (#467)
* improve: status-server主题日常优化
1.首页vps套餐流量增加一种类型max(in,out)类型,感谢@hi2global
2.network页修复逻辑缺陷
3.一些其他小优化

演示地址 https://dev.nezha.pp.ua/

* 修正 NetTransfer 展示方式
2024-11-04 23:11:24 +08:00
nap0o 96c3fd433f feat: status-server主题增加套餐信息展示 (#464)
* feat: status-server主题增加套餐信息展示
1. 首页通过在后台配置PublicNote字段,实现agent套餐信息展示
2. 一些其他小优化

* 1.未获取agent国家时,默认彩虹旗修改为联合国旗
2024-11-01 21:28:14 +08:00
github-actions[bot] 45b0f1edfc update contributors[no ci] 2024-10-30 16:15:58 +00:00
Moraxyc 61fdcd2a9e fix(cli): display version before init app (#463) 2024-10-31 00:15:41 +08:00
UUBulb a474b8484b ddns: replace tencentcloud implemention (#462) 2024-10-29 21:39:45 +08:00
UUBulb 67b003a27d installer: fix download service scripts (#449) 2024-10-22 13:02:54 +08:00
UUBulb 99aeda7939 installer: fix format (#448) 2024-10-22 10:25:31 +08:00
UUBulb d5744d0c73 fix installer (#442)
* fix installer

* version
2024-10-20 00:33:28 +08:00
UUBulb e7837d8eaf installer: fix some style issues (#441)
* installer: fix some style issues

* translate

* translate

* replace cf-ns
2024-10-19 22:03:00 +08:00
UUBulb aa81fc02ab fix: add custom theme key (#440) 2024-10-19 11:59:31 +08:00
UUBulb f6531a52bd ddns: remove ipv6 nameservers, support custom nameservers (#439) 2024-10-18 22:06:01 +08:00
UUBulb c58c4f866a do not check description file for theme-custom (#437)
* do not check description file for theme-custom

* deprecation note
2024-10-18 12:26:59 +08:00
UUBulb fc9f1b6bcc fix(ddns): handle second-level domain correctly (#438) 2024-10-18 12:26:43 +08:00
UUBulb be7b6e9c5e fix(ddns): add missing field WebhookRequestType (#436)
* fix(ddns): add missing field WebhookRequestType

* add missing placeholders
2024-10-17 23:35:28 +08:00
45 changed files with 848 additions and 418 deletions
+8
View File
@@ -0,0 +1,8 @@
.git
.gitignore
docker-compose.yml
Dockerfile
Dockerfile.dev
data/*
+11 -11
View File
@@ -17,7 +17,7 @@ jobs:
goarch: s390x goarch: s390x
- goos: linux - goos: linux
goarch: arm64 goarch: arm64
name: Build artifacts name: Build artifacts
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@@ -44,12 +44,12 @@ jobs:
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: "1.23.x" go-version: "1.23.x"
- name: Build - name: Build
uses: goreleaser/goreleaser-action@v6 uses: goreleaser/goreleaser-action@v6
with: with:
distribution: goreleaser distribution: goreleaser
version: '~> v2' version: "~> v2"
args: build --single-target --clean --skip=validate args: build --single-target --clean --skip=validate
- name: Upload artifacts - name: Upload artifacts
@@ -72,12 +72,12 @@ jobs:
- name: Archive and compress binaries - name: Archive and compress binaries
run: | run: |
for file in assets/*/*/*; do find assets/*/*/* -type f | while read -r file; do
if [ -f "$file" ]; then chmod +x $file
chmod +x "$file" dir=$(dirname "$file")
export fileWithoutExt=${file%.*} filename=$(basename "$file")
zip -jr "$fileWithoutExt.zip" "$file" fileWithoutExt="${filename%.*}"
fi zip -jr "$dir/$fileWithoutExt.zip" "$file"
done done
- name: Release - name: Release
@@ -113,7 +113,7 @@ jobs:
name: Release Docker images name: Release Docker images
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
@@ -130,7 +130,7 @@ jobs:
export TAG_NAME=$(echo ${GITHUB_REF#refs/tags/}) export TAG_NAME=$(echo ${GITHUB_REF#refs/tags/})
echo "tag=$TAG_NAME" >> $GITHUB_OUTPUT echo "tag=$TAG_NAME" >> $GITHUB_OUTPUT
id: extract_branch id: extract_branch
- name: Log into GHCR - name: Log into GHCR
uses: docker/login-action@master uses: docker/login-action@master
with: with:
+1
View File
@@ -6,6 +6,7 @@ on:
jobs: jobs:
sync-release-to-gitee: sync-release-to-gitee:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 30
env: env:
GITEE_TOKEN: ${{ secrets.GITEE_TOKEN }} GITEE_TOKEN: ${{ secrets.GITEE_TOKEN }}
steps: steps:
+63
View File
@@ -0,0 +1,63 @@
# Use build arguments for Go version and architecture
ARG GO_VERSION=1.22
ARG BUILDARCH=amd64
# Stage 1: Builder Stage
# FROM golang:${GO_VERSION}-alpine AS builder
FROM crazymax/xgo:${GO_VERSION} AS builder
# Set up working directory
WORKDIR /app
# Step 1: Copy the source code
COPY . .
# use --mount=type=cache,target=/go/pkg/mod to cache the go mod
# Step 2: Download dependencies
RUN --mount=type=cache,target=/go/pkg/mod \
go mod tidy && go mod download
# Step 3: Build the Go application with CGO enabled and specified ldflags
RUN --mount=type=cache,target=/go/pkg/mod \
CGO_ENABLED=1 GOOS=linux go build -a \
-ldflags "-s -w --extldflags '-static -fpic'" \
-installsuffix cgo -o dashboard cmd/dashboard/main.go
# Stage 2: Create the final image
FROM alpine:latest
ARG COUNTRY
# Install required tools without caching index to minimize image size
RUN if [ "$COUNTRY" = "CN" ] ; then \
echo "It is in China, updating the repositories"; \
sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.tuna.tsinghua.edu.cn/alpine#g' /etc/apk/repositories; \
fi && \
apk update && apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo 'Asia/Shanghai' >/etc/timezone && \
rm -rf /var/cache/apk/* && \
mkdir -p /dashboard/data
# Copy the entrypoint script and ensure it is executable
COPY ./script/entrypoint.sh /entrypoint.sh
# Set up the entrypoint script
RUN chmod +x /entrypoint.sh
WORKDIR /dashboard
# Copy the statically linked binary from the builder stage
COPY --from=builder /app/dashboard ./app
# Copy the configuration file and the resource directory
COPY ./script/config.yaml ./data/config.yaml
COPY ./resource ./resource
# Set up volume and expose ports
VOLUME ["/dashboard/data"]
EXPOSE 80 5555 443
# Define the entrypoint
ENTRYPOINT ["/entrypoint.sh"]
+7 -4
View File
@@ -4,7 +4,7 @@
<br> <br>
<small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small> <small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
<br><br> <br><br>
<img alt="GitHub release (with filter)" src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&style=for-the-badge&logo=github&label=Dashboard">&nbsp;<img src="https://img.shields.io/github/v/release/nezhahq/agent?color=brightgreen&label=Agent&style=for-the-badge&logo=github">&nbsp;<img src="https://img.shields.io/github/actions/workflow/status/nezhahq/agent/agent.yml?label=Agent%20CI&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/badge/Installer-v0.19.2-brightgreen?style=for-the-badge&logo=linux"> <img alt="GitHub release (with filter)" src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&style=for-the-badge&logo=github&label=Dashboard">&nbsp;<img src="https://img.shields.io/github/v/release/nezhahq/agent?color=brightgreen&label=Agent&style=for-the-badge&logo=github">&nbsp;<img src="https://img.shields.io/github/actions/workflow/status/nezhahq/agent/agent.yml?label=Agent%20CI&logo=github&style=for-the-badge">
<br> <br>
<br> <br>
<p>:trollface: <b>Nezha Monitoring: Self-hostable, lightweight, servers and websites monitoring and O&M tool.</b></p> <p>:trollface: <b>Nezha Monitoring: Self-hostable, lightweight, servers and websites monitoring and O&M tool.</b></p>
@@ -63,10 +63,12 @@ You can change the dashboard language in the settings page (`/setting`) after th
<a href="https://github.com/iilemon" title="Sean"><img src="https://avatars.githubusercontent.com/u/33201711?v=4" width="50;" alt="Sean"/></a> <a href="https://github.com/iilemon" title="Sean"><img src="https://avatars.githubusercontent.com/u/33201711?v=4" width="50;" alt="Sean"/></a>
<a href="https://github.com/fscarmen" title="fscarmen"><img src="https://avatars.githubusercontent.com/u/62703343?v=4" width="50;" alt="fscarmen"/></a> <a href="https://github.com/fscarmen" title="fscarmen"><img src="https://avatars.githubusercontent.com/u/62703343?v=4" width="50;" alt="fscarmen"/></a>
<a href="https://github.com/ch8o" title="no-name-now"><img src="https://avatars.githubusercontent.com/u/9103372?v=4" width="50;" alt="no-name-now"/></a> <a href="https://github.com/ch8o" title="no-name-now"><img src="https://avatars.githubusercontent.com/u/9103372?v=4" width="50;" alt="no-name-now"/></a>
<a href="https://github.com/IamTaoChen" title="Tao Chen"><img src="https://avatars.githubusercontent.com/u/42793494?v=4" width="50;" alt="Tao Chen"/></a>
<a href="https://github.com/HsukqiLee" title="HsukqiLee"><img src="https://avatars.githubusercontent.com/u/79034142?v=4" width="50;" alt="HsukqiLee"/></a> <a href="https://github.com/HsukqiLee" title="HsukqiLee"><img src="https://avatars.githubusercontent.com/u/79034142?v=4" width="50;" alt="HsukqiLee"/></a>
<a href="https://github.com/DarcJC" title="Darc Z."><img src="https://avatars.githubusercontent.com/u/53445798?v=4" width="50;" alt="Darc Z."/></a> <a href="https://github.com/DarcJC" title="Darc Z."><img src="https://avatars.githubusercontent.com/u/53445798?v=4" width="50;" alt="Darc Z."/></a>
<a href="https://github.com/Creling" title="Creling"><img src="https://avatars.githubusercontent.com/u/43109504?v=4" width="50;" alt="Creling"/></a> <a href="https://github.com/Creling" title="Creling"><img src="https://avatars.githubusercontent.com/u/43109504?v=4" width="50;" alt="Creling"/></a>
<a href="https://github.com/coreff" title="Core F"><img src="https://avatars.githubusercontent.com/u/38347122?v=4" width="50;" alt="Core F"/></a> <a href="https://github.com/coreff" title="Core F"><img src="https://avatars.githubusercontent.com/u/38347122?v=4" width="50;" alt="Core F"/></a>
<a href="https://github.com/Septrum101" title="Spetrum"><img src="https://avatars.githubusercontent.com/u/11692994?v=4" width="50;" alt="Spetrum"/></a>
<a href="https://github.com/nickfox-taterli" title="Tater Li"><img src="https://avatars.githubusercontent.com/u/19658596?v=4" width="50;" alt="Tater Li"/></a> <a href="https://github.com/nickfox-taterli" title="Tater Li"><img src="https://avatars.githubusercontent.com/u/19658596?v=4" width="50;" alt="Tater Li"/></a>
<a href="https://github.com/hmsjy2017" title="Tony"><img src="https://avatars.githubusercontent.com/u/42692274?v=4" width="50;" alt="Tony"/></a> <a href="https://github.com/hmsjy2017" title="Tony"><img src="https://avatars.githubusercontent.com/u/42692274?v=4" width="50;" alt="Tony"/></a>
<a href="https://github.com/adminsama" title="adminsama"><img src="https://avatars.githubusercontent.com/u/60880076?v=4" width="50;" alt="adminsama"/></a> <a href="https://github.com/adminsama" title="adminsama"><img src="https://avatars.githubusercontent.com/u/60880076?v=4" width="50;" alt="adminsama"/></a>
@@ -81,9 +83,8 @@ You can change the dashboard language in the settings page (`/setting`) after th
<a href="https://github.com/ysicing" title="缘生"><img src="https://avatars.githubusercontent.com/u/8605565?v=4" width="50;" alt="缘生"/></a> <a href="https://github.com/ysicing" title="缘生"><img src="https://avatars.githubusercontent.com/u/8605565?v=4" width="50;" alt="缘生"/></a>
<a href="https://github.com/arkylin" title="凌"><img src="https://avatars.githubusercontent.com/u/35104502?v=4" width="50;" alt="凌"/></a> <a href="https://github.com/arkylin" title="凌"><img src="https://avatars.githubusercontent.com/u/35104502?v=4" width="50;" alt="凌"/></a>
<a href="https://github.com/colour93" title="玖叁"><img src="https://avatars.githubusercontent.com/u/64313711?v=4" width="50;" alt="玖叁"/></a> <a href="https://github.com/colour93" title="玖叁"><img src="https://avatars.githubusercontent.com/u/64313711?v=4" width="50;" alt="玖叁"/></a>
<a href="https://github.com/IamTaoChen" title="Tao Chen"><img src="https://avatars.githubusercontent.com/u/42793494?v=4" width="50;" alt="Tao Chen"/></a>
<a href="https://github.com/Septrum101" title="Spetrum"><img src="https://avatars.githubusercontent.com/u/11692994?v=4" width="50;" alt="Spetrum"/></a>
<a href="https://github.com/dreamingsleeping" title="Nanjing Hopefun Network Technology Co. Ltd."><img src="https://avatars.githubusercontent.com/u/13828658?v=4" width="50;" alt="Nanjing Hopefun Network Technology Co. Ltd."/></a> <a href="https://github.com/dreamingsleeping" title="Nanjing Hopefun Network Technology Co. Ltd."><img src="https://avatars.githubusercontent.com/u/13828658?v=4" width="50;" alt="Nanjing Hopefun Network Technology Co. Ltd."/></a>
<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/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/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/xrgzs" title="MadDogOwner"><img src="https://avatars.githubusercontent.com/u/26499123?v=4" width="50;" alt="MadDogOwner"/></a>
@@ -93,7 +94,9 @@ You can change the dashboard language in the settings page (`/setting`) after th
<a href="https://github.com/GreenTeodoro839" title="GreenTeodoro839"><img src="https://avatars.githubusercontent.com/u/77104800?v=4" width="50;" alt="GreenTeodoro839"/></a> <a href="https://github.com/GreenTeodoro839" title="GreenTeodoro839"><img src="https://avatars.githubusercontent.com/u/77104800?v=4" width="50;" alt="GreenTeodoro839"/></a>
<a href="https://github.com/Es-dese" title="Esdese"><img src="https://avatars.githubusercontent.com/u/71542548?v=4" width="50;" alt="Esdese"/></a> <a href="https://github.com/Es-dese" title="Esdese"><img src="https://avatars.githubusercontent.com/u/71542548?v=4" width="50;" alt="Esdese"/></a>
<a href="https://github.com/wwng2333" title=":D"><img src="https://avatars.githubusercontent.com/u/17147265?v=4" width="50;" alt=":D"/></a> <a href="https://github.com/wwng2333" title=":D"><img src="https://avatars.githubusercontent.com/u/17147265?v=4" width="50;" alt=":D"/></a>
<a href="https://github.com/wellcoming" title="Coming"><img src="https://avatars.githubusercontent.com/u/74850890?v=4" width="50;" alt="Coming"/></a><!--GAMFC_DELIMITER_END--> <a href="https://github.com/wellcoming" title="Coming"><img src="https://avatars.githubusercontent.com/u/74850890?v=4" width="50;" alt="Coming"/></a>
<a href="https://github.com/choyri" title="Chotow"><img src="https://avatars.githubusercontent.com/u/13994362?v=4" width="50;" alt="Chotow"/></a>
<a href="https://github.com/006lp" title="006lp"><img src="https://avatars.githubusercontent.com/u/144674902?v=4" width="50;" alt="006lp"/></a><!--GAMFC_DELIMITER_END-->
## Special Thanks ## Special Thanks
- [IPInfo](https://ipinfo.io/) for providing an accurate GeoIP Database. - [IPInfo](https://ipinfo.io/) for providing an accurate GeoIP Database.
+40
View File
@@ -28,6 +28,7 @@ func (v *apiV1) serve() {
})) }))
r.GET("/server/list", v.serverList) r.GET("/server/list", v.serverList)
r.GET("/server/details", v.serverDetails) r.GET("/server/details", v.serverDetails)
r.POST("/server/register", v.RegisterServer)
// 不强制认证的 API // 不强制认证的 API
mr := v.r.Group("monitor") mr := v.r.Group("monitor")
mr.Use(mygin.Authorize(mygin.AuthorizeOption{ mr.Use(mygin.Authorize(mygin.AuthorizeOption{
@@ -83,6 +84,45 @@ func (v *apiV1) serverDetails(c *gin.Context) {
c.JSON(200, singleton.ServerAPI.GetAllStatus()) c.JSON(200, singleton.ServerAPI.GetAllStatus())
} }
// RegisterServer adds a server and responds with the full ServerRegisterResponse
// header: Authorization: Token
// body: RegisterServer
// response: ServerRegisterResponse or Secret string
func (v *apiV1) RegisterServer(c *gin.Context) {
var rs singleton.RegisterServer
// Attempt to bind JSON to RegisterServer struct
if err := c.ShouldBindJSON(&rs); err != nil {
c.JSON(400, singleton.ServerRegisterResponse{
CommonResponse: singleton.CommonResponse{
Code: 400,
Message: "Parse JSON failed",
},
})
return
}
// Check if simple mode is requested
simple := c.Query("simple") == "true" || c.Query("simple") == "1"
// Set defaults if fields are empty
if rs.Name == "" {
rs.Name = c.ClientIP()
}
if rs.Tag == "" {
rs.Tag = "AutoRegister"
}
if rs.HideForGuest == "" {
rs.HideForGuest = "on"
}
// Call the Register function and get the response
response := singleton.ServerAPI.Register(&rs)
// Respond with Secret only if in simple mode, otherwise full response
if simple {
c.JSON(response.Code, response.Secret)
} else {
c.JSON(response.Code, response)
}
}
func (v *apiV1) monitorHistoriesById(c *gin.Context) { func (v *apiV1) monitorHistoriesById(c *gin.Context) {
idStr := c.Param("id") idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64) id, err := strconv.ParseUint(idStr, 10, 64)
+7
View File
@@ -96,6 +96,13 @@ func loadThirdPartyTemplates(tmpl *template.Template) *template.Template {
} }
themeDir := theme.Name() themeDir := theme.Name()
if themeDir == "theme-custom" {
// for backward compatibility
// note: will remove this in future versions
ret = loadTemplates(ret, themeDir)
continue
}
if strings.HasPrefix(themeDir, "dashboard-") { if strings.HasPrefix(themeDir, "dashboard-") {
// load dashboard templates, ignore desc file // load dashboard templates, ignore desc file
ret = loadTemplates(ret, themeDir) ret = loadTemplates(ret, themeDir)
+6
View File
@@ -781,6 +781,7 @@ type ddnsForm struct {
AccessSecret string AccessSecret string
WebhookURL string WebhookURL string
WebhookMethod uint8 WebhookMethod uint8
WebhookRequestType uint8
WebhookRequestBody string WebhookRequestBody string
WebhookHeaders string WebhookHeaders string
} }
@@ -809,6 +810,7 @@ func (ma *memberAPI) addOrEditDDNS(c *gin.Context) {
p.AccessSecret = df.AccessSecret p.AccessSecret = df.AccessSecret
p.WebhookURL = df.WebhookURL p.WebhookURL = df.WebhookURL
p.WebhookMethod = df.WebhookMethod p.WebhookMethod = df.WebhookMethod
p.WebhookRequestType = df.WebhookRequestType
p.WebhookRequestBody = df.WebhookRequestBody p.WebhookRequestBody = df.WebhookRequestBody
p.WebhookHeaders = df.WebhookHeaders p.WebhookHeaders = df.WebhookHeaders
@@ -1010,6 +1012,7 @@ type settingForm struct {
DashboardTheme string DashboardTheme string
CustomCode string CustomCode string
CustomCodeDashboard string CustomCodeDashboard string
CustomNameservers string
ViewPassword string ViewPassword string
IgnoredIPNotification string IgnoredIPNotification string
IPChangeNotificationTag string // IP变更提醒的通知组 IPChangeNotificationTag string // IP变更提醒的通知组
@@ -1076,6 +1079,7 @@ func (ma *memberAPI) updateSetting(c *gin.Context) {
singleton.Conf.Site.DashboardTheme = sf.DashboardTheme singleton.Conf.Site.DashboardTheme = sf.DashboardTheme
singleton.Conf.Site.CustomCode = sf.CustomCode singleton.Conf.Site.CustomCode = sf.CustomCode
singleton.Conf.Site.CustomCodeDashboard = sf.CustomCodeDashboard singleton.Conf.Site.CustomCodeDashboard = sf.CustomCodeDashboard
singleton.Conf.DNSServers = sf.CustomNameservers
singleton.Conf.Site.ViewPassword = sf.ViewPassword singleton.Conf.Site.ViewPassword = sf.ViewPassword
singleton.Conf.Oauth2.Admin = sf.Admin singleton.Conf.Oauth2.Admin = sf.Admin
// 保证NotificationTag不为空 // 保证NotificationTag不为空
@@ -1091,6 +1095,8 @@ func (ma *memberAPI) updateSetting(c *gin.Context) {
} }
// 更新系统语言 // 更新系统语言
singleton.InitLocalizer() singleton.InitLocalizer()
// 更新DNS服务器
singleton.OnNameserverUpdate()
c.JSON(http.StatusOK, model.Response{ c.JSON(http.StatusOK, model.Response{
Code: http.StatusOK, Code: http.StatusOK,
}) })
+9 -8
View File
@@ -1,6 +1,7 @@
package main package main
import ( import (
"os"
"context" "context"
"fmt" "fmt"
"log" "log"
@@ -32,13 +33,6 @@ func init() {
flag.StringVarP(&dashboardCliParam.ConfigFile, "config", "c", "data/config.yaml", "配置文件路径") flag.StringVarP(&dashboardCliParam.ConfigFile, "config", "c", "data/config.yaml", "配置文件路径")
flag.StringVar(&dashboardCliParam.DatebaseLocation, "db", "data/sqlite.db", "Sqlite3数据库文件路径") flag.StringVar(&dashboardCliParam.DatebaseLocation, "db", "data/sqlite.db", "Sqlite3数据库文件路径")
flag.Parse() flag.Parse()
// 初始化 dao 包
singleton.InitConfigFromPath(dashboardCliParam.ConfigFile)
singleton.InitTimezoneAndCache()
singleton.InitDBFromPath(dashboardCliParam.DatebaseLocation)
singleton.InitLocalizer()
initSystem()
} }
func initSystem() { func initSystem() {
@@ -59,9 +53,16 @@ func initSystem() {
func main() { func main() {
if dashboardCliParam.Version { if dashboardCliParam.Version {
fmt.Println(singleton.Version) fmt.Println(singleton.Version)
return os.Exit(0)
} }
// 初始化 dao 包
singleton.InitConfigFromPath(dashboardCliParam.ConfigFile)
singleton.InitTimezoneAndCache()
singleton.InitDBFromPath(dashboardCliParam.DatebaseLocation)
singleton.InitLocalizer()
initSystem()
// TODO 使用 cmux 在同一端口服务 HTTP 和 gRPC // TODO 使用 cmux 在同一端口服务 HTTP 和 gRPC
singleton.CleanMonitorHistory() singleton.CleanMonitorHistory()
go rpc.ServeRPC(singleton.Conf.GRPCPort) go rpc.ServeRPC(singleton.Conf.GRPCPort)
+17
View File
@@ -0,0 +1,17 @@
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
args:
COUNTRY: CN
image: nezha:dev
container_name: nezha-dev
ports:
- ${NEZHA_PORT:-80}:18080
- 5555:5555
volumes:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
- ./data:/dashboard/data
# - ./resource:/dashboard/resource
+14 -18
View File
@@ -14,17 +14,20 @@ require (
github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-uuid v1.0.3
github.com/jinzhu/copier v0.4.0 github.com/jinzhu/copier v0.4.0
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/knadh/koanf/parsers/yaml v0.1.0
github.com/knadh/koanf/providers/env v1.0.0
github.com/knadh/koanf/providers/file v1.1.2
github.com/knadh/koanf/v2 v2.1.2
github.com/libdns/cloudflare v0.1.1 github.com/libdns/cloudflare v0.1.1
github.com/libdns/libdns v0.2.2 github.com/libdns/libdns v0.2.2
github.com/libdns/tencentcloud v1.0.0
github.com/miekg/dns v1.1.62 github.com/miekg/dns v1.1.62
github.com/nezhahq/libdns-tencentcloud v0.0.0-20241029120103-889957240fff
github.com/nicksnyder/go-i18n/v2 v2.4.0 github.com/nicksnyder/go-i18n/v2 v2.4.0
github.com/ory/graceful v0.1.3 github.com/ory/graceful v0.1.3
github.com/oschwald/maxminddb-golang v1.13.1 github.com/oschwald/maxminddb-golang v1.13.1
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.18.2
github.com/tidwall/gjson v1.18.0 github.com/tidwall/gjson v1.18.0
github.com/xanzy/go-gitlab v0.103.0 github.com/xanzy/go-gitlab v0.103.0
golang.org/x/crypto v0.25.0 golang.org/x/crypto v0.25.0
@@ -34,14 +37,15 @@ require (
golang.org/x/text v0.16.0 golang.org/x/text v0.16.0
google.golang.org/grpc v1.63.0 google.golang.org/grpc v1.63.0
google.golang.org/protobuf v1.34.2 google.golang.org/protobuf v1.34.2
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/sqlite v1.5.5 gorm.io/driver/sqlite v1.5.5
gorm.io/gorm v1.25.10 gorm.io/gorm v1.25.10
sigs.k8s.io/yaml v1.4.0
) )
require ( require (
github.com/bytedance/sonic v1.9.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect
@@ -51,44 +55,36 @@ require (
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/knadh/koanf/maps v0.1.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/leodido/go-urn v1.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/pretty v1.2.0 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect github.com/ugorji/go/codec v1.2.11 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/arch v0.3.0 // indirect golang.org/x/arch v0.3.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.18.0 // indirect golang.org/x/mod v0.18.0 // indirect
golang.org/x/sys v0.22.0 // indirect golang.org/x/sys v0.22.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.22.0 // indirect golang.org/x/tools v0.22.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )
+21 -37
View File
@@ -21,8 +21,6 @@ github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454Wv
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
@@ -54,13 +52,14 @@ github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v47 v47.1.0 h1:Cacm/WxQBOa9lF0FT0EMjZ2BWMetQ1TQfyurn4yF1z8= github.com/google/go-github/v47 v47.1.0 h1:Cacm/WxQBOa9lF0FT0EMjZ2BWMetQ1TQfyurn4yF1z8=
@@ -82,8 +81,6 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
@@ -95,6 +92,16 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
github.com/knadh/koanf/parsers/yaml v0.1.0 h1:ZZ8/iGfRLvKSaMEECEBPM1HQslrZADk8fP1XFUxVI5w=
github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY=
github.com/knadh/koanf/providers/env v1.0.0 h1:ufePaI9BnWH+ajuxGGiJ8pdTG0uLEUWC7/HDDPGLah0=
github.com/knadh/koanf/providers/env v1.0.0/go.mod h1:mzFyRZueYhb37oPmC1HAv/oGEEuyvJDA98r3XAa8Gak=
github.com/knadh/koanf/providers/file v1.1.2 h1:aCC36YGOgV5lTtAFz2qkgtWdeQsgfxUkxDOe+2nQY3w=
github.com/knadh/koanf/providers/file v1.1.2/go.mod h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI=
github.com/knadh/koanf/v2 v2.1.2 h1:I2rtLRqXRy1p01m/utEtpZSSA6dcJbgGVuE27kW2PzQ=
github.com/knadh/koanf/v2 v2.1.2/go.mod h1:Gphfaen0q1Fc1HTgJgSTC4oRX9R2R5ErYMZJy8fLJBo=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
@@ -111,10 +118,6 @@ github.com/libdns/cloudflare v0.1.1 h1:FVPfWwP8zZCqj268LZjmkDleXlHPlFU9KC4OJ3yn0
github.com/libdns/cloudflare v0.1.1/go.mod h1:9VK91idpOjg6v7/WbjkEW49bSCxj00ALesIFDhJ8PBU= github.com/libdns/cloudflare v0.1.1/go.mod h1:9VK91idpOjg6v7/WbjkEW49bSCxj00ALesIFDhJ8PBU=
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
github.com/libdns/tencentcloud v1.0.0 h1:u4LXnYu/lu/9P5W+MCVPeSDnwI+6w+DxYhQ1wSnQOuU=
github.com/libdns/tencentcloud v1.0.0/go.mod h1:NlCgPumzUsZWSOo1+Q/Hfh8G6TNRAaTUeWQdg6LbtUI=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
@@ -124,13 +127,17 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nezhahq/libdns-tencentcloud v0.0.0-20241029120103-889957240fff h1:3WDsbsg3dmsRENYLUPGPTkEcWWmTvk41i+rM91AIIbY=
github.com/nezhahq/libdns-tencentcloud v0.0.0-20241029120103-889957240fff/go.mod h1:k+cDtTbUY+UV56Aqv4Ahmc9bWmhpga9JJXZlAIPKBEc=
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM= github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4= github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
@@ -158,20 +165,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -186,16 +181,15 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597 h1:C0GHdLTfikLVoEzfhgPfrZ7LwlG0xiCmk6iwNKE+xs0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
@@ -204,10 +198,6 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/xanzy/go-gitlab v0.103.0 h1:J9pTQoq0GsEFqzd6srCM1QfdfKAxSNz6mT6ntrpNF2w= github.com/xanzy/go-gitlab v0.103.0 h1:J9pTQoq0GsEFqzd6srCM1QfdfKAxSNz6mT6ntrpNF2w=
github.com/xanzy/go-gitlab v0.103.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xanzy/go-gitlab v0.103.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
@@ -217,8 +207,6 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -266,8 +254,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
@@ -280,5 +266,3 @@ gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATa
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
+42 -37
View File
@@ -1,12 +1,16 @@
package model package model
import ( import (
"errors"
"os" "os"
"strconv" "strconv"
"strings" "strings"
"github.com/spf13/viper" kyaml "github.com/knadh/koanf/parsers/yaml"
"sigs.k8s.io/yaml" "github.com/knadh/koanf/providers/env"
"github.com/knadh/koanf/providers/file"
"github.com/knadh/koanf/v2"
"gopkg.in/yaml.v3"
) )
var Languages = map[string]string{ var Languages = map[string]string{
@@ -23,6 +27,7 @@ var Themes = map[string]string{
"hotaru": "Hotaru", "hotaru": "Hotaru",
"angel-kanade": "AngelKanade", "angel-kanade": "AngelKanade",
"server-status": "ServerStatus", "server-status": "ServerStatus",
"custom": "Custom(local)",
} }
var DashboardThemes = map[string]string{ var DashboardThemes = map[string]string{
@@ -45,35 +50,6 @@ const (
ConfigCoverIgnoreAll ConfigCoverIgnoreAll
) )
type AgentConfig struct {
HardDrivePartitionAllowlist []string
NICAllowlist map[string]bool
v *viper.Viper
}
// Read 从给定的文件目录加载配置文件
func (c *AgentConfig) Read(path string) error {
c.v = viper.New()
c.v.SetConfigFile(path)
err := c.v.ReadInConfig()
if err != nil {
return err
}
err = c.v.Unmarshal(c)
if err != nil {
return err
}
return nil
}
func (c *AgentConfig) Save() error {
data, err := yaml.Marshal(c)
if err != nil {
return err
}
return os.WriteFile(c.v.ConfigFileUsed(), data, 0600)
}
// Config 站点配置 // Config 站点配置
type Config struct { type Config struct {
Debug bool // debug模式开关 Debug bool // debug模式开关
@@ -121,26 +97,52 @@ type Config struct {
Location string // 时区,默认为 Asia/Shanghai Location string // 时区,默认为 Asia/Shanghai
v *viper.Viper
IgnoredIPNotificationServerIDs map[uint64]bool // [ServerID] -> bool(值为true代表当前ServerID在特定服务器列表内) IgnoredIPNotificationServerIDs map[uint64]bool // [ServerID] -> bool(值为true代表当前ServerID在特定服务器列表内)
MaxTCPPingValue int32 MaxTCPPingValue int32
AvgPingCount int AvgPingCount int
DNSServers string
k *koanf.Koanf
filePath string
} }
// Read 读取配置文件并应用 // Read 读取配置文件并应用
func (c *Config) Read(path string) error { func (c *Config) Read(path string) error {
c.v = viper.New() c.k = koanf.New(".")
c.v.SetConfigFile(path) c.filePath = path
err := c.v.ReadInConfig()
// 先读取环境变量,然后读取配置文件;后者可以覆盖前者,因为哪吒支持在线修改配置
err := c.k.Load(env.Provider("NZ_", ".", func(s string) string {
return strings.Replace(strings.ToLower(strings.TrimPrefix(s, "NZ_")), "_", ".", -1)
}), nil)
if err != nil { if err != nil {
return err return err
} }
err = c.v.Unmarshal(c) if _, err := os.Stat(path); err == nil {
err = c.k.Load(file.Provider(path), kyaml.Parser())
if err != nil {
return err
}
}
err = c.k.Unmarshal("", c)
if err != nil { if err != nil {
return err return err
} }
if c.Oauth2.Type == "" || c.Oauth2.Admin == "" || c.Oauth2.ClientID == "" || c.Oauth2.ClientSecret == "" {
return errors.New("missing oauth2 config")
}
if c.Site.Brand == "" {
c.Site.Brand = "Nezha Monitoring"
}
if c.Site.CookieName == "" {
c.Site.CookieName = "nezha-dashboard"
}
if c.Site.Theme == "" { if c.Site.Theme == "" {
c.Site.Theme = "default" c.Site.Theme = "default"
} }
@@ -150,6 +152,9 @@ func (c *Config) Read(path string) error {
if c.Language == "" { if c.Language == "" {
c.Language = "zh-CN" c.Language = "zh-CN"
} }
if c.HTTPPort == 0 {
c.HTTPPort = 80
}
if c.GRPCPort == 0 { if c.GRPCPort == 0 {
c.GRPCPort = 5555 c.GRPCPort = 5555
} }
@@ -201,5 +206,5 @@ func (c *Config) Save() error {
if err != nil { if err != nil {
return err return err
} }
return os.WriteFile(c.v.ConfigFileUsed(), data, 0600) return os.WriteFile(c.filePath, data, 0600)
} }
+2
View File
@@ -51,6 +51,7 @@ var ProviderList = []DDNSProvider{
AccessSecret: true, AccessSecret: true,
WebhookURL: true, WebhookURL: true,
WebhookMethod: true, WebhookMethod: true,
WebhookRequestType: true,
WebhookRequestBody: true, WebhookRequestBody: true,
WebhookHeaders: true, WebhookHeaders: true,
}, },
@@ -93,6 +94,7 @@ type DDNSProvider struct {
AccessSecret bool AccessSecret bool
WebhookURL bool WebhookURL bool
WebhookMethod bool WebhookMethod bool
WebhookRequestType bool
WebhookRequestBody bool WebhookRequestBody bool
WebhookHeaders bool WebhookHeaders bool
} }
+18 -3
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"log" "log"
"strings"
"time" "time"
"github.com/libdns/libdns" "github.com/libdns/libdns"
@@ -13,7 +14,10 @@ import (
"github.com/naiba/nezha/pkg/utils" "github.com/naiba/nezha/pkg/utils"
) )
var dnsTimeOut = 10 * time.Second var (
dnsTimeOut = 10 * time.Second
customDNSServers []string
)
type IP struct { type IP struct {
Ipv4Addr string Ipv4Addr string
@@ -33,6 +37,12 @@ type Provider struct {
Setter libdns.RecordSetter Setter libdns.RecordSetter
} }
func InitDNSServers(s string) {
if s != "" {
customDNSServers = strings.Split(s, ",")
}
}
func (provider *Provider) UpdateDomain(ctx context.Context) { func (provider *Provider) UpdateDomain(ctx context.Context) {
provider.ctx = ctx provider.ctx = ctx
for _, domain := range provider.DDNSProfile.Domains { for _, domain := range provider.DDNSProfile.Domains {
@@ -95,12 +105,17 @@ func splitDomainSOA(domain string) (prefix string, zone string, err error) {
domain += "." domain += "."
indexes := dns.Split(domain) indexes := dns.Split(domain)
servers := utils.DNSServers
if len(customDNSServers) > 0 {
servers = customDNSServers
}
var r *dns.Msg var r *dns.Msg
for _, idx := range indexes { for _, idx := range indexes {
m := new(dns.Msg) m := new(dns.Msg)
m.SetQuestion(domain[idx:], dns.TypeSOA) m.SetQuestion(domain[idx:], dns.TypeSOA)
for _, server := range utils.DNSServers { for _, server := range servers {
r, _, err = c.Exchange(m, server) r, _, err = c.Exchange(m, server)
if err != nil { if err != nil {
return return
@@ -108,7 +123,7 @@ func splitDomainSOA(domain string) (prefix string, zone string, err error) {
if len(r.Answer) > 0 { if len(r.Answer) > 0 {
if soa, ok := r.Answer[0].(*dns.SOA); ok { if soa, ok := r.Answer[0].(*dns.SOA); ok {
zone = soa.Hdr.Name zone = soa.Hdr.Name
prefix = domain[:len(domain)-len(zone)-1] prefix = libdns.RelativeName(domain, zone)
return return
} }
} }
+5
View File
@@ -27,6 +27,11 @@ func TestSplitDomainSOA(t *testing.T) {
zone: "example.com.", zone: "example.com.",
prefix: "abc", prefix: "abc",
}, },
{
domain: "example.com",
zone: "example.com.",
prefix: "",
},
} }
for _, c := range cases { for _, c := range cases {
+2
View File
@@ -159,6 +159,8 @@ func (provider *Provider) formatWebhookString(s string) string {
"#domain#", provider.domain, "#domain#", provider.domain,
"#type#", provider.ipType, "#type#", provider.ipType,
"#record#", provider.recordType, "#record#", provider.recordType,
"#access_id#", provider.DDNSProfile.AccessID,
"#access_secret#", provider.DDNSProfile.AccessSecret,
"\r", "", "\r", "",
) )
+1 -1
View File
@@ -13,7 +13,7 @@ import (
var ( var (
Json = jsoniter.ConfigCompatibleWithStandardLibrary Json = jsoniter.ConfigCompatibleWithStandardLibrary
DNSServers = []string{"1.1.1.1:53", "223.5.5.5:53", "[2606:4700:4700::1111]:53", "[2400:3200::1]:53"} DNSServers = []string{"1.1.1.1:53", "223.5.5.5:53"}
) )
func IsWindows() bool { func IsWindows() bool {
+9
View File
@@ -670,6 +670,9 @@ other = "Webhook URL"
[WebhookMethod] [WebhookMethod]
other = "Webhook Request Method" other = "Webhook Request Method"
[WebhookRequestType]
other = "Webhook Request Type"
[WebhookHeaders] [WebhookHeaders]
other = "Webhook Request Headers" other = "Webhook Request Headers"
@@ -744,3 +747,9 @@ other = "Expired"
[Days] [Days]
other = "d" other = "d"
[CustomNameservers]
other = "Custom Public DNS Nameservers for DDNS (separate with comma)"
[Plan]
other = "Plan"
+9
View File
@@ -670,6 +670,9 @@ other = "URL del Webhook"
[WebhookMethod] [WebhookMethod]
other = "Método de Solicitud del Webhook" other = "Método de Solicitud del Webhook"
[WebhookRequestType]
other = "Tipo de solicitud del Webhook"
[WebhookHeaders] [WebhookHeaders]
other = "Encabezados de Solicitud del Webhook" other = "Encabezados de Solicitud del Webhook"
@@ -744,3 +747,9 @@ other = "Expired"
[Days] [Days]
other = "d" other = "d"
[CustomNameservers]
other = "Servidores DNS públicos personalizados para DDNS (separar con coma)"
[Plan]
other = "Plan"
+14 -5
View File
@@ -632,22 +632,22 @@ other = "DDNS配置"
other = "新配置" other = "新配置"
[EnableDDNS] [EnableDDNS]
other = "启用DDNS" other = "启用 DDNS"
[EnableIPv4] [EnableIPv4]
other = "启用DDNS IPv4" other = "启用 DDNS IPv4"
[EnableIPv6] [EnableIPv6]
other = "启用DDNS IPv6" other = "启用 DDNS IPv6"
[DDNSDomain] [DDNSDomain]
other = "DDNS域名" other = "DDNS 域名"
[DDNSDomains] [DDNSDomains]
other = "域名(逗号分隔)" other = "域名(逗号分隔)"
[DDNSProvider] [DDNSProvider]
other = "DDNS供应商" other = "DDNS 供应商"
[MaxRetries] [MaxRetries]
other = "最大重试次数" other = "最大重试次数"
@@ -670,6 +670,9 @@ other = "Webhook 地址"
[WebhookMethod] [WebhookMethod]
other = "Webhook 请求方式" other = "Webhook 请求方式"
[WebhookRequestType]
other = "Webhook 请求类型"
[WebhookHeaders] [WebhookHeaders]
other = "Webhook 请求头" other = "Webhook 请求头"
@@ -744,3 +747,9 @@ other = "已到期"
[Days] [Days]
other = "天" other = "天"
[CustomNameservers]
other = "自定义DDNS使用的公共DNS服务器(逗号分隔)"
[Plan]
other = "套餐"
+22 -13
View File
@@ -632,49 +632,52 @@ other = "DDNS配置"
other = "新增配置" other = "新增配置"
[EnableDDNS] [EnableDDNS]
other = "啟用DDNS" other = "啟用 DDNS"
[EnableIPv4] [EnableIPv4]
other = "啟用DDNS IPv4" other = "啟用 DDNS IPv4"
[EnableIPv6] [EnableIPv6]
other = "啟用DDNS IPv6" other = "啟用 DDNS IPv6"
[DDNSDomain] [DDNSDomain]
other = "DDNS域名" other = "DDNS 域名"
[DDNSDomains] [DDNSDomains]
other = "域名(逗號分隔)" other = "域名(逗號分隔)"
[DDNSProvider] [DDNSProvider]
other = "DDNS供應商" other = "DDN S供應商"
[MaxRetries] [MaxRetries]
other = "最大重試次數" other = "最大重試次數"
[DDNSAccessID] [DDNSAccessID]
other = "DDNS憑據1" other = "DDNS 憑據 1"
[DDNSAccessSecret] [DDNSAccessSecret]
other = "DDNS憑據2" other = "DDNS 憑據 2"
[DDNSTokenID] [DDNSTokenID]
other = "令牌ID" other = "令牌 ID"
[DDNSTokenSecret] [DDNSTokenSecret]
other = "令牌Secret" other = "令牌 Secret"
[WebhookURL] [WebhookURL]
other = "Webhook地址" other = "Webhook 地址"
[WebhookMethod] [WebhookMethod]
other = "Webhook請求方式" other = "Webhook 請求方式"
[WebhookRequestType]
other = "Webhook 請求類型"
[WebhookHeaders] [WebhookHeaders]
other = "Webhook請求頭" other = "Webhook 請求頭"
[WebhookRequestBody] [WebhookRequestBody]
other = "Webhook請求體" other = "Webhook 請求體"
[Feature] [Feature]
other = "功能" other = "功能"
@@ -744,3 +747,9 @@ other = "已到期"
[Days] [Days]
other = "天" other = "天"
[CustomNameservers]
other = "自訂DDNS使用的公共DNS伺服器(逗號分隔)"
[Plan]
other = "套餐"
+5 -1
View File
@@ -102,7 +102,8 @@ function showFormModal(modelSelector, formID, URL, getData) {
item.name === "Duration" || item.name === "Duration" ||
item.name === "MaxRetries" || item.name === "MaxRetries" ||
item.name === "Provider" || item.name === "Provider" ||
item.name === "WebhookMethod" item.name === "WebhookMethod" ||
item.name === "WebhookRequestType"
) { ) {
obj[item.name] = parseInt(item.value); obj[item.name] = parseInt(item.value);
} else if (item.name.endsWith("Latency")) { } else if (item.name.endsWith("Latency")) {
@@ -299,6 +300,9 @@ function addOrEditDDNS(ddns) {
modal modal
.find("select[name=WebhookMethod]") .find("select[name=WebhookMethod]")
.val(ddns ? ddns.WebhookMethod : 1); .val(ddns ? ddns.WebhookMethod : 1);
modal
.find("select[name=WebhookRequestType]")
.val(ddns ? ddns.WebhookRequestType : 1);
if (ddns && ddns.EnableIPv4) { if (ddns && ddns.EnableIPv4) {
modal.find(".ui.enableipv4.checkbox").checkbox("set checked"); modal.find(".ui.enableipv4.checkbox").checkbox("set checked");
} else { } else {
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

+5 -2
View File
@@ -46,8 +46,6 @@ body[theme="dark"] .content {
background-color: rgba(28, 29, 38, 1); background-color: rgba(28, 29, 38, 1);
border: none; border: none;
box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em; box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em;
-webkit-box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em;
box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em;
} }
body[theme="dark"] .table { body[theme="dark"] .table {
@@ -90,6 +88,11 @@ body[theme="dark"] .table > tbody > tr.expandRow.odd > td:before {
body[theme="dark"] .table > tbody > tr.expandRow.even > td:before { body[theme="dark"] .table > tbody > tr.expandRow.even > td:before {
background-color: rgba(28, 29, 38, 1); background-color: rgba(28, 29, 38, 1);
} }
body[theme="dark"] .plan {
background-image: none;
background-color: rgba(255, 255, 255, 0.075);
}
/* expandRow展开部分样式结束 */ /* expandRow展开部分样式结束 */
body[theme="dark"] .progress { body[theme="dark"] .progress {
-2
View File
@@ -74,8 +74,6 @@ body[theme="dark"] .content {
background-color: rgba(28, 29, 38, 0.8); background-color: rgba(28, 29, 38, 0.8);
border: none; border: none;
box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em; box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em;
-webkit-box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em;
box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em;
} }
body[theme="dark"] .table > thead > tr.node-group-tag > th, body[theme="dark"] .table > thead > tr.node-group-tag > th,
+6 -2
View File
@@ -69,8 +69,6 @@ body[theme="light"] .content {
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
color: rgba(0, 0, 0, 0.87); color: rgba(0, 0, 0, 0.87);
border: 1px #cecece solid; border: 1px #cecece solid;
-webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, .1);
-moz-box-shadow: 0 1px 10px rgba(0, 0, 0, .1);
box-shadow: 0 1px 10px rgba(0, 0, 0, .1); box-shadow: 0 1px 10px rgba(0, 0, 0, .1);
} }
@@ -116,6 +114,12 @@ body[theme="light"] tr.odd.expandRow > :hover {
background: #ffffff !important; background: #ffffff !important;
} }
body[theme="light"] .plan {
color: #000000;
background-color: #f5f5f5;
box-shadow: inset 0 -0.5px 2px rgba(0, 0, 0, .1);
}
body[theme="light"] .progress-bar { body[theme="light"] .progress-bar {
color: #000000; color: #000000;
} }
@@ -104,6 +104,11 @@ body[theme="light"] .table > tbody > tr.expandRow.odd > td:before {
body[theme="light"] .table > tbody > tr.expandRow.even > td:before { body[theme="light"] .table > tbody > tr.expandRow.even > td:before {
background-color: unset; background-color: unset;
} }
body[theme="light"] .plan {
background-image: none;
background-color: rgba(0, 0, 0, 0.015);
}
/* expandRow展开部分样式结束 */ /* expandRow展开部分样式结束 */
body[theme="light"] .progress { body[theme="light"] .progress {
+21 -2
View File
@@ -237,8 +237,8 @@ tr.accordion-toggle{
} }
.node-cell.network { .node-cell.network {
min-width: 100px; min-width: 110px;
max-width: 100px; max-width: 110px;
} }
.node-cell.traffic { .node-cell.traffic {
@@ -268,6 +268,22 @@ tr.accordion-toggle{
font-size: 80%; font-size: 80%;
} }
.plan {
display: inline-block;
font-size: 85%;
margin-right: 2px;
padding: 2px 5px;
border-radius: 2px;
}
.network-route, .extra {
margin-right: 6px;
}
.last {
margin-right: 2px;
}
.temp-detail { .temp-detail {
cursor: pointer; cursor: pointer;
} }
@@ -557,6 +573,9 @@ footer p {
min-width: 75px; min-width: 75px;
max-width: 75px; max-width: 75px;
} }
.plan {
display: inline;
}
.accordian-body { .accordian-body {
margin: 5px 0px 5px 10px; margin: 5px 0px 5px 10px;
} }
+7
View File
@@ -48,6 +48,13 @@
<option value="5">PUT</option> <option value="5">PUT</option>
</select> </select>
</div> </div>
<div class="field">
<label>{{tr "WebhookRequestType"}}</label>
<select name="WebhookRequestType" class="ui fluid dropdown">
<option value="1">JSON</option>
<option value="2">Form</option>
</select>
</div>
<div class="field"> <div class="field">
<label>{{tr "WebhookHeaders"}}</label> <label>{{tr "WebhookHeaders"}}</label>
<textarea name="WebhookHeaders" placeholder='{"User-Agent":"Nezha-Agent"}'></textarea> <textarea name="WebhookHeaders" placeholder='{"User-Agent":"Nezha-Agent"}'></textarea>
+1 -1
View File
@@ -53,7 +53,7 @@
<label>{{tr "LinuxOneKeyInstall"}}</label> <label>{{tr "LinuxOneKeyInstall"}}</label>
<div class="ui message"> <div class="ui message">
{{if .Conf.GRPCHost}} {{if .Conf.GRPCHost}}
curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.sh -o nezha.sh && chmod curl -L https://raw.githubusercontent.com/nezhahq/scripts/main/install.sh -o nezha.sh && chmod
+x nezha.sh && ./nezha.sh install_agent <code class="command">{{.Conf.GRPCHost}}</code> <code +x nezha.sh && ./nezha.sh install_agent <code class="command">{{.Conf.GRPCHost}}</code> <code
class="command">{{if .Conf.ProxyGRPCPort}}{{.Conf.ProxyGRPCPort}}{{else}}{{.Conf.GRPCPort}}{{end}}</code> <code class="command">{{if .Conf.ProxyGRPCPort}}{{.Conf.ProxyGRPCPort}}{{else}}{{.Conf.GRPCPort}}{{end}}</code> <code
class="command hostSecret"></code> <code class="command">{{if .Conf.TLS}}--tls{{end}}</code> class="command hostSecret"></code> <code class="command">{{if .Conf.TLS}}--tls{{end}}</code>
+3 -3
View File
@@ -55,17 +55,17 @@
</td> </td>
<td> <td>
<button class="ui icon green mini button" <button class="ui icon green mini button"
data-clipboard-text="{{if $.Conf.GRPCHost}}{{if eq $.Conf.Language "zh-CN"}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.sh{{else}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install_en.sh{{end}} -o nezha.sh && chmod +x nezha.sh && ./nezha.sh install_agent {{$.Conf.GRPCHost}} {{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}" data-clipboard-text="{{if $.Conf.GRPCHost}}{{if eq $.Conf.Language "zh-CN"}}curl -L https://raw.githubusercontent.com/nezhahq/scripts/main/install.sh{{else}}curl -L https://raw.githubusercontent.com/nezhahq/scripts/main/install_en.sh{{end}} -o nezha.sh && chmod +x nezha.sh && ./nezha.sh install_agent {{$.Conf.GRPCHost}} {{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"
data-tooltip="{{tr "ClickToCopy"}}"> data-tooltip="{{tr "ClickToCopy"}}">
<i class="linux icon"></i> <i class="linux icon"></i>
</button> </button>
<button class="ui icon green mini button" <button class="ui icon green mini button"
data-clipboard-text="{{if $.Conf.GRPCHost}}[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Ssl3 -bor [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12;set-ExecutionPolicy RemoteSigned;Invoke-WebRequest https://raw.githubusercontent.com/naiba/nezha/master/script/install.ps1 -OutFile C:\install.ps1;powershell.exe C:\install.ps1 {{$.Conf.GRPCHost}}:{{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}" data-clipboard-text="{{if $.Conf.GRPCHost}}[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Ssl3 -bor [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12;set-ExecutionPolicy RemoteSigned;Invoke-WebRequest https://raw.githubusercontent.com/nezhahq/scripts/main/extras/install.ps1 -OutFile C:\install.ps1;powershell.exe C:\install.ps1 {{$.Conf.GRPCHost}}:{{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"
data-tooltip="{{tr "ClickToCopy"}}"> data-tooltip="{{tr "ClickToCopy"}}">
<i class="windows icon"></i> <i class="windows icon"></i>
</button> </button>
<button class="ui icon green mini button" <button class="ui icon green mini button"
data-clipboard-text="{{if $.Conf.GRPCHost}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.command -o nezha.command && chmod +x nezha.command && sudo ./nezha.command install_agent {{$.Conf.GRPCHost}} {{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}" data-clipboard-text="{{if $.Conf.GRPCHost}}curl -L https://raw.githubusercontent.com/nezhahq/scripts/main/extras/install.command -o nezha.command && chmod +x nezha.command && sudo ./nezha.command install_agent {{$.Conf.GRPCHost}} {{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"
data-tooltip="{{tr "ClickToCopy"}}"> data-tooltip="{{tr "ClickToCopy"}}">
<i class="apple icon"></i> <i class="apple icon"></i>
</button> </button>
+4
View File
@@ -53,6 +53,10 @@
<label>{{tr "PanelServerDomainAndIP"}}</label> <label>{{tr "PanelServerDomainAndIP"}}</label>
<input type="text" name="GRPCHost" placeholder="" value="{{.Conf.GRPCHost}}"> <input type="text" name="GRPCHost" placeholder="" value="{{.Conf.GRPCHost}}">
</div> </div>
<div class="field">
<label>{{tr "CustomNameservers"}}</label>
<input type="text" name="CustomNameservers" placeholder="" value="{{.Conf.DNSServers}}">
</div>
<div class="field"> <div class="field">
<label>{{tr "IPChangeAlert"}}</label> <label>{{tr "IPChangeAlert"}}</label>
</div> </div>
+2 -2
View File
@@ -28,8 +28,8 @@
</span> </span>
</aside> </aside>
<template v-if="semiTransparent"> <template v-if="semiTransparent">
<link rel="stylesheet" href="/static/theme-server-status/css/light.plus.css?v20241008"> <link rel="stylesheet" href="/static/theme-server-status/css/light.plus.css?v20241103">
<link rel="stylesheet" href="/static/theme-server-status/css/dark.plus.css?v20241008"> <link rel="stylesheet" href="/static/theme-server-status/css/dark.plus.css?v20241103">
</template> </template>
</div> </div>
{{if ts .CustomCode}}{{.CustomCode|safe}}{{end}} {{if ts .CustomCode}}{{.CustomCode|safe}}{{end}}
+3 -3
View File
@@ -26,9 +26,9 @@
<script src="https://unpkg.com/[email protected]/dist/js/bootstrap.min.js"></script> <script src="https://unpkg.com/[email protected]/dist/js/bootstrap.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script> <script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/echarts.min.js"></script> <script src="https://unpkg.com/[email protected]/dist/echarts.min.js"></script>
<link rel="stylesheet" href="/static/theme-server-status/css/main.css?v20241008"> <link rel="stylesheet" href="/static/theme-server-status/css/main.css?v20241103">
<link rel="stylesheet" href="/static/theme-server-status/css/dark.css?v20241008"> <link rel="stylesheet" href="/static/theme-server-status/css/dark.css?v20241103">
<link rel="stylesheet" href="/static/theme-server-status/css/light.css?v20241008"> <link rel="stylesheet" href="/static/theme-server-status/css/light.css?v20241103">
<script src="/static/theme-server-status/js/mixin.js?v20240915"></script> <script src="/static/theme-server-status/js/mixin.js?v20240915"></script>
</head> </head>
<body> <body>
+42 -6
View File
@@ -35,8 +35,8 @@
<span class="node-cell-os-text">@#getPlatformName(node.os) === '' && node.stateuptime > 0 ? 'linux' : getPlatformName(node.os)#@</span> <span class="node-cell-os-text">@#getPlatformName(node.os) === '' && node.stateuptime > 0 ? 'linux' : getPlatformName(node.os)#@</span>
</td> </td>
<td class="node-cell location center"> <td class="node-cell location center">
<i :class="'fi fi-' + (node.stateuptime > 0 ? (node.location || 'rb') : '')"></i> <i :class="'fi fi-' + (node.stateuptime > 0 ? (node.location || 'un') : '')"></i>
<span class="node-cell-location-text text-uppercase">@#node.stateuptime > 0 ? (node.location || 'RB') : ''#@</span> <span class="node-cell-location-text text-uppercase">@#node.stateuptime > 0 ? (node.location || 'UN') : ''#@</span>
</td> </td>
<td v-if="nodesNoTag.some(item => item.additional && item.additional.price && Object.keys(item.additional.price).length > 0)" class="node-cell price center"> <td v-if="nodesNoTag.some(item => item.additional && item.additional.price && Object.keys(item.additional.price).length > 0)" class="node-cell price center">
<template v-if="node.additional && node.additional.price"> <template v-if="node.additional && node.additional.price">
@@ -88,6 +88,45 @@
<td colspan="16"> <td colspan="16">
<div class="accordian-body collapse" :id="'rt'+node.ID"> <div class="accordian-body collapse" :id="'rt'+node.ID">
<div style="display: flex;left-items: center;justify-content: center;flex-direction: column; max-width: 89vw"> <div style="display: flex;left-items: center;justify-content: center;flex-direction: column; max-width: 89vw">
<span v-if="node.additional && Object.keys(node.additional.plan).length > 0" class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "Plan"}}:</span>
<span v-if="node.additional && Object.keys(node.additional.price).length > 0" class="plan price">
<span v-if="node.additional.price.amount == 0">FREE</span>
<span v-else-if="node.additional.price.amount == -1">PAYG</span>
<span v-else><i class="bi bi-cash-stack"></i> @#node.additional.price.amount#@@#(node.additional.price.cycle ? '/' + node.additional.price.cycle : '')#@</span>
</span>
<span v-if="node.additional && node.additional.remaining.endDate" class="plan enddate">
<span v-if="node.additional.remaining.days == 'lifetime'">{{tr "Lifetime"}}</span>
<span v-else-if="node.additional.remaining.days < 0">{{tr "Expired"}}</span>
<span v-else><i class="bi bi-clock-history"></i> @#node.additional.remaining.endDate.toISOString().split('T')[0]#@</span>
</span>
<span v-if="node.additional && node.additional.plan.bandwidth" class="plan bandwidth">
<i class="bi bi-speedometer2"></i>
<span>@#node.additional.plan.bandwidth#@</span>
</span>
<span v-if="node.additional && node.additional.plan.trafficVol" class="plan traffics">
<i v-if="node.additional && node.additional.plan.trafficType == 1" class="bi bi-arrow-up"></i>
<i v-else-if="node.additional && node.additional.plan.trafficType == 3" class="bi bi-arrows-collapse"></i>
<i v-else class="bi bi-arrow-down-up"></i>
<span>@#node.additional.plan.trafficVol#@</span>
</span>
<span v-if="node.additional && node.additional.plan.ipv4" class="plan ipv4">
<span>IPv4</span>
</span>
<span v-if="node.additional && node.additional.plan.ipv6" class="plan ipv6">
<span>IPv6</span>
</span>
<template v-if="node.additional && node.additional.plan.networkRoute.length>0" v-for="(item, index) in node.additional.plan.networkRoute" :key="index">
<span class="plan network-route" :class="{ last: index === node.additional.plan.networkRoute.length - 1 }">
<span>@#item#@</span>
</span>
</template>
<template v-if="node.additional && node.additional.plan.extra.length>0" v-for="(item, index) in node.additional.plan.extra" :key="index">
<span class="plan extra" :class="{ last: index === node.additional.plan.extra.length - 1 }">
<span>@#item#@</span>
</span>
</template>
</span>
<span class="node-cell-expand"> <span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "Platform"}}:</span> <span class="node-cell-expand-label">{{tr "Platform"}}:</span>
<span v-if="node.host.Platform">@#node.host.Platform#@@#node.host.PlatformVersion ? '-' + node.host.PlatformVersion : ''#@</span> <span v-if="node.host.Platform">@#node.host.Platform#@@#node.host.PlatformVersion ? '-' + node.host.PlatformVersion : ''#@</span>
@@ -120,10 +159,7 @@
</span> </span>
<span class="node-cell-expand"> <span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span> <span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span>
<i class="arrow alternate circle down outline icon" IN @#formatByteSize(node.state.NetInTransfer)#@ / OUT @#formatByteSize(node.state.NetOutTransfer)#@
style="margin: 0"></i>@#formatByteSize(node.state.NetInTransfer)#@
<i class="arrow alternate circle up outline icon"
style="margin: 0"></i>@#formatByteSize(node.state.NetOutTransfer)#@
</span> </span>
<span class="node-cell-expand load"> <span class="node-cell-expand load">
<span class="node-cell-expand-label">{{tr "Load"}}:</span> <span class="node-cell-expand-label">{{tr "Load"}}:</span>
+42 -6
View File
@@ -38,8 +38,8 @@
<span class="node-cell-os-text">@#getPlatformName(node.os) === '' && node.stateuptime > 0 ? 'linux' : getPlatformName(node.os)#@</span> <span class="node-cell-os-text">@#getPlatformName(node.os) === '' && node.stateuptime > 0 ? 'linux' : getPlatformName(node.os)#@</span>
</td> </td>
<td class="node-cell location center"> <td class="node-cell location center">
<i :class="'fi fi-' + (node.stateuptime > 0 ? (node.location || 'rb') : '')"></i> <i :class="'fi fi-' + (node.stateuptime > 0 ? (node.location || 'un') : '')"></i>
<span class="node-cell-location-text text-uppercase">@#node.stateuptime > 0 ? (node.location || 'RB') : ''#@</span> <span class="node-cell-location-text text-uppercase">@#node.stateuptime > 0 ? (node.location || 'UN') : ''#@</span>
</td> </td>
<td v-if="group.data.some(item => item.additional && item.additional.price && Object.keys(item.additional.price).length > 0)" class="node-cell price center"> <td v-if="group.data.some(item => item.additional && item.additional.price && Object.keys(item.additional.price).length > 0)" class="node-cell price center">
<template v-if="node.additional && node.additional.price"> <template v-if="node.additional && node.additional.price">
@@ -91,6 +91,45 @@
<td colspan="16"> <td colspan="16">
<div class="accordian-body collapse" :id="'rt'+node.ID"> <div class="accordian-body collapse" :id="'rt'+node.ID">
<div style="display: flex;left-items: center;justify-content: center;flex-direction: column; max-width: 89vw"> <div style="display: flex;left-items: center;justify-content: center;flex-direction: column; max-width: 89vw">
<span v-if="node.additional && Object.keys(node.additional.plan).length > 0" class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "Plan"}}:</span>
<span v-if="node.additional && Object.keys(node.additional.price).length > 0" class="plan price">
<span v-if="node.additional.price.amount == 0">FREE</span>
<span v-else-if="node.additional.price.amount == -1">PAYG</span>
<span v-else><i class="bi bi-cash-stack"></i> @#node.additional.price.amount#@@#(node.additional.price.cycle ? '/' + node.additional.price.cycle : '')#@</span>
</span>
<span v-if="node.additional && node.additional.remaining.endDate" class="plan enddate">
<span v-if="node.additional.remaining.days == 'lifetime'">{{tr "Lifetime"}}</span>
<span v-else-if="node.additional.remaining.days < 0">{{tr "Expired"}}</span>
<span v-else><i class="bi bi-clock-history"></i> @#node.additional.remaining.endDate.toISOString().split('T')[0]#@</span>
</span>
<span v-if="node.additional && node.additional.plan.bandwidth" class="plan bandwidth">
<i class="bi bi-speedometer2"></i>
<span>@#node.additional.plan.bandwidth#@</span>
</span>
<span v-if="node.additional && node.additional.plan.trafficVol" class="plan traffics">
<i v-if="node.additional && node.additional.plan.trafficType == 1" class="bi bi-arrow-up"></i>
<i v-else-if="node.additional && node.additional.plan.trafficType == 3" class="bi bi-arrows-collapse"></i>
<i v-else class="bi bi-arrow-down-up"></i>
<span>@#node.additional.plan.trafficVol#@</span>
</span>
<span v-if="node.additional && node.additional.plan.ipv4" class="plan ipv4">
<span>IPv4</span>
</span>
<span v-if="node.additional && node.additional.plan.ipv6" class="plan ipv6">
<span>IPv6</span>
</span>
<template v-if="node.additional && node.additional.plan.networkRoute.length>0" v-for="(item, index) in node.additional.plan.networkRoute" :key="index">
<span class="plan network-route" :class="{ last: index === node.additional.plan.networkRoute.length - 1 }">
<span>@#item#@</span>
</span>
</template>
<template v-if="node.additional && node.additional.plan.extra.length>0" v-for="(item, index) in node.additional.plan.extra" :key="index">
<span class="plan extra" :class="{ last: index === node.additional.plan.extra.length - 1 }">
<span>@#item#@</span>
</span>
</template>
</span>
<span class="node-cell-expand"> <span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "Platform"}}:</span> <span class="node-cell-expand-label">{{tr "Platform"}}:</span>
<span v-if="node.host.Platform">@#node.host.Platform#@@#node.host.PlatformVersion ? '-' + node.host.PlatformVersion : ''#@</span> <span v-if="node.host.Platform">@#node.host.Platform#@@#node.host.PlatformVersion ? '-' + node.host.PlatformVersion : ''#@</span>
@@ -123,10 +162,7 @@
</span> </span>
<span class="node-cell-expand"> <span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span> <span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span>
<i class="arrow alternate circle down outline icon" IN @#formatByteSize(node.state.NetInTransfer)#@ / OUT @#formatByteSize(node.state.NetOutTransfer)#@
style="margin: 0"></i>@#formatByteSize(node.state.NetInTransfer)#@
<i class="arrow alternate circle up outline icon"
style="margin: 0"></i>@#formatByteSize(node.state.NetOutTransfer)#@
</span> </span>
<span class="node-cell-expand load"> <span class="node-cell-expand load">
<span class="node-cell-expand-label">{{tr "Load"}}:</span> <span class="node-cell-expand-label">{{tr "Load"}}:</span>
+52 -38
View File
@@ -117,43 +117,54 @@
initAdditional(servers) { initAdditional(servers) {
let nodes = {}; let nodes = {};
servers?.forEach(server => { servers?.forEach(server => {
if (server.PublicNote) { //处理异常
const remainingFormat = this.getRemainingFormat(server.live, server.PublicNote); if (!server.PublicNote) return;
const remainingDays = this.getRemainingDays(this.getNoteElementValue(server.PublicNote, "billingDataMod", "endDate"), server.PublicNote);
const remainingPercent = this.getRemainingPercent(
this.getNoteElementValue(server.PublicNote, "billingDataMod", "startDate"),
this.getNoteElementValue(server.PublicNote, "billingDataMod", "endDate"),
server.PublicNote
);
const priceAmount = this.getNoteElementValue(server.PublicNote, "billingDataMod", "amount");
const priceCycle = this.getNoteElementValue(server.PublicNote, "billingDataMod", "cycle");
// 初始化节点 // 初始化节点
nodes[server.ID] = { nodes[server.ID] = {
"remaining": {}, "remaining": {},
"price": {} "price": {},
}; "plan": {}
};
if (remainingFormat) { // 处理 billingDataMod 的 remaining 配置
nodes[server.ID].remaining.format = remainingFormat; const remainingEndDate = this.getRemainingDays(this.getNoteElementValue(server.PublicNote, "billingDataMod", "endDate"), server.PublicNote, 1);
} const remainingFormat = this.getRemainingFormat(server.live, server.PublicNote);
const remainingDays = this.getRemainingDays(this.getNoteElementValue(server.PublicNote, "billingDataMod", "endDate"), server.PublicNote);
const remainingPercent = this.getRemainingPercent(
this.getNoteElementValue(server.PublicNote, "billingDataMod", "startDate"),
this.getNoteElementValue(server.PublicNote, "billingDataMod", "endDate"),
server.PublicNote
);
// 设置 remaining 属性
if (remainingEndDate) nodes[server.ID].remaining.endDate = remainingEndDate;
if (remainingFormat) nodes[server.ID].remaining.format = remainingFormat;
if (remainingDays) nodes[server.ID].remaining.days = remainingDays;
if (remainingPercent) nodes[server.ID].remaining.percent = this.toFixed2(100 - remainingPercent);
if (remainingDays) { // 处理 billingDataMod 的 price 配置
nodes[server.ID].remaining.days = remainingDays; const priceAmount = this.getNoteElementValue(server.PublicNote, "billingDataMod", "amount");
} const priceCycle = this.getNoteElementValue(server.PublicNote, "billingDataMod", "cycle");
// 设置 price 属性
if (remainingPercent) { if (priceAmount) nodes[server.ID].price.amount = priceAmount;
nodes[server.ID].remaining.percent = this.toFixed2(100 - remainingPercent); if (priceCycle && priceAmount) nodes[server.ID].price.cycle = priceCycle;
}
// 处理 planDataMod 配置
if (priceAmount) { const planBandwidth = this.getNoteElementValue(server.PublicNote, "planDataMod", "bandwidth");
nodes[server.ID].price.amount = priceAmount; const planTrafficVol = this.getNoteElementValue(server.PublicNote, "planDataMod", "trafficVol");
} const planTrafficType = this.getNoteElementValue(server.PublicNote, "planDataMod", "trafficType");
const planIPv4 = this.getNoteElementValue(server.PublicNote, "planDataMod", "IPv4");
if (priceCycle && priceAmount) { const planIPv6 = this.getNoteElementValue(server.PublicNote, "planDataMod", "IPv6");
nodes[server.ID].price.cycle = priceCycle; const planNetworkRoute = this.getNoteElementValue(server.PublicNote, "planDataMod", "networkRoute");
} const planExtra = this.getNoteElementValue(server.PublicNote, "planDataMod", "extra");
} // 设置 plan 属性
if (planBandwidth) nodes[server.ID].plan.bandwidth = planBandwidth;
if (planTrafficVol) nodes[server.ID].plan.trafficVol = planTrafficVol;
if (planTrafficType) nodes[server.ID].plan.trafficType = planTrafficType;
if (planIPv4) nodes[server.ID].plan.ipv4 = planIPv4 >= 1;
if (planIPv6) nodes[server.ID].plan.ipv6 = planIPv6 >= 1;
if (planNetworkRoute) nodes[server.ID].plan.networkRoute = planNetworkRoute.split(',');
if (planExtra) nodes[server.ID].plan.extra = planExtra.split(',');
}); });
return nodes; return nodes;
}, },
@@ -859,7 +870,7 @@
const expiration = new Date(endDate); const expiration = new Date(endDate);
const current = this.getAdjustTimezone(new Date(endDate), new Date()); const current = this.getAdjustTimezone(new Date(endDate), new Date());
// 如果 expiration 无效,返回 null 并记录日志 // 如果 expiration 无效,记录日志
if (isNaN(expiration.getTime())) { if (isNaN(expiration.getTime())) {
console.log("getAutoRenewalEndDate: Invalid expiration format"); console.log("getAutoRenewalEndDate: Invalid expiration format");
} }
@@ -1055,7 +1066,7 @@
return this.formatPercents(online, this.toFixed2(percent)); return this.formatPercents(online, this.toFixed2(percent));
}, },
getRemainingDays(endDate, note) { getRemainingDays(endDate, note, type) {
// 检查 endDate 是否有效 // 检查 endDate 是否有效
if (!endDate || typeof endDate !== 'string') { if (!endDate || typeof endDate !== 'string') {
return null; return null;
@@ -1066,9 +1077,9 @@
return "lifetime"; return "lifetime";
} }
// 检查 startDate 和 endDate 是否为合法的Date // 检查 endDate 是否为合法的Date
if (isNaN(new Date(endDate).getTime())) { if (isNaN(new Date(endDate).getTime())) {
return "NaN"; return type === 1 ? null : "NaN";
} }
// 获取当前时间,并调整时区 // 获取当前时间,并调整时区
@@ -1087,6 +1098,9 @@
// 确定到期时间 // 确定到期时间
const end = autoRenewal ? autoEndDate.date : new Date(endDate); const end = autoRenewal ? autoEndDate.date : new Date(endDate);
// 直接返回处理后的到期时间
if (type === 1) return end;
// 计算剩余天数 // 计算剩余天数
const timeDiff = end - currentTime; const timeDiff = end - currentTime;
const daysDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24)); const daysDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
+3 -3
View File
@@ -11,11 +11,11 @@
<input type="text" id="dropdown-search" class="form-control" placeholder="Search..."> <input type="text" id="dropdown-search" class="form-control" placeholder="Search...">
</li> </li>
<li class="dropdown-item" v-for="server in servers" @click="showCharts(server.ID)"> <li class="dropdown-item" v-for="server in servers" @click="showCharts(server.ID)">
<a><i :class="'fi fi-' + (server.Host.CountryCode || 'rb')"></i> @#server.Name#@ <i v-if="server.ID == currentServerId" class="check icon"></i></a> <a><i :class="'fi fi-' + (server.Host.CountryCode || 'un')"></i> @#server.Name#@ <i v-if="server.ID == currentServerId" class="check icon"></i></a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="chartTitle" @click="showCharts(nextServerId)"><i class="chartCountryCode" :class="'fi fi-' + chartCountryCode"></i> @#chartTitle#@</div> <div v-if="chartTitle" class="chartTitle" @click="showCharts(nextServerId)"><i class="chartCountryCode" :class="'fi fi-' + chartCountryCode"></i> @#chartTitle#@</div>
<div id="chartbox" style="width:100%;height:auto;"></div> <div id="chartbox" style="width:100%;height:auto;"></div>
</div> </div>
{{template "theme-server-status/footer" .}} {{template "theme-server-status/footer" .}}
@@ -332,7 +332,7 @@
}, },
getServerCountryCode(id){ getServerCountryCode(id){
const result = this.servers.find(item => item.ID == id); const result = this.servers.find(item => item.ID == id);
return result.Host.CountryCode ? result.Host.CountryCode : 'rb'; return result.Host.CountryCode ? result.Host.CountryCode : 'un';
}, },
getNextServerId(id) { getNextServerId(id) {
const currentIndex = this.servers.findIndex(item => item.ID === id); const currentIndex = this.servers.findIndex(item => item.ID === id);
+1 -1
View File
@@ -51,7 +51,7 @@ if ([string]::IsNullOrWhiteSpace($agenttag)) {
#Region判断 #Region判断
$ipapi = "" $ipapi = ""
$region = "Unknown" $region = "Unknown"
foreach ($url in ("https://dash.cloudflare.com/cdn-cgi/trace","https://cf-ns.com/cdn-cgi/trace","https://1.0.0.1/cdn-cgi/trace")) { foreach ($url in ("https://dash.cloudflare.com/cdn-cgi/trace","https://developers.cloudflare.com/cdn-cgi/trace","https://1.0.0.1/cdn-cgi/trace")) {
try { try {
$ipapi = Invoke-RestMethod -Uri $url -TimeoutSec 5 -UseBasicParsing $ipapi = Invoke-RestMethod -Uri $url -TimeoutSec 5 -UseBasicParsing
if ($ipapi -match "loc=(\w+)" ) { if ($ipapi -match "loc=(\w+)" ) {
+114 -96
View File
@@ -12,13 +12,13 @@ NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard"
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent" NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
NZ_DASHBOARD_SERVICE="/etc/systemd/system/nezha-dashboard.service" NZ_DASHBOARD_SERVICE="/etc/systemd/system/nezha-dashboard.service"
NZ_DASHBOARD_SERVICERC="/etc/init.d/nezha-dashboard" NZ_DASHBOARD_SERVICERC="/etc/init.d/nezha-dashboard"
NZ_VERSION="v0.19.2" NZ_VERSION="v0.20.3"
red='\033[0;31m' red='\033[0;31m'
green='\033[0;32m' green='\033[0;32m'
yellow='\033[0;33m' yellow='\033[0;33m'
plain='\033[0m' plain='\033[0m'
export PATH=$PATH:/usr/local/bin export PATH="$PATH:/usr/local/bin"
os_arch="" os_arch=""
[ -e /etc/os-release ] && grep -i "PRETTY_NAME" /etc/os-release | grep -qi "alpine" && os_alpine='1' [ -e /etc/os-release ] && grep -i "PRETTY_NAME" /etc/os-release | grep -qi "alpine" && os_alpine='1'
@@ -45,20 +45,28 @@ check_systemd() {
} }
err() { err() {
printf "${red}$*${plain}\n" >&2 printf "${red}%s${plain}\n" "$*" >&2
}
success() {
printf "${green}%s${plain}\n" "$*"
}
info() {
printf "${yellow}%s${plain}\n" "$*"
} }
geo_check() { geo_check() {
api_list="https://blog.cloudflare.com/cdn-cgi/trace https://dash.cloudflare.com/cdn-cgi/trace https://cf-ns.com/cdn-cgi/trace" api_list="https://blog.cloudflare.com/cdn-cgi/trace https://dash.cloudflare.com/cdn-cgi/trace https://developers.cloudflare.com/cdn-cgi/trace"
ua="Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0" ua="Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"
set -- $api_list set -- "$api_list"
for url in $api_list; do for url in $api_list; do
text="$(curl -A "$ua" -m 10 -s $url)" text="$(curl -A "$ua" -m 10 -s "$url")"
endpoint="$(echo $text | sed -n 's/.*h=\([^ ]*\).*/\1/p')" endpoint="$(echo "$text" | sed -n 's/.*h=\([^ ]*\).*/\1/p')"
if echo $text | grep -qw 'CN'; then if echo "$text" | grep -qw 'CN'; then
isCN=true isCN=true
break break
elif echo $url | grep -q $endpoint; then elif echo "$url" | grep -q "$endpoint"; then
break break
fi fi
done done
@@ -85,9 +93,9 @@ pre_check() {
## China_IP ## China_IP
if [ -z "$CN" ]; then if [ -z "$CN" ]; then
geo_check geo_check
if [ ! -z "$isCN" ]; then if [ -n "$isCN" ]; then
echo "根据geoip api提供的信息,当前IP可能在中国" echo "根据geoip api提供的信息,当前IP可能在中国"
printf "是否选用中国镜像完成安装? [Y/n] (自定义镜像输入 3):" printf "是否选用中国镜像完成安装? [Y/n] (自定义镜像输入 3)"
read -r input read -r input
case $input in case $input in
[yY][eE][sS] | [yY]) [yY][eE][sS] | [yY])
@@ -180,7 +188,9 @@ installation_check() {
select_version() { select_version() {
if [ -z "$IS_DOCKER_NEZHA" ]; then if [ -z "$IS_DOCKER_NEZHA" ]; then
printf "${yellow}请自行选择您的安装方式(如果你是安装Agent,输入哪个都是一样的):\n1. Docker\n2. 独立安装${plain}\n" info "请自行选择您的安装方式(如果你是安装Agent,输入哪个都是一样的):"
info "1. Docker"
info "2. 独立安装"
while true; do while true; do
printf "请输入选择 [1-2]" printf "请输入选择 [1-2]"
read -r option read -r option
@@ -204,13 +214,18 @@ select_version() {
update_script() { update_script() {
echo "> 更新脚本" echo "> 更新脚本"
curl -sL https://${GITHUB_RAW_URL}/script/install.sh -o /tmp/nezha.sh #curl -sL https://${GITHUB_RAW_URL}/script/install.sh -o /tmp/nezha.sh
new_version=$(grep "NZ_VERSION" /tmp/nezha.sh | head -n 1 | awk -F "=" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g') #new_version=$(grep "NZ_VERSION" /tmp/nezha.sh | head -n 1 | awk -F "=" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
if [ ! -n "$new_version" ]; then #if [ -z "$new_version" ]; then
echo "脚本获取失败,请检查本机能否链接 https://${GITHUB_RAW_URL}/script/install.sh" # echo "脚本获取失败,请检查本机能否链接 https://${GITHUB_RAW_URL}/script/install.sh"
return 1 # return 1
#fi
#echo "当前最新版本为: ${new_version}"
if [ -z "$CN" ]; then
curl -sL https://raw.githubusercontent.com/nezhahq/scripts/main/install.sh -o /tmp/nezha.sh
else
curl -sL https://gitee.com/naibahq/scripts/raw/main/install.sh -o /tmp/nezha.sh
fi fi
echo "当前最新版本为: ${new_version}"
mv -f /tmp/nezha.sh ./nezha.sh && chmod a+x ./nezha.sh mv -f /tmp/nezha.sh ./nezha.sh && chmod a+x ./nezha.sh
echo "3s后执行新脚本" echo "3s后执行新脚本"
@@ -221,7 +236,7 @@ update_script() {
} }
before_show_menu() { before_show_menu() {
echo && printf "${yellow}* 按回车返回主菜单 *${plain}" && read temp echo && info "* 按回车返回主菜单 *" && read temp
show_menu show_menu
} }
@@ -231,7 +246,7 @@ install_base() {
} }
install_arch() { install_arch() {
printf "${green}提示: ${plain} Arch安装libselinux需添加nezha-agent用户,安装完会自动删除,建议手动检查一次\n" info "提示:Arch安装libselinux需添加nezha-agent用户,安装完会自动删除,建议手动检查一次"
read -r -p "是否安装libselinux? [Y/n] " input read -r -p "是否安装libselinux? [Y/n] " input
case $input in case $input in
[yY][eE][sS] | [yY]) [yY][eE][sS] | [yY])
@@ -255,11 +270,11 @@ install_arch() {
} }
install_soft() { install_soft() {
(command -v yum >/dev/null 2>&1 && sudo yum makecache && sudo yum install $* selinux-policy -y) || (command -v yum >/dev/null 2>&1 && sudo yum makecache && sudo yum install "$@" selinux-policy -y) ||
(command -v apt >/dev/null 2>&1 && sudo apt update && sudo apt install $* selinux-utils -y) || (command -v apt >/dev/null 2>&1 && sudo apt update && sudo apt install "$@" selinux-utils -y) ||
(command -v pacman >/dev/null 2>&1 && sudo pacman -Syu $* base-devel --noconfirm && install_arch) || (command -v pacman >/dev/null 2>&1 && sudo pacman -Syu "$@" base-devel --noconfirm && install_arch) ||
(command -v apt-get >/dev/null 2>&1 && sudo apt-get update && sudo apt-get install $* selinux-utils -y) || (command -v apt-get >/dev/null 2>&1 && sudo apt-get update && sudo apt-get install "$@" selinux-utils -y) ||
(command -v apk >/dev/null 2>&1 && sudo apk update && sudo apk add $* -f) (command -v apk >/dev/null 2>&1 && sudo apk update && sudo apk add "$@" -f)
} }
install_dashboard() { install_dashboard() {
@@ -305,12 +320,10 @@ install_dashboard() {
install_dashboard_docker() { install_dashboard_docker() {
if [ ! "$FRESH_INSTALL" = 0 ]; then if [ ! "$FRESH_INSTALL" = 0 ]; then
command -v docker >/dev/null 2>&1 if ! command -v docker >/dev/null 2>&1; then
if [ $? != 0 ]; then
echo "正在安装 Docker" echo "正在安装 Docker"
if [ "$os_alpine" != 1 ]; then if [ "$os_alpine" != 1 ]; then
curl -sL https://${Get_Docker_URL} | sudo bash -s ${Get_Docker_Argu} if ! curl -sL https://${Get_Docker_URL} | sudo bash -s "${Get_Docker_Argu}"; then
if [ $? != 0 ]; then
err "下载脚本失败,请检查本机能否连接 ${Get_Docker_URL}" err "下载脚本失败,请检查本机能否连接 ${Get_Docker_URL}"
return 0 return 0
fi fi
@@ -321,7 +334,7 @@ install_dashboard_docker() {
sudo rc-update add docker sudo rc-update add docker
sudo rc-service docker start sudo rc-service docker start
fi fi
printf "${green}Docker${plain} 安装成功\n" success "Docker 安装成功"
installation_check installation_check
fi fi
fi fi
@@ -334,13 +347,11 @@ install_dashboard_standalone() {
} }
selinux() { selinux() {
#判断当前的状态 #Check SELinux
command -v getenforce >/dev/null 2>&1 if command -v getenforce >/dev/null 2>&1; then
if [ $? -eq 0 ]; then if getenforce | grep '[Ee]nfor'; then
getenforce | grep '[Ee]nfor'
if [ $? -eq 0 ]; then
echo "SELinux是开启状态,正在关闭!" echo "SELinux是开启状态,正在关闭!"
sudo setenforce 0 &>/dev/null sudo setenforce 0 >/dev/null 2>&1
find_key="SELINUX=" find_key="SELINUX="
sudo sed -ri "/^$find_key/c${find_key}disabled" /etc/selinux/config sudo sed -ri "/^$find_key/c${find_key}disabled" /etc/selinux/config
fi fi
@@ -355,22 +366,23 @@ install_agent() {
echo "正在获取监控Agent版本号" echo "正在获取监控Agent版本号"
local version=$(curl -m 10 -sL "https://api.github.com/repos/nezhahq/agent/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
if [ ! -n "$version" ]; then _version=$(curl -m 10 -sL "https://api.github.com/repos/nezhahq/agent/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
version=$(curl -m 10 -sL "https://gitee.com/api/v5/repos/naibahq/agent/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}') if [ -z "$_version" ]; then
_version=$(curl -m 10 -sL "https://gitee.com/api/v5/repos/naibahq/agent/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g') _version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g') _version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
err "获取版本号失败,请检查本机能否链接 https://api.github.com/repos/nezhahq/agent/releases/latest" err "获取版本号失败,请检查本机能否链接 https://api.github.com/repos/nezhahq/agent/releases/latest"
return 1 return 1
else else
echo "当前最新版本为: ${version}" echo "当前最新版本为: ${_version}"
fi fi
# 哪吒监控文件夹 # 哪吒监控文件夹
@@ -378,12 +390,13 @@ install_agent() {
echo "正在下载监控端" echo "正在下载监控端"
if [ -z "$CN" ]; then if [ -z "$CN" ]; then
NZ_AGENT_URL="https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_linux_${os_arch}.zip" NZ_AGENT_URL="https://${GITHUB_URL}/nezhahq/agent/releases/download/${_version}/nezha-agent_linux_${os_arch}.zip"
else else
NZ_AGENT_URL="https://${GITHUB_URL}/naibahq/agent/releases/download/${version}/nezha-agent_linux_${os_arch}.zip" NZ_AGENT_URL="https://${GITHUB_URL}/naibahq/agent/releases/download/${_version}/nezha-agent_linux_${os_arch}.zip"
fi fi
wget -t 2 -T 60 -O nezha-agent_linux_${os_arch}.zip $NZ_AGENT_URL >/dev/null 2>&1
if [ $? != 0 ]; then _cmd="wget -t 2 -T 60 -O nezha-agent_linux_${os_arch}.zip $NZ_AGENT_URL >/dev/null 2>&1"
if ! eval "$_cmd"; then
err "Release 下载失败,请检查本机能否连接 ${GITHUB_URL}" err "Release 下载失败,请检查本机能否连接 ${GITHUB_URL}"
return 1 return 1
fi fi
@@ -435,14 +448,14 @@ modify_agent_config() {
fi fi
fi fi
sudo ${NZ_AGENT_PATH}/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p $nz_client_secret $args >/dev/null 2>&1 _cmd="sudo ${NZ_AGENT_PATH}/nezha-agent service install -s $nz_grpc_host:$nz_grpc_port -p $nz_client_secret $args >/dev/null 2>&1"
if [ $? -ne 0 ]; then if ! eval "$_cmd"; then
sudo ${NZ_AGENT_PATH}/nezha-agent service uninstall >/dev/null 2>&1 sudo "${NZ_AGENT_PATH}"/nezha-agent service uninstall >/dev/null 2>&1
sudo ${NZ_AGENT_PATH}/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p $nz_client_secret $args >/dev/null 2>&1 sudo "${NZ_AGENT_PATH}"/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p "$nz_client_secret" "$args" >/dev/null 2>&1
fi fi
printf "Agent配置 ${green}修改成功,请稍等重启生效${plain}\n" success "Agent配置 修改成功,请稍等重启生效"
#if [[ $# == 0 ]]; then #if [[ $# == 0 ]]; then
# before_show_menu # before_show_menu
@@ -453,10 +466,10 @@ modify_dashboard_config() {
echo "> 修改面板配置" echo "> 修改面板配置"
if [ "$IS_DOCKER_NEZHA" = 1 ]; then if [ "$IS_DOCKER_NEZHA" = 1 ]; then
if [ ! -z "$DOCKER_COMPOSE_COMMAND" ]; then if [ -n "$DOCKER_COMPOSE_COMMAND" ]; then
echo "正在下载 Docker 脚本" echo "正在下载 Docker 脚本"
wget -t 2 -T 60 -O /tmp/nezha-docker-compose.yaml https://${GITHUB_RAW_URL}/script/docker-compose.yaml >/dev/null 2>&1 _cmd="wget -t 2 -T 60 -O /tmp/nezha-docker-compose.yaml https://${GITHUB_RAW_URL}/script/docker-compose.yaml >/dev/null 2>&1"
if [ $? != 0 ]; then if ! eval "$_cmd"; then
err "下载脚本失败,请检查本机能否连接 ${GITHUB_RAW_URL}" err "下载脚本失败,请检查本机能否连接 ${GITHUB_RAW_URL}"
return 0 return 0
fi fi
@@ -466,8 +479,8 @@ modify_dashboard_config() {
fi fi
fi fi
wget -t 2 -T 60 -O /tmp/nezha-config.yaml https://${GITHUB_RAW_URL}/script/config.yaml >/dev/null 2>&1 _cmd="wget -t 2 -T 60 -O /tmp/nezha-config.yaml https://${GITHUB_RAW_URL}/script/config.yaml >/dev/null 2>&1"
if [ $? != 0 ]; then if ! eval "$_cmd"; then
err "下载脚本失败,请检查本机能否连接 ${GITHUB_RAW_URL}" err "下载脚本失败,请检查本机能否连接 ${GITHUB_RAW_URL}"
return 0 return 0
fi fi
@@ -529,18 +542,22 @@ modify_dashboard_config() {
if [ "$IS_DOCKER_NEZHA" = 0 ]; then if [ "$IS_DOCKER_NEZHA" = 0 ]; then
echo "正在下载服务文件" echo "正在下载服务文件"
if [ "$os_alpine" != 1 ]; then if [ "$os_alpine" != 1 ]; then
sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICE https://${GITHUB_RAW_URL}/script/nezha-dashboard.service >/dev/null 2>&1 _download="sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICE https://${GITHUB_RAW_URL}/script/nezha-dashboard.service >/dev/null 2>&1"
else if ! eval "$_download"; then
sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-dashboard >/dev/null 2>&1
sudo chmod +x $NZ_DASHBOARD_SERVICERC
if [ $? != 0 ]; then
err "文件下载失败,请检查本机能否连接 ${GITHUB_RAW_URL}" err "文件下载失败,请检查本机能否连接 ${GITHUB_RAW_URL}"
return 0 return 0
fi fi
else
_download="sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-dashboard >/dev/null 2>&1"
if ! eval "$_download"; then
err "文件下载失败,请检查本机能否连接 ${GITHUB_RAW_URL}"
return 0
fi
sudo chmod +x $NZ_DASHBOARD_SERVICERC
fi fi
fi fi
printf "面板配置 ${green}修改成功,请稍等重启生效${plain}\n" success "面板配置 修改成功,请稍等重启生效"
restart_and_update restart_and_update
@@ -553,14 +570,14 @@ restart_and_update() {
echo "> 重启并更新面板" echo "> 重启并更新面板"
if [ "$IS_DOCKER_NEZHA" = 1 ]; then if [ "$IS_DOCKER_NEZHA" = 1 ]; then
restart_and_update_docker _cmd="restart_and_update_docker"
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
restart_and_update_standalone _cmd="restart_and_update_standalone"
fi fi
if [ $? = 0 ]; then if eval "$_cmd"; then
printf "${green}哪吒监控 重启成功${plain}\n" success "哪吒监控 重启成功"
printf "默认管理面板地址:${yellow}域名:站点访问端口${plain}\n" info "默认管理面板地址:域名:站点访问端口"
else else
err "重启失败,可能是因为启动时间超过了两秒,请稍后查看日志信息" err "重启失败,可能是因为启动时间超过了两秒,请稍后查看日志信息"
fi fi
@@ -577,15 +594,22 @@ restart_and_update_docker() {
} }
restart_and_update_standalone() { restart_and_update_standalone() {
local version=$(curl -m 10 -sL "https://api.github.com/repos/naiba/nezha/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g') _version=$(curl -m 10 -sL "https://api.github.com/repos/naiba/nezha/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
version=$(curl -m 10 -sL "https://gitee.com/api/v5/repos/naibahq/nezha/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}') _version=$(curl -m 10 -sL "https://gitee.com/api/v5/repos/naibahq/nezha/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g') _version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g') _version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g')
fi
if [ -z "$_version" ]; then
err "获取版本号失败,请检查本机能否链接 https://api.github.com/repos/naiba/nezha/releases/latest"
return 1
else
echo "当前最新版本为: ${_version}"
fi fi
if [ "$os_alpine" != 1 ]; then if [ "$os_alpine" != 1 ]; then
@@ -595,20 +619,14 @@ restart_and_update_standalone() {
sudo rc-service nezha-dashboard stop sudo rc-service nezha-dashboard stop
fi fi
if [ ! -n "$version" ]; then
err "获取版本号失败,请检查本机能否链接 https://api.github.com/repos/naiba/nezha/releases/latest"
return 1
else
echo "当前最新版本为: ${version}"
fi
if [ -z "$CN" ]; then if [ -z "$CN" ]; then
NZ_DASHBOARD_URL="https://${GITHUB_URL}/naiba/nezha/releases/download/$version/dashboard-linux-$os_arch.zip" NZ_DASHBOARD_URL="https://${GITHUB_URL}/naiba/nezha/releases/download/${_version}/dashboard-linux-${os_arch}.zip"
else else
NZ_DASHBOARD_URL="https://${GITHUB_URL}/naibahq/nezha/releases/download/$version/dashboard-linux-$os_arch.zip" NZ_DASHBOARD_URL="https://${GITHUB_URL}/naibahq/nezha/releases/download/${_version}/dashboard-linux-${os_arch}.zip"
fi fi
sudo wget -qO $NZ_DASHBOARD_PATH/app.zip $NZ_DASHBOARD_URL >/dev/null 2>&1 && sudo unzip -qq -o $NZ_DASHBOARD_PATH/app.zip -d $NZ_DASHBOARD_PATH && sudo mv $NZ_DASHBOARD_PATH/dashboard-linux-$os_arch $NZ_DASHBOARD_PATH/app && sudo rm $NZ_DASHBOARD_PATH/app.zip sudo wget -qO $NZ_DASHBOARD_PATH/app.zip "$NZ_DASHBOARD_URL" >/dev/null 2>&1 && sudo unzip -qq -o $NZ_DASHBOARD_PATH/app.zip -d $NZ_DASHBOARD_PATH && sudo mv $NZ_DASHBOARD_PATH/dashboard-linux-$os_arch $NZ_DASHBOARD_PATH/app && sudo rm $NZ_DASHBOARD_PATH/app.zip
sudo chmod +x $NZ_DASHBOARD_PATH/app
if [ "$os_alpine" != 1 ]; then if [ "$os_alpine" != 1 ]; then
sudo systemctl enable nezha-dashboard sudo systemctl enable nezha-dashboard
@@ -623,13 +641,13 @@ start_dashboard() {
echo "> 启动面板" echo "> 启动面板"
if [ "$IS_DOCKER_NEZHA" = 1 ]; then if [ "$IS_DOCKER_NEZHA" = 1 ]; then
start_dashboard_docker _cmd="start_dashboard_docker"
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
start_dashboard_standalone _cmd="start_dashboard_standalone"
fi fi
if [ $? = 0 ]; then if eval "$_cmd"; then
printf "${green}哪吒监控 启动成功${plain}\n" success "哪吒监控 启动成功"
else else
err "启动失败,请稍后查看日志信息" err "启动失败,请稍后查看日志信息"
fi fi
@@ -655,13 +673,13 @@ stop_dashboard() {
echo "> 停止面板" echo "> 停止面板"
if [ "$IS_DOCKER_NEZHA" = 1 ]; then if [ "$IS_DOCKER_NEZHA" = 1 ]; then
stop_dashboard_docker _cmd="stop_dashboard_docker"
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
stop_dashboard_standalone _cmd="stop_dashboard_standalone"
fi fi
if [ $? = 0 ]; then if eval "$_cmd"; then
printf "${green}哪吒监控 停止成功${plain}\n" success "哪吒监控 停止成功"
else else
err "停止失败,请稍后查看日志信息" err "停止失败,请稍后查看日志信息"
fi fi
@@ -940,4 +958,4 @@ if [ $# -gt 0 ]; then
else else
select_version select_version
show_menu show_menu
fi fi
+135 -112
View File
@@ -12,13 +12,13 @@ NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard"
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent" NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
NZ_DASHBOARD_SERVICE="/etc/systemd/system/nezha-dashboard.service" NZ_DASHBOARD_SERVICE="/etc/systemd/system/nezha-dashboard.service"
NZ_DASHBOARD_SERVICERC="/etc/init.d/nezha-dashboard" NZ_DASHBOARD_SERVICERC="/etc/init.d/nezha-dashboard"
NZ_VERSION="v0.19.2" NZ_VERSION="v0.20.3"
red='\033[0;31m' red='\033[0;31m'
green='\033[0;32m' green='\033[0;32m'
yellow='\033[0;33m' yellow='\033[0;33m'
plain='\033[0m' plain='\033[0m'
export PATH=$PATH:/usr/local/bin export PATH="$PATH:/usr/local/bin"
os_arch="" os_arch=""
[ -e /etc/os-release ] && grep -i "PRETTY_NAME" /etc/os-release | grep -qi "alpine" && os_alpine='1' [ -e /etc/os-release ] && grep -i "PRETTY_NAME" /etc/os-release | grep -qi "alpine" && os_alpine='1'
@@ -45,20 +45,28 @@ check_systemd() {
} }
err() { err() {
printf "${red}$*${plain}\n" >&2 printf "${red}%s${plain}\n" "$*" >&2
}
success() {
printf "${green}%s${plain}\n" "$*"
}
info() {
printf "${yellow}%s${plain}\n" "$*"
} }
geo_check() { geo_check() {
api_list="https://blog.cloudflare.com/cdn-cgi/trace https://dash.cloudflare.com/cdn-cgi/trace https://cf-ns.com/cdn-cgi/trace" api_list="https://blog.cloudflare.com/cdn-cgi/trace https://dash.cloudflare.com/cdn-cgi/trace https://developers.cloudflare.com/cdn-cgi/trace"
ua="Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0" ua="Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"
set -- $api_list set -- "$api_list"
for url in $api_list; do for url in $api_list; do
text="$(curl -A "$ua" -m 10 -s $url)" text="$(curl -A "$ua" -m 10 -s "$url")"
endpoint="$(echo $text | sed -n 's/.*h=\([^ ]*\).*/\1/p')" endpoint="$(echo "$text" | sed -n 's/.*h=\([^ ]*\).*/\1/p')"
if echo $text | grep -qw 'CN'; then if echo "$text" | grep -qw 'CN'; then
isCN=true isCN=true
break break
elif echo $url | grep -q $endpoint; then elif echo "$url" | grep -q "$endpoint"; then
break break
fi fi
done done
@@ -85,7 +93,7 @@ pre_check() {
## China_IP ## China_IP
if [ -z "$CN" ]; then if [ -z "$CN" ]; then
geo_check geo_check
if [ ! -z "$isCN" ]; then if [ -n "$isCN" ]; then
echo "According to the information provided by various geoip api, the current IP may be in China" echo "According to the information provided by various geoip api, the current IP may be in China"
printf "Will the installation be done with a Chinese Mirror? [Y/n] (Custom Mirror Input 3): " printf "Will the installation be done with a Chinese Mirror? [Y/n] (Custom Mirror Input 3): "
read -r input read -r input
@@ -179,7 +187,9 @@ installation_check() {
select_version() { select_version() {
if [ -z "$IS_DOCKER_NEZHA" ]; then if [ -z "$IS_DOCKER_NEZHA" ]; then
printf "${yellow}Select your installation method(Input anything is ok if you are installing agent):\n1. Docker\n2. Standalone${plain}\n" info "Select your installation method(Input anything is ok if you are installing agent):"
info "1. Docker"
info "2. Standalone"
while true; do while true; do
printf "Please enter [1-2]: " printf "Please enter [1-2]: "
read -r option read -r option
@@ -203,13 +213,18 @@ select_version() {
update_script() { update_script() {
echo "> Update Script" echo "> Update Script"
curl -sL https://${GITHUB_RAW_URL}/script/install_en.sh -o /tmp/nezha.sh #curl -sL https://${GITHUB_RAW_URL}/script/install_en.sh -o /tmp/nezha.sh
new_version=$(grep "NZ_VERSION" /tmp/nezha.sh | head -n 1 | awk -F "=" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g') #new_version=$(grep "NZ_VERSION" /tmp/nezha.sh | head -n 1 | awk -F "=" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
if [ ! -n "$new_version" ]; then #if [ -z "$new_version" ]; then
echo "Script failed to get, please check if the network can link https://${GITHUB_RAW_URL}/script/install.sh" # echo "Script failed to get, please check if the network can link https://${GITHUB_RAW_URL}/script/install.sh"
return 1 # return 1
#fi
#echo "The current latest version is: ${new_version}"
if [ -z "$CN" ]; then
curl -sL https://raw.githubusercontent.com/nezhahq/scripts/main/install_en.sh -o /tmp/nezha.sh
else
curl -sL https://gitee.com/naibahq/scripts/raw/main/install_en.sh -o /tmp/nezha.sh
fi fi
echo "The current latest version is: ${new_version}"
mv -f /tmp/nezha.sh ./nezha.sh && chmod a+x ./nezha.sh mv -f /tmp/nezha.sh ./nezha.sh && chmod a+x ./nezha.sh
echo "Execute new script after 3s" echo "Execute new script after 3s"
@@ -220,7 +235,7 @@ update_script() {
} }
before_show_menu() { before_show_menu() {
echo && printf "${yellow}* Press Enter to return to the main menu *${plain}" && read temp echo && info "* Press Enter to return to the main menu *" && read temp
show_menu show_menu
} }
@@ -230,7 +245,7 @@ install_base() {
} }
install_arch() { install_arch() {
printf "${green}Info: ${plain} Archlinux needs to add nezha-agent user to install libselinux. It will be deleted automatically after installation. It is recommended to check manually\n" info "Archlinux needs to add nezha-agent user to install libselinux. It will be deleted automatically after installation. It is recommended to check manually"
read -r -p "Do you need to install libselinux? [Y/n] " input read -r -p "Do you need to install libselinux? [Y/n] " input
case $input in case $input in
[yY][eE][sS] | [yY]) [yY][eE][sS] | [yY])
@@ -254,11 +269,11 @@ install_arch() {
} }
install_soft() { install_soft() {
(command -v yum >/dev/null 2>&1 && sudo yum makecache && sudo yum install $* selinux-policy -y) || (command -v yum >/dev/null 2>&1 && sudo yum makecache && sudo yum install "$@" selinux-policy -y) ||
(command -v apt >/dev/null 2>&1 && sudo apt update && sudo apt install $* selinux-utils -y) || (command -v apt >/dev/null 2>&1 && sudo apt update && sudo apt install "$@" selinux-utils -y) ||
(command -v pacman >/dev/null 2>&1 && sudo pacman -Syu $* base-devel --noconfirm && install_arch) || (command -v pacman >/dev/null 2>&1 && sudo pacman -Syu "$@" base-devel --noconfirm && install_arch) ||
(command -v apt-get >/dev/null 2>&1 && sudo apt-get update && sudo apt-get install $* selinux-utils -y) || (command -v apt-get >/dev/null 2>&1 && sudo apt-get update && sudo apt-get install "$@" selinux-utils -y) ||
(command -v apk >/dev/null 2>&1 && sudo apk update && sudo apk add $* -f) (command -v apk >/dev/null 2>&1 && sudo apk update && sudo apk add "$@" -f)
} }
install_dashboard() { install_dashboard() {
@@ -304,12 +319,10 @@ install_dashboard() {
install_dashboard_docker() { install_dashboard_docker() {
if [ ! "$FRESH_INSTALL" = 0 ]; then if [ ! "$FRESH_INSTALL" = 0 ]; then
command -v docker >/dev/null 2>&1 if ! command -v docker >/dev/null 2>&1; then
if [ $? != 0 ]; then
echo "Installing Docker" echo "Installing Docker"
if [ "$os_alpine" != 1 ]; then if [ "$os_alpine" != 1 ]; then
curl -sL https://${Get_Docker_URL} | sudo bash -s ${Get_Docker_Argu} if ! curl -sL https://${Get_Docker_URL} | sudo bash -s "${Get_Docker_Argu}"; then
if [ $? != 0 ]; then
err "Script failed to get, please check if the network can link ${Get_Docker_URL}" err "Script failed to get, please check if the network can link ${Get_Docker_URL}"
return 0 return 0
fi fi
@@ -320,7 +333,7 @@ install_dashboard_docker() {
sudo rc-update add docker sudo rc-update add docker
sudo rc-service docker start sudo rc-service docker start
fi fi
printf "${green}Docker${plain} installed successfully\n" success "Docker installed successfully"
installation_check installation_check
fi fi
fi fi
@@ -334,12 +347,10 @@ install_dashboard_standalone() {
selinux() { selinux() {
#Check SELinux #Check SELinux
command -v getenforce >/dev/null 2>&1 if command -v getenforce >/dev/null 2>&1; then
if [ $? -eq 0 ]; then if getenforce | grep '[Ee]nfor'; then
getenforce | grep '[Ee]nfor'
if [ $? -eq 0 ]; then
echo "SELinux running, closing now!" echo "SELinux running, closing now!"
sudo setenforce 0 &>/dev/null sudo setenforce 0 >/dev/null 2>&1
find_key="SELINUX=" find_key="SELINUX="
sudo sed -ri "/^$find_key/c${find_key}disabled" /etc/selinux/config sudo sed -ri "/^$find_key/c${find_key}disabled" /etc/selinux/config
fi fi
@@ -354,30 +365,37 @@ install_agent() {
echo "Obtaining Agent version number" echo "Obtaining Agent version number"
local version=$(curl -m 10 -sL "https://api.github.com/repos/nezhahq/agent/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
if [ ! -n "$version" ]; then _version=$(curl -m 10 -sL "https://api.github.com/repos/nezhahq/agent/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
version=$(curl -m 10 -sL "https://gitee.com/api/v5/repos/naibahq/agent/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}') if [ -z "$_version" ]; then
_version=$(curl -m 10 -sL "https://gitee.com/api/v5/repos/naibahq/agent/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g') _version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g') _version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
err "Fail to obtaine agent version, please check if the network can link https://api.github.com/repos/nezhahq/agent/releases/latest" err "Fail to obtain agent version, please check if the network can link https://api.github.com/repos/nezhahq/agent/releases/latest"
return 1 return 1
else else
echo "The current latest version is: ${version}" echo "The current latest version is: ${_version}"
fi fi
# Nezha Monitoring Folder # Nezha Monitoring Folder
sudo mkdir -p $NZ_AGENT_PATH sudo mkdir -p $NZ_AGENT_PATH
echo "Downloading Agent" echo "Downloading Agent"
wget -t 2 -T 60 -O nezha-agent_linux_${os_arch}.zip https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_linux_${os_arch}.zip >/dev/null 2>&1 if [ -z "$CN" ]; then
if [ $? != 0 ]; then NZ_AGENT_URL="https://${GITHUB_URL}/nezhahq/agent/releases/download/${_version}/nezha-agent_linux_${os_arch}.zip"
else
NZ_AGENT_URL="https://${GITHUB_URL}/naibahq/agent/releases/download/${_version}/nezha-agent_linux_${os_arch}.zip"
fi
_cmd="wget -t 2 -T 60 -O nezha-agent_linux_${os_arch}.zip $NZ_AGENT_URL >/dev/null 2>&1"
if ! eval "$_cmd"; then
err "Fail to download agent, please check if the network can link ${GITHUB_URL}" err "Fail to download agent, please check if the network can link ${GITHUB_URL}"
return 1 return 1
fi fi
@@ -401,10 +419,10 @@ modify_agent_config() {
echo "> Modify Agent Configuration" echo "> Modify Agent Configuration"
if [ $# -lt 3 ]; then if [ $# -lt 3 ]; then
echo "Please add Agent in the admin panel first, record the secret" echo "Please add Agent in the Dashboard first, record the secret"
printf "Please enter a domain that resolves to the IP where the panel is located (no CDN): " printf "Please enter a domain that resolves to the IP where Dashboard is located (no CDN): "
read -r nz_grpc_host read -r nz_grpc_host
printf "Please enter the panel RPC port (default 5555): " printf "Please enter Dashboard RPC port (default 5555): "
read -r nz_grpc_port read -r nz_grpc_port
printf "Please enter the Agent secret: " printf "Please enter the Agent secret: "
read -r nz_client_secret read -r nz_client_secret
@@ -429,14 +447,14 @@ modify_agent_config() {
fi fi
fi fi
sudo ${NZ_AGENT_PATH}/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p $nz_client_secret $args >/dev/null 2>&1 _cmd="sudo ${NZ_AGENT_PATH}/nezha-agent service install -s $nz_grpc_host:$nz_grpc_port -p $nz_client_secret $args >/dev/null 2>&1"
if [ $? -ne 0 ]; then if ! eval "$_cmd"; then
sudo ${NZ_AGENT_PATH}/nezha-agent service uninstall >/dev/null 2>&1 sudo "${NZ_AGENT_PATH}"/nezha-agent service uninstall >/dev/null 2>&1
sudo ${NZ_AGENT_PATH}/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p $nz_client_secret $args >/dev/null 2>&1 sudo "${NZ_AGENT_PATH}"/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p "$nz_client_secret" "$args" >/dev/null 2>&1
fi fi
printf "Agent configuration ${green} modified successfully, please wait for agent self-restart to take effect${plain}\n" success "Agent configuration modified successfully, please wait for agent self-restart to take effect"
#if [[ $# == 0 ]]; then #if [[ $# == 0 ]]; then
# before_show_menu # before_show_menu
@@ -447,21 +465,21 @@ modify_dashboard_config() {
echo "> Modify Dashboard Configuration" echo "> Modify Dashboard Configuration"
if [ "$IS_DOCKER_NEZHA" = 1 ]; then if [ "$IS_DOCKER_NEZHA" = 1 ]; then
if [ ! -z "$DOCKER_COMPOSE_COMMAND" ]; then if [ -n "$DOCKER_COMPOSE_COMMAND" ]; then
echo "Download Docker Script" echo "Download Docker Script"
wget -t 2 -T 60 -O /tmp/nezha-docker-compose.yaml https://${GITHUB_RAW_URL}/script/docker-compose.yaml >/dev/null 2>&1 _cmd="wget -t 2 -T 60 -O /tmp/nezha-docker-compose.yaml https://${GITHUB_RAW_URL}/script/docker-compose.yaml >/dev/null 2>&1"
if [ $? != 0 ]; then if ! eval "$_cmd"; then
err "Script failed to get, please check if the network can link ${GITHUB_RAW_URL}" err "Script failed to get, please check if the network can link ${GITHUB_RAW_URL}"
return 0 return 0
fi fi
else else
err "请手动安装 docker-composehttps://docs.docker.com/compose/install/linux/" err "Please install docker-compose manually. https://docs.docker.com/compose/install/linux/"
before_show_menu before_show_menu
fi fi
fi fi
wget -t 2 -T 60 -O /tmp/nezha-config.yaml https://${GITHUB_RAW_URL}/script/config.yaml >/dev/null 2>&1 _cmd="wget -t 2 -T 60 -O /tmp/nezha-config.yaml https://${GITHUB_RAW_URL}/script/config.yaml >/dev/null 2>&1"
if [ $? != 0 ]; then if ! eval "$_cmd"; then
err "Script failed to get, please check if the network can link ${GITHUB_RAW_URL}" err "Script failed to get, please check if the network can link ${GITHUB_RAW_URL}"
return 0 return 0
fi fi
@@ -523,18 +541,22 @@ modify_dashboard_config() {
if [ "$IS_DOCKER_NEZHA" = 0 ]; then if [ "$IS_DOCKER_NEZHA" = 0 ]; then
echo "Downloading service file" echo "Downloading service file"
if [ "$os_alpine" != 1 ]; then if [ "$os_alpine" != 1 ]; then
sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICE https://${GITHUB_RAW_URL}/script/nezha-dashboard.service >/dev/null 2>&1 _download="sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICE https://${GITHUB_RAW_URL}/script/nezha-dashboard.service >/dev/null 2>&1"
else if ! eval "$_download"; then
sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-dashboard >/dev/null 2>&1
sudo chmod +x $NZ_DASHBOARD_SERVICERC
if [ $? != 0 ]; then
err "File failed to get, please check if the network can link ${GITHUB_RAW_URL}" err "File failed to get, please check if the network can link ${GITHUB_RAW_URL}"
return 0 return 0
fi fi
else
_download="sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-dashboard >/dev/null 2>&1"
if ! eval "$_download"; then
err "File failed to get, please check if the network can link ${GITHUB_RAW_URL}"
return 0
fi
sudo chmod +x $NZ_DASHBOARD_SERVICERC
fi fi
fi fi
printf "Dashboard configuration ${green} modified successfully, please wait for Dashboard self-restart to take effect${plain}\n" success "Dashboard configuration modified successfully, please wait for Dashboard self-restart to take effect"
restart_and_update restart_and_update
@@ -544,17 +566,17 @@ modify_dashboard_config() {
} }
restart_and_update() { restart_and_update() {
echo "> Restart and Update the Panel" echo "> Restart and Update Dashboard"
if [ "$IS_DOCKER_NEZHA" = 1 ]; then if [ "$IS_DOCKER_NEZHA" = 1 ]; then
restart_and_update_docker _cmd="restart_and_update_docker"
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
restart_and_update_standalone _cmd="restart_and_update_standalone"
fi fi
if [ $? = 0 ]; then if eval "$_cmd"; then
printf "${green}Nezha Monitoring Restart Successful${plain}\n" success "Nezha Monitoring Restart Successful"
printf "Default panel address: ${yellow}domain:Site_access_port${plain}\n" info "Default Dashboard address: domain:site_access_port"
else else
err "The restart failed, probably because the boot time exceeded two seconds, please check the log information later" err "The restart failed, probably because the boot time exceeded two seconds, please check the log information later"
fi fi
@@ -571,22 +593,22 @@ restart_and_update_docker() {
} }
restart_and_update_standalone() { restart_and_update_standalone() {
local version=$(curl -m 10 -sL "https://api.github.com/repos/naiba/nezha/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g') _version=$(curl -m 10 -sL "https://api.github.com/repos/naiba/nezha/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
version=$(curl -m 10 -sL "https://gitee.com/api/v5/repos/naibahq/nezha/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}') _version=$(curl -m 10 -sL "https://gitee.com/api/v5/repos/naibahq/nezha/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g') _version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g') _version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g')
fi fi
if [ ! -n "$version" ]; then if [ -z "$_version" ]; then
err "Fail to obtaine agent version, please check if the network can link https://api.github.com/repos/nezhahq/agent/releases/latest" err "Fail to obtain agent version, please check if the network can link https://api.github.com/repos/nezhahq/agent/releases/latest"
return 1 return 1
else else
echo "The current latest version is: ${version}" echo "The current latest version is: ${_version}"
fi fi
if [ "$os_alpine" != 1 ]; then if [ "$os_alpine" != 1 ]; then
@@ -597,12 +619,13 @@ restart_and_update_standalone() {
fi fi
if [ -z "$CN" ]; then if [ -z "$CN" ]; then
NZ_DASHBOARD_URL="https://${GITHUB_URL}/naiba/nezha/releases/download/$version/dashboard-linux-$os_arch.zip" NZ_DASHBOARD_URL="https://${GITHUB_URL}/naiba/nezha/releases/download/${_version}/dashboard-linux-${os_arch}.zip"
else else
NZ_DASHBOARD_URL="https://${GITHUB_URL}/naibahq/nezha/releases/download/$version/dashboard-linux-$os_arch.zip" NZ_DASHBOARD_URL="https://${GITHUB_URL}/naibahq/nezha/releases/download/${_version}/dashboard-linux-${os_arch}.zip"
fi fi
sudo wget -qO $NZ_DASHBOARD_PATH/app.zip $NZ_DASHBOARD_URL >/dev/null 2>&1 && sudo unzip -qq -o $NZ_DASHBOARD_PATH/app.zip -d $NZ_DASHBOARD_PATH && sudo mv $NZ_DASHBOARD_PATH/dashboard-linux-$os_arch $NZ_DASHBOARD_PATH/app && sudo rm $NZ_DASHBOARD_PATH/app.zip sudo wget -qO $NZ_DASHBOARD_PATH/app.zip "$NZ_DASHBOARD_URL" >/dev/null 2>&1 && sudo unzip -qq -o $NZ_DASHBOARD_PATH/app.zip -d $NZ_DASHBOARD_PATH && sudo mv $NZ_DASHBOARD_PATH/dashboard-linux-$os_arch $NZ_DASHBOARD_PATH/app && sudo rm $NZ_DASHBOARD_PATH/app.zip
sudo chmod +x $NZ_DASHBOARD_PATH/app
if [ "$os_alpine" != 1 ]; then if [ "$os_alpine" != 1 ]; then
sudo systemctl enable nezha-dashboard sudo systemctl enable nezha-dashboard
@@ -614,16 +637,16 @@ restart_and_update_standalone() {
} }
start_dashboard() { start_dashboard() {
echo "> Start Panel" echo "> Start Dashboard"
if [ "$IS_DOCKER_NEZHA" = 1 ]; then if [ "$IS_DOCKER_NEZHA" = 1 ]; then
start_dashboard_docker _cmd="start_dashboard_docker"
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
start_dashboard_standalone _cmd="start_dashboard_standalone"
fi fi
if [ $? = 0 ]; then if eval "$_cmd"; then
printf "${green}Nezha Monitoring Start Successful${plain}\n" success "Nezha Monitoring Start Successful"
else else
err "Failed to start, please check the log message later" err "Failed to start, please check the log message later"
fi fi
@@ -646,16 +669,16 @@ start_dashboard_standalone() {
} }
stop_dashboard() { stop_dashboard() {
echo "> Stop Panel" echo "> Stop Dashboard"
if [ "$IS_DOCKER_NEZHA" = 1 ]; then if [ "$IS_DOCKER_NEZHA" = 1 ]; then
stop_dashboard_docker _cmd="stop_dashboard_docker"
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
stop_dashboard_standalone _cmd="stop_dashboard_standalone"
fi fi
if [ $? = 0 ]; then if eval "$_cmd"; then
printf "${green}Nezha Monitoring Stop Successful${plain}\n" success "Nezha Monitoring Stop Successful"
else else
err "Failed to stop, please check the log message later" err "Failed to stop, please check the log message later"
fi fi
@@ -678,7 +701,7 @@ stop_dashboard_standalone() {
} }
show_dashboard_log() { show_dashboard_log() {
echo "> View Panel Log" echo "> View Dashboard Log"
if [ "$IS_DOCKER_NEZHA" = 1 ]; then if [ "$IS_DOCKER_NEZHA" = 1 ]; then
show_dashboard_log_docker show_dashboard_log_docker
@@ -704,7 +727,7 @@ show_dashboard_log_standalone() {
} }
uninstall_dashboard() { uninstall_dashboard() {
echo "> Uninstall Panel" echo "> Uninstall Dashboard"
if [ "$IS_DOCKER_NEZHA" = 1 ]; then if [ "$IS_DOCKER_NEZHA" = 1 ]; then
uninstall_dashboard_docker uninstall_dashboard_docker
@@ -791,13 +814,13 @@ show_usage() {
echo "Nezha Monitor Management Script Usage: " echo "Nezha Monitor Management Script Usage: "
echo "--------------------------------------------------------" echo "--------------------------------------------------------"
echo "./nezha.sh - Show Menu" echo "./nezha.sh - Show Menu"
echo "./nezha.sh install_dashboard - Install Panel" echo "./nezha.sh install_dashboard - Install Dashboard"
echo "./nezha.sh modify_dashboard_config - Modify Panel Configuration" echo "./nezha.sh modify_dashboard_config - Modify Dashboard Configuration"
echo "./nezha.sh start_dashboard - Start Panel" echo "./nezha.sh start_dashboard - Start Dashboard"
echo "./nezha.sh stop_dashboard - Stop Panel" echo "./nezha.sh stop_dashboard - Stop Dashboard"
echo "./nezha.sh restart_and_update - Restart and Update the Panel" echo "./nezha.sh restart_and_update - Restart and Update the Dashboard"
echo "./nezha.sh show_dashboard_log - View Panel Log" echo "./nezha.sh show_dashboard_log - View Dashboard Log"
echo "./nezha.sh uninstall_dashboard - Uninstall Panel" echo "./nezha.sh uninstall_dashboard - Uninstall Dashboard"
echo "--------------------------------------------------------" echo "--------------------------------------------------------"
echo "./nezha.sh install_agent - Install Agent" echo "./nezha.sh install_agent - Install Agent"
echo "./nezha.sh modify_agent_config - Modify Agent Configuration" echo "./nezha.sh modify_agent_config - Modify Agent Configuration"
@@ -812,13 +835,13 @@ show_menu() {
printf " printf "
${green}Nezha Monitor Management Script${plain} ${red}${NZ_VERSION}${plain} ${green}Nezha Monitor Management Script${plain} ${red}${NZ_VERSION}${plain}
--- https://github.com/naiba/nezha --- --- https://github.com/naiba/nezha ---
${green}1.${plain} Install Panel ${green}1.${plain} Install Dashboard
${green}2.${plain} Modify Panel Configuration ${green}2.${plain} Modify Dashbaord Configuration
${green}3.${plain} Start Panel ${green}3.${plain} Start Dashboard
${green}4.${plain} Stop Panel ${green}4.${plain} Stop Dashboard
${green}5.${plain} Restart and Update the Panel ${green}5.${plain} Restart and Update Dashboard
${green}6.${plain} View Panel Log ${green}6.${plain} View Dashboard Log
${green}7.${plain} Uninstall Panel ${green}7.${plain} Uninstall Dashboard
————————————————- ————————————————-
${green}8.${plain} Install Agent ${green}8.${plain} Install Agent
${green}9.${plain} Modify Agent Configuration ${green}9.${plain} Modify Agent Configuration
@@ -934,4 +957,4 @@ if [ $# -gt 0 ]; then
else else
select_version select_version
show_menu show_menu
fi fi
+62
View File
@@ -25,6 +25,19 @@ type CommonResponse struct {
Message string `json:"message"` Message string `json:"message"`
} }
type RegisterServer struct {
Name string
Tag string
Note string
HideForGuest string
}
type ServerRegisterResponse struct {
CommonResponse
Secret string `json:"secret"`
}
type CommonServerInfo struct { type CommonServerInfo struct {
ID uint64 `json:"id"` ID uint64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
@@ -227,6 +240,55 @@ func (s *ServerAPIService) GetAllList() *ServerInfoResponse {
} }
return res return res
} }
func (s *ServerAPIService) Register(rs *RegisterServer) *ServerRegisterResponse {
var serverInfo model.Server
var err error
// Populate serverInfo fields
serverInfo.Name = rs.Name
serverInfo.Tag = rs.Tag
serverInfo.Note = rs.Note
serverInfo.HideForGuest = rs.HideForGuest == "on"
// Generate a random secret
serverInfo.Secret, err = utils.GenerateRandomString(18)
if err != nil {
return &ServerRegisterResponse{
CommonResponse: CommonResponse{
Code: 500,
Message: "Generate secret failed: " + err.Error(),
},
Secret: "",
}
}
// Attempt to save serverInfo in the database
err = DB.Create(&serverInfo).Error
if err != nil {
return &ServerRegisterResponse{
CommonResponse: CommonResponse{
Code: 500,
Message: "Database error: " + err.Error(),
},
Secret: "",
}
}
serverInfo.Host = &model.Host{}
serverInfo.State = &model.HostState{}
serverInfo.TaskCloseLock = new(sync.Mutex)
ServerLock.Lock()
SecretToID[serverInfo.Secret] = serverInfo.ID
ServerList[serverInfo.ID] = &serverInfo
ServerTagToIDList[serverInfo.Tag] = append(ServerTagToIDList[serverInfo.Tag], serverInfo.ID)
ServerLock.Unlock()
ReSortServer()
// Successful response
return &ServerRegisterResponse{
CommonResponse: CommonResponse{
Code: 200,
Message: "Server created successfully",
},
Secret: serverInfo.Secret,
}
}
func (m *MonitorAPIService) GetMonitorHistories(query map[string]any) *MonitorInfoResponse { func (m *MonitorAPIService) GetMonitorHistories(query map[string]any) *MonitorInfoResponse {
var ( var (
+7 -1
View File
@@ -5,7 +5,7 @@ import (
"sync" "sync"
"github.com/libdns/cloudflare" "github.com/libdns/cloudflare"
"github.com/libdns/tencentcloud" tencentcloud "github.com/nezhahq/libdns-tencentcloud"
"github.com/naiba/nezha/model" "github.com/naiba/nezha/model"
ddns2 "github.com/naiba/nezha/pkg/ddns" ddns2 "github.com/naiba/nezha/pkg/ddns"
@@ -20,6 +20,7 @@ var (
func initDDNS() { func initDDNS() {
OnDDNSUpdate() OnDDNSUpdate()
OnNameserverUpdate()
} }
func OnDDNSUpdate() { func OnDDNSUpdate() {
@@ -33,6 +34,10 @@ func OnDDNSUpdate() {
} }
} }
func OnNameserverUpdate() {
ddns2.InitDNSServers(Conf.DNSServers)
}
func GetDDNSProvidersFromProfiles(profileId []uint64, ip *ddns2.IP) ([]*ddns2.Provider, error) { func GetDDNSProvidersFromProfiles(profileId []uint64, ip *ddns2.IP) ([]*ddns2.Provider, error) {
profiles := make([]*model.DDNSProfile, 0, len(profileId)) profiles := make([]*model.DDNSProfile, 0, len(profileId))
ddnsCacheLock.RLock() ddnsCacheLock.RLock()
@@ -40,6 +45,7 @@ func GetDDNSProvidersFromProfiles(profileId []uint64, ip *ddns2.IP) ([]*ddns2.Pr
if profile, ok := ddnsCache[id]; ok { if profile, ok := ddnsCache[id]; ok {
profiles = append(profiles, profile) profiles = append(profiles, profile)
} else { } else {
ddnsCacheLock.RUnlock()
return nil, fmt.Errorf("无法找到DDNS配置 ID %d", id) return nil, fmt.Errorf("无法找到DDNS配置 ID %d", id)
} }
} }