Compare commits

..
80 Commits
Author SHA1 Message Date
UUBulb 4df60c6955 ddns: improve performance (#385) 2024-07-07 10:19:58 +08:00
UUBulb 0501e120f6 fix: timestamp conversion (#383) 2024-07-04 14:32:19 +08:00
UUBulb cfa425bb33 feat: notifications support for GPU & Temperature (#381) 2024-07-03 12:34:45 +08:00
nap0o 0613b0022d 优化server-status主题服务页 (#382) 2024-07-02 22:11:20 +08:00
github-actions[bot] 740d15bf79 update contributors[no ci] 2024-06-28 02:32:48 +00:00
Kris 7ace5d04fa Update README.md (#380) 2024-06-28 10:32:31 +08:00
github-actions[bot] a38d7bb51d update contributors[no ci] 2024-06-25 15:00:50 +00:00
UUBulb 61e16f96c5 fix: EUID is a readonly variable on some shells (#379) 2024-06-25 23:00:30 +08:00
nap0o 61127b3435 优化server-status主题首页网络图表 (#378) 2024-06-25 22:16:32 +08:00
UUBulb 8805dffe85 refactor: make the installer script POSIX compliant (#376) 2024-06-25 22:15:49 +08:00
dependabot[bot] aeb7c52565 Bump github.com/hashicorp/go-retryablehttp from 0.7.2 to 0.7.7 (#377) 2024-06-25 22:11:17 +08:00
nap0o 877b4cd666 优化gpu前端展示代码 (#375) 2024-06-23 22:20:04 +08:00
naiba f75847d3d7 refactor: imporve code style 2024-06-23 16:15:08 +08:00
github-actions[bot] eee3225f3a update contributors[no ci] 2024-06-23 07:59:19 +00:00
UUBulb aa9eb533ad Temporary fix for DDNSDomain leaks (#374) 2024-06-23 15:59:03 +08:00
UUBulb cf9bbb5ff4 feat: Add GPU inspection support (#373) 2024-06-23 10:27:33 +08:00
github-actions[bot] 65dee23137 update contributors[no ci] 2024-06-22 14:52:43 +00:00
UUBulb feb4659cab Hide DDNS domain info for guests (#371) 2024-06-22 22:52:29 +08:00
github-actions[bot] bc7791efd2 update contributors[no ci] 2024-06-22 14:51:57 +00:00
nap0o 6e6ec3256f default和serverstatus主题温度展示相关 (#372) 2024-06-22 22:51:42 +08:00
github-actions[bot] ce66f72cf9 update contributors[no ci] 2024-06-16 10:13:06 +00:00
UUBulb 0ed7436176 Add option to reduct temperature information (#369) 2024-06-16 18:12:45 +08:00
UUBulb 2aabe1bd61 chore: fix some typos (#370) 2024-06-16 18:04:27 +08:00
github-actions[bot] db5e94d0de update contributors[no ci] 2024-06-15 01:43:49 +00:00
nap0o 3eecdc2b3f 修复一些bug (#367)
* bug修复:
1. serverstatus主题agent详情不显示内存信息
2. windows系统icon错误
小优化
1. echarts绘制世界地图所需的world.js坐标信息从本地加载切换为从cdn加载
2. font-logos切换为0.17.0版本,使得图标间距更合适

* 优化agent离线保留信息逻辑,从判断“实时在线”调整为判断“曾经在线”。

* 优化agent离线保留信息逻辑,从判断“实时在线”调整为判断“曾经在线”。
2024-06-15 09:43:30 +08:00
github-actions[bot] b2740e5f3c update contributors[no ci] 2024-06-14 10:03:18 +00:00
nap0o c3fa4cbbee 优化default和server status主题 (#363) 2024-06-14 18:02:55 +08:00
UUBulb a9da084711 ci: using time/tzdata package to provide zoneinfo (#365) 2024-06-14 10:24:58 +08:00
github-actions[bot] f30969e946 update contributors[no ci] 2024-06-01 11:12:04 +00:00
Leon e0e2b8c3c2 Add support for sensor temperature in host state (#359)
* feat: Add support for sensor temperature in host state

* chore: Update file permissions for saving config data
2024-06-01 19:11:48 +08:00
github-actions[bot] 3782c0dcaf update contributors[no ci] 2024-05-31 14:05:21 +00:00
Coming 0331db2c12 Update GPG key for libsepol (#360) 2024-05-31 22:05:05 +08:00
github-actions[bot] 1749247aeb update contributors[no ci] 2024-05-21 15:12:02 +00:00
UUBulb eaba7abd35 Use agent's builtin support for services instead (#357) 2024-05-21 23:11:43 +08:00
github-actions[bot] f5ca66d924 update contributors[no ci] 2024-05-19 14:35:11 +00:00
eya46 d5e7b22fc6 删除多余空格 (#358) 2024-05-19 22:34:57 +08:00
nap0o 5122d48dd8 Update service.html (#356) 2024-05-07 09:09:53 +08:00
github-actions[bot] 3614ef381e update contributors[no ci] 2024-05-05 12:13:15 +00:00
UUBulb 8475674eb7 chore: fix a typo (#355) 2024-05-05 20:12:54 +08:00
Akkia 25e7f8a912 支持cloudflare access OIDC认证 (#354) 2024-05-03 08:47:53 +08:00
UUBulb 5c7652f047 Add DDNS Profiles, use publicsuffixlist domain parser (#350)
* Add DDNS Profiles, use publicsuffixlist domain parser

* Add Tencent Cloud DNS Provider

* Restore validate DDNS provider function

* chore: fmt & upgrade dependencies
2024-04-27 13:36:36 +08:00
naiba 890616f52a daocloud github 镜像已经被打废了 2024-04-18 21:42:04 +08:00
github-actions[bot] c92ec996e0 update contributors[no ci] 2024-04-13 03:15:05 +00:00
Nanjing Hopefun Network Technology Co. Ltd 7fcd4398ea Update install.sh (#347)
修改自动安装超时时间-T 10为-T 60,10秒超时在wget那一步经常连接探针下载失败。
2024-04-13 11:14:46 +08:00
github-actions[bot] 7faba40a1c update contributors[no ci] 2024-04-09 12:43:54 +00:00
nap0o 66b4c88c24 修复ServerStatus主题Bug (#346) 2024-04-09 20:43:35 +08:00
github-actions[bot] f3c90bbf59 update contributors[no ci] 2024-04-08 14:31:45 +00:00
nap0o 8ef5dfb8f8 ServerStatus主题首页增加服务器世界分布图功能 (#344) 2024-04-08 22:31:28 +08:00
lvyaoting d38f611d66 chore: fix some comments (#345) 2024-04-08 22:30:39 +08:00
naiba d9a7002906 Update Go version to 1.20.x in GitHub workflows 2024-04-06 14:25:29 +08:00
naiba d9188f5228 Merge branch 'master' of github.com:naiba/nezha 2024-04-06 11:51:13 +08:00
naiba eb3e2883e2 update ci 2024-04-06 11:51:08 +08:00
github-actions[bot] 83ba5ebc8a update contributors[no ci] 2024-04-06 03:49:43 +00:00
naiba 6d7d3c5e85 ⬆️ Update Go version to 1.20 and update dependencies 2024-04-06 11:49:20 +08:00
naiba 194f3290bc ⬆️ Update dependencies 2024-03-30 11:15:26 +08:00
zhucaidan dc5c79711d Optimize translation (#343) 2024-03-30 11:12:00 +08:00
github-actions[bot] d88989fb85 update contributors[no ci] 2024-03-30 03:08:46 +00:00
UUBulb 0373d03fb2 fix installer bugs & improve (#341)
* fix installer bugs && improve

* Update install_en.sh
2024-03-30 11:08:29 +08:00
github-actions[bot] 140f9809a0 update contributors[no ci] 2024-03-30 03:01:11 +00:00
UUBulb f647a5f8e6 ddns: Add ability to update IPv4 or IPv6 only (#342)
* ddns: Add ability to resolve IPv4 or IPv6 only

* Fix bugs

* cdn cache
2024-03-30 11:00:55 +08:00
github-actions[bot] 506c87dbd8 update contributors[no ci] 2024-03-24 14:46:54 +00:00
naiba 8b5d513c6a Merge branch 'xykt-master' 2024-03-24 22:46:35 +08:00
naiba 6c718c4f38 Remove redundant code for MaxTCPPingValue initialization 2024-03-24 22:45:56 +08:00
xykt 5a2ab8a7ee Update network.html 2024-03-24 19:26:51 +08:00
xykt 0ea0c9ad8c Update network.html 2024-03-24 19:21:32 +08:00
xykt 7d4d8c46b8 Update network.html 2024-03-24 19:21:07 +08:00
xykt a4636ed774 Update network.html 2024-03-24 19:20:34 +08:00
xykt bb48e0912d Update network.html 2024-03-24 19:20:01 +08:00
xykt a575d1a6e0 Merge branch 'naiba:master' into master 2024-03-24 19:13:03 +08:00
github-actions[bot] 420d1ca8ff update contributors[no ci] 2024-03-24 08:13:23 +00:00
naiba 29554ec7ec 🐛 revert shit 2024-03-24 16:12:51 +08:00
xykt 9a8c0e7118 Update network.html 2024-03-24 09:24:23 +08:00
xykt 800af7ce4e Update network.html 2024-03-24 09:22:13 +08:00
xykt 78134a0e8b Update network.html 2024-03-24 09:20:53 +08:00
xykt bad910b686 Update network.html 2024-03-24 09:16:41 +08:00
xykt a7d1bd7487 Update network.html
美化了三网延迟界面:
1. 将Marker缩小降低曲线遮挡
2. 设置为曲线对应的颜色使其更加直观
3. 设置Marker透明度降低对画面的影响
4. 将延迟极小值的Marker倒置显示以快速区别极大值
5. 将超过MaxTCPPingValue的点删除
6. 显示丢包分布(细线),以及服务器断流区间(粗线)
2024-03-24 01:04:03 +08:00
xykt 20a10ac6b8 Merge branch 'naiba:master' into master 2024-03-23 13:25:37 +08:00
xykt 3a395e66c0 Merge branch 'naiba:master' into master 2024-03-04 16:07:13 +08:00
xykt 4e5cc0b642 Update config.go
修复了以下问题:
- 延迟默认最高300ms,超过后默认抹平
- 曲线上有很多ping值为0的无效散点,导致毛刺很多,干扰效果
- 图标的y轴比例失调,上方大片留白,大大降低了有效显示区域
- 默认只显示最近不到半小时左右的延迟表现,想看全天需要拖动,影响效果
- 曲线不显示极大极小值,不够直观
2024-02-19 01:17:42 +08:00
xykt fe2872bbb3 Update network.html
修复以下问题:
- 延迟默认最高300ms,超过后默认抹平
- 曲线上有很多ping值为0的无效散点,导致毛刺很多,干扰效果
- 图标的y轴比例失调,上方大片留白,大大降低了有效显示区域
- 默认只显示最近不到半小时左右的延迟表现,想看全天需要拖动,影响效果
- 曲线不显示极大极小值,不够直观
2024-02-19 01:14:26 +08:00
68 changed files with 3374 additions and 2540 deletions
+3 -2
View File
@@ -22,14 +22,15 @@ jobs:
uses: crazy-max/ghaction-xgo@v2
with:
xgo_version: latest
go_version: 1.21
go_version: 1.20.x
dest: dist
pkg: cmd/dashboard
prefix: dashboard
targets: linux/amd64,linux/arm64,linux/arm-7,linux/s390x,linux/riscv64 # linux/386,
targets: linux/amd64,linux/arm64,linux/arm-7,linux/s390x,linux/riscv64,windows/amd64,windows/386,windows/arm64 # linux/386,
v: true
x: false
race: false
tags: timetzdata
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=${{ steps.extract_branch.outputs.tag }}
buildmode: default
+3 -2
View File
@@ -25,14 +25,15 @@ jobs:
uses: crazy-max/ghaction-xgo@v2
with:
xgo_version: latest
go_version: 1.21
go_version: 1.20.x
dest: dist
pkg: cmd/dashboard
prefix: dashboard
targets: linux/amd64,linux/arm64,linux/arm-7,linux/s390x,linux/riscv64 # linux/386,
targets: linux/amd64,linux/arm64,linux/arm-7,linux/s390x,linux/riscv64,windows/amd64,windows/386,windows/arm64 # linux/386,
v: true
x: false
race: false
tags: timetzdata
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=test
buildmode: default
+3 -2
View File
@@ -32,13 +32,14 @@ jobs:
uses: crazy-max/ghaction-xgo@v2
with:
xgo_version: latest
go_version: 1.21
go_version: 1.20.x
dest: dist
pkg: cmd/dashboard
prefix: dashboard
targets: linux/amd64,linux/arm64,linux/arm-7,linux/s390x,linux/riscv64 # linux/386,
targets: linux/amd64,linux/arm64,linux/arm-7,linux/s390x,linux/riscv64,windows/amd64,windows/386,windows/arm64 # linux/386,
v: true
x: false
race: false
tags: timetzdata
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=test
buildmode: default
+15 -7
View File
@@ -4,13 +4,15 @@
<br>
<small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
<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.15.9-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">&nbsp;<img src="https://img.shields.io/badge/Installer-v0.17.0-brightgreen?style=for-the-badge&logo=linux">
<br>
<br>
<p>:trollface: <b>Nezha Monitoring: Self-hostable, lightweight, servers and websites monitoring and O&M tool.</b></p>
<p>Supports <b>monitoring</b> system status, HTTP (SSL certificate change, upcoming expiration, expired), TCP, Ping and supports <b>push alerts</b>, run scheduled tasks and <b>web terminal</b>.</p>
</div>
\>> Telegram Channel: [哪吒监控(中文通知频道)](https://t.me/nezhanews)
\>> Telegram Group: [Nezha Monitoring Global (English Only)](https://t.me/nezhamonitoring_global), [哪吒监控(中文群组)](https://t.me/nezhamonitoring)
\>> [Use Cases | 我们的用户](https://www.google.com/search?q=%22powered+by+Nezha+Monitoring%22+OR+%22powered+by+%E5%93%AA%E5%90%92%E7%9B%91%E6%8E%A7%22) (Google)
@@ -42,15 +44,16 @@ You can change the dashboard language in the settings page (`/setting`) after th
<a href="https://github.com/AkkiaS7" title="Akkia"><img src="https://avatars.githubusercontent.com/u/68485070?v=4" width="50;" alt="Akkia"/></a>
<a href="https://github.com/Erope" title="卖女孩的小火柴"><img src="https://avatars.githubusercontent.com/u/44471469?v=4" width="50;" alt="卖女孩的小火柴"/></a>
<a href="https://github.com/dysf888" title="黑歌"><img src="https://avatars.githubusercontent.com/u/47450409?v=4" width="50;" alt="黑歌"/></a>
<a href="https://github.com/uubulb" title="UUBulb"><img src="https://avatars.githubusercontent.com/u/35923940?v=4" width="50;" alt="UUBulb"/></a>
<a href="https://github.com/xykt" title="xykt"><img src="https://avatars.githubusercontent.com/u/152045469?v=4" width="50;" alt="xykt"/></a>
<a href="https://github.com/nap0o" title="nap0o"><img src="https://avatars.githubusercontent.com/u/144927971?v=4" width="50;" alt="nap0o"/></a>
<a href="https://github.com/MikoyChinese" title="MikoyChinese"><img src="https://avatars.githubusercontent.com/u/22676744?v=4" width="50;" alt="MikoyChinese"/></a>
<a href="https://github.com/JackieSung4ev" title="JackieSung4ev"><img src="https://avatars.githubusercontent.com/u/24974735?v=4" width="50;" alt="JackieSung4ev"/></a>
<a href="https://github.com/lemoeo" title="Lemoe"><img src="https://avatars.githubusercontent.com/u/18618627?v=4" width="50;" alt="Lemoe"/></a>
<a href="https://github.com/cantoblanco" title="Kris"><img src="https://avatars.githubusercontent.com/u/116849421?v=4" width="50;" alt="Kris"/></a>
<a href="https://github.com/nap0o" title="nap0o"><img src="https://avatars.githubusercontent.com/u/144927971?v=4" width="50;" alt="nap0o"/></a>
<a href="https://github.com/lemoeo" title="Lemoe"><img src="https://avatars.githubusercontent.com/u/18618627?v=4" width="50;" alt="Lemoe"/></a>
<a href="https://github.com/spiritLHLS" title="spiritlhl"><img src="https://avatars.githubusercontent.com/u/103393591?v=4" width="50;" alt="spiritlhl"/></a>
<a href="https://github.com/liuyanxi975" title="刘颜溪"><img src="https://avatars.githubusercontent.com/u/24417037?v=4" width="50;" alt="刘颜溪"/></a>
<a href="https://github.com/CosmosZ-code" title="CosmosZ-code"><img src="https://avatars.githubusercontent.com/u/81398224?v=4" width="50;" alt="CosmosZ-code"/></a>
<a href="https://github.com/uubulb" title="UUBulb"><img src="https://avatars.githubusercontent.com/u/35923940?v=4" width="50;" alt="UUBulb"/></a>
<a href="https://github.com/lvgj-stack" title="Ko no dio"><img src="https://avatars.githubusercontent.com/u/38449861?v=4" width="50;" alt="Ko no dio"/></a>
<a href="https://github.com/hhhkkk520" title="Kris"><img src="https://avatars.githubusercontent.com/u/52115472?v=4" width="50;" alt="Kris"/></a>
<a href="https://github.com/1ridic" title="1ridic"><img src="https://avatars.githubusercontent.com/u/88495501?v=4" width="50;" alt="1ridic"/></a>
@@ -59,27 +62,32 @@ 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/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/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/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/colour93" title="玖叁"><img src="https://avatars.githubusercontent.com/u/64313711?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/zhucaidan" title="zhucaidan"><img src="https://avatars.githubusercontent.com/u/47970938?v=4" width="50;" alt="zhucaidan"/></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/xykt" title="xykt"><img src="https://avatars.githubusercontent.com/u/152045469?v=4" width="50;" alt="xykt"/></a>
<a href="https://github.com/unclezs" title="unclezs"><img src="https://avatars.githubusercontent.com/u/42318775?v=4" width="50;" alt="unclezs"/></a>
<a href="https://github.com/lvyaoting" title="lvyaoting"><img src="https://avatars.githubusercontent.com/u/166296299?v=4" width="50;" alt="lvyaoting"/></a>
<a href="https://github.com/yuanweize" title="I"><img src="https://avatars.githubusercontent.com/u/30067203?v=4" width="50;" alt="I"/></a>
<a href="https://github.com/guoyongchang" title="guoyongchang"><img src="https://avatars.githubusercontent.com/u/10484506?v=4" width="50;" alt="guoyongchang"/></a>
<a href="https://github.com/eya46" title="eya46"><img src="https://avatars.githubusercontent.com/u/61458340?v=4" width="50;" alt="eya46"/></a>
<a href="https://github.com/acgpiano" title="Acgpiano"><img src="https://avatars.githubusercontent.com/u/15900800?v=4" width="50;" alt="Acgpiano"/></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/hmsjy2017" title="Tony"><img src="https://avatars.githubusercontent.com/u/42692274?v=4" width="50;" alt="Tony"/></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/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/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/funnyzak" title="Leon"><img src="https://avatars.githubusercontent.com/u/2562087?v=4" width="50;" alt="Leon"/></a>
<a href="https://github.com/KorenKrita" title="KorenKrita"><img src="https://avatars.githubusercontent.com/u/22239339?v=4" width="50;" alt="KorenKrita"/></a>
<a href="https://github.com/techotaku" title="Ian Li"><img src="https://avatars.githubusercontent.com/u/1948179?v=4" width="50;" alt="Ian Li"/></a>
<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/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/wwng2333" title="Crazy"><img src="https://avatars.githubusercontent.com/u/17147265?v=4" width="50;" alt="Crazy"/></a><!--GAMFC_DELIMITER_END-->
<a href="https://github.com/wwng2333" title="Crazy"><img src="https://avatars.githubusercontent.com/u/17147265?v=4" width="50;" alt="Crazy"/></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-->
## Star History
+13 -6
View File
@@ -2,6 +2,7 @@ package controller
import (
"errors"
"fmt"
"log"
"net/http"
"regexp"
@@ -223,19 +224,25 @@ func (cp *commonPage) network(c *gin.Context) {
}
func (cp *commonPage) getServerStat(c *gin.Context) ([]byte, error) {
v, err, _ := cp.requestGroup.Do("serverStats", func() (any, error) {
_, isMember := c.Get(model.CtxKeyAuthorizedUser)
_, isViewPasswordVerfied := c.Get(model.CtxKeyViewPasswordVerified)
authorized := isMember || isViewPasswordVerfied
v, err, _ := cp.requestGroup.Do(fmt.Sprintf("serverStats::%t", authorized), func() (interface{}, error) {
singleton.SortedServerLock.RLock()
defer singleton.SortedServerLock.RUnlock()
_, isMember := c.Get(model.CtxKeyAuthorizedUser)
_, isViewPasswordVerfied := c.Get(model.CtxKeyViewPasswordVerified)
var servers []*model.Server
if isMember || isViewPasswordVerfied {
if authorized {
servers = singleton.SortedServerList
} else {
servers = singleton.SortedServerListForGuest
filteredServers := make([]*model.Server, len(singleton.SortedServerListForGuest))
for i, server := range singleton.SortedServerListForGuest {
filteredServer := *server
filteredServer.DDNSDomain = "redacted"
filteredServers[i] = &filteredServer
}
servers = filteredServers
}
return utils.Json.Marshal(Data{
+3
View File
@@ -49,6 +49,9 @@ func (gp *guestPage) login(c *gin.Context) {
} else if singleton.Conf.Oauth2.Type == model.ConfigTypeGitea {
LoginType = "Gitea"
RegistrationLink = fmt.Sprintf("%s/user/sign_up", singleton.Conf.Oauth2.Endpoint)
} else if singleton.Conf.Oauth2.Type == model.ConfigTypeCloudflare {
LoginType = "Cloudflare"
RegistrationLink = "https://dash.cloudflare.com/sign-up/teams"
}
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/login", mygin.CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
+22 -18
View File
@@ -301,7 +301,10 @@ type serverForm struct {
Note string
HideForGuest string
EnableDDNS string
EnableIPv4 string
EnableIpv6 string
DDNSDomain string
DDNSProfile string
}
func (ma *memberAPI) addOrEditServer(c *gin.Context) {
@@ -318,7 +321,10 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
s.Note = sf.Note
s.HideForGuest = sf.HideForGuest == "on"
s.EnableDDNS = sf.EnableDDNS == "on"
s.EnableIPv4 = sf.EnableIPv4 == "on"
s.EnableIpv6 = sf.EnableIpv6 == "on"
s.DDNSDomain = sf.DDNSDomain
s.DDNSProfile = sf.DDNSProfile
if s.ID == 0 {
s.Secret, err = utils.GenerateRandomString(18)
if err == nil {
@@ -431,25 +437,23 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
if m.NotificationTag == "" {
m.NotificationTag = "default"
}
if err == nil {
err = utils.Json.Unmarshal([]byte(mf.FailTriggerTasksRaw), &m.FailTriggerTasks)
err = utils.Json.Unmarshal([]byte(mf.FailTriggerTasksRaw), &m.FailTriggerTasks)
}
if err == nil {
err = utils.Json.Unmarshal([]byte(mf.RecoverTriggerTasksRaw), &m.RecoverTriggerTasks)
}
if err == nil {
if m.ID == 0 {
err = singleton.DB.Create(&m).Error
} else {
err = singleton.DB.Save(&m).Error
}
if err == nil {
err = utils.Json.Unmarshal([]byte(mf.RecoverTriggerTasksRaw), &m.RecoverTriggerTasks)
}
if err == nil {
if m.ID == 0 {
err = singleton.DB.Create(&m).Error
} else {
err = singleton.DB.Save(&m).Error
}
}
if err == nil {
if m.Cover == 0 {
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ? and server_id in (?)", m.ID, strings.Split(m.SkipServersRaw[1:len(m.SkipServersRaw)-1], ",")).Error
} else {
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ? and server_id not in (?)", m.ID, strings.Split(m.SkipServersRaw[1:len(m.SkipServersRaw)-1], ",")).Error
}
}
if err == nil {
if m.Cover == 0 {
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ? and server_id in (?)", m.ID, strings.Split(m.SkipServersRaw[1:len(m.SkipServersRaw)-1], ",")).Error
} else {
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ? and server_id not in (?)", m.ID, strings.Split(m.SkipServersRaw[1:len(m.SkipServersRaw)-1], ",")).Error
}
}
if err == nil {
+26 -4
View File
@@ -2,6 +2,7 @@ package controller
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
@@ -9,6 +10,8 @@ import (
"strings"
"time"
"github.com/naiba/nezha/pkg/oidc/cloudflare"
"code.gitea.io/sdk/gitea"
"github.com/gin-gonic/gin"
GitHubAPI "github.com/google/go-github/v47/github"
@@ -74,6 +77,17 @@ func (oa *oauth2controller) getCommonOauth2Config(c *gin.Context) *oauth2.Config
},
RedirectURL: oa.getRedirectURL(c),
}
} else if singleton.Conf.Oauth2.Type == model.ConfigTypeCloudflare {
return &oauth2.Config{
ClientID: singleton.Conf.Oauth2.ClientID,
ClientSecret: singleton.Conf.Oauth2.ClientSecret,
Scopes: []string{"openid", "email", "profile", "groups"},
Endpoint: oauth2.Endpoint{
AuthURL: fmt.Sprintf("%s/cdn-cgi/access/sso/oidc/%s/authorization", singleton.Conf.Oauth2.Endpoint, singleton.Conf.Oauth2.ClientID),
TokenURL: fmt.Sprintf("%s/cdn-cgi/access/sso/oidc/%s/token", singleton.Conf.Oauth2.Endpoint, singleton.Conf.Oauth2.ClientID),
},
RedirectURL: oa.getRedirectURL(c),
}
} else {
return &oauth2.Config{
ClientID: singleton.Conf.Oauth2.ClientID,
@@ -155,6 +169,17 @@ func (oa *oauth2controller) callback(c *gin.Context) {
if err == nil {
user = model.NewUserFromGitea(u)
}
} else if singleton.Conf.Oauth2.Type == model.ConfigTypeCloudflare {
client := oauth2Config.Client(context.Background(), otk)
resp, err := client.Get(fmt.Sprintf("%s/cdn-cgi/access/sso/oidc/%s/userinfo", singleton.Conf.Oauth2.Endpoint, singleton.Conf.Oauth2.ClientID))
if err == nil {
defer resp.Body.Close()
var cloudflareUserInfo *cloudflare.UserInfo
if err := json.NewDecoder(resp.Body).Decode(&cloudflareUserInfo); err == nil {
user = cloudflareUserInfo.MapToNezhaUser()
}
}
} else {
var client *GitHubAPI.Client
oc := oauth2Config.Client(ctx, otk)
@@ -168,15 +193,12 @@ func (oa *oauth2controller) callback(c *gin.Context) {
client = GitHubAPI.NewClient(oc)
}
var gu *GitHubAPI.User
if err == nil {
gu, _, err = client.Users.Get(ctx, "")
}
gu, _, err = client.Users.Get(ctx, "")
if err == nil {
user = model.NewUserFromGitHub(gu)
}
}
}
if err == nil && user.Login == "" {
err = errors.New("获取用户信息失败")
}
+14 -18
View File
@@ -1,12 +1,10 @@
module github.com/naiba/nezha
go 1.21
toolchain go1.21.3
go 1.20
require (
code.cloudfoundry.org/bytefmt v0.0.0-20240322144145-4816192cb114
code.gitea.io/sdk/gitea v0.17.1
code.cloudfoundry.org/bytefmt v0.0.0-20240425163905-bcdc1ad063ea
code.gitea.io/sdk/gitea v0.18.0
github.com/BurntSushi/toml v1.3.2
github.com/gin-contrib/pprof v1.4.0
github.com/gin-gonic/gin v1.9.1
@@ -22,15 +20,16 @@ require (
github.com/samber/lo v1.39.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.18.2
github.com/xanzy/go-gitlab v0.100.0
golang.org/x/crypto v0.21.0
golang.org/x/oauth2 v0.18.0
golang.org/x/sync v0.6.0
github.com/xanzy/go-gitlab v0.103.0
golang.org/x/crypto v0.22.0
golang.org/x/net v0.24.0
golang.org/x/oauth2 v0.19.0
golang.org/x/sync v0.7.0
golang.org/x/text v0.14.0
google.golang.org/grpc v1.62.1
google.golang.org/grpc v1.63.0
google.golang.org/protobuf v1.33.0
gorm.io/driver/sqlite v1.5.5
gorm.io/gorm v1.25.8
gorm.io/gorm v1.25.10
sigs.k8s.io/yaml v1.4.0
)
@@ -46,10 +45,9 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // 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
@@ -57,7 +55,7 @@ require (
github.com/klauspost/cpuid/v2 v2.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.19 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -76,11 +74,9 @@ require (
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // 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
)
+33 -87
View File
@@ -1,7 +1,7 @@
code.cloudfoundry.org/bytefmt v0.0.0-20240322144145-4816192cb114 h1:7KJsK0gPah7XfO46ARJA2TUXHZaJEnPI80mzxQLre68=
code.cloudfoundry.org/bytefmt v0.0.0-20240322144145-4816192cb114/go.mod h1:TNAH6xe5WOszc47+zM7NnpaJWBR8oYt12BUf4WLIZ98=
code.gitea.io/sdk/gitea v0.17.1 h1:3jCPOG2ojbl8AcfaUCRYLT5MUcBMFwS0OSK2mA5Zok8=
code.gitea.io/sdk/gitea v0.17.1/go.mod h1:aCnBqhHpoEWA180gMbaCtdX9Pl6BWBAuuP2miadoTNM=
code.cloudfoundry.org/bytefmt v0.0.0-20240425163905-bcdc1ad063ea h1:1tgMNDgo8PjpsHhlaxdibj28C0WyLeOW2SPJ7GGdc9A=
code.cloudfoundry.org/bytefmt v0.0.0-20240425163905-bcdc1ad063ea/go.mod h1:3+xXJBOD8PsGHDqHedtCLalbaVJ+yi1OW+mXx9IcNxI=
code.gitea.io/sdk/gitea v0.18.0 h1:+zZrwVmujIrgobt6wVBWCqITz6bn1aBjnCUHmpZrerI=
code.gitea.io/sdk/gitea v0.18.0/go.mod h1:IG9xZJoltDNeDSW0qiF2Vqx5orMWa7OhVWrjvrd5NpI=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
@@ -14,13 +14,10 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
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/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
@@ -35,10 +32,8 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
@@ -49,35 +44,27 @@ github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXS
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
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/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
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/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
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.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/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/go.mod h1:VPZBXNbFSJGjyjFRUKo9vZGawTajnWzC/YjGw/oFKi0=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240320155624-b11c3daa6f07 h1:57oOH2Mu5Nw16KnZAVLdlUjmPH/TSYCKTJgG0OVfX0Y=
github.com/google/pprof v0.0.0-20240320155624-b11c3daa6f07/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
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=
@@ -99,7 +86,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
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.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -110,10 +96,9 @@ github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNa
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/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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@@ -125,10 +110,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/onsi/ginkgo/v2 v2.17.0 h1:kdnunFXpBjbzN56hcJHrXZ8M+LOkenKA7NnBzTNigTI=
github.com/onsi/ginkgo/v2 v2.17.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE=
github.com/ory/graceful v0.1.3 h1:FaeXcHZh168WzS+bqruqWEw/HgXWLdNv2nJ+fbhxbhc=
github.com/ory/graceful v0.1.3/go.mod h1:4zFz687IAF7oNHHiB586U4iL+/4aV09o/PYLE34t2bA=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
@@ -141,13 +124,11 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
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/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=
@@ -167,7 +148,6 @@ github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMV
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.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -186,9 +166,8 @@ github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/xanzy/go-gitlab v0.100.0 h1:jaOtYj5nWI19+9oVVmgy233pax2oYqucwetogYU46ks=
github.com/xanzy/go-gitlab v0.100.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/xanzy/go-gitlab v0.103.0 h1:J9pTQoq0GsEFqzd6srCM1QfdfKAxSNz6mT6ntrpNF2w=
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=
@@ -200,78 +179,45 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8=
google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
@@ -291,8 +237,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E=
gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE=
gorm.io/gorm v1.25.8 h1:WAGEZ/aEcznN4D03laj8DKnehe1e9gYQAjW8xyPRdeo=
gorm.io/gorm v1.25.8/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
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=
+20 -14
View File
@@ -22,7 +22,7 @@ var Themes = map[string]string{
"mdui": "Neko Mdui",
"hotaru": "Hotaru",
"angel-kanade": "AngelKanade",
"server-status": "SeverStatus",
"server-status": "ServerStatus",
"custom": "Custom(local)",
}
@@ -32,11 +32,12 @@ var DashboardThemes = map[string]string{
}
const (
ConfigTypeGitHub = "github"
ConfigTypeGitee = "gitee"
ConfigTypeGitlab = "gitlab"
ConfigTypeJihulab = "jihulab"
ConfigTypeGitea = "gitea"
ConfigTypeGitHub = "github"
ConfigTypeGitee = "gitee"
ConfigTypeGitlab = "gitlab"
ConfigTypeJihulab = "jihulab"
ConfigTypeGitea = "gitea"
ConfigTypeCloudflare = "cloudflare"
)
const (
@@ -70,7 +71,7 @@ func (c *AgentConfig) Save() error {
if err != nil {
return err
}
return os.WriteFile(c.v.ConfigFileUsed(), data, os.ModePerm)
return os.WriteFile(c.v.ConfigFileUsed(), data, 0600)
}
// Config 站点配置
@@ -125,9 +126,20 @@ type Config struct {
WebhookRequestBody string
WebhookHeaders string
MaxRetries uint32
Profiles map[string]DDNSProfile
}
}
type DDNSProfile struct {
Provider string
AccessID string
AccessSecret string
WebhookURL string
WebhookMethod string
WebhookRequestBody string
WebhookHeaders string
}
// Read 读取配置文件并应用
func (c *Config) Read(path string) error {
c.v = viper.New()
@@ -166,12 +178,6 @@ func (c *Config) Read(path string) error {
if c.AvgPingCount == 0 {
c.AvgPingCount = 2
}
if c.DDNS.Provider == "" {
c.DDNS.Provider = "webhook"
}
if c.DDNS.WebhookMethod == "" {
c.DDNS.WebhookMethod = "POST"
}
if c.DDNS.MaxRetries == 0 {
c.DDNS.MaxRetries = 3
}
@@ -199,5 +205,5 @@ func (c *Config) Save() error {
if err != nil {
return err
}
return os.WriteFile(c.v.ConfigFileUsed(), data, os.ModePerm)
return os.WriteFile(c.v.ConfigFileUsed(), data, 0600)
}
+30
View File
@@ -10,6 +10,11 @@ const (
MTReportHostState
)
type SensorTemperature struct {
Name string
Temperature float64
}
type HostState struct {
CPU float64
MemUsed uint64
@@ -26,9 +31,19 @@ type HostState struct {
TcpConnCount uint64
UdpConnCount uint64
ProcessCount uint64
Temperatures []SensorTemperature
GPU float64
}
func (s *HostState) PB() *pb.State {
var ts []*pb.State_SensorTemperature
for _, t := range s.Temperatures {
ts = append(ts, &pb.State_SensorTemperature{
Name: t.Name,
Temperature: t.Temperature,
})
}
return &pb.State{
Cpu: s.CPU,
MemUsed: s.MemUsed,
@@ -45,10 +60,20 @@ func (s *HostState) PB() *pb.State {
TcpConnCount: s.TcpConnCount,
UdpConnCount: s.UdpConnCount,
ProcessCount: s.ProcessCount,
Temperatures: ts,
Gpu: s.GPU,
}
}
func PB2State(s *pb.State) HostState {
var ts []SensorTemperature
for _, t := range s.GetTemperatures() {
ts = append(ts, SensorTemperature{
Name: t.GetName(),
Temperature: t.GetTemperature(),
})
}
return HostState{
CPU: s.GetCpu(),
MemUsed: s.GetMemUsed(),
@@ -65,6 +90,8 @@ func PB2State(s *pb.State) HostState {
TcpConnCount: s.GetTcpConnCount(),
UdpConnCount: s.GetUdpConnCount(),
ProcessCount: s.GetProcessCount(),
Temperatures: ts,
GPU: s.GetGpu(),
}
}
@@ -81,6 +108,7 @@ type Host struct {
IP string `json:"-"`
CountryCode string
Version string
GPU []string
}
func (h *Host) PB() *pb.Host {
@@ -97,6 +125,7 @@ func (h *Host) PB() *pb.Host {
Ip: h.IP,
CountryCode: h.CountryCode,
Version: h.Version,
Gpu: h.GPU,
}
}
@@ -114,5 +143,6 @@ func PB2Host(h *pb.Host) Host {
IP: h.GetIp(),
CountryCode: h.GetCountryCode(),
Version: h.GetVersion(),
GPU: h.GetGpu(),
}
}
-1
View File
@@ -19,4 +19,3 @@ type MonitorHistory struct {
Down uint64 // 检查状态异常计数
Data string
}
+28 -3
View File
@@ -42,6 +42,19 @@ func percentage(used, total uint64) float64 {
return float64(used) * 100 / float64(total)
}
func maxSliceValue(slice []float64) float64 {
if len(slice) != 0 {
max := slice[0]
for _, val := range slice {
if max < val {
max = val
}
}
return max
}
return 0
}
// Snapshot 未通过规则返回 struct{}{}, 通过返回 nil
func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server, db *gorm.DB) interface{} {
// 监控全部但是排除了此服务器
@@ -63,6 +76,8 @@ func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server,
switch u.Type {
case "cpu":
src = float64(server.State.CPU)
case "gpu":
src = float64(server.State.GPU)
case "memory":
src = percentage(server.State.MemUsed, server.Host.MemTotal)
case "swap":
@@ -91,21 +106,21 @@ func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server,
src = float64(server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
if u.CycleInterval != 0 {
var res NResult
db.Model(&Transfer{}).Select("SUM(`in`) AS n").Where("created_at > ? AND server_id = ?", u.GetTransferDurationStart(), server.ID).Scan(&res)
db.Model(&Transfer{}).Select("SUM(`in`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
src += float64(res.N)
}
case "transfer_out_cycle":
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut))
if u.CycleInterval != 0 {
var res NResult
db.Model(&Transfer{}).Select("SUM(`out`) AS n").Where("created_at > ? AND server_id = ?", u.GetTransferDurationStart(), server.ID).Scan(&res)
db.Model(&Transfer{}).Select("SUM(`out`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
src += float64(res.N)
}
case "transfer_all_cycle":
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut) + server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
if u.CycleInterval != 0 {
var res NResult
db.Model(&Transfer{}).Select("SUM(`in`+`out`) AS n").Where("created_at > ? AND server_id = ?", u.GetTransferDurationStart(), server.ID).Scan(&res)
db.Model(&Transfer{}).Select("SUM(`in`+`out`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
src += float64(res.N)
}
case "load1":
@@ -120,6 +135,16 @@ func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server,
src = float64(server.State.UdpConnCount)
case "process_count":
src = float64(server.State.ProcessCount)
case "temperature_max":
var temp []float64
if server.State.Temperatures != nil {
for _, tempStat := range server.State.Temperatures {
if tempStat.Temperature != 0 {
temp = append(temp, tempStat.Temperature)
}
}
src = maxSliceValue(temp)
}
}
// 循环区间流量检测 · 更新下次需要检测时间
+5 -1
View File
@@ -18,7 +18,10 @@ type Server struct {
DisplayIndex int // 展示排序,越大越靠前
HideForGuest bool // 对游客隐藏
EnableDDNS bool // 是否启用DDNS 未在配置文件中启用DDNS 或 DDNS检查时间为0时此项无效
EnableIPv4 bool // 是否启用DDNS IPv4
EnableIpv6 bool // 是否启用DDNS IPv6
DDNSDomain string // DDNS中的前缀 如基础域名为abc.oracle DDNSName为mjj 就会把mjj.abc.oracle解析服务器IP 为空则停用
DDNSProfile string // DDNS配置
Host *Host `gorm:"-"`
State *HostState `gorm:"-"`
@@ -54,5 +57,6 @@ func (s Server) Marshal() template.JS {
note, _ := utils.Json.Marshal(s.Note)
secret, _ := utils.Json.Marshal(s.Secret)
ddnsDomain, _ := utils.Json.Marshal(s.DDNSDomain)
return template.JS(fmt.Sprintf(`{"ID":%d,"Name":%s,"Secret":%s,"DisplayIndex":%d,"Tag":%s,"Note":%s,"HideForGuest": %s,"EnableDDNS": %s,"DDNSDomain": %s}`, s.ID, name, secret, s.DisplayIndex, tag, note, boolToString(s.HideForGuest), boolToString(s.EnableDDNS), ddnsDomain)) // #nosec
ddnsProfile, _ := utils.Json.Marshal(s.DDNSProfile)
return template.JS(fmt.Sprintf(`{"ID":%d,"Name":%s,"Secret":%s,"DisplayIndex":%d,"Tag":%s,"Note":%s,"HideForGuest": %s,"EnableDDNS": %s,"EnableIPv4": %s,"EnableIpv6": %s,"DDNSDomain": %s,"DDNSProfile": %s}`, s.ID, name, secret, s.DisplayIndex, tag, note, boolToString(s.HideForGuest), boolToString(s.EnableDDNS), boolToString(s.EnableIPv4), boolToString(s.EnableIpv6), ddnsDomain, ddnsProfile)) // #nosec
}
+7 -7
View File
@@ -13,7 +13,7 @@ type ProviderCloudflare struct {
Secret string
}
func (provider ProviderCloudflare) UpdateDomain(domainConfig *DomainConfig) bool {
func (provider *ProviderCloudflare) UpdateDomain(domainConfig *DomainConfig) bool {
if domainConfig == nil {
return false
}
@@ -42,7 +42,7 @@ func (provider ProviderCloudflare) UpdateDomain(domainConfig *DomainConfig) bool
return resultV4 && resultV6
}
func (provider ProviderCloudflare) addDomainRecord(zoneID string, domainConfig *DomainConfig, isIpv4 bool) bool {
func (provider *ProviderCloudflare) addDomainRecord(zoneID string, domainConfig *DomainConfig, isIpv4 bool) bool {
record, err := provider.findDNSRecord(zoneID, domainConfig.FullDomain, isIpv4)
if err != nil {
log.Printf("查找 DNS 记录时出错: %s\n", err)
@@ -58,7 +58,7 @@ func (provider ProviderCloudflare) addDomainRecord(zoneID string, domainConfig *
}
}
func (provider ProviderCloudflare) getZoneID(domain string) (string, error) {
func (provider *ProviderCloudflare) getZoneID(domain string) (string, error) {
_, realDomain := SplitDomain(domain)
url := fmt.Sprintf("https://api.cloudflare.com/client/v4/zones?name=%s", realDomain)
body, err := provider.sendRequest("GET", url, nil)
@@ -81,7 +81,7 @@ func (provider ProviderCloudflare) getZoneID(domain string) (string, error) {
return "", fmt.Errorf("找不到 Zone ID")
}
func (provider ProviderCloudflare) findDNSRecord(zoneID string, domain string, isIPv4 bool) (map[string]interface{}, error) {
func (provider *ProviderCloudflare) findDNSRecord(zoneID string, domain string, isIPv4 bool) (map[string]interface{}, error) {
var ipType = "A"
if !isIPv4 {
ipType = "AAAA"
@@ -106,7 +106,7 @@ func (provider ProviderCloudflare) findDNSRecord(zoneID string, domain string, i
return nil, nil // 没有找到 DNS 记录
}
func (provider ProviderCloudflare) createDNSRecord(zoneID string, domainConfig *DomainConfig, isIPv4 bool) bool {
func (provider *ProviderCloudflare) createDNSRecord(zoneID string, domainConfig *DomainConfig, isIPv4 bool) bool {
var ipType = "A"
var ipAddr = domainConfig.Ipv4Addr
if !isIPv4 {
@@ -126,7 +126,7 @@ func (provider ProviderCloudflare) createDNSRecord(zoneID string, domainConfig *
return err == nil
}
func (provider ProviderCloudflare) updateDNSRecord(zoneID string, recordID string, domainConfig *DomainConfig, isIPv4 bool) bool {
func (provider *ProviderCloudflare) updateDNSRecord(zoneID string, recordID string, domainConfig *DomainConfig, isIPv4 bool) bool {
var ipType = "A"
var ipAddr = domainConfig.Ipv4Addr
if !isIPv4 {
@@ -147,7 +147,7 @@ func (provider ProviderCloudflare) updateDNSRecord(zoneID string, recordID strin
}
// 以下为辅助方法,如发送 HTTP 请求等
func (provider ProviderCloudflare) sendRequest(method string, url string, data []byte) ([]byte, error) {
func (provider *ProviderCloudflare) sendRequest(method string, url string, data []byte) ([]byte, error) {
client := &http.Client{}
req, err := http.NewRequest(method, url, bytes.NewBuffer(data))
if err != nil {
+1 -1
View File
@@ -2,6 +2,6 @@ package ddns
type ProviderDummy struct{}
func (provider ProviderDummy) UpdateDomain(domainConfig *DomainConfig) bool {
func (provider *ProviderDummy) UpdateDomain(domainConfig *DomainConfig) bool {
return false
}
+5 -26
View File
@@ -1,7 +1,7 @@
package ddns
import (
"fmt"
"golang.org/x/net/publicsuffix"
"net/http"
"strings"
)
@@ -33,29 +33,8 @@ func SetStringHeadersToRequest(req *http.Request, headers []string) {
}
// SplitDomain 分割域名为前缀和一级域名
func SplitDomain(domain string) (prefix string, topLevelDomain string) {
// 带有二级TLD的一些常见例子,需要特别处理
secondLevelTLDs := map[string]bool{
".co.uk": true, ".com.cn": true, ".gov.cn": true, ".net.cn": true, ".org.cn": true,
}
// 分割域名为"."的各部分
parts := strings.Split(domain, ".")
// 处理特殊情况,例如 ".co.uk"
for i := len(parts) - 2; i > 0; i-- {
potentialTLD := fmt.Sprintf(".%s.%s", parts[i], parts[i+1])
if secondLevelTLDs[potentialTLD] {
if i > 1 {
return strings.Join(parts[:i-1], "."), strings.Join(parts[i-1:], ".")
}
return "", domain // 当域名仅为二级TLD时,无前缀
}
}
// 常规处理,查找最后一个"."前的所有内容作为前缀
if len(parts) > 2 {
return strings.Join(parts[:len(parts)-2], "."), strings.Join(parts[len(parts)-2:], ".")
}
return "", domain // 当域名不包含子域名时,无前缀
func SplitDomain(domain string) (prefix string, realDomain string) {
realDomain, _ = publicsuffix.EffectiveTLDPlusOne(domain)
prefix = domain[:len(domain)-len(realDomain)-1]
return prefix, realDomain
}
+228
View File
@@ -0,0 +1,228 @@
package ddns
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"io"
"log"
"net/http"
"strconv"
"strings"
"time"
)
const (
url = "https://dnspod.tencentcloudapi.com"
)
type ProviderTencentCloud struct {
SecretID string
SecretKey string
}
func (provider *ProviderTencentCloud) UpdateDomain(domainConfig *DomainConfig) bool {
if domainConfig == nil {
return false
}
// 当IPv4和IPv6同时成功才算作成功
var resultV4 = true
var resultV6 = true
if domainConfig.EnableIPv4 {
if !provider.addDomainRecord(domainConfig, true) {
resultV4 = false
}
}
if domainConfig.EnableIpv6 {
if !provider.addDomainRecord(domainConfig, false) {
resultV6 = false
}
}
return resultV4 && resultV6
}
func (provider *ProviderTencentCloud) addDomainRecord(domainConfig *DomainConfig, isIpv4 bool) bool {
record, err := provider.findDNSRecord(domainConfig.FullDomain, isIpv4)
if err != nil {
log.Printf("查找 DNS 记录时出错: %s\n", err)
return false
}
if errResponse, ok := record["Error"].(map[string]interface{}); ok {
if errCode, ok := errResponse["Code"].(string); ok && errCode == "ResourceNotFound.NoDataOfRecord" { // 没有找到 DNS 记录
// 添加 DNS 记录
return provider.createDNSRecord(domainConfig.FullDomain, domainConfig, isIpv4)
} else {
log.Printf("查询 DNS 记录时出错,错误代码为: %s\n", errCode)
}
}
// 默认情况下更新 DNS 记录
return provider.updateDNSRecord(domainConfig.FullDomain, record["RecordList"].([]interface{})[0].(map[string]interface{})["RecordId"].(float64), domainConfig, isIpv4)
}
func (provider *ProviderTencentCloud) findDNSRecord(domain string, isIPv4 bool) (map[string]interface{}, error) {
var ipType = "A"
if !isIPv4 {
ipType = "AAAA"
}
_, realDomain := SplitDomain(domain)
prefix, _ := SplitDomain(domain)
data := map[string]interface{}{
"RecordType": ipType,
"Domain": realDomain,
"RecordLine": "默认",
"Subdomain": prefix,
}
jsonData, _ := json.Marshal(data)
body, err := provider.sendRequest("DescribeRecordList", jsonData)
if err != nil {
return nil, err
}
var res map[string]interface{}
err = json.Unmarshal(body, &res)
if err != nil {
return nil, err
}
result := res["Response"].(map[string]interface{})
return result, nil
}
func (provider *ProviderTencentCloud) createDNSRecord(domain string, domainConfig *DomainConfig, isIPv4 bool) bool {
var ipType = "A"
var ipAddr = domainConfig.Ipv4Addr
if !isIPv4 {
ipType = "AAAA"
ipAddr = domainConfig.Ipv6Addr
}
_, realDomain := SplitDomain(domain)
prefix, _ := SplitDomain(domain)
data := map[string]interface{}{
"RecordType": ipType,
"RecordLine": "默认",
"Domain": realDomain,
"SubDomain": prefix,
"Value": ipAddr,
"TTL": 600,
}
jsonData, _ := json.Marshal(data)
_, err := provider.sendRequest("CreateRecord", jsonData)
return err == nil
}
func (provider *ProviderTencentCloud) updateDNSRecord(domain string, recordID float64, domainConfig *DomainConfig, isIPv4 bool) bool {
var ipType = "A"
var ipAddr = domainConfig.Ipv4Addr
if !isIPv4 {
ipType = "AAAA"
ipAddr = domainConfig.Ipv6Addr
}
_, realDomain := SplitDomain(domain)
prefix, _ := SplitDomain(domain)
data := map[string]interface{}{
"RecordType": ipType,
"RecordLine": "默认",
"Domain": realDomain,
"SubDomain": prefix,
"Value": ipAddr,
"TTL": 600,
"RecordId": recordID,
}
jsonData, _ := json.Marshal(data)
_, err := provider.sendRequest("ModifyRecord", jsonData)
return err == nil
}
// 以下为辅助方法,如发送 HTTP 请求等
func (provider *ProviderTencentCloud) sendRequest(action string, data []byte) ([]byte, error) {
client := &http.Client{}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-TC-Version", "2021-03-23")
provider.signRequest(provider.SecretID, provider.SecretKey, req, action, string(data))
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
log.Printf("NEZHA>> 无法关闭HTTP响应体流: %s\n", err.Error())
}
}(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
// https://github.com/jeessy2/ddns-go/blob/master/util/tencent_cloud_signer.go
func (provider *ProviderTencentCloud) sha256hex(s string) string {
b := sha256.Sum256([]byte(s))
return hex.EncodeToString(b[:])
}
func (provider *ProviderTencentCloud) hmacsha256(s, key string) string {
hashed := hmac.New(sha256.New, []byte(key))
hashed.Write([]byte(s))
return string(hashed.Sum(nil))
}
func (provider *ProviderTencentCloud) WriteString(strs ...string) string {
var b strings.Builder
for _, str := range strs {
b.WriteString(str)
}
return b.String()
}
func (provider *ProviderTencentCloud) signRequest(secretId string, secretKey string, r *http.Request, action string, payload string) {
algorithm := "TC3-HMAC-SHA256"
service := "dnspod"
host := provider.WriteString(service, ".tencentcloudapi.com")
timestamp := time.Now().Unix()
timestampStr := strconv.FormatInt(timestamp, 10)
// 步骤 1:拼接规范请求串
canonicalHeaders := provider.WriteString("content-type:application/json\nhost:", host, "\nx-tc-action:", strings.ToLower(action), "\n")
signedHeaders := "content-type;host;x-tc-action"
hashedRequestPayload := provider.sha256hex(payload)
canonicalRequest := provider.WriteString("POST\n/\n\n", canonicalHeaders, "\n", signedHeaders, "\n", hashedRequestPayload)
// 步骤 2:拼接待签名字符串
date := time.Unix(timestamp, 0).UTC().Format("2006-01-02")
credentialScope := provider.WriteString(date, "/", service, "/tc3_request")
hashedCanonicalRequest := provider.sha256hex(canonicalRequest)
string2sign := provider.WriteString(algorithm, "\n", timestampStr, "\n", credentialScope, "\n", hashedCanonicalRequest)
// 步骤 3:计算签名
secretDate := provider.hmacsha256(date, provider.WriteString("TC3", secretKey))
secretService := provider.hmacsha256(service, secretDate)
secretSigning := provider.hmacsha256("tc3_request", secretService)
signature := hex.EncodeToString([]byte(provider.hmacsha256(string2sign, secretSigning)))
// 步骤 4:拼接 Authorization
authorization := provider.WriteString(algorithm, " Credential=", secretId, "/", credentialScope, ", SignedHeaders=", signedHeaders, ", Signature=", signature)
r.Header.Add("Authorization", authorization)
r.Header.Set("Host", host)
r.Header.Set("X-TC-Action", action)
r.Header.Add("X-TC-Timestamp", timestampStr)
}
+1 -1
View File
@@ -14,7 +14,7 @@ type ProviderWebHook struct {
RequestHeader string
}
func (provider ProviderWebHook) UpdateDomain(domainConfig *DomainConfig) bool {
func (provider *ProviderWebHook) UpdateDomain(domainConfig *DomainConfig) bool {
if domainConfig == nil {
return false
}
+22
View File
@@ -0,0 +1,22 @@
package cloudflare
import (
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/service/singleton"
)
type UserInfo struct {
Sub string `json:"sub"`
Email string `json:"email"`
Name string `json:"name"`
Groups []string `json:"groups"`
}
func (u UserInfo) MapToNezhaUser() model.User {
var user model.User
singleton.DB.Where("login = ?", u.Sub).First(&user)
user.Login = u.Sub
user.Email = u.Email
user.Name = u.Name
return user
}
+213 -108
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.30.0
// protoc v3.21.12
// protoc-gen-go v1.34.1
// protoc v5.26.1
// source: proto/nezha.proto
package proto
@@ -37,6 +37,7 @@ type Host struct {
Ip string `protobuf:"bytes,10,opt,name=ip,proto3" json:"ip,omitempty"`
CountryCode string `protobuf:"bytes,11,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"`
Version string `protobuf:"bytes,12,opt,name=version,proto3" json:"version,omitempty"`
Gpu []string `protobuf:"bytes,13,rep,name=gpu,proto3" json:"gpu,omitempty"`
}
func (x *Host) Reset() {
@@ -155,26 +156,35 @@ func (x *Host) GetVersion() string {
return ""
}
func (x *Host) GetGpu() []string {
if x != nil {
return x.Gpu
}
return nil
}
type State struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Cpu float64 `protobuf:"fixed64,1,opt,name=cpu,proto3" json:"cpu,omitempty"`
MemUsed uint64 `protobuf:"varint,3,opt,name=mem_used,json=memUsed,proto3" json:"mem_used,omitempty"`
SwapUsed uint64 `protobuf:"varint,4,opt,name=swap_used,json=swapUsed,proto3" json:"swap_used,omitempty"`
DiskUsed uint64 `protobuf:"varint,5,opt,name=disk_used,json=diskUsed,proto3" json:"disk_used,omitempty"`
NetInTransfer uint64 `protobuf:"varint,6,opt,name=net_in_transfer,json=netInTransfer,proto3" json:"net_in_transfer,omitempty"`
NetOutTransfer uint64 `protobuf:"varint,7,opt,name=net_out_transfer,json=netOutTransfer,proto3" json:"net_out_transfer,omitempty"`
NetInSpeed uint64 `protobuf:"varint,8,opt,name=net_in_speed,json=netInSpeed,proto3" json:"net_in_speed,omitempty"`
NetOutSpeed uint64 `protobuf:"varint,9,opt,name=net_out_speed,json=netOutSpeed,proto3" json:"net_out_speed,omitempty"`
Uptime uint64 `protobuf:"varint,10,opt,name=uptime,proto3" json:"uptime,omitempty"`
Load1 float64 `protobuf:"fixed64,11,opt,name=load1,proto3" json:"load1,omitempty"`
Load5 float64 `protobuf:"fixed64,12,opt,name=load5,proto3" json:"load5,omitempty"`
Load15 float64 `protobuf:"fixed64,13,opt,name=load15,proto3" json:"load15,omitempty"`
TcpConnCount uint64 `protobuf:"varint,14,opt,name=tcp_conn_count,json=tcpConnCount,proto3" json:"tcp_conn_count,omitempty"`
UdpConnCount uint64 `protobuf:"varint,15,opt,name=udp_conn_count,json=udpConnCount,proto3" json:"udp_conn_count,omitempty"`
ProcessCount uint64 `protobuf:"varint,16,opt,name=process_count,json=processCount,proto3" json:"process_count,omitempty"`
Cpu float64 `protobuf:"fixed64,1,opt,name=cpu,proto3" json:"cpu,omitempty"`
MemUsed uint64 `protobuf:"varint,3,opt,name=mem_used,json=memUsed,proto3" json:"mem_used,omitempty"`
SwapUsed uint64 `protobuf:"varint,4,opt,name=swap_used,json=swapUsed,proto3" json:"swap_used,omitempty"`
DiskUsed uint64 `protobuf:"varint,5,opt,name=disk_used,json=diskUsed,proto3" json:"disk_used,omitempty"`
NetInTransfer uint64 `protobuf:"varint,6,opt,name=net_in_transfer,json=netInTransfer,proto3" json:"net_in_transfer,omitempty"`
NetOutTransfer uint64 `protobuf:"varint,7,opt,name=net_out_transfer,json=netOutTransfer,proto3" json:"net_out_transfer,omitempty"`
NetInSpeed uint64 `protobuf:"varint,8,opt,name=net_in_speed,json=netInSpeed,proto3" json:"net_in_speed,omitempty"`
NetOutSpeed uint64 `protobuf:"varint,9,opt,name=net_out_speed,json=netOutSpeed,proto3" json:"net_out_speed,omitempty"`
Uptime uint64 `protobuf:"varint,10,opt,name=uptime,proto3" json:"uptime,omitempty"`
Load1 float64 `protobuf:"fixed64,11,opt,name=load1,proto3" json:"load1,omitempty"`
Load5 float64 `protobuf:"fixed64,12,opt,name=load5,proto3" json:"load5,omitempty"`
Load15 float64 `protobuf:"fixed64,13,opt,name=load15,proto3" json:"load15,omitempty"`
TcpConnCount uint64 `protobuf:"varint,14,opt,name=tcp_conn_count,json=tcpConnCount,proto3" json:"tcp_conn_count,omitempty"`
UdpConnCount uint64 `protobuf:"varint,15,opt,name=udp_conn_count,json=udpConnCount,proto3" json:"udp_conn_count,omitempty"`
ProcessCount uint64 `protobuf:"varint,16,opt,name=process_count,json=processCount,proto3" json:"process_count,omitempty"`
Temperatures []*State_SensorTemperature `protobuf:"bytes,17,rep,name=temperatures,proto3" json:"temperatures,omitempty"`
Gpu float64 `protobuf:"fixed64,18,opt,name=gpu,proto3" json:"gpu,omitempty"`
}
func (x *State) Reset() {
@@ -314,6 +324,75 @@ func (x *State) GetProcessCount() uint64 {
return 0
}
func (x *State) GetTemperatures() []*State_SensorTemperature {
if x != nil {
return x.Temperatures
}
return nil
}
func (x *State) GetGpu() float64 {
if x != nil {
return x.Gpu
}
return 0
}
type State_SensorTemperature struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Temperature float64 `protobuf:"fixed64,2,opt,name=temperature,proto3" json:"temperature,omitempty"`
}
func (x *State_SensorTemperature) Reset() {
*x = State_SensorTemperature{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_nezha_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *State_SensorTemperature) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*State_SensorTemperature) ProtoMessage() {}
func (x *State_SensorTemperature) ProtoReflect() protoreflect.Message {
mi := &file_proto_nezha_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use State_SensorTemperature.ProtoReflect.Descriptor instead.
func (*State_SensorTemperature) Descriptor() ([]byte, []int) {
return file_proto_nezha_proto_rawDescGZIP(), []int{2}
}
func (x *State_SensorTemperature) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *State_SensorTemperature) GetTemperature() float64 {
if x != nil {
return x.Temperature
}
return 0
}
type Task struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -327,7 +406,7 @@ type Task struct {
func (x *Task) Reset() {
*x = Task{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_nezha_proto_msgTypes[2]
mi := &file_proto_nezha_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -340,7 +419,7 @@ func (x *Task) String() string {
func (*Task) ProtoMessage() {}
func (x *Task) ProtoReflect() protoreflect.Message {
mi := &file_proto_nezha_proto_msgTypes[2]
mi := &file_proto_nezha_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -353,7 +432,7 @@ func (x *Task) ProtoReflect() protoreflect.Message {
// Deprecated: Use Task.ProtoReflect.Descriptor instead.
func (*Task) Descriptor() ([]byte, []int) {
return file_proto_nezha_proto_rawDescGZIP(), []int{2}
return file_proto_nezha_proto_rawDescGZIP(), []int{3}
}
func (x *Task) GetId() uint64 {
@@ -392,7 +471,7 @@ type TaskResult struct {
func (x *TaskResult) Reset() {
*x = TaskResult{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_nezha_proto_msgTypes[3]
mi := &file_proto_nezha_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -405,7 +484,7 @@ func (x *TaskResult) String() string {
func (*TaskResult) ProtoMessage() {}
func (x *TaskResult) ProtoReflect() protoreflect.Message {
mi := &file_proto_nezha_proto_msgTypes[3]
mi := &file_proto_nezha_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -418,7 +497,7 @@ func (x *TaskResult) ProtoReflect() protoreflect.Message {
// Deprecated: Use TaskResult.ProtoReflect.Descriptor instead.
func (*TaskResult) Descriptor() ([]byte, []int) {
return file_proto_nezha_proto_rawDescGZIP(), []int{3}
return file_proto_nezha_proto_rawDescGZIP(), []int{4}
}
func (x *TaskResult) GetId() uint64 {
@@ -467,7 +546,7 @@ type Receipt struct {
func (x *Receipt) Reset() {
*x = Receipt{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_nezha_proto_msgTypes[4]
mi := &file_proto_nezha_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -480,7 +559,7 @@ func (x *Receipt) String() string {
func (*Receipt) ProtoMessage() {}
func (x *Receipt) ProtoReflect() protoreflect.Message {
mi := &file_proto_nezha_proto_msgTypes[4]
mi := &file_proto_nezha_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -493,7 +572,7 @@ func (x *Receipt) ProtoReflect() protoreflect.Message {
// Deprecated: Use Receipt.ProtoReflect.Descriptor instead.
func (*Receipt) Descriptor() ([]byte, []int) {
return file_proto_nezha_proto_rawDescGZIP(), []int{4}
return file_proto_nezha_proto_rawDescGZIP(), []int{5}
}
func (x *Receipt) GetProced() bool {
@@ -507,7 +586,7 @@ var File_proto_nezha_proto protoreflect.FileDescriptor
var file_proto_nezha_proto_rawDesc = []byte{
0x0a, 0x11, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6e, 0x65, 0x7a, 0x68, 0x61, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe0, 0x02, 0x0a, 0x04, 0x48,
0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf2, 0x02, 0x0a, 0x04, 0x48,
0x6f, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12,
0x29, 0x0a, 0x10, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73,
@@ -529,65 +608,77 @@ var file_proto_nezha_proto_rawDesc = []byte{
0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65,
0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43,
0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xd3, 0x03,
0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x01,
0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x65, 0x6d,
0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d, 0x65, 0x6d,
0x55, 0x73, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x75, 0x73, 0x65,
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x77, 0x61, 0x70, 0x55, 0x73, 0x65,
0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x05,
0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x65, 0x64, 0x12, 0x26,
0x0a, 0x0f, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65,
0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6e, 0x65, 0x74, 0x49, 0x6e, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x6e, 0x65, 0x74, 0x5f, 0x6f, 0x75,
0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04,
0x52, 0x0e, 0x6e, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72,
0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64,
0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x49, 0x6e, 0x53, 0x70, 0x65,
0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x70,
0x65, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x4f, 0x75,
0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x31, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x6c,
0x6f, 0x61, 0x64, 0x31, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x35, 0x18, 0x0c, 0x20,
0x01, 0x28, 0x01, 0x52, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x35, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x6f,
0x61, 0x64, 0x31, 0x35, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x6c, 0x6f, 0x61, 0x64,
0x31, 0x35, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x74, 0x63, 0x70, 0x43,
0x6f, 0x6e, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x75, 0x64, 0x70, 0x5f,
0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04,
0x52, 0x0c, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23,
0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18,
0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f,
0x75, 0x6e, 0x74, 0x22, 0x3e, 0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74,
0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12,
0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64,
0x61, 0x74, 0x61, 0x22, 0x7a, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69,
0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03,
0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64,
0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12,
0x1e, 0x0a, 0x0a, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, 0x05, 0x20,
0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x22,
0x21, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72,
0x6f, 0x63, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x63,
0x65, 0x64, 0x32, 0xd6, 0x01, 0x0a, 0x0c, 0x4e, 0x65, 0x7a, 0x68, 0x61, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73,
0x74, 0x65, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52,
0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0a, 0x52,
0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x0e, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x2b,
0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0b, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x00, 0x30, 0x01, 0x42, 0x09, 0x5a, 0x07, 0x2e,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a,
0x03, 0x67, 0x70, 0x75, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x67, 0x70, 0x75, 0x22,
0xa9, 0x04, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x70, 0x75,
0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x19, 0x0a, 0x08, 0x6d,
0x65, 0x6d, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d,
0x65, 0x6d, 0x55, 0x73, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x75,
0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x77, 0x61, 0x70, 0x55,
0x73, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x75, 0x73, 0x65, 0x64,
0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x65, 0x64,
0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73,
0x66, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6e, 0x65, 0x74, 0x49, 0x6e,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x6e, 0x65, 0x74, 0x5f,
0x6f, 0x75, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01,
0x28, 0x04, 0x52, 0x0e, 0x6e, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66,
0x65, 0x72, 0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x5f, 0x73, 0x70, 0x65,
0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x49, 0x6e, 0x53,
0x70, 0x65, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x5f,
0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6e, 0x65, 0x74,
0x4f, 0x75, 0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69,
0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x31, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52,
0x05, 0x6c, 0x6f, 0x61, 0x64, 0x31, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x35, 0x18,
0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x35, 0x12, 0x16, 0x0a, 0x06,
0x6c, 0x6f, 0x61, 0x64, 0x31, 0x35, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x6c, 0x6f,
0x61, 0x64, 0x31, 0x35, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e,
0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x74, 0x63,
0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x75, 0x64,
0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01,
0x28, 0x04, 0x52, 0x0c, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74,
0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x0c, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61,
0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72,
0x54, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0c, 0x74, 0x65, 0x6d,
0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x70, 0x75,
0x18, 0x12, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x67, 0x70, 0x75, 0x22, 0x4f, 0x0a, 0x17, 0x53,
0x74, 0x61, 0x74, 0x65, 0x5f, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x54, 0x65, 0x6d, 0x70, 0x65,
0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x65,
0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52,
0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x3e, 0x0a, 0x04,
0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x7a, 0x0a, 0x0a,
0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79,
0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x64,
0x65, 0x6c, 0x61, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x75, 0x63, 0x63,
0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x75,
0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x22, 0x21, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x65,
0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x32, 0xd6, 0x01, 0x0a, 0x0c,
0x4e, 0x65, 0x7a, 0x68, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x11,
0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x53, 0x74, 0x61, 0x74,
0x65, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a,
0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22,
0x00, 0x12, 0x31, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65,
0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x6f,
0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69,
0x70, 0x74, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61,
0x73, 0x6b, 0x12, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52,
0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65,
0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48,
0x6f, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b,
0x22, 0x00, 0x30, 0x01, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -602,28 +693,30 @@ func file_proto_nezha_proto_rawDescGZIP() []byte {
return file_proto_nezha_proto_rawDescData
}
var file_proto_nezha_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_proto_nezha_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_proto_nezha_proto_goTypes = []interface{}{
(*Host)(nil), // 0: proto.Host
(*State)(nil), // 1: proto.State
(*Task)(nil), // 2: proto.Task
(*TaskResult)(nil), // 3: proto.TaskResult
(*Receipt)(nil), // 4: proto.Receipt
(*Host)(nil), // 0: proto.Host
(*State)(nil), // 1: proto.State
(*State_SensorTemperature)(nil), // 2: proto.State_SensorTemperature
(*Task)(nil), // 3: proto.Task
(*TaskResult)(nil), // 4: proto.TaskResult
(*Receipt)(nil), // 5: proto.Receipt
}
var file_proto_nezha_proto_depIdxs = []int32{
1, // 0: proto.NezhaService.ReportSystemState:input_type -> proto.State
0, // 1: proto.NezhaService.ReportSystemInfo:input_type -> proto.Host
3, // 2: proto.NezhaService.ReportTask:input_type -> proto.TaskResult
0, // 3: proto.NezhaService.RequestTask:input_type -> proto.Host
4, // 4: proto.NezhaService.ReportSystemState:output_type -> proto.Receipt
4, // 5: proto.NezhaService.ReportSystemInfo:output_type -> proto.Receipt
4, // 6: proto.NezhaService.ReportTask:output_type -> proto.Receipt
2, // 7: proto.NezhaService.RequestTask:output_type -> proto.Task
4, // [4:8] is the sub-list for method output_type
0, // [0:4] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
2, // 0: proto.State.temperatures:type_name -> proto.State_SensorTemperature
1, // 1: proto.NezhaService.ReportSystemState:input_type -> proto.State
0, // 2: proto.NezhaService.ReportSystemInfo:input_type -> proto.Host
4, // 3: proto.NezhaService.ReportTask:input_type -> proto.TaskResult
0, // 4: proto.NezhaService.RequestTask:input_type -> proto.Host
5, // 5: proto.NezhaService.ReportSystemState:output_type -> proto.Receipt
5, // 6: proto.NezhaService.ReportSystemInfo:output_type -> proto.Receipt
5, // 7: proto.NezhaService.ReportTask:output_type -> proto.Receipt
3, // 8: proto.NezhaService.RequestTask:output_type -> proto.Task
5, // [5:9] is the sub-list for method output_type
1, // [1:5] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_proto_nezha_proto_init() }
@@ -657,7 +750,7 @@ func file_proto_nezha_proto_init() {
}
}
file_proto_nezha_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Task); i {
switch v := v.(*State_SensorTemperature); i {
case 0:
return &v.state
case 1:
@@ -669,7 +762,7 @@ func file_proto_nezha_proto_init() {
}
}
file_proto_nezha_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TaskResult); i {
switch v := v.(*Task); i {
case 0:
return &v.state
case 1:
@@ -681,6 +774,18 @@ func file_proto_nezha_proto_init() {
}
}
file_proto_nezha_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TaskResult); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_nezha_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Receipt); i {
case 0:
return &v.state
@@ -699,7 +804,7 @@ func file_proto_nezha_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proto_nezha_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},
+8
View File
@@ -23,6 +23,7 @@ message Host {
string ip = 10;
string country_code = 11;
string version = 12;
repeated string gpu = 13;
}
message State {
@@ -41,6 +42,13 @@ message State {
uint64 tcp_conn_count = 14;
uint64 udp_conn_count = 15;
uint64 process_count = 16;
repeated State_SensorTemperature temperatures = 17;
double gpu = 18;
}
message State_SensorTemperature {
string name = 1;
double temperature = 2;
}
message Task {
+27 -12
View File
@@ -32,10 +32,10 @@ other = "Logout"
other = "Login"
[ConfirmLogout]
other = "Confirm Logout?"
other = "Do you want to Logout?"
[AfterLoggingOutYouHaveToLoginAgain]
other = "You need to login again after logout to continue"
other = "You need to Login again to continue"
[Cancel]
other = "Cancel"
@@ -227,7 +227,7 @@ other = "Secret"
other = "Note"
[LinuxOneKeyInstall]
other = "Linux One-Key Install"
other = "Linux One-Command Install"
[NoDomainAlert]
other = "Set CDN bypassed Domain/IP in setting before using this function"
@@ -257,7 +257,7 @@ other = "Execute by Trigger"
other = "Delete Scheduled Task"
[ConfirmToDeleteThisScheduledTask]
other = "Confirm Delete?"
other = "Are you sure you want to Delete?"
[AccessDenied]
other = "Access Denied"
@@ -293,7 +293,7 @@ other = "Delete Notification Method"
other = "Confirm to Delete This Notification Method?"
[ForceUpdate]
other = "Force Update"
other = "Force to Update"
[SelectAll]
other = "Select All"
@@ -302,7 +302,7 @@ other = "Select All"
other = "Version"
[OneKeyInstall]
other = "One-Key Install"
other = "One-Command Install"
[ClickToCopy]
other = "Click To Copy"
@@ -398,7 +398,7 @@ other = "Virtualization"
other = "Swap"
[NetTransfer]
other = "Transfer"
other = "Usage"
[Load]
other = "Load"
@@ -419,7 +419,7 @@ other = "Last Active"
other = "Version"
[NetSpeed]
other = "Speed"
other = "NIC"
[Uptime]
other = "Uptime"
@@ -473,7 +473,7 @@ other = "Next check"
other = "Current Usage"
[VerifyPassword]
other = "Verify Password"
other = "Please enter your password"
[LightMode]
other = "Light Mode"
@@ -482,7 +482,7 @@ other = "Light Mode"
other = "Dark Mode"
[FollowSystem]
other = "Follow System"
other = "System Auto"
[GridLayout]
other = "Grid Layout"
@@ -619,9 +619,18 @@ other = "Enable Show in Service"
[EnableDDNS]
other = "Enable DDNS"
[EnableIPv4]
other = "Enable DDNS IPv4"
[EnableIpv6]
other = "Enable DDNS IPv6"
[DDNSDomain]
other = "DDNS Domain"
[DDNSProfile]
other = "DDNS Profile Name"
[Feature]
other = "Feature"
@@ -629,7 +638,13 @@ other = "Feature"
other = "Template"
[Stat]
other = "Stat"
other = "Asset"
[Temperature]
other = "Temperature"
[DisableSwitchTemplateInFrontend]
other = "Disable Switch Template in Frontend"
other = "Disable Switch Template in Frontend"
[ServersOnWorldMap]
other = "Servers On World Map"
+16 -1
View File
@@ -619,9 +619,18 @@ other = "Mostrar en servicio"
[EnableDDNS]
other = "Habilitar DDNS"
[EnableIPv4]
other = "Habilitar DDNS IPv4"
[EnableIpv6]
other = "Habilitar DDNS IPv6"
[DDNSDomain]
other = "Dominio DDNS"
[DDNSProfile]
other = "Nombre del perfil de DDNS"
[Feature]
other = "Característica"
@@ -631,5 +640,11 @@ other = "Plantilla"
[Stat]
other = "Stat"
[Temperature]
other = "Temperatura"
[DisableSwitchTemplateInFrontend]
other = "Deshabilitar Cambio de Plantilla en Frontend"
other = "Deshabilitar Cambio de Plantilla en Frontend"
[ServersOnWorldMap]
other = "Servidores en el mapa mundial"
+15
View File
@@ -619,9 +619,18 @@ other = "在服务中显示"
[EnableDDNS]
other = "启用DDNS"
[EnableIPv4]
other = "启用DDNS IPv4"
[EnableIpv6]
other = "启用DDNS IPv6"
[DDNSDomain]
other = "DDNS域名"
[DDNSProfile]
other = "DDNS配置名"
[Feature]
other = "功能"
@@ -631,5 +640,11 @@ other = "主题"
[Stat]
other = "信息"
[Temperature]
other = "温度"
[DisableSwitchTemplateInFrontend]
other = "禁止前台切换模板"
[ServersOnWorldMap]
other = "服务器世界分布图"
+15
View File
@@ -619,9 +619,18 @@ other = "在服務中顯示"
[EnableDDNS]
other = "啟用DDNS"
[EnableIPv4]
other = "啟用DDNS IPv4"
[EnableIpv6]
other = "啟用DDNS IPv6"
[DDNSDomain]
other = "DDNS網域"
[DDNSProfile]
other = "DDNS設定名"
[Feature]
other = "功能"
@@ -631,5 +640,11 @@ other = "主題"
[Stat]
other = "信息"
[Temperature]
other = "溫度"
[DisableSwitchTemplateInFrontend]
other = "禁止前台切換主題"
[ServersOnWorldMap]
other = "伺服器世界分布圖"
+11
View File
@@ -303,6 +303,7 @@ function addOrEditServer(server, conf) {
modal.find("input[name=name]").val(server ? server.Name : null);
modal.find("input[name=Tag]").val(server ? server.Tag : null);
modal.find("input[name=DDNSDomain]").val(server ? server.DDNSDomain : null);
modal.find("input[name=DDNSProfile]").val(server ? server.DDNSProfile : null);
modal
.find("input[name=DisplayIndex]")
.val(server ? server.DisplayIndex : null);
@@ -327,6 +328,16 @@ function addOrEditServer(server, conf) {
} else {
modal.find(".ui.enableddns.checkbox").checkbox("set unchecked");
}
if (server && server.EnableIPv4) {
modal.find(".ui.enableipv4.checkbox").checkbox("set checked");
} else {
modal.find(".ui.enableipv4.checkbox").checkbox("set unchecked");
}
if (server && server.EnableIpv6) {
modal.find(".ui.enableipv6.checkbox").checkbox("set checked");
} else {
modal.find(".ui.enableipv6.checkbox").checkbox("set unchecked");
}
showFormModal(".server.modal", "#serverForm", "/api/server");
}
+4
View File
@@ -145,6 +145,10 @@ td {
z-index: 9999;
}
.temp-detail {
cursor: pointer;
}
.ui.content {
margin:0 !important;
padding:1em !important;
+1 -1
View File
@@ -6,7 +6,7 @@ const mixinsVue = {
adaptedTemplates: [
{ key: 'default', name: 'Default', icon: 'th large' },
{ key: 'angel-kanade', name: 'AngelKanade', icon: 'square' },
{ key: 'server-status', name: 'SeverStatus', icon: 'list' }
{ key: 'server-status', name: 'ServerStatus', icon: 'list' }
]
},
created() {
+13
View File
@@ -157,3 +157,16 @@ body[theme="dark"] footer p a:hover {
color: #f1f1f1;
text-decoration: none;
}
body[theme="dark"] .modal-content{
background-color: #1c1d26;
color: #f1f1f1;
}
body[theme="dark"] .modal-header{
border-bottom-color:#080808;
}
body[theme="dark"] .modal-header i{
color: #f1f1f1;
}
+13
View File
@@ -131,4 +131,17 @@ body[theme="light"] footer p a,
body[theme="light"] footer p a:hover {
color: #333333;
text-decoration: none;
}
body[theme="light"] .modal-content{
background-color: #ffffff;
color: rgba(0, 0, 0, 0.87);
}
body[theme="light"] .modal-header{
border-bottom-color:#f1f1f1;
}
body[theme="light"] .modal-header i{
color: rgba(0, 0, 0, 0.87);
}
+49 -3
View File
@@ -230,6 +230,10 @@ body {
max-width: 50px;
}
.temp-detail {
cursor: pointer;
}
/*正文结束*/
/* 服务页 正文*/
@@ -281,10 +285,42 @@ body {
.service-status .tooltip-inner {
max-width: 500px;
}
/* 服务页 正文结束 */
/* 服务器分布图 */
#mapChartBox{
z-index: 999999999;
}
.modal-content{
display: flex;
flex-direction: column;
pointer-events: auto;
}
.modal-dialog-centered{
margin: 0 auto;
width: 1134px;
max-width: 1134px;
display: flex;
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
min-height: calc(100%) /* 确保模态框占据整个视口高度 */
}
.modal-header{
position: relative;
}
.modal-header i{
cursor: pointer;
position: absolute;
font-size: 2em;
top: 13px;
right: 13px;
}
@media only screen and (max-width: 1200px) {
.accordian-body{
margin: 5px 0px 5px 10px;
@@ -365,6 +401,16 @@ body {
.toolbox {
right: 18px;
}
.modal-dialog-centered{
width: 95%;
}
.modal-title{
line-height: 0.5;
}
.modal-header i{
top: 8px;
right: 8px;
}
}
@media only screen and (min-width: 768px) {
+1 -1
View File
@@ -21,7 +21,7 @@
/** Name of the expando, to work with multiple documents or to re-shiv one document */
var expando = '_html5shiv';
/** The id for the the documents expando */
/** The id for the documents expando */
var expanID = 0;
/** Cached data for each document */
+5 -2
View File
@@ -10,7 +10,7 @@ const mixinsVue = {
adaptedTemplates: [
{ key: 'default', name: 'Default', icon: 'th large' },
{ key: 'angel-kanade', name: 'AngelKanade', icon: 'square' },
{ key: 'server-status', name: 'SeverStatus', icon: 'list' }
{ key: 'server-status', name: 'ServerStatus', icon: 'list' }
]
},
created() {
@@ -27,13 +27,16 @@ const mixinsVue = {
toggleView() {
this.showGroup = !this.showGroup;
localStorage.setItem("showGroup", JSON.stringify(this.showGroup));
if(this.$root.page == 'service') {
this.$root.initTooltip();
}
return this.showGroup;
},
storedShowGroup() {
const storedShowGroup = localStorage.getItem("showGroup");
if (storedShowGroup !== null) {
this.showGroup = JSON.parse(storedShowGroup);
}
}
},
toggleTemplate(template) {
if( template != this.preferredTemplate){
+1 -1
View File
@@ -10,7 +10,7 @@
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/semantic-ui/2.4.1/semantic.min.js"></script>
<script src="/static/semantic-ui-alerts.min.js"></script>
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/vue/2.6.14/vue.min.js"></script>
<script src="/static/main.js?v20240224"></script>
<script src="/static/main.js?v20240330"></script>
<script>
(function () {
updateLang({{.LANG }});
+17 -1
View File
@@ -32,10 +32,26 @@
<label>{{tr "EnableDDNS"}}</label>
</div>
</div>
<div class="field">
<div class="ui enableipv4 checkbox">
<input name="EnableIPv4" type="checkbox" tabindex="0" />
<label>{{tr "EnableIPv4"}}</label>
</div>
</div>
<div class="field">
<div class="ui enableipv6 checkbox">
<input name="EnableIpv6" type="checkbox" tabindex="0" />
<label>{{tr "EnableIpv6"}}</label>
</div>
</div>
<div class="field">
<label>{{tr "DDNSDomain"}}</label>
<input type="text" name="DDNSDomain" placeholder="{{tr "DDNSDomain"}}">
</div>
<div class="field">
<label>{{tr "DDNSProfile"}}</label>
<input type="text" name="DDNSProfile" placeholder="{{tr "DDNSProfile"}}">
</div>
<div class="field">
<label>{{tr "Note"}}</label>
<textarea name="Note"></textarea>
@@ -45,7 +61,7 @@
<div class="ui message">
{{if .Conf.GRPCHost}}
curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.sh -o nezha.sh && chmod
+x nezha.sh && sudo ./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 hostSecret"></code> <code class="command">{{if .Conf.TLS}}--tls{{end}}</code>
{{else}}
+9
View File
@@ -30,6 +30,8 @@
<th>{{tr "VersionNumber"}}</th>
<th>{{tr "HideForGuest"}}</th>
<th>{{tr "EnableDDNS"}}</th>
<th>{{tr "EnableIPv4"}}</th>
<th>{{tr "EnableIpv6"}}</th>
<th>{{tr "DDNSDomain"}}</th>
<th>{{tr "Secret"}}</th>
<th>{{tr "OneKeyInstall"}}</th>
@@ -48,6 +50,8 @@
<td>{{$server.Host.Version}}</td>
<td>{{$server.HideForGuest}}</td>
<td>{{$server.EnableDDNS}}</td>
<td>{{$server.EnableIPv4}}</td>
<td>{{$server.EnableIpv6}}</td>
<td>{{$server.DDNSDomain}}</td>
<td>
<button class="ui icon green mini button" data-clipboard-text="{{$server.Secret}}" data-tooltip="{{tr "ClickToCopy"}}">
@@ -65,6 +69,11 @@
data-tooltip="{{tr "ClickToCopy"}}">
<i class="windows icon"></i>
</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-tooltip="{{tr "ClickToCopy"}}">
<i class="apple icon"></i>
</button>
</td>
<td style="word-break: break-word;white-space: pre-wrap;">{{$server.Note}}</td>
<td>
+1 -1
View File
@@ -13,7 +13,7 @@
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/semantic-ui/2.4.1/semantic.min.js"></script>
<script src="/static/semantic-ui-alerts.min.js"></script>
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/vue/2.6.14/vue.min.js"></script>
<script src="/static/main.js?v20240224"></script>
<script src="/static/main.js?v20240330"></script>
<script src="/static/theme-default/js/mixin.js?v20240302"></script>
<script>
(function () {
+3
View File
@@ -24,6 +24,9 @@
[<span
v-if="server.Host.Virtualization">@#server.Host.Virtualization#@:</span>@#server.Host.Arch#@]<br />
CPU: @#server.Host.CPU#@<br />
<template v-if="server.Host.GPU">
GPU: @#server.Host.GPU#@
</template>
{{tr "DiskUsed"}}:
@#formatByteSize(server.State.DiskUsed)#@/@#formatByteSize(server.Host.DiskTotal)#@<br />
{{tr "MemUsed"}}:
+3
View File
@@ -24,6 +24,9 @@
<i :class="item.icon + ' icon'"></i>@#item.name#@
<i class="check icon" v-if="preferredTemplate === item.key"></i>
</a>
<a v-if="defaultTemplate === 'custom'" @click="toggleTemplate('custom')" class="item">
<i class="expand icon"></i>Custom
</a>
</div>
</div>
{{ end }}
+153 -128
View File
@@ -20,101 +20,101 @@
</head>
<body data-theme="light" data-gridlist="grid">
<header>
<section class="nav-bar clearfix">
<figure class="logo">
<a href="/">
<img src="/static/logo.svg?v20210804" alt='{{tr "NezhaMonitoring"}}' width="50" height="50">
</a>
<a href="/">{{.Conf.Site.Brand}}</a>
</figure>
<div class="icon-container">
<div class="row cf">
<div class="three col">
<div class="hamburger" id="hamburger-icon"><span class="line"></span><span
class="line"></span><span class="line"></span></div>
<header>
<section class="nav-bar clearfix">
<figure class="logo">
<a href="/">
<img src="/static/logo.svg?v20210804" alt='{{tr "NezhaMonitoring"}}' width="50" height="50">
</a>
<a href="/">{{.Conf.Site.Brand}}</a>
</figure>
<div class="icon-container">
<div class="row cf">
<div class="three col">
<div class="hamburger" id="hamburger-icon"><span class="line"></span><span
class="line"></span><span class="line"></span></div>
</div>
</div>
</div>
<nav class="nav-menu">
<ul>
<li><a href="/">{{tr "Home"}}</a></li>
<li><a href="/service">{{tr "Services"}}</a></li>
<li><a href="/network">{{tr "NetworkSpiter"}}</a></li>
{{if .Admin}}
<li><a href="/server">{{tr "AdminPanel"}}</a></li>
{{else}}
<li><a href="/login">{{tr "Login"}}</a></li>
{{end}}
</ul>
</nav>
</section>
</header>
<main>
<div id="network">
<div class="server-info-container" v-for='server in servers' :id="server.ID">
<div class="info-body" @click="redirectNetwork(server.ID)">
<ul class="server-info-body-container">
<li>
<h3>@#server.Name#@</h3>
</li>
<li><img :src="'/static/theme-daynight/img/flag/'+(server.Host&&server.Host.CountryCode?server.Host.CountryCode.toUpperCase():'CN')+'.png'"
:title="server.Host.CountryCode.toUpperCase()" /></li>
</ul>
</div>
</div>
</div>
<nav class="nav-menu">
<ul>
<li><a href="/">{{tr "Home"}}</a></li>
<li><a href="/service">{{tr "Services"}}</a></li>
<li><a href="/network">{{tr "NetworkSpiter"}}</a></li>
{{if .Admin}}
<li><a href="/server">{{tr "AdminPanel"}}</a></li>
{{else}}
<li><a href="/login">{{tr "Login"}}</a></li>
{{end}}
</ul>
</nav>
</section>
</header>
<main>
<div id="network">
<div class="server-info-container" v-for='server in servers' :id="server.ID" style="font-size: .6em">
<div class="info-body" @click="redirectNetwork(server.ID)">
<ul class="server-info-body-container">
<li>
<h3>@#server.Name#@</h3>
</li>
<li><img :src="'/static/theme-daynight/img/flag/'+(server.Host&&server.Host.CountryCode?server.Host.CountryCode.toUpperCase():'CN')+'.png'"
:title="server.Host.CountryCode.toUpperCase()" /></li>
</ul>
<div class="network-chart" style="height: 800px;overflow: hidden">
<div id="monitor-info-container" style="height: 520px;max-width: 1400px">
</div>
</div>
</div>
<div class="network-chart" style="height: 800px;overflow: hidden">
<div id="monitor-info-container" style="height: 520px;max-width: 1400px">
<div class="sidebar-container">
<ul>
<li><i class="fas fa-sun" title='{{tr "LightMode"}}'></i><span>{{tr "LightMode"}}</span></li>
<li><i class="fas fa-moon" title='{{tr "DarkMode"}}'></i><span>{{tr "DarkMode"}}</span></li>
<li><i class="fas fa-th" title='{{tr "GridLayout"}}'></i><span>{{tr "GridLayout"}}</span></li>
<li><i class="fas fa-list-ul" title='{{tr "ListLayout"}}'></i><span>{{tr "ListLayout"}}</span></li>
</ul>
</div>
</div>
<div class="sidebar-container">
<ul>
<li><i class="fas fa-sun" title='{{tr "LightMode"}}'></i><span>{{tr "LightMode"}}</span></li>
<li><i class="fas fa-moon" title='{{tr "DarkMode"}}'></i><span>{{tr "DarkMode"}}</span></li>
<li><i class="fas fa-th" title='{{tr "GridLayout"}}'></i><span>{{tr "GridLayout"}}</span></li>
<li><i class="fas fa-list-ul" title='{{tr "ListLayout"}}'></i><span>{{tr "ListLayout"}}</span></li>
</ul>
</div>
</main>
</main>
<section class="dark-light-toggle">
<label class="switcher">
<input type="checkbox" name="theme" id="dark-light" />
<div>
<i class="fas fa-adjust"></i>
</div>
</label>
</section>
<section class="dark-light-toggle">
<label class="switcher">
<input type="checkbox" name="theme" id="dark-light" />
<div>
<i class="fas fa-adjust"></i>
</div>
</label>
</section>
<!-- Back to top button -->
<a id="back-to-top"></a>
<!-- Back to top button -->
<a id="back-to-top"></a>
<footer>
<div class="footer-container">
<div><a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "NezhaMonitoring"}} · {{.Version}}</a>
<p>&copy; <span id="copyright-date">
<footer>
<div class="footer-container">
<div><a href="https://github.com/naiba/nezha" target="_blank">Powered by {{tr "NezhaMonitoring"}} ·
{{.Version}}</a>
<p>&copy; <span id="copyright-date">
<script>document.getElementById('copyright-date').appendChild(document.createTextNode(new Date().getFullYear()))</script>
</span> · <a href="https://blog.jackiesung.com" target="_blank">Theme designed by Jackie Sung</a>
</p>
</p>
</div>
</div>
</div>
</footer>
</footer>
<script src="/static/theme-daynight/js/main.js?v202102012266"></script>
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/vue/2.6.14/vue.min.js"></script>
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/limonte-sweetalert2/11.4.4/sweetalert2.all.min.js"></script>
<script src="/static/theme-daynight/js/main.js?v202102012266"></script>
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/vue/2.6.14/vue.min.js"></script>
<script
src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/limonte-sweetalert2/11.4.4/sweetalert2.all.min.js"></script>
<script>
const monitorInfo = JSON.parse('{{.MonitorInfos}}');
<script>
const monitorInfo = JSON.parse('{{.MonitorInfos}}');
const initData = JSON.parse('{{.Servers}}').servers;
let MaxTCPPingValue = {{.Conf.MaxTCPPingValue}};
if (MaxTCPPingValue == null) {
MaxTCPPingValue = 1000;
}
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('monitor-info-container'));
const myChart = echarts.init(document.getElementById('monitor-info-container'));
// 使用刚指定的配置项和数据显示图表。
var statusCards = new Vue({
el: '#network',
@@ -128,11 +128,11 @@
position: function (pt) {
return [pt[0], '10%'];
},
formatter: function(params){
formatter: function (params) {
let result = params[0].axisValueLabel + "<br />";
params.forEach(function(item){
params.forEach(function (item) {
result += item.marker + item.seriesName + ": " + item.value[1].toFixed(2) + " ms<br />";
})
})
return result;
},
confine: true,
@@ -179,9 +179,9 @@
mounted() {
this.DarkMode();
this.parseMonitorInfo(monitorInfo);
window.addEventListener('resize', this.resizeHandle);
window.addEventListener('resize', this.resizeHandle);
},
destroyed () {
destroyed() {
window.removeEventListener('resize', this.resizeHandle)
},
methods: {
@@ -195,81 +195,106 @@
},
redirectNetwork(id) {
this.getMonitorHistory(id)
.then(function(monitorInfo) {
var vm = network.__vue__;
vm.parseMonitorInfo(monitorInfo);
})
.catch(function(error){
window.location.href = "/404";
})
.then(function (monitorInfo) {
var vm = network.__vue__;
vm.parseMonitorInfo(monitorInfo);
})
.catch(function (error) {
window.location.href = "/404";
})
},
getMonitorHistory(id) {
return $.ajax({
url: "/api/v1/monitor/"+id,
return $.ajax({
url: "/api/v1/monitor/" + id,
method: "GET"
});
});
},
parseMonitorInfo(monitorInfo) {
let tSeries = [];
let tLegendData = [];
var lcolors = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
for (let i = 0; i < monitorInfo.result.length; i++) {
var lcolor = lcolors[i % lcolors.length];
var rgbaColorMarker = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.5)';
var rgbaColorBar = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.35)';
let loss = 0;
let data = [];
let datal = [];
for (let j = 0; j < monitorInfo.result[i].created_at.length; j++) {
avgDelay = monitorInfo.result[i].avg_delay[j];
if (avgDelay > 0.9 * MaxTCPPingValue) {
loss += 1
avgDelay = Math.round(monitorInfo.result[i].avg_delay[j]);
if (avgDelay > 0 && avgDelay < MaxTCPPingValue) {
data.push([monitorInfo.result[i].created_at[j], avgDelay]);
}
else {
loss += 1;
datal.push({
xAxis: monitorInfo.result[i].created_at[j],
label: { show: false },
emphasis: { disabled: true },
lineStyle: {
type: "solid",
color: rgbaColorBar
}
});
}
data.push([monitorInfo.result[i].created_at[j], avgDelay]);
}
lossRate = ((loss / monitorInfo.result[i].created_at.length) * 100).toFixed(1);
legendName = monitorInfo.result[i].monitor_name +" "+ lossRate + "%";
if (lossRate > 99) {
datal = [];
}
legendName = monitorInfo.result[i].monitor_name + " " + lossRate + "%";
tLegendData.push(legendName);
tSeries.push({
name: legendName,
type: 'line',
smooth: true,
symbol: 'none',
data: data
name: legendName,
type: 'line',
smooth: true,
symbol: 'none',
data: data,
markLine: {
symbol: "none",
symbolSize: 0,
data: datal
},
markPoint: {
data: [
{ type: 'max', symbol: 'pin', name: 'Max', itemStyle: { color: rgbaColorMarker }, symbolSize: 30, label: { fontSize: 8 } },
{ type: 'min', symbol: 'pin', name: 'Min', itemStyle: { color: rgbaColorMarker }, symbolSize: 30, label: { fontSize: 8, offset: [0, 7.5] }, symbolRotate: 180 }
]
}
});
}
this.option.title.text = monitorInfo.result[0].server_name;
this.option.series = tSeries;
this.option.legend.data = tLegendData;
const hour = new Date(Date.now()).getHours()
if (hour > 17 || hour < 4) {
this.option.legend.textStyle.color = "#F1F1F2";
this.option.title.textStyle.color = "#ccc";
}
myChart.clear();
myChart.setOption(this.option);
},
resizeHandle () {
this.myChart.resize();
resizeHandle() {
myChart.resize();
},
}
});
</script>
</body>
<style>
#network {
display: grid;
/*grid-template-columns: repeat(5, 1fr);*/
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
grid-gap: 1em;
width: 100%;
width: calc(100vw - 6em);
max-width: 1400px;
margin: 1em auto;
align-content: start;
}
#monitor-info-container{
margin: 0em auto;
align-content: start;
background-color: #F1F1F2;
}
#network {
width: calc(100vw - 6em);
max-width: 1400px;
margin: 1em auto;
}
#monitor-info-container {
margin: 0em auto;
align-content: start;
background-color: #F1F1F2;
}
.server-info-container {
font-size: .6em;
width: fit-content;
display: inline-block;
}
</style>
</html>
{{end}}
{{end}}
+12 -11
View File
@@ -7,19 +7,20 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta content="telephone=no" name="format-detection">
<title>{{.Title}}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/assets/font-logos.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/lipis/[email protected]/css/flag-icons.min.css">
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
<link rel="stylesheet" type="text/css" href="/static/theme-default/css/main.css?v20240226">
<link rel="shortcut icon" type="image/png" href="/static/logo.svg" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/semantic.min.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/assets/font-logos.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/css/flag-icons.min.css">
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
<link rel="stylesheet" type="text/css" href="/static/theme-default/css/main.css?v20240616">
<script src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/semantic.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="/static/semantic-ui-alerts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
<script src="/static/theme-default/js/mixin.js?v20240302"></script>
</head>
<body>
{{end}}
{{end}}
File diff suppressed because it is too large Load Diff
+3
View File
@@ -27,6 +27,9 @@
<i :class="item.icon + ' icon'"></i>@#item.name#@
<i class="check icon" v-if="preferredTemplate === item.key"></i>
</a>
<a v-if="defaultTemplate === 'custom'" @click="toggleTemplate('custom')" class="item">
<i class="expand icon"></i>Custom
</a>
</div>
</div>
{{ end }}
+28 -9
View File
@@ -28,9 +28,6 @@
const monitorInfo = JSON.parse('{{.MonitorInfos}}');
const initData = JSON.parse('{{.Servers}}').servers;
let MaxTCPPingValue = {{.Conf.MaxTCPPingValue}};
if (MaxTCPPingValue == null) {
MaxTCPPingValue = 1000;
}
new Vue({
el: '#app',
delimiters: ['@#', '#@'],
@@ -185,19 +182,36 @@
parseMonitorInfo(monitorInfo) {
let tSeries = [];
let tLegendData = [];
var lcolors = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
for (let i = 0; i < monitorInfo.result.length; i++) {
var lcolor = lcolors[i % lcolors.length];
var rgbaColorMarker = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.5)';
var rgbaColorBar = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.35)';
let loss = 0;
let data = [];
let datal = [];
for (let j = 0; j < monitorInfo.result[i].created_at.length; j++) {
avgDelay = Math.round(monitorInfo.result[i].avg_delay[j]);
if (avgDelay > 0.9 * MaxTCPPingValue) {
loss += 1
}
if (avgDelay > 0) {
if (avgDelay > 0 && avgDelay < MaxTCPPingValue) {
data.push([monitorInfo.result[i].created_at[j], avgDelay]);
}
else {
loss += 1;
datal.push({
xAxis: monitorInfo.result[i].created_at[j],
label: { show: false },
emphasis: { disabled: true },
lineStyle: {
type: "solid",
color: rgbaColorBar
}
});
}
}
lossRate = ((loss / monitorInfo.result[i].created_at.length) * 100).toFixed(1);
if (lossRate > 99) {
datal = [];
}
legendName = monitorInfo.result[i].monitor_name +" "+ lossRate + "%";
tLegendData.push(legendName);
tSeries.push({
@@ -206,10 +220,15 @@
smooth: true,
symbol: 'none',
data: data,
markLine: {
symbol: "none",
symbolSize :0,
data: datal
},
markPoint: {
data: [
{ type: 'max', symbol: 'pin', name: 'Max', itemStyle: { color: '#f00' } },
{ type: 'min', symbol: 'pin', name: 'Min', itemStyle: { color: '#0f0' } }
{ type: 'max', symbol: 'pin', name: 'Max', itemStyle: { color: rgbaColorMarker }, symbolSize: 30, label: { fontSize: 8 } },
{ type: 'min', symbol: 'pin', name: 'Min', itemStyle: { color: rgbaColorMarker }, symbolSize: 30, label: { fontSize: 8, offset: [0, 7.5] }, symbolRotate: 180 }
]
}
});
+1 -1
View File
@@ -221,7 +221,7 @@
var disk = this.formatByteSize(server.State.DiskUsed) + '/' + this.formatByteSize(server.Host.DiskTotal);
var upTime = this.secondToDate(server.State.Uptime);
var tooltip =
`{content: 'System: ${server.Host.Platform}-${server.Host.PlatformVersion}[${server.Host.Arch}]<br>CPU: ${server.Host.CPU}<br>Disk: ${disk}<br>Online: ${upTime}<br>Version: ${server.Host.Version}'}`;
`{content: 'System: ${server.Host.Platform}-${server.Host.PlatformVersion}[${server.Host.Arch}]<br>CPU: ${server.Host.CPU}<br>GPU: ${server.Host.GPU}<br>Disk: ${disk}<br>Online: ${upTime}<br>Version: ${server.Host.Version}'}`;
return tooltip
}
}
+29 -10
View File
@@ -55,9 +55,6 @@
const monitorInfo = JSON.parse('{{.MonitorInfos}}');
const initData = JSON.parse('{{.Servers}}').servers;
let MaxTCPPingValue = {{.Conf.MaxTCPPingValue}};
if (MaxTCPPingValue == null) {
MaxTCPPingValue = 1000;
}
new Vue({
el: '#app',
delimiters: ['@#', '#@'],
@@ -208,19 +205,36 @@
parseMonitorInfo(monitorInfo) {
let tSeries = [];
let tLegendData = [];
var lcolors = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
for (let i = 0; i < monitorInfo.result.length; i++) {
var lcolor = lcolors[i % lcolors.length];
var rgbaColorMarker = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.5)';
var rgbaColorBar = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.35)';
let loss = 0;
let data = [];
let datal = [];
for (let j = 0; j < monitorInfo.result[i].created_at.length; j++) {
avgDelay = Math.round(monitorInfo.result[i].avg_delay[j]);
if (avgDelay > 0.9 * MaxTCPPingValue) {
loss += 1
}
if (avgDelay > 0) {
if (avgDelay > 0 && avgDelay < MaxTCPPingValue) {
data.push([monitorInfo.result[i].created_at[j], avgDelay]);
}
else {
loss += 1;
datal.push({
xAxis: monitorInfo.result[i].created_at[j],
label: { show: false },
emphasis: { disabled: true },
lineStyle: {
type: "solid",
color: rgbaColorBar
}
});
}
}
lossRate = ((loss / monitorInfo.result[i].created_at.length) * 100).toFixed(1);
if (lossRate > 99) {
datal = [];
}
legendName = monitorInfo.result[i].monitor_name +" "+ lossRate + "%";
tLegendData.push(legendName);
tSeries.push({
@@ -229,10 +243,15 @@
smooth: true,
symbol: 'none',
data: data,
markLine: {
symbol: "none",
symbolSize :0,
data: datal
},
markPoint: {
data: [
{ type: 'max', symbol: 'pin', name: 'Max', itemStyle: { color: '#f00' } },
{ type: 'min', symbol: 'pin', name: 'Min', itemStyle: { color: '#0f0' } }
data: [
{ type: 'max', symbol: 'pin', name: 'Max', itemStyle: { color: rgbaColorMarker }, symbolSize: 30, label: { fontSize: 8 } },
{ type: 'min', symbol: 'pin', name: 'Min', itemStyle: { color: rgbaColorMarker }, symbolSize: 30, label: { fontSize: 8, offset: [0, 7.5] }, symbolRotate: 180 }
]
}
});
@@ -5,6 +5,9 @@
</p>
</footer>
<aside class="toolbox">
<span v-if="page=='index' && countryMapChartData.length!=0" class="showMapChart">
<i @click="showMapChart" data-toggle="modal" data-target="#mapChartBox" class="bi bi-geo-alt"></i>
</span>
<span class="toggleView">
<i v-if="showGroup" @click="toggleView" class="show-nogroup bi bi-justify"></i>
<i v-else @click="toggleView" class="show-group bi bi-view-stacked"></i>
@@ -39,6 +39,11 @@
<i class="check icon" v-if="preferredTemplate === item.key"></i>
</a>
</li>
<li v-if="defaultTemplate === 'custom'">
<a @click="toggleTemplate('custom')" class="item">
<i class="expand icon" style="font-size:1em"></i>Custom
</a>
</li>
</ul>
</li>
{{ end }}
+23 -15
View File
@@ -6,16 +6,22 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/theme-server-status/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="/static/theme-server-status/css/main.css?v20240225">
<link rel="stylesheet" href="/static/theme-server-status/css/dark.css">
<link rel="stylesheet" href="/static/theme-server-status/css/light.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/assets/font-logos.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/lipis/[email protected]/css/flag-icons.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.css">
<link rel="shortcut icon" type="image/png" href="/static/logo.svg" />
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="/static/theme-server-status/css/main.css?v20240616">
<link rel="stylesheet" href="/static/theme-server-status/css/dark.css?v20240407">
<link rel="stylesheet" href="/static/theme-server-status/css/light.css?v20240407">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/assets/font-logos.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/css/flag-icons.min.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/semantic.min.css">
<script src="https://unpkg.com/[email protected]/dist/jquery.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/echarts.min.js"></script>
<script src="https://unpkg.com/[email protected]/map/js/world.js"></script>
<script src="/static/theme-server-status/js/mixin.js?v20240630"></script>
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="/static/theme-server-status/js/html5shiv.js"></script>
@@ -24,11 +30,13 @@
{{if ts .CustomCode}}
{{.CustomCode|safe}}
{{end}}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
<script src="/static/theme-server-status/js/mixin.js?v20240302"></script>
</head>
<body>
{{end}}
{{end}}
+29 -8
View File
@@ -27,10 +27,10 @@
</td>
<td class="node-cell name center">@#node.name#@</td>
<td class="node-cell os center">
<i v-if='node.os == "darwin"' class="apple icon"></i>
<i v-else-if='isWindowsPlatform(node.host.Platform)' class="windows icon"></i>
<i v-if='isWindowsPlatform(node.host.Platform)' class="windows icon"></i>
<i v-else-if='getFontLogoClass(node.host.Platform) == "" && node.stateuptime > 0' class="fl-tux"></i>
<i v-else :class="'fl-' + getFontLogoClass(node.host.Platform)"></i>
<span class="node-cell-os-text">@#node.os#@</span>
<span class="node-cell-os-text">@#getPlatformName(node.os)#@</span>
</td>
<td style="text-align: center;" class="node-cell location">
<i :class="'fi fi-' + node.location"></i>
@@ -71,20 +71,28 @@
</span>
<span class="node-cell-expand" v-if="node.host.CPU">
<span class="node-cell-expand-label">CPU:</span>
@#node.host.CPU.join(",")#@
@#node.host.CPU.join(",")#@ (@#node.cpu.percent#@%)
</span>
<span class="node-cell-expand" v-if="node.host.GPU">
<span class="node-cell-expand-label">GPU:</span>
@#node.host.GPU.join(",")#@
(@#parseInt(node.state.GPU >=0 ? node.state.GPU : 0)#@%)
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "DiskUsed"}}:</span>
@#formatByteSize(node.state.DiskUsed)#@ / @#formatByteSize(node.host.DiskTotal)#@
@#formatByteSize(node.state.DiskUsed)#@ / @#formatByteSize(node.host.DiskTotal)#@ (@#node.hdd.percent#@%)
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "MemUsed"}}:</span>
@#formatByteSize(node.state.MemUsed)#@ / @#formatByteSize(node.host.MemTotal)#@(@#toFixed2(node.state.MemUsed / node.host.MemTotal * 100)#@%)
@#formatByteSize(node.state.MemUsed)#@ / @#formatByteSize(node.host.MemTotal)#@ (@#node.memory.percent#@%)
</span>
<span class="node-cell-expand">
<span v-if="node.host.SwapTotal > 0" class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "SwapUsed"}}:</span>
@#formatByteSize(node.state.SwapUsed)#@ / @#formatByteSize(node.host.SwapTotal)#@
<span v-if="node.host.SwapTotal">(@#toFixed2(node.state.SwapUsed / node.host.SwapTotal * 100)#@%)</span>
<span>(@#toFixed2(node.state.SwapUsed / node.host.SwapTotal * 100)#@%)</span>
</span>
<span v-else class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "SwapUsed"}}: OFF</span>
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span>
@@ -117,6 +125,19 @@
<span class="node-cell-expand-label">{{tr "Uptime"}}:</span>
@#node.uptime#@
</span>
<span v-if="node.state.Temperatures && getTemperature(node.state.Temperatures, sensorList) > 0" @click="toggleDetailedTemp(node.ID)" class="node-cell-expand temp-detail" :id="`temp-${node.ID}`" temp-detail-show="0">
<span class="node-cell-expand-label">{{tr "Temperature"}}:</span>
<span :id="`temp-main-${node.ID}`" class="node-cell-expand-label">
@#getTemperature(node.state.Temperatures, sensorList)#@°C
<i class="bi bi-chevron-double-down"></i>
</span>
<span :id="`temp-detail-${node.ID}`" class="node-cell-expand-label" style="display:none">
<span v-for="temp in node.state.Temperatures" :key="temp.Name" v-if="temp.Temperature !== 0">
[ @#temp.Name#@ : @#temp.Temperature#@°C ]
</span>
<i class="bi bi-chevron-double-up"></i>
</span>
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "Version"}}:</span>
@#node.host.Version#@
+29 -8
View File
@@ -30,10 +30,10 @@
</td>
<td class="node-cell name center">@#node.name#@</td>
<td class="node-cell os center">
<i v-if='node.os == "darwin"' class="apple icon"></i>
<i v-else-if='isWindowsPlatform(node.host.Platform)' class="windows icon"></i>
<i v-if='isWindowsPlatform(node.host.Platform)' class="windows icon"></i>
<i v-else-if='getFontLogoClass(node.host.Platform) == "" && node.stateuptime > 0' class="fl-tux"></i>
<i v-else :class="'fl-' + getFontLogoClass(node.host.Platform)"></i>
<span class="node-cell-os-text">@#node.os#@</span>
<span class="node-cell-os-text">@#getPlatformName(node.os)#@</span>
</td>
<td style="text-align: center;" class="node-cell location">
<i :class="'fi fi-' + node.location"></i>
@@ -74,20 +74,28 @@
</span>
<span class="node-cell-expand" v-if="node.host.CPU">
<span class="node-cell-expand-label">CPU:</span>
@#node.host.CPU.join(",")#@
@#node.host.CPU.join(",")#@ (@#node.cpu.percent#@%)
</span>
<span class="node-cell-expand" v-if="node.host.GPU">
<span class="node-cell-expand-label">GPU:</span>
@#node.host.GPU.join(",")#@
(@#parseInt(node.state.GPU >=0 ? node.state.GPU : 0)#@%)
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "DiskUsed"}}:</span>
@#formatByteSize(node.state.DiskUsed)#@ / @#formatByteSize(node.host.DiskTotal)#@
@#formatByteSize(node.state.DiskUsed)#@ / @#formatByteSize(node.host.DiskTotal)#@ (@#node.hdd.percent#@%)
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "MemUsed"}}:</span>
@#formatByteSize(node.state.MemUsed)#@ / @#formatByteSize(node.host.MemTotal)#@(@#toFixed2(node.state.MemUsed / node.host.MemTotal * 100)#@%)
@#formatByteSize(node.state.MemUsed)#@ / @#formatByteSize(node.host.MemTotal)#@ (@#node.memory.percent#@%)
</span>
<span class="node-cell-expand">
<span v-if="node.host.SwapTotal > 0" class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "SwapUsed"}}:</span>
@#formatByteSize(node.state.SwapUsed)#@ / @#formatByteSize(node.host.SwapTotal)#@
<span v-if="node.host.SwapTotal">(@#toFixed2(node.state.SwapUsed / node.host.SwapTotal * 100)#@%)</span>
<span>(@#toFixed2(node.state.SwapUsed / node.host.SwapTotal * 100)#@%)</span>
</span>
<span v-else class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "SwapUsed"}}: OFF</span>
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span>
@@ -120,6 +128,19 @@
<span class="node-cell-expand-label">{{tr "Uptime"}}:</span>
@#node.uptime#@
</span>
<span v-if="node.state.Temperatures && getTemperature(node.state.Temperatures, sensorList) > 0" @click="toggleDetailedTemp(node.ID)" class="node-cell-expand temp-detail" :id="`temp-${node.ID}`" temp-detail-show="0">
<span class="node-cell-expand-label">{{tr "Temperature"}}:</span>
<span :id="`temp-main-${node.ID}`" class="node-cell-expand-label">
@#getTemperature(node.state.Temperatures, sensorList)#@°C
<i class="bi bi-chevron-double-down"></i>
</span>
<span :id="`temp-detail-${node.ID}`" class="node-cell-expand-label" style="display:none">
<span v-for="temp in node.state.Temperatures" :key="temp.Name" v-if="temp.Temperature !== 0">
[ @#temp.Name#@ : @#temp.Temperature#@°C ]
</span>
<i class="bi bi-chevron-double-up"></i>
</span>
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "Version"}}:</span>
@#node.host.Version#@
File diff suppressed because one or more lines are too long
+28 -9
View File
@@ -22,9 +22,6 @@
const monitorInfo = JSON.parse('{{.MonitorInfos}}');
const initData = JSON.parse('{{.Servers}}').servers;
let MaxTCPPingValue = {{.Conf.MaxTCPPingValue}};
if (MaxTCPPingValue == null) {
MaxTCPPingValue = 1000;
}
new Vue({
el: '#app',
delimiters: ['@#', '#@'],
@@ -171,19 +168,36 @@
parseMonitorInfo(monitorInfo) {
let tSeries = [];
let tLegendData = [];
var lcolors = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
for (let i = 0; i < monitorInfo.result.length; i++) {
var lcolor = lcolors[i % lcolors.length];
var rgbaColorMarker = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.5)';
var rgbaColorBar = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.35)';
let loss = 0;
let data = [];
let datal = [];
for (let j = 0; j < monitorInfo.result[i].created_at.length; j++) {
avgDelay = Math.round(monitorInfo.result[i].avg_delay[j]);
if (avgDelay > 0.9 * MaxTCPPingValue) {
loss += 1
}
if (avgDelay > 0) {
if (avgDelay > 0 && avgDelay < MaxTCPPingValue) {
data.push([monitorInfo.result[i].created_at[j], avgDelay]);
}
else {
loss += 1;
datal.push({
xAxis: monitorInfo.result[i].created_at[j],
label: { show: false },
emphasis: { disabled: true },
lineStyle: {
type: "solid",
color: rgbaColorBar
}
});
}
}
lossRate = ((loss / monitorInfo.result[i].created_at.length) * 100).toFixed(1);
if (lossRate > 99) {
datal = [];
}
legendName = monitorInfo.result[i].monitor_name +" "+ lossRate + "%";
tLegendData.push(legendName);
tSeries.push({
@@ -192,10 +206,15 @@
smooth: true,
symbol: 'none',
data: data,
markLine: {
symbol: "none",
symbolSize :0,
data: datal
},
markPoint: {
data: [
{ type: 'max', symbol: 'pin', name: 'Max', itemStyle: { color: '#f00' } },
{ type: 'min', symbol: 'pin', name: 'Min', itemStyle: { color: '#0f0' } }
{ type: 'max', symbol: 'pin', name: 'Max', itemStyle: { color: rgbaColorMarker }, symbolSize: 30, label: { fontSize: 8 } },
{ type: 'min', symbol: 'pin', name: 'Min', itemStyle: { color: rgbaColorMarker }, symbolSize: 30, label: { fontSize: 8, offset: [0, 7.5] }, symbolRotate: 180 }
]
}
});
+118 -99
View File
@@ -4,74 +4,74 @@
{{template "theme-server-status/content-nav" .}}
<!-- showGroup true -->
<template v-if="showGroup">
<section class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;" v-for="group in servicesTag">
<section v-if="servicesTag.length === 0" class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;">
<p>No Valid Service Monitor Configuration Entries Found. Please Verify in the <a href="/monitor">Admin Panel</a>.</p>
</section>
<section v-else class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;" v-for="group in servicesTag">
{{template "theme-server-status/service-group-true" .}}
</section>
</template>
<!-- showGroup false -->
<template v-else>
<section class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;">
<section v-if="servicesNoTag.length === 0" class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;">
<p>No Valid Service Monitor Configuration Entries Found. Please Verify in the <a href="/monitor">Admin Panel</a>.</p>
</section>
<section v-else class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;">
{{template "theme-server-status/service-group-false" .}}
</section>
</template>
<section class="container content table-responsive" style="max-width: 95vw">
{{if .CycleTransferStats}}
<table class="table table-striped table-condensed table-hover">
<thead>
<tr class="node-group-tag">
<th colspan="16" style="border:none;">
{{tr "CycleTransferStats"}}
</th>
</tr>
<tr class="node-group-cell">
<th class="node-cell center">ID</th>
<th class="node-cell center">{{tr "Rules"}}</th>
<th class="node-cell center">{{tr "Server"}}</th>
<th class="node-cell center">{{tr "From"}}</th>
<th class="node-cell center">{{tr "To"}}</th>
<th class="node-cell center">MAX</th>
<th class="node-cell center">MIN</th>
<th class="node-cell center">{{tr "NextCheck"}}</th>
<th class="node-cell center">{{tr "CurrentUsage"}}</th>
<th class="node-cell center">{{tr "Transleft"}}</th>
</tr>
</thead>
<tbody>
{{range $id, $stats := .CycleTransferStats}}
{{range $innerId, $transfer := $stats.Transfer}}
{{$TransLeftPercent := TransLeftPercent (UintToFloat $transfer) (UintToFloat $stats.Max)}}
<tr>
<td class="node-cell center">{{$id}}</td>
<td class="node-cell center">{{$stats.Name}}</td>
<td class="node-cell center">{{index $stats.ServerName $innerId}}</td>
<td class="node-cell center">{{$stats.From|tf}}</td>
<td class="node-cell center">{{$stats.To|tf}}</td>
<td class="node-cell center">{{$stats.Max|bf}}</td>
<td class="node-cell center">{{$stats.Min|bf}}</td>
<td class="node-cell center">{{(index $stats.NextUpdate $innerId)|sft}}</td>
<td class="node-cell center">{{$transfer|bf}}</td>
<td class="node-cell center">
<div class="progress">
<div style="width: {{$TransLeftPercent}}%" :class="'progress-bar progress-bar-' + toSSBar('{{TransClassName $TransLeftPercent}}')">
<small style="display: inline-block;width: max-content;">{{TransLeft $stats.Max $transfer}} / {{$TransLeftPercent}} %</small>
</div>
</div>
</td>
</tr>
{{end}}
{{end}}
</tbody>
</table>
{{end}}
</section>
{{if .CycleTransferStats}}
<section class="container content table-responsive" style="max-width: 95vw">
<table class="table table-striped table-condensed table-hover">
<thead>
<tr class="node-group-tag">
<th colspan="16" style="border:none;">
{{tr "CycleTransferStats"}}
</th>
</tr>
<tr class="node-group-cell">
<th class="node-cell center">ID</th>
<th class="node-cell center">{{tr "Rules"}}</th>
<th class="node-cell center">{{tr "Server"}}</th>
<th class="node-cell center">{{tr "From"}}</th>
<th class="node-cell center">{{tr "To"}}</th>
<th class="node-cell center">MAX</th>
<th class="node-cell center">MIN</th>
<th class="node-cell center">{{tr "NextCheck"}}</th>
<th class="node-cell center">{{tr "CurrentUsage"}}</th>
<th class="node-cell center">{{tr "Transleft"}}</th>
</tr>
</thead>
<tbody>
{{range $id, $stats := .CycleTransferStats}}
{{range $innerId, $transfer := $stats.Transfer}}
{{$TransLeftPercent := TransLeftPercent (UintToFloat $transfer) (UintToFloat $stats.Max)}}
<tr>
<td class="node-cell center">{{$id}}</td>
<td class="node-cell center">{{$stats.Name}}</td>
<td class="node-cell center">{{index $stats.ServerName $innerId}}</td>
<td class="node-cell center">{{$stats.From|tf}}</td>
<td class="node-cell center">{{$stats.To|tf}}</td>
<td class="node-cell center">{{$stats.Max|bf}}</td>
<td class="node-cell center">{{$stats.Min|bf}}</td>
<td class="node-cell center">{{(index $stats.NextUpdate $innerId)|sft}}</td>
<td class="node-cell center">{{$transfer|bf}}</td>
<td class="node-cell center">
<div class="progress">
<div style="width: {{$TransLeftPercent}}%" :class="'progress-bar progress-bar-' + toSSBar('{{TransClassName $TransLeftPercent}}')">
<small style="display: inline-block;width: max-content;">{{TransLeft $stats.Max $transfer}} / {{$TransLeftPercent}} %</small>
</div>
</div>
</td>
</tr>
{{end}}
{{end}}
</tbody>
</table>
</section>
{{end}}
{{template "theme-server-status/content-footer" .}}
</div>
<script>
// 初始化 Tooltip
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});
</script>
<script>
new Vue({
el: '#app',
@@ -80,13 +80,16 @@
page: 'service',
defaultTemplate: {{.Conf.Site.Theme}},
templates: {{.Themes}},
services: {{.Services}},
servicesTag: [],
servicesNoTag: [],
servicesNoTag: []
},
created() {
this.initData();
this.servicesTag = this.groupingData(this.initData(this.services),"type");
this.servicesNoTag = this.initData(this.services);
},
mounted() {
this.initTooltip();
},
mixins: [mixinsVue],
methods: {
@@ -103,32 +106,36 @@
}
return n
},
initData() {
// @formatter:off
const services = []
{{range $service := .Services}}
services.push({
type: '{{$service.Monitor.Type}}',
name: '{{$service.Monitor.Name}}',
currentUp: parseInt('{{$service.CurrentUp}}'),
currentDown: parseInt('{{$service.CurrentDown}}'),
totalUp: parseInt('{{$service.TotalUp}}'),
totalDown: parseInt('{{$service.TotalDown}}'),
delay: '{{$service.Delay}}'.replaceAll("[","").replaceAll("]","").split(" "),
up: '{{$service.Up}}'.replaceAll("[","").replaceAll("]","").split(" "),
down: '{{$service.Down}}'.replaceAll("[","").replaceAll("]","").split(" "),
})
{{end}}
// @formatter:on
for (let i = 0; i < services.length; i++) {
const service = services[i];
service.avgDelay = parseInt(service.delay[service.delay.length - 1]) + "ms"
service.health = this.getStateInfo(this.getPercent(service.currentUp, service.currentDown))
service.dayDetail = this.getDayTails(service)
service.totalUpTime = this.getProgressInfo(this.getPercent(service.totalUp, service.totalDown))
initData(services) {
let nodes = [];
for (let key in services) {
const service = services[key];
let node = {
type: service.Monitor.Type,
name: service.Monitor.Name,
currentUp: parseInt(service.CurrentUp),
currentDown: parseInt(service.CurrentDown),
totalUp: parseInt(service.TotalUp),
totalDown: parseInt(service.TotalDown),
up: service.Up,
down: service.Down,
delay: service.Delay,
avgDelay: parseInt(this.getAvgDelay(service.Delay)) + "ms",
health: this.getStateInfo(this.getPercent(service.CurrentUp, service.CurrentDown)),
totalUpTime: this.getProgressInfo(this.getPercent(service.TotalUp, service.TotalDown))
};
nodes.push(node);
};
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
node.dayDetail = this.getDayTails(node)
}
this.servicesTag = this.groupingData(services,"type");
this.servicesNoTag = services;
return nodes
},
initTooltip() {
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});
},
getPercent(up, down) {
if (!up) {
@@ -151,24 +158,24 @@
return this.toFixed2(currentUp / total * 100)
},
getDayTails(service) {
const result = []
const result = [];
for (let i = 0; i < service.up.length; i++) {
const up = service.up[i]
const down = service.down[i]
const delay = service.delay[i]
let percent = this.getPercent(up, down)
const up = service.up[i];
const down = service.down[i];
let delay = Number(service.delay[i]);
let percent = this.getPercent(up, down);
if (percent <= 0) {
percent = 0;
}
let className = this.getStateInfo(percent).className
let available = '{{tr "Availability"}}'
let averageLatency = '{{tr "AverageLatency"}}'
const text = `${this.beforeDay(service.up.length - i - 1)}${available}${percent}%${averageLatency}${delay}ms`
let className = this.getStateInfo(percent).className;
let available = '{{tr "Availability"}}';
let averageLatency = '{{tr "AverageLatency"}}';
const text = `${this.beforeDay(service.up.length - i - 1)}${available}${Number(percent).toFixed(3)}%${averageLatency}${Number(delay).toFixed(3)}ms`;
result.push({
text, className
})
});
}
return result
return result;
},
beforeDay(days) {
const today = new Date();
@@ -203,12 +210,13 @@
return result;
},
getProgressInfo(percent) {
const result = this.getStateInfo(percent)
const result = this.getStateInfo(percent);
result.style = `width: ${parseInt(percent)}%`;
result.percent = Number(percent).toFixed(2);
const className = result.className;
if (className === "good") {
result.className = 'progress-bar progress-bar-success'
} else if (className === "waining") {
} else if (className === "warning") {
result.className = 'progress-bar progress-bar-warning'
} else if (className === "danger") {
result.className = 'progress-bar progress-bar-danger'
@@ -218,8 +226,19 @@
}
return result
},
getAvgDelay(array) {
const { sum, count } = array.reduce((acc, value) => {
if (value !== 0) {
acc.sum += value;
acc.count += 1;
}
return acc;
}, { sum: 0, count: 0 });
return count > 0 ? sum / count : 0;
}
}
})
</script>
{{template "theme-server-status/footer" .}}
{{end}}
{{end}}
+10 -1
View File
@@ -14,7 +14,7 @@ site:
theme: "default"
ddns:
enable: false
provider: "webhook"
provider: "webhook" # 如需使用多配置功能,请把此项留空
accessid: ""
accesssecret: ""
webhookmethod: ""
@@ -22,3 +22,12 @@ ddns:
webhookrequestbody: ""
webhookheaders: ""
maxretries: 3
profiles:
example:
provider: ""
accessid: ""
accesssecret: ""
webhookmethod: ""
webhookurl: ""
webhookrequestbody: ""
webhookheaders: ""
+291
View File
@@ -0,0 +1,291 @@
#!/bin/bash
#========================================================
# System Required: macOS 10.13+
# Description: Nezha Agent Install Script (macOS)
# Github: https://github.com/naiba/nezha
#========================================================
NZ_BASE_PATH="/opt/nezha"
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
red='\033[0;31m'
green='\033[0;32m'
yellow='\033[0;33m'
plain='\033[0m'
export PATH=$PATH:/usr/local/bin
pre_check() {
# check root
[[ $EUID -ne 0 ]] && echo -e "${red}ERROR: ${plain} This script must be run with the root user!\n" && exit 1
## os_arch
if [[ $(uname -m | grep 'x86_64') != "" ]]; then
os_arch="amd64"
elif [[ $(uname -m | grep 'arm64\|arm64e') != "" ]]; then
os_arch="arm64"
fi
## China_IP
if [[ -z "${CN}" ]]; then
if [[ $(curl -m 10 -s https://ipapi.co/json | grep 'China') != "" ]]; then
echo "According to the information provided by ipapi.co, the current IP may be in China"
read -e -r -p "Is the installation done with a Chinese Mirror? [Y/n] (Custom Mirror Input 3):" input
case $input in
[yY][eE][sS] | [yY])
echo "Use Chinese Mirror"
CN=true
;;
[nN][oO] | [nN])
echo "No Use Chinese Mirror"
;;
[3])
echo "Use Custom Mirror"
read -e -r -p "Please enter a custom image (e.g. :dn-dao-github-mirror.daocloud.io), leave blank to nouse: " input
case $input in
*)
CUSTOM_MIRROR=$input
;;
esac
;;
*)
echo "No Use Chinese Mirror"
;;
esac
fi
fi
if [[ -n "${CUSTOM_MIRROR}" ]]; then
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
GITHUB_URL=$CUSTOM_MIRROR
else
if [[ -z "${CN}" ]]; then
GITHUB_RAW_URL="raw.githubusercontent.com/naiba/nezha/master"
GITHUB_URL="github.com"
Get_Docker_URL="get.docker.com"
Get_Docker_Argu=" "
Docker_IMG="ghcr.io\/naiba\/nezha-dashboard"
else
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
GITHUB_URL="github.com"
Get_Docker_URL="get.docker.com"
Get_Docker_Argu=" -s docker --mirror Aliyun"
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
fi
fi
}
before_show_menu() {
echo && echo -n -e "${yellow}* Press Enter to return to the main menu *${plain}" && read temp
show_menu
}
install_agent() {
echo -e "> Install Nezha Agent"
echo -e "Obtaining Agent version"
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://fastly.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
fi
if [ ! -n "$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')
fi
if [ ! -n "$version" ]; then
echo -e "Fail to obtaine agent version, please check if the network can link https://api.github.com/repos/nezhahq/agent/releases/latest"
return 0
else
echo -e "The current latest version is: ${version}"
fi
# Nezha Agent Folder
mkdir -p $NZ_AGENT_PATH
chmod -R 777 $NZ_AGENT_PATH
echo -e "Downloading Agent"
curl -o nezha-agent_darwin_${os_arch}.zip -L -f --retry 2 --retry-max-time 60 https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_darwin_${os_arch}.zip >/dev/null 2>&1
if [[ $? != 0 ]]; then
echo -e "${red}Fail to download agent, please check if the network can link ${GITHUB_URL}${plain}"
return 0
fi
unzip -qo nezha-agent_darwin_${os_arch}.zip &&
mv nezha-agent $NZ_AGENT_PATH &&
rm -rf nezha-agent_darwin_${os_arch}.zip README.md
if [ $# -ge 3 ]; then
modify_agent_config "$@"
else
modify_agent_config 0
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
modify_agent_config() {
echo -e "> Modify Agent Configuration"
if [ $# -lt 3 ]; then
echo "Please add Agent in the admin panel first, record the secret" &&
read -ep "Please enter a domain that resolves to the IP where the panel is located (no CDN sets): " nz_grpc_host &&
read -ep "Please enter the panel RPC port (default 5555): " nz_grpc_port &&
read -ep "Please enter the Agent secret: " nz_client_secret &&
read -ep "Do you want to enable SSL/TLS encryption for the gRPC port (--tls)? Press [y] if yes, the default is not required, and users can press Enter to skip if you don't understand: " nz_grpc_proxy
grep -qiw 'Y' <<<"${nz_grpc_proxy}" && args='--tls'
if [[ -z "${nz_grpc_host}" || -z "${nz_client_secret}" ]]; then
echo -e "${red}All options cannot be empty${plain}"
before_show_menu
return 1
fi
if [[ -z "${nz_grpc_port}" ]]; then
nz_grpc_port=5555
fi
else
nz_grpc_host=$1
nz_grpc_port=$2
nz_client_secret=$3
shift 3
if [ $# -gt 0 ]; then
args=" $*"
fi
fi
${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
${NZ_AGENT_PATH}/nezha-agent service uninstall >/dev/null 2>&1
${NZ_AGENT_PATH}/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p $nz_client_secret $args >/dev/null 2>&1
fi
echo -e "Agent configuration ${green} modified successfully, please wait for agent self-restart to take effect${plain}"
#if [[ $# == 0 ]]; then
# before_show_menu
#fi
}
show_agent_log() {
echo -e "> > View Agent Log"
tail -n 10 /var/log/nezha-agent.err.log
if [[ $# == 0 ]]; then
before_show_menu
fi
}
uninstall_agent() {
echo -e "> Uninstall Agent"
${NZ_AGENT_PATH}/nezha-agent service uninstall
rm -rf $NZ_AGENT_PATH
clean_all
if [[ $# == 0 ]]; then
before_show_menu
fi
}
restart_agent() {
echo -e "> Restart Agent"
${NZ_AGENT_PATH}/nezha-agent service restart
if [[ $# == 0 ]]; then
before_show_menu
fi
}
clean_all() {
if [ -z "$(ls -A ${NZ_BASE_PATH})" ]; then
rm -rf ${NZ_BASE_PATH}
fi
}
show_usage() {
echo "Nezha Agent Management Script Usage: "
echo "--------------------------------------------------------"
echo "./nezha.sh install_agent - Install Agent"
echo "./nezha.sh modify_agent_config - Modify Agent Configuration"
echo "./nezha.sh show_agent_log - View Agent Log"
echo "./nezha.sh uninstall_agent - Uninstall Agent"
echo "./nezha.sh restart_agent - Restart Agent"
echo "./nezha.sh update_script - Update Script"
echo "--------------------------------------------------------"
}
show_menu() {
echo -e "
${green}Nezha Agent Management Script${plain} ${red}macOS${plain}
--- https://github.com/naiba/nezha ---
${green}1.${plain} Install Agent
${green}2.${plain} Modify Agent Configuration
${green}3.${plain} View Agent Log
${green}4.${plain} Uninstall Agent
${green}5.${plain} Restart Agent
————————————————-
${green}0.${plain} Exit Script
"
echo && read -ep "Please enter [0-5]: " num
case "${num}" in
0)
exit 0
;;
1)
install_agent
;;
2)
modify_agent_config
;;
3)
show_agent_log
;;
4)
uninstall_agent
;;
5)
restart_agent
;;
*)
echo -e "${red}Please enter the correct number [0-5]${plain}"
;;
esac
}
pre_check
if [[ $# > 0 ]]; then
case $1 in
"install_agent")
shift
if [ $# -ge 3 ]; then
install_agent "$@"
else
install_agent 0
fi
;;
"modify_agent_config")
modify_agent_config 0
;;
"show_agent_log")
show_agent_log 0
;;
"uninstall_agent")
uninstall_agent 0
;;
"restart_agent")
restart_agent 0
;;
*) show_usage ;;
esac
else
show_menu
fi
+30 -25
View File
@@ -7,64 +7,69 @@ if($PSVersionTable.PSVersion.Major -lt 5){
exit
}
$agentrepo = "nezhahq/agent"
$nssmrepo = "nezhahq/nssm-backup"
# x86 or x64
# x86 or x64 or arm64
if ([System.Environment]::Is64BitOperatingSystem) {
$file = "nezha-agent_windows_amd64.zip"
if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") {
$file = "nezha-agent_windows_arm64.zip"
} else {
$file = "nezha-agent_windows_amd64.zip"
}
}
else {
$file = "nezha-agent_windows_386.zip"
}
$agentreleases = "https://api.github.com/repos/$agentrepo/releases"
$nssmreleases = "https://api.github.com/repos/$nssmrepo/releases"
#重复运行自动更新
if (Test-Path "C:\nezha") {
if (Test-Path "C:\nezha\nezha-agent.exe") {
Write-Host "Nezha monitoring already exists, delete and reinstall" -BackgroundColor DarkGreen -ForegroundColor White
C:/nezha/nssm.exe stop nezha
C:/nezha/nssm.exe remove nezha
C:\nezha\nezha-agent.exe service uninstall
Remove-Item "C:\nezha" -Recurse
}
#TLS/SSL
Write-Host "Determining latest nezha release" -BackgroundColor DarkGreen -ForegroundColor White
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$agenttag = (Invoke-WebRequest -Uri $agentreleases -UseBasicParsing | ConvertFrom-Json)[0].tag_name
$nssmtag = (Invoke-WebRequest -Uri $nssmreleases -UseBasicParsing | ConvertFrom-Json)[0].tag_name
if ([string]::IsNullOrWhiteSpace($agenttag)) {
$optionUrl = "https://fastly.jsdelivr.net/gh/nezhahq/agent/"
Try {
$response = Invoke-WebRequest -Uri $optionUrl -UseBasicParsing -TimeoutSec 10
if ($response.StatusCode -eq 200) {
$versiontext = $response.Content | findstr /c:"option.value"
$version = [regex]::Match($versiontext, "@(\d+\.\d+\.\d+)").Groups[1].Value
$agenttag = "v" + $version
}
} Catch {
$optionUrl = "https://gcore.jsdelivr.net/gh/nezhahq/agent/"
$response = Invoke-WebRequest -Uri $optionUrl -UseBasicParsing -TimeoutSec 10
if ($response.StatusCode -eq 200) {
$versiontext = $response.Content | findstr /c:"option.value"
$version = [regex]::Match($versiontext, "@(\d+\.\d+\.\d+)").Groups[1].Value
$agenttag = "v" + $version
}
}
}
#Region判断
$ipapi= Invoke-RestMethod -Uri "https://api.myip.com/" -UserAgent "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1"
$region=$ipapi.cc
echo $ipapi
if($region -ne "CN"){
$download = "https://github.com/$agentrepo/releases/download/$agenttag/$file"
$nssmdownload="https://github.com/$nssmrepo/releases/download/$nssmtag/nssm.zip"
Write-Host "Location:$region,connect directly!" -BackgroundColor DarkRed -ForegroundColor Green
}else{
$download = "https://dn-dao-github-mirror.daocloud.io/$agentrepo/releases/download/$agenttag/$file"
$nssmdownload="https://dn-dao-github-mirror.daocloud.io/$nssmrepo/releases/download/$nssmtag/nssm.zip"
$download = "https://github.com/$agentrepo/releases/download/$agenttag/$file"
Write-Host "Location:CN,use mirror address" -BackgroundColor DarkRed -ForegroundColor Green
}
echo $download
echo $nssmdownload
Invoke-WebRequest $download -OutFile "C:\nezha.zip"
#使用nssm安装服务
Invoke-WebRequest $nssmdownload -OutFile "C:\nssm.zip"
#解压
Expand-Archive "C:\nezha.zip" -DestinationPath "C:\temp" -Force
Expand-Archive "C:\nssm.zip" -DestinationPath "C:\temp" -Force
if (!(Test-Path "C:\nezha")) { New-Item -Path "C:\nezha" -type directory }
#整理文件
Move-Item -Path "C:\temp\nezha-agent.exe" -Destination "C:\nezha\nezha-agent.exe"
if ($file = "nezha-agent_windows_amd64.zip") {
Move-Item -Path "C:\temp\nssm-2.24\win64\nssm.exe" -Destination "C:\nezha\nssm.exe"
}
else {
Move-Item -Path "C:\temp\nssm-2.24\win32\nssm.exe" -Destination "C:\nezha\nssm.exe"
}
#清理垃圾
Remove-Item "C:\nezha.zip"
Remove-Item "C:\nssm.zip"
Remove-Item "C:\temp" -Recurse
#安装部分
C:\nezha\nssm.exe install nezha C:\nezha\nezha-agent.exe -s $server -p $key $tls -d
C:\nezha\nssm.exe start nezha
C:\nezha\nezha-agent.exe service install -s $server -p $key $tls
#enjoy
Write-Host "Enjoy It!" -BackgroundColor DarkGreen -ForegroundColor Red
Write-Host "Enjoy It!" -BackgroundColor DarkGreen -ForegroundColor Red
+385 -637
View File
File diff suppressed because it is too large Load Diff
+365 -613
View File
File diff suppressed because it is too large Load Diff
-62
View File
@@ -1,62 +0,0 @@
#!/sbin/openrc-run
supervisor=supervise-daemon
name=nezha-agent
supervise_daemon_args="--stdout /var/log/${name}.log --stderr /var/log/${name}.err"
SERVER="nz_grpc_host:nz_grpc_port" #Dashboard 地址 ip:port
SECRET="nz_client_secret" #SECRET
NZ_BASE_PATH="/opt/nezha"
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
pidfile="/run/${RC_SVCNAME}.pid"
command="/opt/nezha/agent/nezha-agent"
command_args="-s ${SERVER} -p ${SECRET}"
command_background=true
depend() {
need net
}
checkconfig() {
GITHUB_URL="github.com"
if [ ! -f "${NZ_AGENT_PATH}/nezha-agent" ]; then
if [[ $(uname -m | grep 'x86_64') != "" ]]; then
os_arch="amd64"
elif [[ $(uname -m | grep 'i386\|i686') != "" ]]; then
os_arch="386"
elif [[ $(uname -m | grep 'aarch64\|armv8b\|armv8l') != "" ]]; then
os_arch="arm64"
elif [[ $(uname -m | grep 'arm') != "" ]]; then
os_arch="arm"
elif [[ $(uname -m | grep 's390x') != "" ]]; then
os_arch="s390x"
elif [[ $(uname -m | grep 'riscv64') != "" ]]; then
os_arch="riscv64"
fi
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://fastly.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
fi
if [ ! -n "$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')
fi
if [ ! -n "$version" ]; then
echo -e "获取版本号失败,请检查本机能否链接 https://api.github.com/repos/nezhahq/agent/releases/latest"
return 0
else
echo -e "当前最新版本为: ${version}"
fi
wget -t 2 -T 10 -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 [[ $? != 0 ]]; then
echo -e "Release 下载失败,请检查本机能否连接 ${GITHUB_URL}${plain}"
return 0
fi
mkdir -p $NZ_AGENT_PATH
chmod 755 -R $NZ_AGENT_PATH
unzip -qo nezha-agent_linux_${os_arch}.zip && mv nezha-agent $NZ_AGENT_PATH && rm -rf nezha-agent_linux_${os_arch}.zip README.md
fi
if [ ! -x "${NZ_AGENT_PATH}/nezha-agent" ]; then
chmod +x ${NZ_AGENT_PATH}/nezha-agent
fi
}
start_pre() {
if [ "${RC_CMD}" != "restart" ]; then
checkconfig || return $?
fi
}
-30
View File
@@ -1,30 +0,0 @@
[Unit]
Description=Nezha Agent
After=syslog.target
#After=network.target
#After=nezha-dashboard.service
[Service]
# Modify these two values and uncomment them if you have
# repos with lots of files and get an HTTP error 500 because
# of that
###
#LimitMEMLOCK=infinity
#LimitNOFILE=65535
Type=simple
User=root
Group=root
WorkingDirectory=/opt/nezha/agent/
ExecStart=/opt/nezha/agent/nezha-agent -s nz_grpc_host:nz_grpc_port -p nz_client_secret
Restart=always
#Environment=DEBUG=true
# Some distributions may not support these hardening directives. If you cannot start the service due
# to an unknown option, comment out the ones not supported by your version of systemd.
#ProtectSystem=full
#PrivateDevices=yes
#PrivateTmp=yes
#NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
Regular → Executable
+7 -5
View File
@@ -1,4 +1,8 @@
#!/sbin/openrc-run
supervisor=supervise-daemon
name=nezha-dashboard
output_log=/var/log/${name}.log
error_log=/var/log/${name}.err
pidfile="/run/${RC_SVCNAME}.pid"
command="/opt/nezha/dashboard/app"
command_args=""
@@ -6,11 +10,9 @@ command_background=true
directory="/opt/nezha/dashboard"
depend() {
need net
need net
}
reload() {
ebegin "Reloading ${RC_SVCNAME}"
start-stop-daemon --signal HUP --pidfile "${pidfile}"
eend $?
start_pre() {
checkpath -f -m 0644 -o root:root "/var/log/${name}.log"
}
+9 -4
View File
@@ -106,6 +106,7 @@ func (s *NezhaHandler) ReportSystemState(c context.Context, r *pb.State) (*pb.Re
func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Receipt, error) {
var clientID uint64
var provider ddns.Provider
var err error
if clientID, err = s.Auth.Check(c); err != nil {
return nil, err
@@ -122,13 +123,17 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece
singleton.ServerList[clientID].Host.IP != host.IP {
serverDomain := singleton.ServerList[clientID].DDNSDomain
provider, err := singleton.GetDDNSProviderFromString(singleton.Conf.DDNS.Provider)
if singleton.Conf.DDNS.Provider == "" {
provider, err = singleton.GetDDNSProviderFromProfile(singleton.ServerList[clientID].DDNSProfile)
} else {
provider, err = singleton.GetDDNSProviderFromString(singleton.Conf.DDNS.Provider)
}
if err == nil && serverDomain != "" {
ipv4, ipv6, _ := utils.SplitIPAddr(host.IP)
maxRetries := int(singleton.Conf.DDNS.MaxRetries)
config := &ddns.DomainConfig{
EnableIPv4: true,
EnableIpv6: true,
EnableIPv4: singleton.ServerList[clientID].EnableIPv4,
EnableIpv6: singleton.ServerList[clientID].EnableIpv6,
FullDomain: serverDomain,
Ipv4Addr: ipv4,
Ipv6Addr: ipv6,
@@ -137,7 +142,7 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece
} else {
// 虽然会在启动时panic, 可以断言不会走这个分支, 但是考虑到动态加载配置或者其它情况, 这里输出一下方便检查奇奇怪怪的BUG
log.Printf("NEZHA>> 未找到对应的DDNS提供者(%s), 请前往config.yml检查你的设置\n", singleton.Conf.DDNS.Provider)
log.Printf("NEZHA>> 未找到对应的DDNS配置(%s), 或者是provider填写不正确, 请前往config.yml检查你的设置\n", singleton.ServerList[clientID].DDNSProfile)
}
}
+52 -6
View File
@@ -1,10 +1,10 @@
package singleton
import (
"errors"
"fmt"
ddns2 "github.com/naiba/nezha/pkg/ddns"
"log"
ddns2 "github.com/naiba/nezha/pkg/ddns"
)
func RetryableUpdateDomain(provider ddns2.Provider, config *ddns2.DomainConfig, maxRetries int) bool {
@@ -25,18 +25,64 @@ func RetryableUpdateDomain(provider ddns2.Provider, config *ddns2.DomainConfig,
func GetDDNSProviderFromString(provider string) (ddns2.Provider, error) {
switch provider {
case "webhook":
return ddns2.ProviderWebHook{
return &ddns2.ProviderWebHook{
URL: Conf.DDNS.WebhookURL,
RequestMethod: Conf.DDNS.WebhookMethod,
RequestBody: Conf.DDNS.WebhookRequestBody,
RequestHeader: Conf.DDNS.WebhookHeaders,
}, nil
case "dummy":
return ddns2.ProviderDummy{}, nil
return &ddns2.ProviderDummy{}, nil
case "cloudflare":
return ddns2.ProviderCloudflare{
return &ddns2.ProviderCloudflare{
Secret: Conf.DDNS.AccessSecret,
}, nil
case "tencentcloud":
return &ddns2.ProviderTencentCloud{
SecretID: Conf.DDNS.AccessID,
SecretKey: Conf.DDNS.AccessSecret,
}, nil
}
return ddns2.ProviderDummy{}, errors.New(fmt.Sprintf("无法找到配置的DDNS提供者%s", Conf.DDNS.Provider))
return &ddns2.ProviderDummy{}, fmt.Errorf("无法找到配置的DDNS提供者%s", Conf.DDNS.Provider)
}
func GetDDNSProviderFromProfile(profileName string) (ddns2.Provider, error) {
profile, ok := Conf.DDNS.Profiles[profileName]
if !ok {
return &ddns2.ProviderDummy{}, fmt.Errorf("未找到配置项 %s", profileName)
}
switch profile.Provider {
case "webhook":
return &ddns2.ProviderWebHook{
URL: profile.WebhookURL,
RequestMethod: profile.WebhookMethod,
RequestBody: profile.WebhookRequestBody,
RequestHeader: profile.WebhookHeaders,
}, nil
case "dummy":
return &ddns2.ProviderDummy{}, nil
case "cloudflare":
return &ddns2.ProviderCloudflare{
Secret: profile.AccessSecret,
}, nil
case "tencentcloud":
return &ddns2.ProviderTencentCloud{
SecretID: profile.AccessID,
SecretKey: profile.AccessSecret,
}, nil
}
return &ddns2.ProviderDummy{}, fmt.Errorf("无法找到配置的DDNS提供者%s", profile.Provider)
}
func ValidateDDNSProvidersFromProfiles() error {
validProviders := map[string]bool{"webhook": true, "dummy": true, "cloudflare": true, "tencentcloud": true}
providers := make(map[string]string)
for profileName, profile := range Conf.DDNS.Profiles {
if _, ok := validProviders[profile.Provider]; !ok {
return fmt.Errorf("无法找到配置的DDNS提供者%s", profile.Provider)
}
providers[profileName] = profile.Provider
}
return nil
}
+2 -2
View File
@@ -172,7 +172,7 @@ func (ss *ServiceSentinel) Monitors() []*model.Monitor {
return monitors
}
// LoadStats 加载服务监控器的历史状态信息
// loadMonitorHistory 加载服务监控器的历史状态信息
func (ss *ServiceSentinel) loadMonitorHistory() {
var monitors []*model.Monitor
err := DB.Find(&monitors).Error
@@ -335,7 +335,7 @@ func (ss *ServiceSentinel) worker() {
// 从服务状态汇报管道获取汇报的服务数据
for r := range ss.serviceReportChannel {
if ss.monitors[r.Data.GetId()] == nil || ss.monitors[r.Data.GetId()].ID == 0 {
log.Printf("NEZAH>> 错误的服务监控上报 %+v", r)
log.Printf("NEZHA>> 错误的服务监控上报 %+v", r)
continue
}
mh := r.Data
+13 -9
View File
@@ -52,12 +52,16 @@ func InitConfigFromPath(path string) {
// ValidateConfig 验证配置文件有效性
func ValidateConfig() {
// 如果DDNS启用则检查Provider是否存在, 不存在直接退出
var err error
if Conf.DDNS.Provider == "" {
err = ValidateDDNSProvidersFromProfiles()
} else {
_, err = GetDDNSProviderFromString(Conf.DDNS.Provider)
}
if err != nil {
panic(err)
}
if Conf.DDNS.Enable {
_, err := GetDDNSProviderFromString(Conf.DDNS.Provider)
if err != nil {
panic(err)
}
if Conf.DDNS.MaxRetries < 1 || Conf.DDNS.MaxRetries > 10 {
panic(fmt.Errorf("DDNS.MaxRetries值域为[1, 10]的整数, 当前为 %d", Conf.DDNS.MaxRetries))
}
@@ -89,7 +93,7 @@ func RecordTransferHourlyUsage() {
ServerLock.Lock()
defer ServerLock.Unlock()
now := time.Now()
nowTrimSeconds := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, Loc)
nowTrimSeconds := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
var txs []model.Transfer
for id, server := range ServerList {
tx := model.Transfer{
@@ -132,7 +136,7 @@ func CleanMonitorHistory() {
if !rule.IsTransferDurationRule() {
continue
}
dataCouldRemoveBefore := rule.GetTransferDurationStart()
dataCouldRemoveBefore := rule.GetTransferDurationStart().UTC()
// 判断规则影响的机器范围
if rule.Cover == model.RuleCoverAll {
// 更新全局可以清理的数据点
@@ -151,12 +155,12 @@ func CleanMonitorHistory() {
}
}
for id, couldRemove := range specialServerKeep {
DB.Unscoped().Delete(&model.Transfer{}, "server_id = ? AND created_at < ?", id, couldRemove)
DB.Unscoped().Delete(&model.Transfer{}, "server_id = ? AND datetime(`created_at`) < datetime(?)", id, couldRemove)
}
if allServerKeep.IsZero() {
DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?)", specialServerIDs)
} else {
DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?) AND created_at < ?", specialServerIDs, allServerKeep)
DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?) AND datetime(`created_at`) < datetime(?)", specialServerIDs, allServerKeep)
}
}