Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe234f4f38 | ||
|
|
df9487b5fc | ||
|
|
26d81f6d7a | ||
|
|
9d96c58ff9 | ||
|
|
5bb7efdeb9 | ||
|
|
519882c4a9 | ||
|
|
ed96432b79 | ||
|
|
1c057d93bd | ||
|
|
6005004681 | ||
|
|
d8f4236404 | ||
|
|
f95191c8af | ||
|
|
34fedd91d2 | ||
|
|
f675b884f5 | ||
|
|
0b13fec029 | ||
|
|
67b788a969 | ||
|
|
b63f693661 | ||
|
|
ac64aa7355 | ||
|
|
05d69d5c07 | ||
|
|
ce624a0ca6 | ||
|
|
1c91fcffac | ||
|
|
417f972659 | ||
|
|
ada344cd6b | ||
|
|
9d6682fd58 | ||
|
|
22c687c044 | ||
|
|
e1513203b4 | ||
|
|
17373e2dee | ||
|
|
e7c6984c72 | ||
|
|
f4c6f4c57d | ||
|
|
4df60c6955 | ||
|
|
0501e120f6 | ||
|
|
cfa425bb33 | ||
|
|
0613b0022d | ||
|
|
740d15bf79 | ||
|
|
7ace5d04fa | ||
|
|
a38d7bb51d | ||
|
|
61e16f96c5 | ||
|
|
61127b3435 | ||
|
|
8805dffe85 | ||
|
|
aeb7c52565 | ||
|
|
877b4cd666 | ||
|
|
f75847d3d7 | ||
|
|
eee3225f3a | ||
|
|
aa9eb533ad | ||
|
|
cf9bbb5ff4 | ||
|
|
65dee23137 | ||
|
|
feb4659cab | ||
|
|
bc7791efd2 | ||
|
|
6e6ec3256f | ||
|
|
ce66f72cf9 | ||
|
|
0ed7436176 | ||
|
|
2aabe1bd61 | ||
|
|
db5e94d0de | ||
|
|
3eecdc2b3f | ||
|
|
b2740e5f3c | ||
|
|
c3fa4cbbee | ||
|
|
a9da084711 | ||
|
|
f30969e946 | ||
|
|
e0e2b8c3c2 | ||
|
|
3782c0dcaf | ||
|
|
0331db2c12 | ||
|
|
1749247aeb |
@@ -0,0 +1,90 @@
|
|||||||
|
import os
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
import hashlib
|
||||||
|
from github import Github
|
||||||
|
|
||||||
|
|
||||||
|
def get_github_latest_release():
|
||||||
|
g = Github()
|
||||||
|
repo = g.get_repo("naiba/nezha")
|
||||||
|
release = repo.get_latest_release()
|
||||||
|
if release:
|
||||||
|
print(f"Latest release tag is: {release.tag_name}")
|
||||||
|
print(f"Latest release info is: {release.body}")
|
||||||
|
files = []
|
||||||
|
for asset in release.get_assets():
|
||||||
|
url = asset.browser_download_url
|
||||||
|
name = asset.name
|
||||||
|
|
||||||
|
response = requests.get(url)
|
||||||
|
if response.status_code == 200:
|
||||||
|
with open(name, 'wb') as f:
|
||||||
|
f.write(response.content)
|
||||||
|
print(f"Downloaded {name}")
|
||||||
|
else:
|
||||||
|
print(f"Failed to download {name}")
|
||||||
|
file_abs_path = get_abs_path(asset.name)
|
||||||
|
files.append(file_abs_path)
|
||||||
|
sync_to_gitee(release.tag_name, release.body, files)
|
||||||
|
else:
|
||||||
|
print("No releases found.")
|
||||||
|
|
||||||
|
|
||||||
|
def sync_to_gitee(tag: str, body: str, files: slice):
|
||||||
|
release_id = ""
|
||||||
|
owner = "naibahq"
|
||||||
|
repo = "nezha"
|
||||||
|
release_api_uri = f"https://gitee.com/api/v5/repos/{owner}/{repo}/releases"
|
||||||
|
api_client = requests.Session()
|
||||||
|
api_client.headers.update({
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
})
|
||||||
|
|
||||||
|
access_token = os.environ['GITEE_TOKEN']
|
||||||
|
release_data = {
|
||||||
|
'access_token': access_token,
|
||||||
|
'tag_name': tag,
|
||||||
|
'name': tag,
|
||||||
|
'body': body,
|
||||||
|
'prerelease': False,
|
||||||
|
'target_commitish': 'master'
|
||||||
|
}
|
||||||
|
release_api_response = api_client.post(release_api_uri, json=release_data)
|
||||||
|
if release_api_response.status_code == 201:
|
||||||
|
release_info = release_api_response.json()
|
||||||
|
release_id = release_info.get('id')
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"Request failed with status code {release_api_response.status_code}")
|
||||||
|
|
||||||
|
print(f"Gitee release id: {release_id}")
|
||||||
|
asset_api_uri = f"{release_api_uri}/{release_id}/attach_files"
|
||||||
|
|
||||||
|
for file_path in files:
|
||||||
|
files = {
|
||||||
|
'file': open(file_path, 'rb')
|
||||||
|
}
|
||||||
|
|
||||||
|
asset_api_response = requests.post(
|
||||||
|
asset_api_uri, params={'access_token': access_token}, files=files)
|
||||||
|
|
||||||
|
if asset_api_response.status_code == 201:
|
||||||
|
asset_info = asset_api_response.json()
|
||||||
|
asset_name = asset_info.get('name')
|
||||||
|
print(f"Successfully uploaded {asset_name}!")
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"Request failed with status code {asset_api_response.status_code}")
|
||||||
|
|
||||||
|
api_client.close()
|
||||||
|
print("Sync is completed!")
|
||||||
|
|
||||||
|
|
||||||
|
def get_abs_path(path: str):
|
||||||
|
wd = os.getcwd()
|
||||||
|
return os.path.join(wd, path)
|
||||||
|
|
||||||
|
|
||||||
|
get_github_latest_release()
|
||||||
@@ -12,6 +12,13 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Fetch IPInfo GeoIP Database
|
||||||
|
env:
|
||||||
|
IPINFO_TOKEN: ${{ secrets.IPINFO_TOKEN }}
|
||||||
|
run: |
|
||||||
|
rm pkg/geoip/geoip.db
|
||||||
|
wget -O pkg/geoip/geoip.db https://ipinfo.io/data/free/country.mmdb?token=${IPINFO_TOKEN}
|
||||||
|
|
||||||
- name: Extract branch name
|
- name: Extract branch name
|
||||||
run: |
|
run: |
|
||||||
export TAG_NAME=$(echo ${GITHUB_REF#refs/tags/})
|
export TAG_NAME=$(echo ${GITHUB_REF#refs/tags/})
|
||||||
@@ -22,7 +29,7 @@ jobs:
|
|||||||
uses: crazy-max/ghaction-xgo@v2
|
uses: crazy-max/ghaction-xgo@v2
|
||||||
with:
|
with:
|
||||||
xgo_version: latest
|
xgo_version: latest
|
||||||
go_version: 1.20.x
|
go_version: 1.21.x
|
||||||
dest: dist
|
dest: dist
|
||||||
pkg: cmd/dashboard
|
pkg: cmd/dashboard
|
||||||
prefix: dashboard
|
prefix: dashboard
|
||||||
@@ -30,11 +37,13 @@ jobs:
|
|||||||
v: true
|
v: true
|
||||||
x: false
|
x: false
|
||||||
race: false
|
race: false
|
||||||
|
tags: timetzdata
|
||||||
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=${{ steps.extract_branch.outputs.tag }}
|
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=${{ steps.extract_branch.outputs.tag }}
|
||||||
buildmode: default
|
buildmode: default
|
||||||
|
|
||||||
- name: fix dist
|
- name: fix dist
|
||||||
run: |
|
run: |
|
||||||
|
ls -al dist/
|
||||||
mv dist/dashboard-linux-arm-7 dist/dashboard-linux-arm
|
mv dist/dashboard-linux-arm-7 dist/dashboard-linux-arm
|
||||||
|
|
||||||
- name: Log in to the GHCR
|
- name: Log in to the GHCR
|
||||||
@@ -106,3 +115,16 @@ jobs:
|
|||||||
curl -s https://purge.jsdelivr.net/gh/$LOWER_USERNAME/nezha@master/script/nezha-agent.service
|
curl -s https://purge.jsdelivr.net/gh/$LOWER_USERNAME/nezha@master/script/nezha-agent.service
|
||||||
curl -s https://purge.jsdelivr.net/gh/$LOWER_USERNAME/nezha@master/script/docker-compose.yaml
|
curl -s https://purge.jsdelivr.net/gh/$LOWER_USERNAME/nezha@master/script/docker-compose.yaml
|
||||||
curl -s https://purge.jsdelivr.net/gh/$LOWER_USERNAME/nezha@master/script/config.yaml
|
curl -s https://purge.jsdelivr.net/gh/$LOWER_USERNAME/nezha@master/script/config.yaml
|
||||||
|
|
||||||
|
- name: Trigger sync
|
||||||
|
if: ${{ env.SYNCED == 0 }}
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
await github.rest.actions.createWorkflowDispatch({
|
||||||
|
owner: 'naiba',
|
||||||
|
repo: 'nezha',
|
||||||
|
workflow_id: 'sync-release.yml',
|
||||||
|
ref: 'master'
|
||||||
|
})
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
name: Sync Release to Gitee
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync-release-to-gitee:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
GITEE_TOKEN: ${{ secrets.GITEE_TOKEN }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Sync to Gitee
|
||||||
|
run: |
|
||||||
|
pip3 install PyGitHub
|
||||||
|
python3 .github/sync.py
|
||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
uses: crazy-max/ghaction-xgo@v2
|
uses: crazy-max/ghaction-xgo@v2
|
||||||
with:
|
with:
|
||||||
xgo_version: latest
|
xgo_version: latest
|
||||||
go_version: 1.20.x
|
go_version: 1.21.x
|
||||||
dest: dist
|
dest: dist
|
||||||
pkg: cmd/dashboard
|
pkg: cmd/dashboard
|
||||||
prefix: dashboard
|
prefix: dashboard
|
||||||
@@ -33,6 +33,11 @@ jobs:
|
|||||||
v: true
|
v: true
|
||||||
x: false
|
x: false
|
||||||
race: false
|
race: false
|
||||||
|
tags: timetzdata
|
||||||
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=test
|
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=test
|
||||||
buildmode: default
|
buildmode: default
|
||||||
|
- name: fix dist
|
||||||
|
run: |
|
||||||
|
ls -al dist/
|
||||||
|
mv dist/dashboard-linux-arm-7 dist/dashboard-linux-arm
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
uses: crazy-max/ghaction-xgo@v2
|
uses: crazy-max/ghaction-xgo@v2
|
||||||
with:
|
with:
|
||||||
xgo_version: latest
|
xgo_version: latest
|
||||||
go_version: 1.20.x
|
go_version: 1.21.x
|
||||||
dest: dist
|
dest: dist
|
||||||
pkg: cmd/dashboard
|
pkg: cmd/dashboard
|
||||||
prefix: dashboard
|
prefix: dashboard
|
||||||
@@ -40,5 +40,10 @@ jobs:
|
|||||||
v: true
|
v: true
|
||||||
x: false
|
x: false
|
||||||
race: false
|
race: false
|
||||||
|
tags: timetzdata
|
||||||
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=test
|
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=test
|
||||||
buildmode: default
|
buildmode: default
|
||||||
|
- name: fix dist
|
||||||
|
run: |
|
||||||
|
ls -al dist/
|
||||||
|
mv dist/dashboard-linux-arm-7 dist/dashboard-linux-arm
|
||||||
|
|||||||
@@ -4,13 +4,15 @@
|
|||||||
<br>
|
<br>
|
||||||
<small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
|
<small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
|
||||||
<br><br>
|
<br><br>
|
||||||
<img alt="GitHub release (with filter)" src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&style=for-the-badge&logo=github&label=Dashboard"> <img src="https://img.shields.io/github/v/release/nezhahq/agent?color=brightgreen&label=Agent&style=for-the-badge&logo=github"> <img src="https://img.shields.io/github/actions/workflow/status/nezhahq/agent/agent.yml?label=Agent%20CI&logo=github&style=for-the-badge"> <img src="https://img.shields.io/badge/Installer-v0.16.3-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"> <img src="https://img.shields.io/github/v/release/nezhahq/agent?color=brightgreen&label=Agent&style=for-the-badge&logo=github"> <img src="https://img.shields.io/github/actions/workflow/status/nezhahq/agent/agent.yml?label=Agent%20CI&logo=github&style=for-the-badge"> <img src="https://img.shields.io/badge/Installer-v0.18.2-brightgreen?style=for-the-badge&logo=linux">
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<p>:trollface: <b>Nezha Monitoring: Self-hostable, lightweight, servers and websites monitoring and O&M tool.</b></p>
|
<p>:trollface: <b>Nezha Monitoring: Self-hostable, lightweight, servers and websites monitoring and O&M tool.</b></p>
|
||||||
<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>
|
<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>
|
</div>
|
||||||
|
|
||||||
|
\>> Telegram Channel: [哪吒监控(中文通知频道)](https://t.me/nezhanews)
|
||||||
|
|
||||||
\>> Telegram Group: [Nezha Monitoring Global (English Only)](https://t.me/nezhamonitoring_global), [哪吒监控(中文群组)](https://t.me/nezhamonitoring)
|
\>> 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)
|
\>> [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)
|
||||||
@@ -41,49 +43,57 @@ You can change the dashboard language in the settings page (`/setting`) after th
|
|||||||
<!--GAMFC_DELIMITER--><a href="https://github.com/naiba" title="naiba"><img src="https://avatars.githubusercontent.com/u/29243953?v=4" width="50;" alt="naiba"/></a>
|
<!--GAMFC_DELIMITER--><a href="https://github.com/naiba" title="naiba"><img src="https://avatars.githubusercontent.com/u/29243953?v=4" width="50;" alt="naiba"/></a>
|
||||||
<a href="https://github.com/AkkiaS7" title="Akkia"><img src="https://avatars.githubusercontent.com/u/68485070?v=4" width="50;" alt="Akkia"/></a>
|
<a href="https://github.com/AkkiaS7" title="Akkia"><img src="https://avatars.githubusercontent.com/u/68485070?v=4" width="50;" alt="Akkia"/></a>
|
||||||
<a href="https://github.com/Erope" title="卖女孩的小火柴"><img src="https://avatars.githubusercontent.com/u/44471469?v=4" width="50;" alt="卖女孩的小火柴"/></a>
|
<a href="https://github.com/Erope" title="卖女孩的小火柴"><img src="https://avatars.githubusercontent.com/u/44471469?v=4" width="50;" alt="卖女孩的小火柴"/></a>
|
||||||
|
<a href="https://github.com/uubulb" title="UUBulb"><img src="https://avatars.githubusercontent.com/u/35923940?v=4" width="50;" alt="UUBulb"/></a>
|
||||||
<a href="https://github.com/dysf888" title="黑歌"><img src="https://avatars.githubusercontent.com/u/47450409?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/nap0o" title="nap0o"><img src="https://avatars.githubusercontent.com/u/144927971?v=4" width="50;" alt="nap0o"/></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/xykt" title="xykt"><img src="https://avatars.githubusercontent.com/u/152045469?v=4" width="50;" alt="xykt"/></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/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/JackieSung4ev" title="JackieSung4ev"><img src="https://avatars.githubusercontent.com/u/24974735?v=4" width="50;" alt="JackieSung4ev"/></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/uubulb" title="UUBulb"><img src="https://avatars.githubusercontent.com/u/35923940?v=4" width="50;" alt="UUBulb"/></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/cantoblanco" title="Kris"><img src="https://avatars.githubusercontent.com/u/116849421?v=4" width="50;" alt="Kris"/></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/lemoeo" title="Lemoe"><img src="https://avatars.githubusercontent.com/u/18618627?v=4" width="50;" alt="Lemoe"/></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/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/liuyanxi975" title="刘颜溪"><img src="https://avatars.githubusercontent.com/u/24417037?v=4" width="50;" alt="刘颜溪"/></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/1ridic" title="1ridic"><img src="https://avatars.githubusercontent.com/u/88495501?v=4" width="50;" alt="1ridic"/></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/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/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>
|
|
||||||
<a href="https://github.com/Mmx233" title="Mmx"><img src="https://avatars.githubusercontent.com/u/36563672?v=4" width="50;" alt="Mmx"/></a>
|
|
||||||
<a href="https://github.com/rootmelo92118" title="rootmelo92118"><img src="https://avatars.githubusercontent.com/u/32770959?v=4" width="50;" alt="rootmelo92118"/></a>
|
<a href="https://github.com/rootmelo92118" title="rootmelo92118"><img src="https://avatars.githubusercontent.com/u/32770959?v=4" width="50;" alt="rootmelo92118"/></a>
|
||||||
<a href="https://github.com/iilemon" title="Sean"><img src="https://avatars.githubusercontent.com/u/33201711?v=4" width="50;" alt="Sean"/></a>
|
<a href="https://github.com/Mmx233" title="Mmx"><img src="https://avatars.githubusercontent.com/u/36563672?v=4" width="50;" alt="Mmx"/></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/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/Creling" title="Creling"><img src="https://avatars.githubusercontent.com/u/43109504?v=4" width="50;" alt="Creling"/></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/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/zhucaidan" title="zhucaidan"><img src="https://avatars.githubusercontent.com/u/47970938?v=4" width="50;" alt="zhucaidan"/></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/ysicing" title="缘生"><img src="https://avatars.githubusercontent.com/u/8605565?v=4" width="50;" alt="缘生"/></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/unclezs" title="unclezs"><img src="https://avatars.githubusercontent.com/u/42318775?v=4" width="50;" alt="unclezs"/></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/lvyaoting" title="lvyaoting"><img src="https://avatars.githubusercontent.com/u/166296299?v=4" width="50;" alt="lvyaoting"/></a>
|
<a href="https://github.com/iilemon" title="Sean"><img src="https://avatars.githubusercontent.com/u/33201711?v=4" width="50;" alt="Sean"/></a>
|
||||||
<a href="https://github.com/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/nickfox-taterli" title="Tater Li"><img src="https://avatars.githubusercontent.com/u/19658596?v=4" width="50;" alt="Tater Li"/></a>
|
||||||
|
<a href="https://github.com/hmsjy2017" title="Tony"><img src="https://avatars.githubusercontent.com/u/42692274?v=4" width="50;" alt="Tony"/></a>
|
||||||
|
<a href="https://github.com/adminsama" title="adminsama"><img src="https://avatars.githubusercontent.com/u/60880076?v=4" width="50;" alt="adminsama"/></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/eya46" title="eya46"><img src="https://avatars.githubusercontent.com/u/61458340?v=4" width="50;" alt="eya46"/></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/yuanweize" title="I"><img src="https://avatars.githubusercontent.com/u/30067203?v=4" width="50;" alt="I"/></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/unclezs" title="unclezs"><img src="https://avatars.githubusercontent.com/u/42318775?v=4" width="50;" alt="unclezs"/></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/zhucaidan" title="zhucaidan"><img src="https://avatars.githubusercontent.com/u/47970938?v=4" width="50;" alt="zhucaidan"/></a>
|
||||||
|
<a href="https://github.com/arkylin" title="凌"><img src="https://avatars.githubusercontent.com/u/35104502?v=4" width="50;" alt="凌"/></a>
|
||||||
|
<a href="https://github.com/colour93" title="玖叁"><img src="https://avatars.githubusercontent.com/u/64313711?v=4" width="50;" alt="玖叁"/></a>
|
||||||
|
<a href="https://github.com/IamTaoChen" title="Tao Chen"><img src="https://avatars.githubusercontent.com/u/42793494?v=4" width="50;" alt="Tao Chen"/></a>
|
||||||
|
<a href="https://github.com/Septrum101" title="Spetrum"><img src="https://avatars.githubusercontent.com/u/11692994?v=4" width="50;" alt="Spetrum"/></a>
|
||||||
<a href="https://github.com/dreamingsleeping" title="Nanjing Hopefun Network Technology Co. Ltd."><img src="https://avatars.githubusercontent.com/u/13828658?v=4" width="50;" alt="Nanjing Hopefun Network Technology Co. Ltd."/></a>
|
<a href="https://github.com/dreamingsleeping" title="Nanjing Hopefun Network Technology Co. Ltd."><img src="https://avatars.githubusercontent.com/u/13828658?v=4" width="50;" alt="Nanjing Hopefun Network Technology Co. Ltd."/></a>
|
||||||
<a href="https://github.com/MartijnLindeman" title="Martijn Lindeman"><img src="https://avatars.githubusercontent.com/u/78365708?v=4" width="50;" alt="Martijn Lindeman"/></a>
|
<a href="https://github.com/MartijnLindeman" title="Martijn Lindeman"><img src="https://avatars.githubusercontent.com/u/78365708?v=4" width="50;" alt="Martijn Lindeman"/></a>
|
||||||
|
<a href="https://github.com/xrgzs" title="MadDogOwner"><img src="https://avatars.githubusercontent.com/u/26499123?v=4" width="50;" alt="MadDogOwner"/></a>
|
||||||
|
<a href="https://github.com/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/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/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/GreenTeodoro839" title="GreenTeodoro839"><img src="https://avatars.githubusercontent.com/u/77104800?v=4" width="50;" alt="GreenTeodoro839"/></a>
|
<a href="https://github.com/GreenTeodoro839" title="GreenTeodoro839"><img src="https://avatars.githubusercontent.com/u/77104800?v=4" width="50;" alt="GreenTeodoro839"/></a>
|
||||||
<a href="https://github.com/Es-dese" title="Esdese"><img src="https://avatars.githubusercontent.com/u/71542548?v=4" width="50;" alt="Esdese"/></a>
|
<a href="https://github.com/Es-dese" title="Esdese"><img src="https://avatars.githubusercontent.com/u/71542548?v=4" width="50;" alt="Esdese"/></a>
|
||||||
<a href="https://github.com/wwng2333" title="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-->
|
||||||
|
|
||||||
|
## Special Thanks
|
||||||
|
- [IPInfo](https://ipinfo.io/) for providing an accurate GeoIP Database.
|
||||||
|
|
||||||
## Star History
|
## Star History
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,9 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -23,22 +20,13 @@ import (
|
|||||||
"github.com/naiba/nezha/pkg/utils"
|
"github.com/naiba/nezha/pkg/utils"
|
||||||
"github.com/naiba/nezha/pkg/websocketx"
|
"github.com/naiba/nezha/pkg/websocketx"
|
||||||
"github.com/naiba/nezha/proto"
|
"github.com/naiba/nezha/proto"
|
||||||
|
"github.com/naiba/nezha/service/rpc"
|
||||||
"github.com/naiba/nezha/service/singleton"
|
"github.com/naiba/nezha/service/singleton"
|
||||||
)
|
)
|
||||||
|
|
||||||
type terminalContext struct {
|
|
||||||
agentConn *websocketx.Conn
|
|
||||||
userConn *websocketx.Conn
|
|
||||||
serverID uint64
|
|
||||||
host string
|
|
||||||
useSSL bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type commonPage struct {
|
type commonPage struct {
|
||||||
r *gin.Engine
|
r *gin.Engine
|
||||||
terminals map[string]*terminalContext
|
requestGroup singleflight.Group
|
||||||
terminalsLock *sync.Mutex
|
|
||||||
requestGroup singleflight.Group
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *commonPage) serve() {
|
func (cp *commonPage) serve() {
|
||||||
@@ -67,7 +55,6 @@ type viewPasswordForm struct {
|
|||||||
func (p *commonPage) issueViewPassword(c *gin.Context) {
|
func (p *commonPage) issueViewPassword(c *gin.Context) {
|
||||||
var vpf viewPasswordForm
|
var vpf viewPasswordForm
|
||||||
err := c.ShouldBind(&vpf)
|
err := c.ShouldBind(&vpf)
|
||||||
log.Println("bingo", vpf)
|
|
||||||
var hash []byte
|
var hash []byte
|
||||||
if err == nil && vpf.Password != singleton.Conf.Site.ViewPassword {
|
if err == nil && vpf.Password != singleton.Conf.Site.ViewPassword {
|
||||||
err = errors.New(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "WrongAccessPassword"}))
|
err = errors.New(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "WrongAccessPassword"}))
|
||||||
@@ -223,19 +210,25 @@ func (cp *commonPage) network(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cp *commonPage) getServerStat(c *gin.Context) ([]byte, error) {
|
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()
|
singleton.SortedServerLock.RLock()
|
||||||
defer singleton.SortedServerLock.RUnlock()
|
defer singleton.SortedServerLock.RUnlock()
|
||||||
|
|
||||||
_, isMember := c.Get(model.CtxKeyAuthorizedUser)
|
|
||||||
_, isViewPasswordVerfied := c.Get(model.CtxKeyViewPasswordVerified)
|
|
||||||
|
|
||||||
var servers []*model.Server
|
var servers []*model.Server
|
||||||
|
|
||||||
if isMember || isViewPasswordVerfied {
|
if authorized {
|
||||||
servers = singleton.SortedServerList
|
servers = singleton.SortedServerList
|
||||||
} else {
|
} 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{
|
return utils.Json.Marshal(Data{
|
||||||
@@ -267,8 +260,8 @@ func (cp *commonPage) home(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var upgrader = websocket.Upgrader{
|
var upgrader = websocket.Upgrader{
|
||||||
ReadBufferSize: 1024,
|
ReadBufferSize: 10240,
|
||||||
WriteBufferSize: 1024,
|
WriteBufferSize: 10240,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Data struct {
|
type Data struct {
|
||||||
@@ -276,8 +269,6 @@ type Data struct {
|
|||||||
Servers []*model.Server `json:"servers,omitempty"`
|
Servers []*model.Server `json:"servers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var cloudflareCookiesValidator = regexp.MustCompile("^[A-Za-z0-9-_]+$")
|
|
||||||
|
|
||||||
func (cp *commonPage) ws(c *gin.Context) {
|
func (cp *commonPage) ws(c *gin.Context) {
|
||||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -314,10 +305,8 @@ func (cp *commonPage) ws(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cp *commonPage) terminal(c *gin.Context) {
|
func (cp *commonPage) terminal(c *gin.Context) {
|
||||||
terminalID := c.Param("id")
|
streamId := c.Param("id")
|
||||||
cp.terminalsLock.Lock()
|
if _, err := rpc.NezhaHandlerSingleton.GetStream(streamId); err != nil {
|
||||||
if terminalID == "" || cp.terminals[terminalID] == nil {
|
|
||||||
cp.terminalsLock.Unlock()
|
|
||||||
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
||||||
Code: http.StatusForbidden,
|
Code: http.StatusForbidden,
|
||||||
Title: "无权访问",
|
Title: "无权访问",
|
||||||
@@ -327,104 +316,7 @@ func (cp *commonPage) terminal(c *gin.Context) {
|
|||||||
}, true)
|
}, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer rpc.NezhaHandlerSingleton.CloseStream(streamId)
|
||||||
terminal := cp.terminals[terminalID]
|
|
||||||
cp.terminalsLock.Unlock()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
// 清理 context
|
|
||||||
cp.terminalsLock.Lock()
|
|
||||||
defer cp.terminalsLock.Unlock()
|
|
||||||
delete(cp.terminals, terminalID)
|
|
||||||
}()
|
|
||||||
|
|
||||||
var isAgent bool
|
|
||||||
|
|
||||||
if _, authorized := c.Get(model.CtxKeyAuthorizedUser); !authorized {
|
|
||||||
singleton.ServerLock.RLock()
|
|
||||||
_, hasID := singleton.SecretToID[c.Request.Header.Get("Secret")]
|
|
||||||
singleton.ServerLock.RUnlock()
|
|
||||||
if !hasID {
|
|
||||||
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
Code: http.StatusForbidden,
|
|
||||||
Title: "无权访问",
|
|
||||||
Msg: "用户未登录或非法终端",
|
|
||||||
Link: "/",
|
|
||||||
Btn: "返回首页",
|
|
||||||
}, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if terminal.userConn == nil {
|
|
||||||
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
Code: http.StatusForbidden,
|
|
||||||
Title: "无权访问",
|
|
||||||
Msg: "用户不在线",
|
|
||||||
Link: "/",
|
|
||||||
Btn: "返回首页",
|
|
||||||
}, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if terminal.agentConn != nil {
|
|
||||||
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
Code: http.StatusInternalServerError,
|
|
||||||
Title: "连接已存在",
|
|
||||||
Msg: "Websocket协议切换失败",
|
|
||||||
Link: "/",
|
|
||||||
Btn: "返回首页",
|
|
||||||
}, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
isAgent = true
|
|
||||||
} else {
|
|
||||||
singleton.ServerLock.RLock()
|
|
||||||
server := singleton.ServerList[terminal.serverID]
|
|
||||||
singleton.ServerLock.RUnlock()
|
|
||||||
if server == nil || server.TaskStream == nil {
|
|
||||||
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
Code: http.StatusForbidden,
|
|
||||||
Title: "请求失败",
|
|
||||||
Msg: "服务器不存在或处于离线状态",
|
|
||||||
Link: "/server",
|
|
||||||
Btn: "返回重试",
|
|
||||||
}, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cloudflareCookies, _ := c.Cookie("CF_Authorization")
|
|
||||||
// Cloudflare Cookies 合法性验证
|
|
||||||
// 其应该包含.分隔的三组BASE64-URL编码
|
|
||||||
if cloudflareCookies != "" {
|
|
||||||
encodedCookies := strings.Split(cloudflareCookies, ".")
|
|
||||||
if len(encodedCookies) == 3 {
|
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
if !cloudflareCookiesValidator.MatchString(encodedCookies[i]) {
|
|
||||||
cloudflareCookies = ""
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cloudflareCookies = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
terminalData, _ := utils.Json.Marshal(&model.TerminalTask{
|
|
||||||
Host: terminal.host,
|
|
||||||
UseSSL: terminal.useSSL,
|
|
||||||
Session: terminalID,
|
|
||||||
Cookie: cloudflareCookies,
|
|
||||||
})
|
|
||||||
if err := server.TaskStream.Send(&proto.Task{
|
|
||||||
Type: model.TaskTypeTerminal,
|
|
||||||
Data: string(terminalData),
|
|
||||||
}); err != nil {
|
|
||||||
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
Code: http.StatusForbidden,
|
|
||||||
Title: "请求失败",
|
|
||||||
Msg: "Agent信令下发失败",
|
|
||||||
Link: "/server",
|
|
||||||
Btn: "返回重试",
|
|
||||||
}, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wsConn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
wsConn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -440,36 +332,7 @@ func (cp *commonPage) terminal(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer wsConn.Close()
|
defer wsConn.Close()
|
||||||
conn := &websocketx.Conn{Conn: wsConn}
|
conn := websocketx.NewConn(wsConn)
|
||||||
|
|
||||||
log.Printf("NEZHA>> terminal connected %t %q", isAgent, c.Request.URL)
|
|
||||||
defer log.Printf("NEZHA>> terminal disconnected %t %q", isAgent, c.Request.URL)
|
|
||||||
|
|
||||||
if isAgent {
|
|
||||||
terminal.agentConn = conn
|
|
||||||
defer func() {
|
|
||||||
// Agent断开链接时断开用户连接
|
|
||||||
if terminal.userConn != nil {
|
|
||||||
terminal.userConn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
} else {
|
|
||||||
terminal.userConn = conn
|
|
||||||
defer func() {
|
|
||||||
// 用户断开链接时断开 Agent 连接
|
|
||||||
if terminal.agentConn != nil {
|
|
||||||
terminal.agentConn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
deadlineCh := make(chan interface{})
|
|
||||||
go func() {
|
|
||||||
// 对方连接超时
|
|
||||||
connectDeadline := time.NewTimer(time.Second * 15)
|
|
||||||
<-connectDeadline.C
|
|
||||||
deadlineCh <- struct{}{}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// PING 保活
|
// PING 保活
|
||||||
@@ -481,58 +344,11 @@ func (cp *commonPage) terminal(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
dataCh := make(chan []byte)
|
if err = rpc.NezhaHandlerSingleton.UserConnected(streamId, conn); err != nil {
|
||||||
errorCh := make(chan error)
|
return
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
msgType, data, err := conn.ReadMessage()
|
|
||||||
if err != nil {
|
|
||||||
errorCh <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 将文本消息转换为命令输入
|
|
||||||
if msgType == websocket.TextMessage {
|
|
||||||
data = append([]byte{0}, data...)
|
|
||||||
}
|
|
||||||
dataCh <- data
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
var dataBuffer [][]byte
|
|
||||||
var distConn *websocketx.Conn
|
|
||||||
checkDistConn := func() {
|
|
||||||
if distConn == nil {
|
|
||||||
if isAgent {
|
|
||||||
distConn = terminal.userConn
|
|
||||||
} else {
|
|
||||||
distConn = terminal.agentConn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
rpc.NezhaHandlerSingleton.StartStream(streamId, time.Second*10)
|
||||||
select {
|
|
||||||
case <-deadlineCh:
|
|
||||||
checkDistConn()
|
|
||||||
if distConn == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case <-errorCh:
|
|
||||||
return
|
|
||||||
case data := <-dataCh:
|
|
||||||
dataBuffer = append(dataBuffer, data)
|
|
||||||
checkDistConn()
|
|
||||||
if distConn != nil {
|
|
||||||
for i := 0; i < len(dataBuffer); i++ {
|
|
||||||
err = distConn.WriteMessage(websocket.BinaryMessage, dataBuffer[i])
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dataBuffer = dataBuffer[:0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type createTerminalRequest struct {
|
type createTerminalRequest struct {
|
||||||
@@ -564,7 +380,7 @@ func (cp *commonPage) createTerminal(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := uuid.GenerateUUID()
|
streamId, err := uuid.GenerateUUID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
@@ -578,6 +394,8 @@ func (cp *commonPage) createTerminal(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpc.NezhaHandlerSingleton.CreateStream(streamId)
|
||||||
|
|
||||||
singleton.ServerLock.RLock()
|
singleton.ServerLock.RLock()
|
||||||
server := singleton.ServerList[createTerminalReq.ID]
|
server := singleton.ServerList[createTerminalReq.ID]
|
||||||
singleton.ServerLock.RUnlock()
|
singleton.ServerLock.RUnlock()
|
||||||
@@ -592,17 +410,25 @@ func (cp *commonPage) createTerminal(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cp.terminalsLock.Lock()
|
terminalData, _ := utils.Json.Marshal(&model.TerminalTask{
|
||||||
defer cp.terminalsLock.Unlock()
|
StreamID: streamId,
|
||||||
|
})
|
||||||
cp.terminals[id] = &terminalContext{
|
if err := server.TaskStream.Send(&proto.Task{
|
||||||
serverID: createTerminalReq.ID,
|
Type: model.TaskTypeTerminalGRPC,
|
||||||
host: createTerminalReq.Host,
|
Data: string(terminalData),
|
||||||
useSSL: createTerminalReq.Protocol == "https:",
|
}); err != nil {
|
||||||
|
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
Title: "请求失败",
|
||||||
|
Msg: "Agent信令下发失败",
|
||||||
|
Link: "/server",
|
||||||
|
Btn: "返回重试",
|
||||||
|
}, true)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/terminal", mygin.CommonEnvironment(c, gin.H{
|
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/terminal", mygin.CommonEnvironment(c, gin.H{
|
||||||
"SessionID": id,
|
"SessionID": streamId,
|
||||||
"ServerName": server.Name,
|
"ServerName": server.Name,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
@@ -9,22 +10,31 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.cloudfoundry.org/bytefmt"
|
"code.cloudfoundry.org/bytefmt"
|
||||||
"github.com/gin-contrib/pprof"
|
"github.com/gin-contrib/pprof"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/hashicorp/go-uuid"
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
|
|
||||||
|
"github.com/naiba/nezha/model"
|
||||||
"github.com/naiba/nezha/pkg/mygin"
|
"github.com/naiba/nezha/pkg/mygin"
|
||||||
|
"github.com/naiba/nezha/pkg/utils"
|
||||||
|
"github.com/naiba/nezha/proto"
|
||||||
"github.com/naiba/nezha/resource"
|
"github.com/naiba/nezha/resource"
|
||||||
|
"github.com/naiba/nezha/service/rpc"
|
||||||
"github.com/naiba/nezha/service/singleton"
|
"github.com/naiba/nezha/service/singleton"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ServeWeb(port uint) *http.Server {
|
func ServeWeb(port uint) *http.Server {
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
if singleton.Conf.Debug {
|
||||||
|
gin.SetMode(gin.DebugMode)
|
||||||
|
pprof.Register(r)
|
||||||
|
}
|
||||||
|
r.Use(natGateway)
|
||||||
tmpl := template.New("").Funcs(funcMap)
|
tmpl := template.New("").Funcs(funcMap)
|
||||||
var err error
|
var err error
|
||||||
tmpl, err = tmpl.ParseFS(resource.TemplateFS, "template/**/*.html")
|
tmpl, err = tmpl.ParseFS(resource.TemplateFS, "template/**/*.html")
|
||||||
@@ -33,10 +43,6 @@ func ServeWeb(port uint) *http.Server {
|
|||||||
}
|
}
|
||||||
tmpl = loadThirdPartyTemplates(tmpl)
|
tmpl = loadThirdPartyTemplates(tmpl)
|
||||||
r.SetHTMLTemplate(tmpl)
|
r.SetHTMLTemplate(tmpl)
|
||||||
if singleton.Conf.Debug {
|
|
||||||
gin.SetMode(gin.DebugMode)
|
|
||||||
pprof.Register(r)
|
|
||||||
}
|
|
||||||
r.Use(mygin.RecordPath)
|
r.Use(mygin.RecordPath)
|
||||||
staticFs, err := fs.Sub(resource.StaticFS, "static")
|
staticFs, err := fs.Sub(resource.StaticFS, "static")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -45,7 +51,6 @@ func ServeWeb(port uint) *http.Server {
|
|||||||
r.StaticFS("/static", http.FS(staticFs))
|
r.StaticFS("/static", http.FS(staticFs))
|
||||||
r.Static("/static-custom", "resource/static/custom")
|
r.Static("/static-custom", "resource/static/custom")
|
||||||
routers(r)
|
routers(r)
|
||||||
|
|
||||||
page404 := func(c *gin.Context) {
|
page404 := func(c *gin.Context) {
|
||||||
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
||||||
Code: http.StatusNotFound,
|
Code: http.StatusNotFound,
|
||||||
@@ -68,7 +73,7 @@ func ServeWeb(port uint) *http.Server {
|
|||||||
|
|
||||||
func routers(r *gin.Engine) {
|
func routers(r *gin.Engine) {
|
||||||
// 通用页面
|
// 通用页面
|
||||||
cp := commonPage{r: r, terminals: make(map[string]*terminalContext), terminalsLock: new(sync.Mutex)}
|
cp := commonPage{r: r}
|
||||||
cp.serve()
|
cp.serve()
|
||||||
// 游客页面
|
// 游客页面
|
||||||
gp := guestPage{r}
|
gp := guestPage{r}
|
||||||
@@ -239,3 +244,64 @@ var funcMap = template.FuncMap{
|
|||||||
return singleton.StatusCodeToString(singleton.GetStatusCode(val))
|
return singleton.StatusCodeToString(singleton.GetStatusCode(val))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func natGateway(c *gin.Context) {
|
||||||
|
natConfig := singleton.GetNATConfigByDomain(c.Request.Host)
|
||||||
|
if natConfig == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
singleton.ServerLock.RLock()
|
||||||
|
server := singleton.ServerList[natConfig.ServerID]
|
||||||
|
singleton.ServerLock.RUnlock()
|
||||||
|
if server == nil || server.TaskStream == nil {
|
||||||
|
c.Writer.WriteString("server not found or not connected")
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
streamId, err := uuid.GenerateUUID()
|
||||||
|
if err != nil {
|
||||||
|
c.Writer.WriteString(fmt.Sprintf("stream id error: %v", err))
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc.NezhaHandlerSingleton.CreateStream(streamId)
|
||||||
|
defer rpc.NezhaHandlerSingleton.CloseStream(streamId)
|
||||||
|
|
||||||
|
taskData, err := json.Marshal(model.TaskNAT{
|
||||||
|
StreamID: streamId,
|
||||||
|
Host: natConfig.Host,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.Writer.WriteString(fmt.Sprintf("task data error: %v", err))
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := server.TaskStream.Send(&proto.Task{
|
||||||
|
Type: model.TaskTypeNAT,
|
||||||
|
Data: string(taskData),
|
||||||
|
}); err != nil {
|
||||||
|
c.Writer.WriteString(fmt.Sprintf("send task error: %v", err))
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := utils.NewRequestWrapper(c.Request, c.Writer)
|
||||||
|
if err != nil {
|
||||||
|
c.Writer.WriteString(fmt.Sprintf("request wrapper error: %v", err))
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rpc.NezhaHandlerSingleton.UserConnected(streamId, w); err != nil {
|
||||||
|
c.Writer.WriteString(fmt.Sprintf("user connected error: %v", err))
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc.NezhaHandlerSingleton.StartStream(streamId, time.Second*10)
|
||||||
|
c.Abort()
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ func (gp *guestPage) serve() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gp *guestPage) login(c *gin.Context) {
|
func (gp *guestPage) login(c *gin.Context) {
|
||||||
|
if singleton.Conf.Oauth2.OidcAutoLogin {
|
||||||
|
c.Redirect(http.StatusFound, "/oauth2/login")
|
||||||
|
return
|
||||||
|
}
|
||||||
LoginType := "GitHub"
|
LoginType := "GitHub"
|
||||||
RegistrationLink := "https://github.com/join"
|
RegistrationLink := "https://github.com/join"
|
||||||
if singleton.Conf.Oauth2.Type == model.ConfigTypeGitee {
|
if singleton.Conf.Oauth2.Type == model.ConfigTypeGitee {
|
||||||
@@ -52,6 +56,9 @@ func (gp *guestPage) login(c *gin.Context) {
|
|||||||
} else if singleton.Conf.Oauth2.Type == model.ConfigTypeCloudflare {
|
} else if singleton.Conf.Oauth2.Type == model.ConfigTypeCloudflare {
|
||||||
LoginType = "Cloudflare"
|
LoginType = "Cloudflare"
|
||||||
RegistrationLink = "https://dash.cloudflare.com/sign-up/teams"
|
RegistrationLink = "https://dash.cloudflare.com/sign-up/teams"
|
||||||
|
} else if singleton.Conf.Oauth2.Type == model.ConfigTypeOidc {
|
||||||
|
LoginType = singleton.Conf.Oauth2.OidcDisplayName
|
||||||
|
RegistrationLink = singleton.Conf.Oauth2.OidcRegisterURL
|
||||||
}
|
}
|
||||||
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/login", mygin.CommonEnvironment(c, gin.H{
|
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/login", mygin.CommonEnvironment(c, gin.H{
|
||||||
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
|
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ func (ma *memberAPI) serve() {
|
|||||||
mr.POST("/batch-update-server-group", ma.batchUpdateServerGroup)
|
mr.POST("/batch-update-server-group", ma.batchUpdateServerGroup)
|
||||||
mr.POST("/batch-delete-server", ma.batchDeleteServer)
|
mr.POST("/batch-delete-server", ma.batchDeleteServer)
|
||||||
mr.POST("/notification", ma.addOrEditNotification)
|
mr.POST("/notification", ma.addOrEditNotification)
|
||||||
|
mr.POST("/nat", ma.addOrEditNAT)
|
||||||
mr.POST("/alert-rule", ma.addOrEditAlertRule)
|
mr.POST("/alert-rule", ma.addOrEditAlertRule)
|
||||||
mr.POST("/setting", ma.updateSetting)
|
mr.POST("/setting", ma.updateSetting)
|
||||||
mr.DELETE("/:model/:id", ma.delete)
|
mr.DELETE("/:model/:id", ma.delete)
|
||||||
@@ -209,6 +210,11 @@ func (ma *memberAPI) delete(c *gin.Context) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
singleton.OnDeleteNotification(id)
|
singleton.OnDeleteNotification(id)
|
||||||
}
|
}
|
||||||
|
case "nat":
|
||||||
|
err = singleton.DB.Unscoped().Delete(&model.NAT{}, "id = ?", id).Error
|
||||||
|
if err == nil {
|
||||||
|
singleton.OnNATUpdate()
|
||||||
|
}
|
||||||
case "monitor":
|
case "monitor":
|
||||||
err = singleton.DB.Unscoped().Delete(&model.Monitor{}, "id = ?", id).Error
|
err = singleton.DB.Unscoped().Delete(&model.Monitor{}, "id = ?", id).Error
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -437,25 +443,23 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
|
|||||||
if m.NotificationTag == "" {
|
if m.NotificationTag == "" {
|
||||||
m.NotificationTag = "default"
|
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.Cover == 0 {
|
||||||
if err == nil {
|
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
|
||||||
if m.ID == 0 {
|
} else {
|
||||||
err = singleton.DB.Create(&m).Error
|
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
|
||||||
} 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 err == nil {
|
||||||
@@ -735,6 +739,45 @@ func (ma *memberAPI) addOrEditNotification(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type natForm struct {
|
||||||
|
ID uint64
|
||||||
|
Name string
|
||||||
|
ServerID uint64
|
||||||
|
Host string
|
||||||
|
Domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ma *memberAPI) addOrEditNAT(c *gin.Context) {
|
||||||
|
var nf natForm
|
||||||
|
var n model.NAT
|
||||||
|
err := c.ShouldBindJSON(&nf)
|
||||||
|
if err == nil {
|
||||||
|
n.Name = nf.Name
|
||||||
|
n.ID = nf.ID
|
||||||
|
n.Domain = nf.Domain
|
||||||
|
n.Host = nf.Host
|
||||||
|
n.ServerID = nf.ServerID
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
if n.ID == 0 {
|
||||||
|
err = singleton.DB.Create(&n).Error
|
||||||
|
} else {
|
||||||
|
err = singleton.DB.Save(&n).Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusOK, model.Response{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
Message: fmt.Sprintf("请求错误:%s", err),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
singleton.OnNATUpdate()
|
||||||
|
c.JSON(http.StatusOK, model.Response{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type alertRuleForm struct {
|
type alertRuleForm struct {
|
||||||
ID uint64
|
ID uint64
|
||||||
Name string
|
Name string
|
||||||
@@ -849,6 +892,11 @@ func (ma *memberAPI) logout(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, model.Response{
|
c.JSON(http.StatusOK, model.Response{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if oidcLogoutUrl := singleton.Conf.Oauth2.OidcLogoutURL; oidcLogoutUrl != "" {
|
||||||
|
// 重定向到 OIDC 退出登录地址。不知道为什么,这里的重定向不生效
|
||||||
|
c.Redirect(http.StatusOK, oidcLogoutUrl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type settingForm struct {
|
type settingForm struct {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ func (mp *memberPage) serve() {
|
|||||||
mr.GET("/monitor", mp.monitor)
|
mr.GET("/monitor", mp.monitor)
|
||||||
mr.GET("/cron", mp.cron)
|
mr.GET("/cron", mp.cron)
|
||||||
mr.GET("/notification", mp.notification)
|
mr.GET("/notification", mp.notification)
|
||||||
|
mr.GET("/nat", mp.nat)
|
||||||
mr.GET("/setting", mp.setting)
|
mr.GET("/setting", mp.setting)
|
||||||
mr.GET("/api", mp.api)
|
mr.GET("/api", mp.api)
|
||||||
}
|
}
|
||||||
@@ -77,6 +78,15 @@ func (mp *memberPage) notification(c *gin.Context) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mp *memberPage) nat(c *gin.Context) {
|
||||||
|
var data []model.NAT
|
||||||
|
singleton.DB.Find(&data)
|
||||||
|
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/nat", mygin.CommonEnvironment(c, gin.H{
|
||||||
|
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "NAT"}),
|
||||||
|
"NAT": data,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
func (mp *memberPage) setting(c *gin.Context) {
|
func (mp *memberPage) setting(c *gin.Context) {
|
||||||
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/setting", mygin.CommonEnvironment(c, gin.H{
|
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/setting", mygin.CommonEnvironment(c, gin.H{
|
||||||
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Settings"}),
|
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Settings"}),
|
||||||
|
|||||||
@@ -5,29 +5,32 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/naiba/nezha/pkg/oidc/cloudflare"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
|
"github.com/naiba/nezha/pkg/oidc/cloudflare"
|
||||||
|
myOidc "github.com/naiba/nezha/pkg/oidc/general"
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
GitHubAPI "github.com/google/go-github/v47/github"
|
GitHubAPI "github.com/google/go-github/v47/github"
|
||||||
|
"github.com/naiba/nezha/model"
|
||||||
|
"github.com/naiba/nezha/pkg/mygin"
|
||||||
|
"github.com/naiba/nezha/pkg/utils"
|
||||||
|
"github.com/naiba/nezha/service/singleton"
|
||||||
"github.com/patrickmn/go-cache"
|
"github.com/patrickmn/go-cache"
|
||||||
"github.com/xanzy/go-gitlab"
|
"github.com/xanzy/go-gitlab"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
GitHubOauth2 "golang.org/x/oauth2/github"
|
GitHubOauth2 "golang.org/x/oauth2/github"
|
||||||
GitlabOauth2 "golang.org/x/oauth2/gitlab"
|
GitlabOauth2 "golang.org/x/oauth2/gitlab"
|
||||||
|
|
||||||
"github.com/naiba/nezha/model"
|
|
||||||
"github.com/naiba/nezha/pkg/mygin"
|
|
||||||
"github.com/naiba/nezha/pkg/utils"
|
|
||||||
"github.com/naiba/nezha/service/singleton"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type oauth2controller struct {
|
type oauth2controller struct {
|
||||||
r gin.IRoutes
|
r gin.IRoutes
|
||||||
|
oidcProvider *oidc.Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
func (oa *oauth2controller) serve() {
|
func (oa *oauth2controller) serve() {
|
||||||
@@ -87,6 +90,27 @@ func (oa *oauth2controller) getCommonOauth2Config(c *gin.Context) *oauth2.Config
|
|||||||
},
|
},
|
||||||
RedirectURL: oa.getRedirectURL(c),
|
RedirectURL: oa.getRedirectURL(c),
|
||||||
}
|
}
|
||||||
|
} else if singleton.Conf.Oauth2.Type == model.ConfigTypeOidc {
|
||||||
|
var err error
|
||||||
|
oa.oidcProvider, err = oidc.NewProvider(c.Request.Context(), singleton.Conf.Oauth2.OidcIssuer)
|
||||||
|
if err != nil {
|
||||||
|
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
Title: fmt.Sprintf("Cannot get OIDC infomaion from issuer from %s", singleton.Conf.Oauth2.OidcIssuer),
|
||||||
|
Msg: err.Error(),
|
||||||
|
}, true)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
scopes := strings.Split(singleton.Conf.Oauth2.OidcScopes, ",")
|
||||||
|
scopes = append(scopes, oidc.ScopeOpenID)
|
||||||
|
uniqueScopes := removeDuplicates(scopes)
|
||||||
|
return &oauth2.Config{
|
||||||
|
ClientID: singleton.Conf.Oauth2.ClientID,
|
||||||
|
ClientSecret: singleton.Conf.Oauth2.ClientSecret,
|
||||||
|
Scopes: uniqueScopes,
|
||||||
|
Endpoint: oa.oidcProvider.Endpoint(),
|
||||||
|
RedirectURL: oa.getRedirectURL(c),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return &oauth2.Config{
|
return &oauth2.Config{
|
||||||
ClientID: singleton.Conf.Oauth2.ClientID,
|
ClientID: singleton.Conf.Oauth2.ClientID,
|
||||||
@@ -99,7 +123,8 @@ func (oa *oauth2controller) getCommonOauth2Config(c *gin.Context) *oauth2.Config
|
|||||||
|
|
||||||
func (oa *oauth2controller) getRedirectURL(c *gin.Context) string {
|
func (oa *oauth2controller) getRedirectURL(c *gin.Context) string {
|
||||||
scheme := "http://"
|
scheme := "http://"
|
||||||
if strings.HasPrefix(c.Request.Referer(), "https://") {
|
referer := c.Request.Referer()
|
||||||
|
if forwardedProto := c.Request.Header.Get("X-Forwarded-Proto"); forwardedProto == "https" || strings.HasPrefix(referer, "https://") {
|
||||||
scheme = "https://"
|
scheme = "https://"
|
||||||
}
|
}
|
||||||
return scheme + c.Request.Host + "/oauth2/callback"
|
return scheme + c.Request.Host + "/oauth2/callback"
|
||||||
@@ -178,7 +203,18 @@ func (oa *oauth2controller) callback(c *gin.Context) {
|
|||||||
user = cloudflareUserInfo.MapToNezhaUser()
|
user = cloudflareUserInfo.MapToNezhaUser()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if singleton.Conf.Oauth2.Type == model.ConfigTypeOidc {
|
||||||
|
userInfo, err := oa.oidcProvider.UserInfo(c.Request.Context(), oauth2.StaticTokenSource(otk))
|
||||||
|
if err == nil {
|
||||||
|
loginClaim := singleton.Conf.Oauth2.OidcLoginClaim
|
||||||
|
groupClain := singleton.Conf.Oauth2.OidcGroupClaim
|
||||||
|
adminGroups := strings.Split(singleton.Conf.Oauth2.AdminGroups, ",")
|
||||||
|
autoCreate := singleton.Conf.Oauth2.OidcAutoCreate
|
||||||
|
var oidceUserInfo *myOidc.UserInfo
|
||||||
|
if err := userInfo.Claims(&oidceUserInfo); err == nil {
|
||||||
|
user = oidceUserInfo.MapToNezhaUser(loginClaim, groupClain, adminGroups, autoCreate)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var client *GitHubAPI.Client
|
var client *GitHubAPI.Client
|
||||||
oc := oauth2Config.Client(ctx, otk)
|
oc := oauth2Config.Client(ctx, otk)
|
||||||
@@ -192,15 +228,12 @@ func (oa *oauth2controller) callback(c *gin.Context) {
|
|||||||
client = GitHubAPI.NewClient(oc)
|
client = GitHubAPI.NewClient(oc)
|
||||||
}
|
}
|
||||||
var gu *GitHubAPI.User
|
var gu *GitHubAPI.User
|
||||||
if err == nil {
|
gu, _, err = client.Users.Get(ctx, "")
|
||||||
gu, _, err = client.Users.Get(ctx, "")
|
|
||||||
}
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
user = model.NewUserFromGitHub(gu)
|
user = model.NewUserFromGitHub(gu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && user.Login == "" {
|
if err == nil && user.Login == "" {
|
||||||
err = errors.New("获取用户信息失败")
|
err = errors.New("获取用户信息失败")
|
||||||
}
|
}
|
||||||
@@ -214,10 +247,15 @@ func (oa *oauth2controller) callback(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var isAdmin bool
|
var isAdmin bool
|
||||||
for _, admin := range strings.Split(singleton.Conf.Oauth2.Admin, ",") {
|
|
||||||
if admin != "" && strings.EqualFold(user.Login, admin) {
|
if user.SuperAdmin {
|
||||||
isAdmin = true
|
isAdmin = true
|
||||||
break
|
} else {
|
||||||
|
for _, admin := range strings.Split(singleton.Conf.Oauth2.Admin, ",") {
|
||||||
|
if admin != "" && strings.EqualFold(user.Login, admin) {
|
||||||
|
isAdmin = true
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !isAdmin {
|
if !isAdmin {
|
||||||
@@ -244,3 +282,16 @@ func (oa *oauth2controller) callback(c *gin.Context) {
|
|||||||
"URL": "/",
|
"URL": "/",
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeDuplicates(elements []string) []string {
|
||||||
|
encountered := map[string]bool{}
|
||||||
|
result := []string{}
|
||||||
|
|
||||||
|
for _, v := range elements {
|
||||||
|
if !encountered[v] {
|
||||||
|
encountered[v] = true
|
||||||
|
result = append(result, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 使用 cmux 在同一端口服务 HTTP 和 gRPC
|
||||||
singleton.CleanMonitorHistory()
|
singleton.CleanMonitorHistory()
|
||||||
go rpc.ServeRPC(singleton.Conf.GRPCPort)
|
go rpc.ServeRPC(singleton.Conf.GRPCPort)
|
||||||
serviceSentinelDispatchBus := make(chan model.Monitor) // 用于传递服务监控任务信息的channel
|
serviceSentinelDispatchBus := make(chan model.Monitor) // 用于传递服务监控任务信息的channel
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ import (
|
|||||||
|
|
||||||
func ServeRPC(port uint) {
|
func ServeRPC(port uint) {
|
||||||
server := grpc.NewServer()
|
server := grpc.NewServer()
|
||||||
pb.RegisterNezhaServiceServer(server, &rpcService.NezhaHandler{
|
rpcService.NezhaHandlerSingleton = rpcService.NewNezhaHandler()
|
||||||
Auth: &rpcService.AuthHandler{},
|
pb.RegisterNezhaServiceServer(server, rpcService.NezhaHandlerSingleton)
|
||||||
})
|
|
||||||
listen, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
listen, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
module github.com/naiba/nezha
|
module github.com/naiba/nezha
|
||||||
|
|
||||||
go 1.20
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.cloudfoundry.org/bytefmt v0.0.0-20240425163905-bcdc1ad063ea
|
code.cloudfoundry.org/bytefmt v0.0.0-20240425163905-bcdc1ad063ea
|
||||||
code.gitea.io/sdk/gitea v0.18.0
|
code.gitea.io/sdk/gitea v0.18.0
|
||||||
github.com/BurntSushi/toml v1.3.2
|
github.com/BurntSushi/toml v1.3.2
|
||||||
|
github.com/coreos/go-oidc/v3 v3.11.0
|
||||||
github.com/gin-contrib/pprof v1.4.0
|
github.com/gin-contrib/pprof v1.4.0
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/google/go-github/v47 v47.1.0
|
github.com/google/go-github/v47 v47.1.0
|
||||||
@@ -17,17 +18,16 @@ require (
|
|||||||
github.com/ory/graceful v0.1.3
|
github.com/ory/graceful v0.1.3
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/samber/lo v1.39.0
|
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/spf13/viper v1.18.2
|
github.com/spf13/viper v1.18.2
|
||||||
github.com/xanzy/go-gitlab v0.103.0
|
github.com/xanzy/go-gitlab v0.103.0
|
||||||
golang.org/x/crypto v0.22.0
|
golang.org/x/crypto v0.25.0
|
||||||
golang.org/x/net v0.24.0
|
golang.org/x/net v0.27.0
|
||||||
golang.org/x/oauth2 v0.19.0
|
golang.org/x/oauth2 v0.21.0
|
||||||
golang.org/x/sync v0.7.0
|
golang.org/x/sync v0.7.0
|
||||||
golang.org/x/text v0.14.0
|
golang.org/x/text v0.16.0
|
||||||
google.golang.org/grpc v1.63.0
|
google.golang.org/grpc v1.63.0
|
||||||
google.golang.org/protobuf v1.33.0
|
google.golang.org/protobuf v1.34.2
|
||||||
gorm.io/driver/sqlite v1.5.5
|
gorm.io/driver/sqlite v1.5.5
|
||||||
gorm.io/gorm v1.25.10
|
gorm.io/gorm v1.25.10
|
||||||
sigs.k8s.io/yaml v1.4.0
|
sigs.k8s.io/yaml v1.4.0
|
||||||
@@ -41,13 +41,14 @@ require (
|
|||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-fed/httpsig v1.1.0 // indirect
|
github.com/go-fed/httpsig v1.1.0 // indirect
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
@@ -55,11 +56,12 @@ require (
|
|||||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
github.com/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/mattn/go-sqlite3 v1.14.17 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||||
@@ -74,7 +76,7 @@ require (
|
|||||||
go.uber.org/multierr v1.9.0 // indirect
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||||
golang.org/x/sys v0.19.0 // indirect
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
|||||||
@@ -10,14 +10,19 @@ github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZX
|
|||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||||
|
github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI=
|
||||||
|
github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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.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 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 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
|
||||||
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
|
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
|
||||||
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
|
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||||
@@ -31,9 +36,13 @@ github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
|||||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||||
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
|
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-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
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.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 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.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 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
@@ -44,6 +53,7 @@ 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 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||||
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
@@ -52,20 +62,22 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-github/v47 v47.1.0 h1:Cacm/WxQBOa9lF0FT0EMjZ2BWMetQ1TQfyurn4yF1z8=
|
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-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 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
|
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
|
||||||
|
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
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 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
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.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||||
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
|
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
|
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
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 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||||
@@ -87,6 +99,7 @@ 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.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
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/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.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
@@ -97,9 +110,10 @@ 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 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
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 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
@@ -112,9 +126,13 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
|
|||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
||||||
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
|
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
|
||||||
github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE=
|
github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE=
|
||||||
|
github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
|
||||||
github.com/ory/graceful v0.1.3 h1:FaeXcHZh168WzS+bqruqWEw/HgXWLdNv2nJ+fbhxbhc=
|
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/ory/graceful v0.1.3/go.mod h1:4zFz687IAF7oNHHiB586U4iL+/4aV09o/PYLE34t2bA=
|
||||||
|
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||||
|
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||||
@@ -125,17 +143,17 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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.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 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 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
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.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.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
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/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||||
github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA=
|
|
||||||
github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
|
||||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||||
@@ -149,7 +167,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.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
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.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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
@@ -181,16 +198,16 @@ 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-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-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-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||||
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
|
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
|
||||||
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
|
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -201,19 +218,21 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.22.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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||||
|
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
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/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
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 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/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
|
||||||
@@ -221,8 +240,8 @@ 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/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-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
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.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
|||||||
+31
-8
@@ -22,7 +22,7 @@ var Themes = map[string]string{
|
|||||||
"mdui": "Neko Mdui",
|
"mdui": "Neko Mdui",
|
||||||
"hotaru": "Hotaru",
|
"hotaru": "Hotaru",
|
||||||
"angel-kanade": "AngelKanade",
|
"angel-kanade": "AngelKanade",
|
||||||
"server-status": "SeverStatus",
|
"server-status": "ServerStatus",
|
||||||
"custom": "Custom(local)",
|
"custom": "Custom(local)",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +38,7 @@ const (
|
|||||||
ConfigTypeJihulab = "jihulab"
|
ConfigTypeJihulab = "jihulab"
|
||||||
ConfigTypeGitea = "gitea"
|
ConfigTypeGitea = "gitea"
|
||||||
ConfigTypeCloudflare = "cloudflare"
|
ConfigTypeCloudflare = "cloudflare"
|
||||||
|
ConfigTypeOidc = "oidc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -71,7 +72,7 @@ func (c *AgentConfig) Save() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.WriteFile(c.v.ConfigFileUsed(), data, os.ModePerm)
|
return os.WriteFile(c.v.ConfigFileUsed(), data, 0600)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config 站点配置
|
// Config 站点配置
|
||||||
@@ -87,11 +88,21 @@ type Config struct {
|
|||||||
ViewPassword string // 前台查看密码
|
ViewPassword string // 前台查看密码
|
||||||
}
|
}
|
||||||
Oauth2 struct {
|
Oauth2 struct {
|
||||||
Type string
|
Type string
|
||||||
Admin string // 管理员用户名列表
|
Admin string // 管理员用户名列表
|
||||||
ClientID string
|
AdminGroups string // 管理员用户组列表
|
||||||
ClientSecret string
|
ClientID string
|
||||||
Endpoint string
|
ClientSecret string
|
||||||
|
Endpoint string
|
||||||
|
OidcDisplayName string // for OIDC Display Name
|
||||||
|
OidcIssuer string // for OIDC Issuer
|
||||||
|
OidcLogoutURL string // for OIDC Logout URL
|
||||||
|
OidcRegisterURL string // for OIDC Register URL
|
||||||
|
OidcLoginClaim string // for OIDC Claim
|
||||||
|
OidcGroupClaim string // for OIDC Group Claim
|
||||||
|
OidcScopes string // for OIDC Scopes
|
||||||
|
OidcAutoCreate bool // for OIDC Auto Create
|
||||||
|
OidcAutoLogin bool // for OIDC Auto Login
|
||||||
}
|
}
|
||||||
HTTPPort uint
|
HTTPPort uint
|
||||||
GRPCPort uint
|
GRPCPort uint
|
||||||
@@ -181,6 +192,18 @@ func (c *Config) Read(path string) error {
|
|||||||
if c.DDNS.MaxRetries == 0 {
|
if c.DDNS.MaxRetries == 0 {
|
||||||
c.DDNS.MaxRetries = 3
|
c.DDNS.MaxRetries = 3
|
||||||
}
|
}
|
||||||
|
if c.Oauth2.OidcScopes == "" {
|
||||||
|
c.Oauth2.OidcScopes = "openid,profile,email"
|
||||||
|
}
|
||||||
|
if c.Oauth2.OidcLoginClaim == "" {
|
||||||
|
c.Oauth2.OidcLoginClaim = "sub"
|
||||||
|
}
|
||||||
|
if c.Oauth2.OidcDisplayName == "" {
|
||||||
|
c.Oauth2.OidcDisplayName = "OIDC"
|
||||||
|
}
|
||||||
|
if c.Oauth2.OidcGroupClaim == "" {
|
||||||
|
c.Oauth2.OidcGroupClaim = "groups"
|
||||||
|
}
|
||||||
|
|
||||||
c.updateIgnoredIPNotificationID()
|
c.updateIgnoredIPNotificationID()
|
||||||
return nil
|
return nil
|
||||||
@@ -205,5 +228,5 @@ func (c *Config) Save() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.WriteFile(c.v.ConfigFileUsed(), data, os.ModePerm)
|
return os.WriteFile(c.v.ConfigFileUsed(), data, 0600)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ const (
|
|||||||
MTReportHostState
|
MTReportHostState
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SensorTemperature struct {
|
||||||
|
Name string
|
||||||
|
Temperature float64
|
||||||
|
}
|
||||||
|
|
||||||
type HostState struct {
|
type HostState struct {
|
||||||
CPU float64
|
CPU float64
|
||||||
MemUsed uint64
|
MemUsed uint64
|
||||||
@@ -26,9 +31,19 @@ type HostState struct {
|
|||||||
TcpConnCount uint64
|
TcpConnCount uint64
|
||||||
UdpConnCount uint64
|
UdpConnCount uint64
|
||||||
ProcessCount uint64
|
ProcessCount uint64
|
||||||
|
Temperatures []SensorTemperature
|
||||||
|
GPU float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HostState) PB() *pb.State {
|
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{
|
return &pb.State{
|
||||||
Cpu: s.CPU,
|
Cpu: s.CPU,
|
||||||
MemUsed: s.MemUsed,
|
MemUsed: s.MemUsed,
|
||||||
@@ -45,10 +60,20 @@ func (s *HostState) PB() *pb.State {
|
|||||||
TcpConnCount: s.TcpConnCount,
|
TcpConnCount: s.TcpConnCount,
|
||||||
UdpConnCount: s.UdpConnCount,
|
UdpConnCount: s.UdpConnCount,
|
||||||
ProcessCount: s.ProcessCount,
|
ProcessCount: s.ProcessCount,
|
||||||
|
Temperatures: ts,
|
||||||
|
Gpu: s.GPU,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PB2State(s *pb.State) HostState {
|
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{
|
return HostState{
|
||||||
CPU: s.GetCpu(),
|
CPU: s.GetCpu(),
|
||||||
MemUsed: s.GetMemUsed(),
|
MemUsed: s.GetMemUsed(),
|
||||||
@@ -65,6 +90,8 @@ func PB2State(s *pb.State) HostState {
|
|||||||
TcpConnCount: s.GetTcpConnCount(),
|
TcpConnCount: s.GetTcpConnCount(),
|
||||||
UdpConnCount: s.GetUdpConnCount(),
|
UdpConnCount: s.GetUdpConnCount(),
|
||||||
ProcessCount: s.GetProcessCount(),
|
ProcessCount: s.GetProcessCount(),
|
||||||
|
Temperatures: ts,
|
||||||
|
GPU: s.GetGpu(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +108,7 @@ type Host struct {
|
|||||||
IP string `json:"-"`
|
IP string `json:"-"`
|
||||||
CountryCode string
|
CountryCode string
|
||||||
Version string
|
Version string
|
||||||
|
GPU []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Host) PB() *pb.Host {
|
func (h *Host) PB() *pb.Host {
|
||||||
@@ -97,6 +125,7 @@ func (h *Host) PB() *pb.Host {
|
|||||||
Ip: h.IP,
|
Ip: h.IP,
|
||||||
CountryCode: h.CountryCode,
|
CountryCode: h.CountryCode,
|
||||||
Version: h.Version,
|
Version: h.Version,
|
||||||
|
Gpu: h.GPU,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,5 +143,6 @@ func PB2Host(h *pb.Host) Host {
|
|||||||
IP: h.GetIp(),
|
IP: h.GetIp(),
|
||||||
CountryCode: h.GetCountryCode(),
|
CountryCode: h.GetCountryCode(),
|
||||||
Version: h.GetVersion(),
|
Version: h.GetVersion(),
|
||||||
|
GPU: h.GetGpu(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -20,17 +20,17 @@ const (
|
|||||||
TaskTypeTerminal
|
TaskTypeTerminal
|
||||||
TaskTypeUpgrade
|
TaskTypeUpgrade
|
||||||
TaskTypeKeepalive
|
TaskTypeKeepalive
|
||||||
|
TaskTypeTerminalGRPC
|
||||||
|
TaskTypeNAT
|
||||||
)
|
)
|
||||||
|
|
||||||
type TerminalTask struct {
|
type TerminalTask struct {
|
||||||
// websocket 主机名
|
StreamID string
|
||||||
Host string `json:"host,omitempty"`
|
}
|
||||||
// 是否启用 SSL
|
|
||||||
UseSSL bool `json:"use_ssl,omitempty"`
|
type TaskNAT struct {
|
||||||
// 会话标识
|
StreamID string
|
||||||
Session string `json:"session,omitempty"`
|
Host string
|
||||||
// Agent在连接Server时需要的额外Cookie信息
|
|
||||||
Cookie string `json:"cookie,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -120,7 +120,7 @@ func (m *Monitor) AfterFind(tx *gorm.DB) error {
|
|||||||
|
|
||||||
// IsServiceSentinelNeeded 判断该任务类型是否需要进行服务监控 需要则返回true
|
// IsServiceSentinelNeeded 判断该任务类型是否需要进行服务监控 需要则返回true
|
||||||
func IsServiceSentinelNeeded(t uint64) bool {
|
func IsServiceSentinelNeeded(t uint64) bool {
|
||||||
return t != TaskTypeCommand && t != TaskTypeTerminal && t != TaskTypeUpgrade
|
return t != TaskTypeCommand && t != TaskTypeTerminalGRPC && t != TaskTypeUpgrade
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Monitor) InitSkipServers() error {
|
func (m *Monitor) InitSkipServers() error {
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type NAT struct {
|
||||||
|
Common
|
||||||
|
Name string
|
||||||
|
ServerID uint64
|
||||||
|
Host string
|
||||||
|
Domain string `gorm:"unique"`
|
||||||
|
}
|
||||||
+28
-3
@@ -42,6 +42,19 @@ func percentage(used, total uint64) float64 {
|
|||||||
return float64(used) * 100 / float64(total)
|
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
|
// Snapshot 未通过规则返回 struct{}{}, 通过返回 nil
|
||||||
func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server, db *gorm.DB) interface{} {
|
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 {
|
switch u.Type {
|
||||||
case "cpu":
|
case "cpu":
|
||||||
src = float64(server.State.CPU)
|
src = float64(server.State.CPU)
|
||||||
|
case "gpu":
|
||||||
|
src = float64(server.State.GPU)
|
||||||
case "memory":
|
case "memory":
|
||||||
src = percentage(server.State.MemUsed, server.Host.MemTotal)
|
src = percentage(server.State.MemUsed, server.Host.MemTotal)
|
||||||
case "swap":
|
case "swap":
|
||||||
@@ -91,21 +106,21 @@ func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server,
|
|||||||
src = float64(server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
|
src = float64(server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
|
||||||
if u.CycleInterval != 0 {
|
if u.CycleInterval != 0 {
|
||||||
var res NResult
|
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)
|
src += float64(res.N)
|
||||||
}
|
}
|
||||||
case "transfer_out_cycle":
|
case "transfer_out_cycle":
|
||||||
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut))
|
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut))
|
||||||
if u.CycleInterval != 0 {
|
if u.CycleInterval != 0 {
|
||||||
var res NResult
|
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)
|
src += float64(res.N)
|
||||||
}
|
}
|
||||||
case "transfer_all_cycle":
|
case "transfer_all_cycle":
|
||||||
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut) + server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
|
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut) + server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
|
||||||
if u.CycleInterval != 0 {
|
if u.CycleInterval != 0 {
|
||||||
var res NResult
|
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)
|
src += float64(res.N)
|
||||||
}
|
}
|
||||||
case "load1":
|
case "load1":
|
||||||
@@ -120,6 +135,16 @@ func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server,
|
|||||||
src = float64(server.State.UdpConnCount)
|
src = float64(server.State.UdpConnCount)
|
||||||
case "process_count":
|
case "process_count":
|
||||||
src = float64(server.State.ProcessCount)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 循环区间流量检测 · 更新下次需要检测时间
|
// 循环区间流量检测 · 更新下次需要检测时间
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type ProviderCloudflare struct {
|
|||||||
Secret string
|
Secret string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderCloudflare) UpdateDomain(domainConfig *DomainConfig) bool {
|
func (provider *ProviderCloudflare) UpdateDomain(domainConfig *DomainConfig) bool {
|
||||||
if domainConfig == nil {
|
if domainConfig == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ func (provider ProviderCloudflare) UpdateDomain(domainConfig *DomainConfig) bool
|
|||||||
return resultV4 && resultV6
|
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)
|
record, err := provider.findDNSRecord(zoneID, domainConfig.FullDomain, isIpv4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("查找 DNS 记录时出错: %s\n", err)
|
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)
|
_, realDomain := SplitDomain(domain)
|
||||||
url := fmt.Sprintf("https://api.cloudflare.com/client/v4/zones?name=%s", realDomain)
|
url := fmt.Sprintf("https://api.cloudflare.com/client/v4/zones?name=%s", realDomain)
|
||||||
body, err := provider.sendRequest("GET", url, nil)
|
body, err := provider.sendRequest("GET", url, nil)
|
||||||
@@ -81,7 +81,7 @@ func (provider ProviderCloudflare) getZoneID(domain string) (string, error) {
|
|||||||
return "", fmt.Errorf("找不到 Zone ID")
|
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"
|
var ipType = "A"
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
ipType = "AAAA"
|
ipType = "AAAA"
|
||||||
@@ -106,7 +106,7 @@ func (provider ProviderCloudflare) findDNSRecord(zoneID string, domain string, i
|
|||||||
return nil, nil // 没有找到 DNS 记录
|
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 ipType = "A"
|
||||||
var ipAddr = domainConfig.Ipv4Addr
|
var ipAddr = domainConfig.Ipv4Addr
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
@@ -126,7 +126,7 @@ func (provider ProviderCloudflare) createDNSRecord(zoneID string, domainConfig *
|
|||||||
return err == nil
|
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 ipType = "A"
|
||||||
var ipAddr = domainConfig.Ipv4Addr
|
var ipAddr = domainConfig.Ipv4Addr
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
@@ -147,7 +147,7 @@ func (provider ProviderCloudflare) updateDNSRecord(zoneID string, recordID strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 以下为辅助方法,如发送 HTTP 请求等
|
// 以下为辅助方法,如发送 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{}
|
client := &http.Client{}
|
||||||
req, err := http.NewRequest(method, url, bytes.NewBuffer(data))
|
req, err := http.NewRequest(method, url, bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+1
-1
@@ -2,6 +2,6 @@ package ddns
|
|||||||
|
|
||||||
type ProviderDummy struct{}
|
type ProviderDummy struct{}
|
||||||
|
|
||||||
func (provider ProviderDummy) UpdateDomain(domainConfig *DomainConfig) bool {
|
func (provider *ProviderDummy) UpdateDomain(domainConfig *DomainConfig) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -23,7 +23,7 @@ type ProviderTencentCloud struct {
|
|||||||
SecretKey string
|
SecretKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) UpdateDomain(domainConfig *DomainConfig) bool {
|
func (provider *ProviderTencentCloud) UpdateDomain(domainConfig *DomainConfig) bool {
|
||||||
if domainConfig == nil {
|
if domainConfig == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ func (provider ProviderTencentCloud) UpdateDomain(domainConfig *DomainConfig) bo
|
|||||||
return resultV4 && resultV6
|
return resultV4 && resultV6
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) addDomainRecord(domainConfig *DomainConfig, isIpv4 bool) bool {
|
func (provider *ProviderTencentCloud) addDomainRecord(domainConfig *DomainConfig, isIpv4 bool) bool {
|
||||||
record, err := provider.findDNSRecord(domainConfig.FullDomain, isIpv4)
|
record, err := provider.findDNSRecord(domainConfig.FullDomain, isIpv4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("查找 DNS 记录时出错: %s\n", err)
|
log.Printf("查找 DNS 记录时出错: %s\n", err)
|
||||||
@@ -66,7 +66,7 @@ func (provider ProviderTencentCloud) addDomainRecord(domainConfig *DomainConfig,
|
|||||||
return provider.updateDNSRecord(domainConfig.FullDomain, record["RecordList"].([]interface{})[0].(map[string]interface{})["RecordId"].(float64), domainConfig, isIpv4)
|
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) {
|
func (provider *ProviderTencentCloud) findDNSRecord(domain string, isIPv4 bool) (map[string]interface{}, error) {
|
||||||
var ipType = "A"
|
var ipType = "A"
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
ipType = "AAAA"
|
ipType = "AAAA"
|
||||||
@@ -95,7 +95,7 @@ func (provider ProviderTencentCloud) findDNSRecord(domain string, isIPv4 bool) (
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) createDNSRecord(domain string, domainConfig *DomainConfig, isIPv4 bool) bool {
|
func (provider *ProviderTencentCloud) createDNSRecord(domain string, domainConfig *DomainConfig, isIPv4 bool) bool {
|
||||||
var ipType = "A"
|
var ipType = "A"
|
||||||
var ipAddr = domainConfig.Ipv4Addr
|
var ipAddr = domainConfig.Ipv4Addr
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
@@ -117,7 +117,7 @@ func (provider ProviderTencentCloud) createDNSRecord(domain string, domainConfig
|
|||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) updateDNSRecord(domain string, recordID float64, domainConfig *DomainConfig, isIPv4 bool) bool {
|
func (provider *ProviderTencentCloud) updateDNSRecord(domain string, recordID float64, domainConfig *DomainConfig, isIPv4 bool) bool {
|
||||||
var ipType = "A"
|
var ipType = "A"
|
||||||
var ipAddr = domainConfig.Ipv4Addr
|
var ipAddr = domainConfig.Ipv4Addr
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
@@ -141,7 +141,7 @@ func (provider ProviderTencentCloud) updateDNSRecord(domain string, recordID flo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 以下为辅助方法,如发送 HTTP 请求等
|
// 以下为辅助方法,如发送 HTTP 请求等
|
||||||
func (provider ProviderTencentCloud) sendRequest(action string, data []byte) ([]byte, error) {
|
func (provider *ProviderTencentCloud) sendRequest(action string, data []byte) ([]byte, error) {
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -173,18 +173,18 @@ func (provider ProviderTencentCloud) sendRequest(action string, data []byte) ([]
|
|||||||
|
|
||||||
// https://github.com/jeessy2/ddns-go/blob/master/util/tencent_cloud_signer.go
|
// https://github.com/jeessy2/ddns-go/blob/master/util/tencent_cloud_signer.go
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) sha256hex(s string) string {
|
func (provider *ProviderTencentCloud) sha256hex(s string) string {
|
||||||
b := sha256.Sum256([]byte(s))
|
b := sha256.Sum256([]byte(s))
|
||||||
return hex.EncodeToString(b[:])
|
return hex.EncodeToString(b[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) hmacsha256(s, key string) string {
|
func (provider *ProviderTencentCloud) hmacsha256(s, key string) string {
|
||||||
hashed := hmac.New(sha256.New, []byte(key))
|
hashed := hmac.New(sha256.New, []byte(key))
|
||||||
hashed.Write([]byte(s))
|
hashed.Write([]byte(s))
|
||||||
return string(hashed.Sum(nil))
|
return string(hashed.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) WriteString(strs ...string) string {
|
func (provider *ProviderTencentCloud) WriteString(strs ...string) string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
for _, str := range strs {
|
for _, str := range strs {
|
||||||
b.WriteString(str)
|
b.WriteString(str)
|
||||||
@@ -193,7 +193,7 @@ func (provider ProviderTencentCloud) WriteString(strs ...string) string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) signRequest(secretId string, secretKey string, r *http.Request, action string, payload string) {
|
func (provider *ProviderTencentCloud) signRequest(secretId string, secretKey string, r *http.Request, action string, payload string) {
|
||||||
algorithm := "TC3-HMAC-SHA256"
|
algorithm := "TC3-HMAC-SHA256"
|
||||||
service := "dnspod"
|
service := "dnspod"
|
||||||
host := provider.WriteString(service, ".tencentcloudapi.com")
|
host := provider.WriteString(service, ".tencentcloudapi.com")
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ type ProviderWebHook struct {
|
|||||||
RequestHeader string
|
RequestHeader string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderWebHook) UpdateDomain(domainConfig *DomainConfig) bool {
|
func (provider *ProviderWebHook) UpdateDomain(domainConfig *DomainConfig) bool {
|
||||||
if domainConfig == nil {
|
if domainConfig == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
stub
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package geoip
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
maxminddb "github.com/oschwald/maxminddb-golang"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed geoip.db
|
||||||
|
var geoDBFS embed.FS
|
||||||
|
|
||||||
|
var (
|
||||||
|
dbData []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
type IPInfo struct {
|
||||||
|
Country string `maxminddb:"country"`
|
||||||
|
CountryName string `maxminddb:"country_name"`
|
||||||
|
Continent string `maxminddb:"continent"`
|
||||||
|
ContinentName string `maxminddb:"continent_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbData, err = geoDBFS.ReadFile("geoip.db")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("NEZHA>> Failed to open geoip database: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Lookup(ip net.IP, record *IPInfo) (string, error) {
|
||||||
|
db, err := maxminddb.FromBytes(dbData)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
err = db.Lookup(ip, record)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if record.Country != "" {
|
||||||
|
return strings.ToLower(record.Country), nil
|
||||||
|
} else if record.Continent != "" {
|
||||||
|
return strings.ToLower(record.Continent), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("IP not found")
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package grpcx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/naiba/nezha/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ io.ReadWriteCloser = &IOStreamWrapper{}
|
||||||
|
|
||||||
|
type IOStream interface {
|
||||||
|
Recv() (*proto.IOStreamData, error)
|
||||||
|
Send(*proto.IOStreamData) error
|
||||||
|
Context() context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
type IOStreamWrapper struct {
|
||||||
|
IOStream
|
||||||
|
dataBuf []byte
|
||||||
|
closed *atomic.Bool
|
||||||
|
closeCh chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIOStreamWrapper(stream IOStream) *IOStreamWrapper {
|
||||||
|
return &IOStreamWrapper{
|
||||||
|
IOStream: stream,
|
||||||
|
closeCh: make(chan struct{}),
|
||||||
|
closed: new(atomic.Bool),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iw *IOStreamWrapper) Read(p []byte) (n int, err error) {
|
||||||
|
if len(iw.dataBuf) > 0 {
|
||||||
|
n := copy(p, iw.dataBuf)
|
||||||
|
iw.dataBuf = iw.dataBuf[n:]
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
var data *proto.IOStreamData
|
||||||
|
if data, err = iw.Recv(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
n = copy(p, data.Data)
|
||||||
|
if n < len(data.Data) {
|
||||||
|
iw.dataBuf = data.Data[n:]
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iw *IOStreamWrapper) Write(p []byte) (n int, err error) {
|
||||||
|
err = iw.Send(&proto.IOStreamData{Data: p})
|
||||||
|
return len(p), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iw *IOStreamWrapper) Close() error {
|
||||||
|
if iw.closed.CompareAndSwap(false, true) {
|
||||||
|
close(iw.closeCh)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iw *IOStreamWrapper) Wait() {
|
||||||
|
<-iw.closeCh
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ var adminPage = map[string]bool{
|
|||||||
"/monitor": true,
|
"/monitor": true,
|
||||||
"/setting": true,
|
"/setting": true,
|
||||||
"/notification": true,
|
"/notification": true,
|
||||||
|
"/nat": true,
|
||||||
"/cron": true,
|
"/cron": true,
|
||||||
"/api": true,
|
"/api": true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package general
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/naiba/nezha/model"
|
||||||
|
"github.com/naiba/nezha/service/singleton"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserInfo struct {
|
||||||
|
Sub string `json:"sub"`
|
||||||
|
Username string `json:"preferred_username"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Groups []string `json:"groups,omitempty"`
|
||||||
|
Roles []string `json:"roles,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UserInfo) MapToNezhaUser(loginClaim string, groupClaim string, adminGroups []string, autoCreate bool) model.User {
|
||||||
|
var user model.User
|
||||||
|
var login string
|
||||||
|
var groups []string
|
||||||
|
var isAdmin bool
|
||||||
|
if loginClaim == "email" {
|
||||||
|
login = u.Email
|
||||||
|
} else if loginClaim == "preferred_username" {
|
||||||
|
login = u.Username
|
||||||
|
} else {
|
||||||
|
login = u.Sub
|
||||||
|
}
|
||||||
|
if groupClaim == "roles" {
|
||||||
|
groups = u.Roles
|
||||||
|
} else {
|
||||||
|
groups = u.Groups
|
||||||
|
}
|
||||||
|
// Check if user is admin
|
||||||
|
adminGroupSet := make(map[string]struct{}, len(adminGroups))
|
||||||
|
for _, adminGroup := range adminGroups {
|
||||||
|
adminGroupSet[adminGroup] = struct{}{}
|
||||||
|
}
|
||||||
|
for _, group := range groups {
|
||||||
|
if _, found := adminGroupSet[group]; found {
|
||||||
|
isAdmin = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result := singleton.DB.Where("login = ?", login).First(&user)
|
||||||
|
user.Login = login
|
||||||
|
user.Email = u.Email
|
||||||
|
user.Name = u.Name
|
||||||
|
user.SuperAdmin = isAdmin
|
||||||
|
if result.Error != nil && autoCreate {
|
||||||
|
singleton.DB.Create(&user)
|
||||||
|
} else if result.Error != nil {
|
||||||
|
return model.User{}
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ io.ReadWriteCloser = &RequestWrapper{}
|
||||||
|
|
||||||
|
type RequestWrapper struct {
|
||||||
|
req *http.Request
|
||||||
|
reader *bytes.Buffer
|
||||||
|
writer net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRequestWrapper(req *http.Request, writer gin.ResponseWriter) (*RequestWrapper, error) {
|
||||||
|
conn, _, err := writer.Hijack()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
if err = req.Write(buf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &RequestWrapper{
|
||||||
|
req: req,
|
||||||
|
reader: buf,
|
||||||
|
writer: conn,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *RequestWrapper) Read(p []byte) (int, error) {
|
||||||
|
count, err := rw.reader.Read(p)
|
||||||
|
if err == nil {
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
if err != io.EOF {
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
// request 数据读完之后等待客户端断开连接或 grpc 超时
|
||||||
|
return rw.writer.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *RequestWrapper) Write(p []byte) (int, error) {
|
||||||
|
return rw.writer.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *RequestWrapper) Close() error {
|
||||||
|
rw.req.Body.Close()
|
||||||
|
rw.writer.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+41
-10
@@ -1,25 +1,56 @@
|
|||||||
package websocketx
|
package websocketx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/samber/lo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ io.ReadWriteCloser = &Conn{}
|
||||||
|
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
*websocket.Conn
|
*websocket.Conn
|
||||||
writeLock sync.Mutex
|
writeLock *sync.Mutex
|
||||||
|
dataBuf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) WriteMessage(msgType int, data []byte) error {
|
func NewConn(conn *websocket.Conn) *Conn {
|
||||||
|
return &Conn{Conn: conn, writeLock: new(sync.Mutex)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *Conn) Write(data []byte) (int, error) {
|
||||||
conn.writeLock.Lock()
|
conn.writeLock.Lock()
|
||||||
defer conn.writeLock.Unlock()
|
defer conn.writeLock.Unlock()
|
||||||
var err error
|
if err := conn.Conn.WriteMessage(websocket.BinaryMessage, data); err != nil {
|
||||||
lo.TryCatchWithErrorValue(func() error {
|
return 0, err
|
||||||
return conn.Conn.WriteMessage(msgType, data)
|
}
|
||||||
}, func(res any) {
|
return len(data), nil
|
||||||
err = res.(error)
|
}
|
||||||
})
|
|
||||||
return err
|
func (conn *Conn) WriteMessage(messageType int, data []byte) error {
|
||||||
|
conn.writeLock.Lock()
|
||||||
|
defer conn.writeLock.Unlock()
|
||||||
|
return conn.Conn.WriteMessage(messageType, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *Conn) Read(data []byte) (int, error) {
|
||||||
|
if len(conn.dataBuf) > 0 {
|
||||||
|
n := copy(data, conn.dataBuf)
|
||||||
|
conn.dataBuf = conn.dataBuf[n:]
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
mType, innerData, err := conn.Conn.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
// 将文本消息转换为命令输入
|
||||||
|
if mType == websocket.TextMessage {
|
||||||
|
innerData = append([]byte{0}, innerData...)
|
||||||
|
}
|
||||||
|
n := copy(data, innerData)
|
||||||
|
if n < len(innerData) {
|
||||||
|
conn.dataBuf = innerData[n:]
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+358
-109
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.30.0
|
// protoc-gen-go v1.34.1
|
||||||
// protoc v3.21.12
|
// protoc v5.26.1
|
||||||
// source: proto/nezha.proto
|
// source: proto/nezha.proto
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
@@ -35,8 +35,9 @@ type Host struct {
|
|||||||
Virtualization string `protobuf:"bytes,8,opt,name=virtualization,proto3" json:"virtualization,omitempty"`
|
Virtualization string `protobuf:"bytes,8,opt,name=virtualization,proto3" json:"virtualization,omitempty"`
|
||||||
BootTime uint64 `protobuf:"varint,9,opt,name=boot_time,json=bootTime,proto3" json:"boot_time,omitempty"`
|
BootTime uint64 `protobuf:"varint,9,opt,name=boot_time,json=bootTime,proto3" json:"boot_time,omitempty"`
|
||||||
Ip string `protobuf:"bytes,10,opt,name=ip,proto3" json:"ip,omitempty"`
|
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"`
|
CountryCode string `protobuf:"bytes,11,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"` // deprecated
|
||||||
Version string `protobuf:"bytes,12,opt,name=version,proto3" json:"version,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() {
|
func (x *Host) Reset() {
|
||||||
@@ -155,26 +156,35 @@ func (x *Host) GetVersion() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Host) GetGpu() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Gpu
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Cpu float64 `protobuf:"fixed64,1,opt,name=cpu,proto3" json:"cpu,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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
Uptime uint64 `protobuf:"varint,10,opt,name=uptime,proto3" json:"uptime,omitempty"`
|
||||||
Load1 float64 `protobuf:"fixed64,11,opt,name=load1,proto3" json:"load1,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"`
|
Load5 float64 `protobuf:"fixed64,12,opt,name=load5,proto3" json:"load5,omitempty"`
|
||||||
Load15 float64 `protobuf:"fixed64,13,opt,name=load15,proto3" json:"load15,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"`
|
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"`
|
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"`
|
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() {
|
func (x *State) Reset() {
|
||||||
@@ -314,6 +324,75 @@ func (x *State) GetProcessCount() uint64 {
|
|||||||
return 0
|
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 {
|
type Task struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -327,7 +406,7 @@ type Task struct {
|
|||||||
func (x *Task) Reset() {
|
func (x *Task) Reset() {
|
||||||
*x = Task{}
|
*x = Task{}
|
||||||
if protoimpl.UnsafeEnabled {
|
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 := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -340,7 +419,7 @@ func (x *Task) String() string {
|
|||||||
func (*Task) ProtoMessage() {}
|
func (*Task) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Task) ProtoReflect() protoreflect.Message {
|
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 {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -353,7 +432,7 @@ func (x *Task) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Task.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Task.ProtoReflect.Descriptor instead.
|
||||||
func (*Task) Descriptor() ([]byte, []int) {
|
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 {
|
func (x *Task) GetId() uint64 {
|
||||||
@@ -392,7 +471,7 @@ type TaskResult struct {
|
|||||||
func (x *TaskResult) Reset() {
|
func (x *TaskResult) Reset() {
|
||||||
*x = TaskResult{}
|
*x = TaskResult{}
|
||||||
if protoimpl.UnsafeEnabled {
|
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 := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -405,7 +484,7 @@ func (x *TaskResult) String() string {
|
|||||||
func (*TaskResult) ProtoMessage() {}
|
func (*TaskResult) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *TaskResult) ProtoReflect() protoreflect.Message {
|
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 {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -418,7 +497,7 @@ func (x *TaskResult) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use TaskResult.ProtoReflect.Descriptor instead.
|
// Deprecated: Use TaskResult.ProtoReflect.Descriptor instead.
|
||||||
func (*TaskResult) Descriptor() ([]byte, []int) {
|
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 {
|
func (x *TaskResult) GetId() uint64 {
|
||||||
@@ -467,7 +546,7 @@ type Receipt struct {
|
|||||||
func (x *Receipt) Reset() {
|
func (x *Receipt) Reset() {
|
||||||
*x = Receipt{}
|
*x = Receipt{}
|
||||||
if protoimpl.UnsafeEnabled {
|
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 := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -480,7 +559,7 @@ func (x *Receipt) String() string {
|
|||||||
func (*Receipt) ProtoMessage() {}
|
func (*Receipt) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Receipt) ProtoReflect() protoreflect.Message {
|
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 {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -493,7 +572,7 @@ func (x *Receipt) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Receipt.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Receipt.ProtoReflect.Descriptor instead.
|
||||||
func (*Receipt) Descriptor() ([]byte, []int) {
|
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 {
|
func (x *Receipt) GetProced() bool {
|
||||||
@@ -503,11 +582,113 @@ func (x *Receipt) GetProced() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IOStreamData struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *IOStreamData) Reset() {
|
||||||
|
*x = IOStreamData{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_proto_nezha_proto_msgTypes[6]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *IOStreamData) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*IOStreamData) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *IOStreamData) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_proto_nezha_proto_msgTypes[6]
|
||||||
|
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 IOStreamData.ProtoReflect.Descriptor instead.
|
||||||
|
func (*IOStreamData) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proto_nezha_proto_rawDescGZIP(), []int{6}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *IOStreamData) GetData() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Data
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GeoIP struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"`
|
||||||
|
CountryCode string `protobuf:"bytes,2,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GeoIP) Reset() {
|
||||||
|
*x = GeoIP{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_proto_nezha_proto_msgTypes[7]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GeoIP) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GeoIP) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GeoIP) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_proto_nezha_proto_msgTypes[7]
|
||||||
|
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 GeoIP.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GeoIP) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proto_nezha_proto_rawDescGZIP(), []int{7}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GeoIP) GetIp() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Ip
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GeoIP) GetCountryCode() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.CountryCode
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
var File_proto_nezha_proto protoreflect.FileDescriptor
|
var File_proto_nezha_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_proto_nezha_proto_rawDesc = []byte{
|
var file_proto_nezha_proto_rawDesc = []byte{
|
||||||
0x0a, 0x11, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6e, 0x65, 0x7a, 0x68, 0x61, 0x2e, 0x70, 0x72,
|
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,
|
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,
|
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,
|
0x29, 0x0a, 0x10, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73,
|
||||||
@@ -529,65 +710,89 @@ var file_proto_nezha_proto_rawDesc = []byte{
|
|||||||
0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65,
|
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,
|
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,
|
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,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a,
|
||||||
0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x01,
|
0x03, 0x67, 0x70, 0x75, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x67, 0x70, 0x75, 0x22,
|
||||||
0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x65, 0x6d,
|
0xa9, 0x04, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x70, 0x75,
|
||||||
0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d, 0x65, 0x6d,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x19, 0x0a, 0x08, 0x6d,
|
||||||
0x55, 0x73, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x75, 0x73, 0x65,
|
0x65, 0x6d, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d,
|
||||||
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x77, 0x61, 0x70, 0x55, 0x73, 0x65,
|
0x65, 0x6d, 0x55, 0x73, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x75,
|
||||||
0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x05,
|
0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x77, 0x61, 0x70, 0x55,
|
||||||
0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x65, 0x64, 0x12, 0x26,
|
0x73, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x75, 0x73, 0x65, 0x64,
|
||||||
0x0a, 0x0f, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65,
|
0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x65, 0x64,
|
||||||
0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6e, 0x65, 0x74, 0x49, 0x6e, 0x54, 0x72,
|
0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73,
|
||||||
0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x6e, 0x65, 0x74, 0x5f, 0x6f, 0x75,
|
0x66, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6e, 0x65, 0x74, 0x49, 0x6e,
|
||||||
0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04,
|
0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x6e, 0x65, 0x74, 0x5f,
|
||||||
0x52, 0x0e, 0x6e, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72,
|
0x6f, 0x75, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01,
|
||||||
0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64,
|
0x28, 0x04, 0x52, 0x0e, 0x6e, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66,
|
||||||
0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x49, 0x6e, 0x53, 0x70, 0x65,
|
0x65, 0x72, 0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x5f, 0x73, 0x70, 0x65,
|
||||||
0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x70,
|
0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x49, 0x6e, 0x53,
|
||||||
0x65, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x4f, 0x75,
|
0x70, 0x65, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x5f,
|
||||||
0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
|
0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6e, 0x65, 0x74,
|
||||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14,
|
0x4f, 0x75, 0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69,
|
||||||
0x0a, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x31, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x6c,
|
0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
|
||||||
0x6f, 0x61, 0x64, 0x31, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x35, 0x18, 0x0c, 0x20,
|
0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x31, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52,
|
||||||
0x01, 0x28, 0x01, 0x52, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x35, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x6f,
|
0x05, 0x6c, 0x6f, 0x61, 0x64, 0x31, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x35, 0x18,
|
||||||
0x61, 0x64, 0x31, 0x35, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x6c, 0x6f, 0x61, 0x64,
|
0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x35, 0x12, 0x16, 0x0a, 0x06,
|
||||||
0x31, 0x35, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x63,
|
0x6c, 0x6f, 0x61, 0x64, 0x31, 0x35, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x6c, 0x6f,
|
||||||
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x74, 0x63, 0x70, 0x43,
|
0x61, 0x64, 0x31, 0x35, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e,
|
||||||
0x6f, 0x6e, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x75, 0x64, 0x70, 0x5f,
|
0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x74, 0x63,
|
||||||
0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04,
|
0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x75, 0x64,
|
||||||
0x52, 0x0c, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23,
|
0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01,
|
||||||
0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18,
|
0x28, 0x04, 0x52, 0x0c, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74,
|
||||||
0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f,
|
0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e,
|
||||||
0x75, 0x6e, 0x74, 0x22, 0x3e, 0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
|
||||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74,
|
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x0c, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61,
|
||||||
0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12,
|
0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72,
|
||||||
0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64,
|
0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72,
|
||||||
0x61, 0x74, 0x61, 0x22, 0x7a, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c,
|
0x54, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0c, 0x74, 0x65, 0x6d,
|
||||||
0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69,
|
0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x70, 0x75,
|
||||||
0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
|
0x18, 0x12, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x67, 0x70, 0x75, 0x22, 0x4f, 0x0a, 0x17, 0x53,
|
||||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03,
|
0x74, 0x61, 0x74, 0x65, 0x5f, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x54, 0x65, 0x6d, 0x70, 0x65,
|
||||||
0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64,
|
0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
|
||||||
0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x65,
|
||||||
0x1e, 0x0a, 0x0a, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, 0x05, 0x20,
|
0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52,
|
||||||
0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x22,
|
0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x3e, 0x0a, 0x04,
|
||||||
0x21, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72,
|
0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
|
||||||
0x6f, 0x63, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x63,
|
0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||||
0x65, 0x64, 0x32, 0xd6, 0x01, 0x0a, 0x0c, 0x4e, 0x65, 0x7a, 0x68, 0x61, 0x53, 0x65, 0x72, 0x76,
|
0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61,
|
||||||
0x69, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73,
|
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x7a, 0x0a, 0x0a,
|
||||||
0x74, 0x65, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
|
||||||
0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79,
|
||||||
0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f,
|
0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14,
|
||||||
0x72, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, 0x2e, 0x70,
|
0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x64,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
0x65, 0x6c, 0x61, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01,
|
||||||
0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0a, 0x52,
|
0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x75, 0x63, 0x63,
|
||||||
0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x75,
|
||||||
0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x0e, 0x2e, 0x70,
|
0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x22, 0x21, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x65,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x2b,
|
0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x18, 0x01, 0x20,
|
||||||
0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0b, 0x2e,
|
0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x22, 0x22, 0x0a, 0x0c, 0x49,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f,
|
0x4f, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x64,
|
||||||
0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x00, 0x30, 0x01, 0x42, 0x09, 0x5a, 0x07, 0x2e,
|
0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22,
|
||||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x3a, 0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e,
|
||||||
|
0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
|
||||||
|
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x32, 0xbf, 0x02, 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, 0x12, 0x3a, 0x0a, 0x08, 0x49, 0x4f, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
|
||||||
|
0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x4f, 0x53, 0x74, 0x72, 0x65, 0x61,
|
||||||
|
0x6d, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x4f,
|
||||||
|
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01,
|
||||||
|
0x12, 0x2b, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12,
|
||||||
|
0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x1a, 0x0c, 0x2e,
|
||||||
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x22, 0x00, 0x42, 0x09, 0x5a,
|
||||||
|
0x07, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -602,28 +807,36 @@ func file_proto_nezha_proto_rawDescGZIP() []byte {
|
|||||||
return file_proto_nezha_proto_rawDescData
|
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, 8)
|
||||||
var file_proto_nezha_proto_goTypes = []interface{}{
|
var file_proto_nezha_proto_goTypes = []interface{}{
|
||||||
(*Host)(nil), // 0: proto.Host
|
(*Host)(nil), // 0: proto.Host
|
||||||
(*State)(nil), // 1: proto.State
|
(*State)(nil), // 1: proto.State
|
||||||
(*Task)(nil), // 2: proto.Task
|
(*State_SensorTemperature)(nil), // 2: proto.State_SensorTemperature
|
||||||
(*TaskResult)(nil), // 3: proto.TaskResult
|
(*Task)(nil), // 3: proto.Task
|
||||||
(*Receipt)(nil), // 4: proto.Receipt
|
(*TaskResult)(nil), // 4: proto.TaskResult
|
||||||
|
(*Receipt)(nil), // 5: proto.Receipt
|
||||||
|
(*IOStreamData)(nil), // 6: proto.IOStreamData
|
||||||
|
(*GeoIP)(nil), // 7: proto.GeoIP
|
||||||
}
|
}
|
||||||
var file_proto_nezha_proto_depIdxs = []int32{
|
var file_proto_nezha_proto_depIdxs = []int32{
|
||||||
1, // 0: proto.NezhaService.ReportSystemState:input_type -> proto.State
|
2, // 0: proto.State.temperatures:type_name -> proto.State_SensorTemperature
|
||||||
0, // 1: proto.NezhaService.ReportSystemInfo:input_type -> proto.Host
|
1, // 1: proto.NezhaService.ReportSystemState:input_type -> proto.State
|
||||||
3, // 2: proto.NezhaService.ReportTask:input_type -> proto.TaskResult
|
0, // 2: proto.NezhaService.ReportSystemInfo:input_type -> proto.Host
|
||||||
0, // 3: proto.NezhaService.RequestTask:input_type -> proto.Host
|
4, // 3: proto.NezhaService.ReportTask:input_type -> proto.TaskResult
|
||||||
4, // 4: proto.NezhaService.ReportSystemState:output_type -> proto.Receipt
|
0, // 4: proto.NezhaService.RequestTask:input_type -> proto.Host
|
||||||
4, // 5: proto.NezhaService.ReportSystemInfo:output_type -> proto.Receipt
|
6, // 5: proto.NezhaService.IOStream:input_type -> proto.IOStreamData
|
||||||
4, // 6: proto.NezhaService.ReportTask:output_type -> proto.Receipt
|
7, // 6: proto.NezhaService.LookupGeoIP:input_type -> proto.GeoIP
|
||||||
2, // 7: proto.NezhaService.RequestTask:output_type -> proto.Task
|
5, // 7: proto.NezhaService.ReportSystemState:output_type -> proto.Receipt
|
||||||
4, // [4:8] is the sub-list for method output_type
|
5, // 8: proto.NezhaService.ReportSystemInfo:output_type -> proto.Receipt
|
||||||
0, // [0:4] is the sub-list for method input_type
|
5, // 9: proto.NezhaService.ReportTask:output_type -> proto.Receipt
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
3, // 10: proto.NezhaService.RequestTask:output_type -> proto.Task
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
6, // 11: proto.NezhaService.IOStream:output_type -> proto.IOStreamData
|
||||||
0, // [0:0] is the sub-list for field type_name
|
7, // 12: proto.NezhaService.LookupGeoIP:output_type -> proto.GeoIP
|
||||||
|
7, // [7:13] is the sub-list for method output_type
|
||||||
|
1, // [1:7] 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() }
|
func init() { file_proto_nezha_proto_init() }
|
||||||
@@ -657,7 +870,7 @@ func file_proto_nezha_proto_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_proto_nezha_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
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:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
case 1:
|
case 1:
|
||||||
@@ -669,7 +882,7 @@ func file_proto_nezha_proto_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_proto_nezha_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
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:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
case 1:
|
case 1:
|
||||||
@@ -681,6 +894,18 @@ func file_proto_nezha_proto_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_proto_nezha_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
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 {
|
switch v := v.(*Receipt); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -692,6 +917,30 @@ func file_proto_nezha_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
file_proto_nezha_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*IOStreamData); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_proto_nezha_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*GeoIP); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
@@ -699,7 +948,7 @@ func file_proto_nezha_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_proto_nezha_proto_rawDesc,
|
RawDescriptor: file_proto_nezha_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 5,
|
NumMessages: 8,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
+20
-1
@@ -8,6 +8,8 @@ service NezhaService {
|
|||||||
rpc ReportSystemInfo(Host)returns(Receipt){}
|
rpc ReportSystemInfo(Host)returns(Receipt){}
|
||||||
rpc ReportTask(TaskResult)returns(Receipt){}
|
rpc ReportTask(TaskResult)returns(Receipt){}
|
||||||
rpc RequestTask(Host)returns(stream Task){}
|
rpc RequestTask(Host)returns(stream Task){}
|
||||||
|
rpc IOStream(stream IOStreamData)returns(stream IOStreamData){}
|
||||||
|
rpc LookupGeoIP(GeoIP)returns(GeoIP){}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Host {
|
message Host {
|
||||||
@@ -21,8 +23,9 @@ message Host {
|
|||||||
string virtualization = 8;
|
string virtualization = 8;
|
||||||
uint64 boot_time = 9;
|
uint64 boot_time = 9;
|
||||||
string ip = 10;
|
string ip = 10;
|
||||||
string country_code = 11;
|
string country_code = 11; // deprecated
|
||||||
string version = 12;
|
string version = 12;
|
||||||
|
repeated string gpu = 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
message State {
|
message State {
|
||||||
@@ -41,6 +44,13 @@ message State {
|
|||||||
uint64 tcp_conn_count = 14;
|
uint64 tcp_conn_count = 14;
|
||||||
uint64 udp_conn_count = 15;
|
uint64 udp_conn_count = 15;
|
||||||
uint64 process_count = 16;
|
uint64 process_count = 16;
|
||||||
|
repeated State_SensorTemperature temperatures = 17;
|
||||||
|
double gpu = 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
message State_SensorTemperature {
|
||||||
|
string name = 1;
|
||||||
|
double temperature = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Task {
|
message Task {
|
||||||
@@ -60,3 +70,12 @@ message TaskResult {
|
|||||||
message Receipt{
|
message Receipt{
|
||||||
bool proced = 1;
|
bool proced = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message IOStreamData {
|
||||||
|
bytes data = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GeoIP {
|
||||||
|
string ip = 1;
|
||||||
|
string country_code = 2;
|
||||||
|
}
|
||||||
+107
-1
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.3.0
|
// - protoc-gen-go-grpc v1.3.0
|
||||||
// - protoc v3.21.12
|
// - protoc v5.26.1
|
||||||
// source: proto/nezha.proto
|
// source: proto/nezha.proto
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
@@ -23,6 +23,8 @@ const (
|
|||||||
NezhaService_ReportSystemInfo_FullMethodName = "/proto.NezhaService/ReportSystemInfo"
|
NezhaService_ReportSystemInfo_FullMethodName = "/proto.NezhaService/ReportSystemInfo"
|
||||||
NezhaService_ReportTask_FullMethodName = "/proto.NezhaService/ReportTask"
|
NezhaService_ReportTask_FullMethodName = "/proto.NezhaService/ReportTask"
|
||||||
NezhaService_RequestTask_FullMethodName = "/proto.NezhaService/RequestTask"
|
NezhaService_RequestTask_FullMethodName = "/proto.NezhaService/RequestTask"
|
||||||
|
NezhaService_IOStream_FullMethodName = "/proto.NezhaService/IOStream"
|
||||||
|
NezhaService_LookupGeoIP_FullMethodName = "/proto.NezhaService/LookupGeoIP"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NezhaServiceClient is the client API for NezhaService service.
|
// NezhaServiceClient is the client API for NezhaService service.
|
||||||
@@ -33,6 +35,8 @@ type NezhaServiceClient interface {
|
|||||||
ReportSystemInfo(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error)
|
ReportSystemInfo(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error)
|
||||||
ReportTask(ctx context.Context, in *TaskResult, opts ...grpc.CallOption) (*Receipt, error)
|
ReportTask(ctx context.Context, in *TaskResult, opts ...grpc.CallOption) (*Receipt, error)
|
||||||
RequestTask(ctx context.Context, in *Host, opts ...grpc.CallOption) (NezhaService_RequestTaskClient, error)
|
RequestTask(ctx context.Context, in *Host, opts ...grpc.CallOption) (NezhaService_RequestTaskClient, error)
|
||||||
|
IOStream(ctx context.Context, opts ...grpc.CallOption) (NezhaService_IOStreamClient, error)
|
||||||
|
LookupGeoIP(ctx context.Context, in *GeoIP, opts ...grpc.CallOption) (*GeoIP, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type nezhaServiceClient struct {
|
type nezhaServiceClient struct {
|
||||||
@@ -102,6 +106,46 @@ func (x *nezhaServiceRequestTaskClient) Recv() (*Task, error) {
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *nezhaServiceClient) IOStream(ctx context.Context, opts ...grpc.CallOption) (NezhaService_IOStreamClient, error) {
|
||||||
|
stream, err := c.cc.NewStream(ctx, &NezhaService_ServiceDesc.Streams[1], NezhaService_IOStream_FullMethodName, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x := &nezhaServiceIOStreamClient{stream}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NezhaService_IOStreamClient interface {
|
||||||
|
Send(*IOStreamData) error
|
||||||
|
Recv() (*IOStreamData, error)
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type nezhaServiceIOStreamClient struct {
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nezhaServiceIOStreamClient) Send(m *IOStreamData) error {
|
||||||
|
return x.ClientStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nezhaServiceIOStreamClient) Recv() (*IOStreamData, error) {
|
||||||
|
m := new(IOStreamData)
|
||||||
|
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nezhaServiceClient) LookupGeoIP(ctx context.Context, in *GeoIP, opts ...grpc.CallOption) (*GeoIP, error) {
|
||||||
|
out := new(GeoIP)
|
||||||
|
err := c.cc.Invoke(ctx, NezhaService_LookupGeoIP_FullMethodName, in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// NezhaServiceServer is the server API for NezhaService service.
|
// NezhaServiceServer is the server API for NezhaService service.
|
||||||
// All implementations should embed UnimplementedNezhaServiceServer
|
// All implementations should embed UnimplementedNezhaServiceServer
|
||||||
// for forward compatibility
|
// for forward compatibility
|
||||||
@@ -110,6 +154,8 @@ type NezhaServiceServer interface {
|
|||||||
ReportSystemInfo(context.Context, *Host) (*Receipt, error)
|
ReportSystemInfo(context.Context, *Host) (*Receipt, error)
|
||||||
ReportTask(context.Context, *TaskResult) (*Receipt, error)
|
ReportTask(context.Context, *TaskResult) (*Receipt, error)
|
||||||
RequestTask(*Host, NezhaService_RequestTaskServer) error
|
RequestTask(*Host, NezhaService_RequestTaskServer) error
|
||||||
|
IOStream(NezhaService_IOStreamServer) error
|
||||||
|
LookupGeoIP(context.Context, *GeoIP) (*GeoIP, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnimplementedNezhaServiceServer should be embedded to have forward compatible implementations.
|
// UnimplementedNezhaServiceServer should be embedded to have forward compatible implementations.
|
||||||
@@ -128,6 +174,12 @@ func (UnimplementedNezhaServiceServer) ReportTask(context.Context, *TaskResult)
|
|||||||
func (UnimplementedNezhaServiceServer) RequestTask(*Host, NezhaService_RequestTaskServer) error {
|
func (UnimplementedNezhaServiceServer) RequestTask(*Host, NezhaService_RequestTaskServer) error {
|
||||||
return status.Errorf(codes.Unimplemented, "method RequestTask not implemented")
|
return status.Errorf(codes.Unimplemented, "method RequestTask not implemented")
|
||||||
}
|
}
|
||||||
|
func (UnimplementedNezhaServiceServer) IOStream(NezhaService_IOStreamServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method IOStream not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNezhaServiceServer) LookupGeoIP(context.Context, *GeoIP) (*GeoIP, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method LookupGeoIP not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
// UnsafeNezhaServiceServer may be embedded to opt out of forward compatibility for this service.
|
// UnsafeNezhaServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
// Use of this interface is not recommended, as added methods to NezhaServiceServer will
|
// Use of this interface is not recommended, as added methods to NezhaServiceServer will
|
||||||
@@ -215,6 +267,50 @@ func (x *nezhaServiceRequestTaskServer) Send(m *Task) error {
|
|||||||
return x.ServerStream.SendMsg(m)
|
return x.ServerStream.SendMsg(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _NezhaService_IOStream_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||||
|
return srv.(NezhaServiceServer).IOStream(&nezhaServiceIOStreamServer{stream})
|
||||||
|
}
|
||||||
|
|
||||||
|
type NezhaService_IOStreamServer interface {
|
||||||
|
Send(*IOStreamData) error
|
||||||
|
Recv() (*IOStreamData, error)
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type nezhaServiceIOStreamServer struct {
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nezhaServiceIOStreamServer) Send(m *IOStreamData) error {
|
||||||
|
return x.ServerStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nezhaServiceIOStreamServer) Recv() (*IOStreamData, error) {
|
||||||
|
m := new(IOStreamData)
|
||||||
|
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func _NezhaService_LookupGeoIP_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GeoIP)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(NezhaServiceServer).LookupGeoIP(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: NezhaService_LookupGeoIP_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(NezhaServiceServer).LookupGeoIP(ctx, req.(*GeoIP))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
// NezhaService_ServiceDesc is the grpc.ServiceDesc for NezhaService service.
|
// NezhaService_ServiceDesc is the grpc.ServiceDesc for NezhaService service.
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
// and not to be introspected or modified (even as a copy)
|
// and not to be introspected or modified (even as a copy)
|
||||||
@@ -234,6 +330,10 @@ var NezhaService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "ReportTask",
|
MethodName: "ReportTask",
|
||||||
Handler: _NezhaService_ReportTask_Handler,
|
Handler: _NezhaService_ReportTask_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "LookupGeoIP",
|
||||||
|
Handler: _NezhaService_LookupGeoIP_Handler,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{
|
Streams: []grpc.StreamDesc{
|
||||||
{
|
{
|
||||||
@@ -241,6 +341,12 @@ var NezhaService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
Handler: _NezhaService_RequestTask_Handler,
|
Handler: _NezhaService_RequestTask_Handler,
|
||||||
ServerStreams: true,
|
ServerStreams: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
StreamName: "IOStream",
|
||||||
|
Handler: _NezhaService_IOStream_Handler,
|
||||||
|
ServerStreams: true,
|
||||||
|
ClientStreams: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Metadata: "proto/nezha.proto",
|
Metadata: "proto/nezha.proto",
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+6
@@ -640,8 +640,14 @@ other = "Template"
|
|||||||
[Stat]
|
[Stat]
|
||||||
other = "Asset"
|
other = "Asset"
|
||||||
|
|
||||||
|
[Temperature]
|
||||||
|
other = "Temperature"
|
||||||
|
|
||||||
[DisableSwitchTemplateInFrontend]
|
[DisableSwitchTemplateInFrontend]
|
||||||
other = "Disable Switch Template in Frontend"
|
other = "Disable Switch Template in Frontend"
|
||||||
|
|
||||||
[ServersOnWorldMap]
|
[ServersOnWorldMap]
|
||||||
other = "Servers On World Map"
|
other = "Servers On World Map"
|
||||||
|
|
||||||
|
[NAT]
|
||||||
|
other = "NAT"
|
||||||
Vendored
+7
-1
@@ -640,8 +640,14 @@ other = "Plantilla"
|
|||||||
[Stat]
|
[Stat]
|
||||||
other = "Stat"
|
other = "Stat"
|
||||||
|
|
||||||
|
[Temperature]
|
||||||
|
other = "Temperatura"
|
||||||
|
|
||||||
[DisableSwitchTemplateInFrontend]
|
[DisableSwitchTemplateInFrontend]
|
||||||
other = "Deshabilitar Cambio de Plantilla en Frontend"
|
other = "Deshabilitar Cambio de Plantilla en Frontend"
|
||||||
|
|
||||||
[ServersOnWorldMap]
|
[ServersOnWorldMap]
|
||||||
other = "Servidores en el mapa mundial"
|
other = "Servidores en el mapa mundial"
|
||||||
|
|
||||||
|
[NAT]
|
||||||
|
other = "NAT"
|
||||||
Vendored
+6
@@ -640,8 +640,14 @@ other = "主题"
|
|||||||
[Stat]
|
[Stat]
|
||||||
other = "信息"
|
other = "信息"
|
||||||
|
|
||||||
|
[Temperature]
|
||||||
|
other = "温度"
|
||||||
|
|
||||||
[DisableSwitchTemplateInFrontend]
|
[DisableSwitchTemplateInFrontend]
|
||||||
other = "禁止前台切换模板"
|
other = "禁止前台切换模板"
|
||||||
|
|
||||||
[ServersOnWorldMap]
|
[ServersOnWorldMap]
|
||||||
other = "服务器世界分布图"
|
other = "服务器世界分布图"
|
||||||
|
|
||||||
|
[NAT]
|
||||||
|
other = "内网穿透"
|
||||||
Vendored
+6
@@ -640,8 +640,14 @@ other = "主題"
|
|||||||
[Stat]
|
[Stat]
|
||||||
other = "信息"
|
other = "信息"
|
||||||
|
|
||||||
|
[Temperature]
|
||||||
|
other = "溫度"
|
||||||
|
|
||||||
[DisableSwitchTemplateInFrontend]
|
[DisableSwitchTemplateInFrontend]
|
||||||
other = "禁止前台切換主題"
|
other = "禁止前台切換主題"
|
||||||
|
|
||||||
[ServersOnWorldMap]
|
[ServersOnWorldMap]
|
||||||
other = "伺服器世界分布圖"
|
other = "伺服器世界分布圖"
|
||||||
|
|
||||||
|
[NAT]
|
||||||
|
other = "NAT"
|
||||||
@@ -91,6 +91,7 @@ function showFormModal(modelSelector, formID, URL, getData) {
|
|||||||
item.name.endsWith("_id") ||
|
item.name.endsWith("_id") ||
|
||||||
item.name === "id" ||
|
item.name === "id" ||
|
||||||
item.name === "ID" ||
|
item.name === "ID" ||
|
||||||
|
item.name === "ServerID" ||
|
||||||
item.name === "RequestType" ||
|
item.name === "RequestType" ||
|
||||||
item.name === "RequestMethod" ||
|
item.name === "RequestMethod" ||
|
||||||
item.name === "TriggerMode" ||
|
item.name === "TriggerMode" ||
|
||||||
@@ -255,6 +256,28 @@ function addOrEditNotification(notification) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addOrEditNAT(nat) {
|
||||||
|
const modal = $(".nat.modal");
|
||||||
|
modal.children(".header").text((nat ? LANG.Edit : LANG.Add));
|
||||||
|
modal
|
||||||
|
.find(".nezha-primary-btn.button")
|
||||||
|
.html(
|
||||||
|
nat
|
||||||
|
? LANG.Edit + '<i class="edit icon"></i>'
|
||||||
|
: LANG.Add + '<i class="add icon"></i>'
|
||||||
|
);
|
||||||
|
modal.find("input[name=ID]").val(nat ? nat.ID : null);
|
||||||
|
modal.find("input[name=ServerID]").val(nat ? nat.ServerID : null);
|
||||||
|
modal.find("input[name=Name]").val(nat ? nat.Name : null);
|
||||||
|
modal.find("input[name=Host]").val(nat ? nat.Host : null);
|
||||||
|
modal.find("input[name=Domain]").val(nat ? nat.Domain : null);
|
||||||
|
showFormModal(
|
||||||
|
".nat.modal",
|
||||||
|
"#natForm",
|
||||||
|
"/api/nat"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function connectToServer(id) {
|
function connectToServer(id) {
|
||||||
post('/terminal', { Host: window.location.host, Protocol: window.location.protocol, ID: id })
|
post('/terminal', { Host: window.location.host, Protocol: window.location.protocol, ID: id })
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -145,6 +145,10 @@ td {
|
|||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.temp-detail {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.ui.content {
|
.ui.content {
|
||||||
margin:0 !important;
|
margin:0 !important;
|
||||||
padding:1em !important;
|
padding:1em !important;
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ const mixinsVue = {
|
|||||||
adaptedTemplates: [
|
adaptedTemplates: [
|
||||||
{ key: 'default', name: 'Default', icon: 'th large' },
|
{ key: 'default', name: 'Default', icon: 'th large' },
|
||||||
{ key: 'angel-kanade', name: 'AngelKanade', icon: 'square' },
|
{ key: 'angel-kanade', name: 'AngelKanade', icon: 'square' },
|
||||||
{ key: 'server-status', name: 'SeverStatus', icon: 'list' }
|
{ key: 'server-status', name: 'ServerStatus', icon: 'list' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|||||||
+74
-72
@@ -1,5 +1,6 @@
|
|||||||
body[theme="dark"] {
|
body[theme="dark"] {
|
||||||
background: #31363b;
|
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||||
|
background: rgba(49, 54, 59, 1);
|
||||||
color: #f1f1f1;
|
color: #f1f1f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7,14 +8,10 @@ body[theme="dark"] .navbar .navbar-brand {
|
|||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .navbar .navbar-brand {
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .navbar .dropdown-menu {
|
body[theme="dark"] .navbar .dropdown-menu {
|
||||||
list-style-image: initial;
|
list-style-image: initial;
|
||||||
background-color: #171a1e;
|
background-color: rgba(23, 26, 30, 1);
|
||||||
border-color: #31363b;
|
border-color: rgba(49, 54, 59, 1);
|
||||||
box-shadow: rgba(0, 0, 0, 0.18) 0px 6px 12px;
|
box-shadow: rgba(0, 0, 0, 0.18) 0px 6px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,8 +21,8 @@ body[theme="dark"] .navbar .dropdown-menu > li > a {
|
|||||||
|
|
||||||
body[theme="dark"] .navbar .dropdown-menu > li > a:focus,
|
body[theme="dark"] .navbar .dropdown-menu > li > a:focus,
|
||||||
body[theme="dark"] .navbar .dropdown-menu > li > a:hover {
|
body[theme="dark"] .navbar .dropdown-menu > li > a:hover {
|
||||||
background-color: #25282a;
|
background-color: rgba(37, 40, 42, 1);
|
||||||
background-image: linear-gradient(#1c1d26 0, #1c1d26 100%);
|
background-image: linear-gradient(rgba(28, 29, 38, 1) 0, rgba(28, 29, 38, 1) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .navbar .navbar-nav > .open > a:focus,
|
body[theme="dark"] .navbar .navbar-nav > .open > a:focus,
|
||||||
@@ -37,18 +34,13 @@ body[theme="dark"] .navbar .navbar-nav > .open > a{
|
|||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .navbar .navbar-nav .open .dropdown-menu>li>a {
|
body[theme="dark"] .navbar .navbar-nav .open .dropdown-menu > li > a {
|
||||||
color: #f1f1f1;
|
color: #f1f1f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .toolbox i{
|
|
||||||
color: rgba(241,241,241,1);
|
|
||||||
background-color: rgba(0,0,0,0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .content {
|
body[theme="dark"] .content {
|
||||||
background-image: initial;
|
background-image: initial;
|
||||||
background-color: #1c1d26;
|
background-color: rgba(28, 29, 38, 1);
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em;
|
box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em;
|
||||||
-webkit-box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em;
|
-webkit-box-shadow: rgba(0, 0, 0, 0.5) 0 0.625em 2em;
|
||||||
@@ -57,57 +49,10 @@ body[theme="dark"] .content {
|
|||||||
|
|
||||||
body[theme="dark"] .table {
|
body[theme="dark"] .table {
|
||||||
background-image: initial;
|
background-image: initial;
|
||||||
background-color: #1c1d26;
|
background-color: rgba(28, 29, 38, 1);
|
||||||
border-color: #545b5e;
|
border-color: #545b5e;
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .table>thead>tr.node-group-tag>th {
|
|
||||||
background-color: #1c1d26;
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .table-striped tbody > tr.even > td,
|
|
||||||
body[theme="dark"] .table-striped tbody > tr.even > th {
|
|
||||||
background-color: #1c1d26;
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .table-striped tbody > tr.odd > td,
|
|
||||||
body[theme="dark"] .table-striped tbody > tr.odd > th {
|
|
||||||
background-color: #1c1d26;
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .progress {
|
|
||||||
background-image: linear-gradient(#2c2c2c 0,#1c1d26 100%);
|
|
||||||
background-color: #1c1d26;
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .progress-bar {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .progress-bar-success {
|
|
||||||
background-image: linear-gradient(#4d853a 0, #367e36 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .progress-offline .progress-bar-success {
|
|
||||||
background-image: linear-gradient(grey 0, grey 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .progress-bar-warning {
|
|
||||||
background-image: linear-gradient(#995f0d 0, #b5710f 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .progress-offline .progress-bar-warning {
|
|
||||||
background-image: linear-gradient(grey 0, grey 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .progress-bar-danger {
|
|
||||||
background-image: linear-gradient(#942320 0, #a12623 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .progress-offline .progress-bar-danger {
|
|
||||||
background-image: linear-gradient(grey 0, grey 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
body[theme="dark"] .table > tbody > tr > td:before,
|
body[theme="dark"] .table > tbody > tr > td:before,
|
||||||
body[theme="dark"] .table > tfoot > tr > td:before,
|
body[theme="dark"] .table > tfoot > tr > td:before,
|
||||||
body[theme="dark"] .table > thead > tr > td:before,
|
body[theme="dark"] .table > thead > tr > td:before,
|
||||||
@@ -115,17 +60,69 @@ body[theme="dark"] .table > thead > tr.node-group-cell > th:before{
|
|||||||
background-color: rgba(58, 62, 65, 1);
|
background-color: rgba(58, 62, 65, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .table > tbody > tr.expandRow > td:before,
|
body[theme="dark"] .table-striped tbody > tr,
|
||||||
body[theme="dark"] .table > thead > tr.node-group-tag > th:before{
|
body[theme="dark"] .table-striped tbody > tr.even > td,
|
||||||
background-color: #1c1d26;
|
body[theme="dark"] .table-striped tbody > tr.even > th {
|
||||||
|
background-color: rgba(28, 29, 38, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .table-striped tbody > tr,
|
||||||
|
body[theme="dark"] .table-striped tbody > tr.odd > td,
|
||||||
|
body[theme="dark"] .table-striped tbody > tr.odd > th {
|
||||||
|
/* background-color: rgba(28, 29, 38, 1); 282B2E*/
|
||||||
|
background-color: rgba(34, 35, 46, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .table-hover > tbody > tr:hover{
|
||||||
|
background-color: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .table-hover > tbody > tr:not(.expandRow):hover > td {
|
body[theme="dark"] .table-hover > tbody > tr:not(.expandRow):hover > td {
|
||||||
background-color: #171a1e;
|
background-color: rgba(48, 50, 65, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .table-striped > tbody > tr:nth-of-type(2n+1) {
|
/* expandRow展开部分样式 */
|
||||||
background-color: #1c1d26;
|
body[theme="dark"] .table > tbody > tr.expandRow.odd > td:before{
|
||||||
|
/* background-color: rgba(28, 29, 38, 1); 282B2E*/
|
||||||
|
background-color: rgba(34, 35, 46, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .table > tbody > tr.expandRow.even > td:before{
|
||||||
|
background-color: rgba(28, 29, 38, 1);
|
||||||
|
}
|
||||||
|
/* expandRow展开部分样式结束 */
|
||||||
|
|
||||||
|
body[theme="dark"] .progress {
|
||||||
|
background-image: linear-gradient(#2c2c2c 0,rgba(28, 29, 38, 1) 100%);
|
||||||
|
background-color: rgba(28, 29, 38, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .progress-bar {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .progress-bar-success {
|
||||||
|
background-image: linear-gradient(#4d853a 0, #367e36 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .progress-offline .progress-bar-success {
|
||||||
|
background-image: linear-gradient(#808080 0, #808080 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .progress-bar-warning {
|
||||||
|
background-image: linear-gradient(#995f0d 0, #b5710f 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .progress-offline .progress-bar-warning {
|
||||||
|
background-image: linear-gradient(#808080 0, #808080 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .progress-bar-danger {
|
||||||
|
background-image: linear-gradient(#942320 0, #a12623 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .progress-offline .progress-bar-danger {
|
||||||
|
background-image: linear-gradient(#808080 0, #808080 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .node-cell.status .status-icon.online {
|
body[theme="dark"] .node-cell.status .status-icon.online {
|
||||||
@@ -149,7 +146,7 @@ body[theme="dark"] .service-status .warning {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .service-day-status-icon {
|
body[theme="dark"] .service-day-status-icon {
|
||||||
background-color: grey;
|
background-color: rgba(128, 128, 128, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] footer p a,
|
body[theme="dark"] footer p a,
|
||||||
@@ -159,7 +156,7 @@ body[theme="dark"] footer p a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body[theme="dark"] .modal-content{
|
body[theme="dark"] .modal-content{
|
||||||
background-color: #1c1d26;
|
background-color: rgba(28, 29, 38, 1);
|
||||||
color: #f1f1f1;
|
color: #f1f1f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,3 +167,8 @@ body[theme="dark"] .modal-header{
|
|||||||
body[theme="dark"] .modal-header i{
|
body[theme="dark"] .modal-header i{
|
||||||
color: #f1f1f1;
|
color: #f1f1f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body[theme="dark"] .toolbox i{
|
||||||
|
color: rgba(241, 241, 241, 1);
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
+36
-1
@@ -50,6 +50,11 @@ body {
|
|||||||
/*margin-right: 5px;*/
|
/*margin-right: 5px;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar .dropdown:hover,
|
||||||
|
.navbar .dropdown a{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar .dropdown .dropdown-toggle {
|
.navbar .dropdown .dropdown-toggle {
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
@@ -59,7 +64,7 @@ body {
|
|||||||
margin:0px -15px;
|
margin:0px -15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar .navbar-nav>li>a {
|
.navbar .navbar-nav > li > a {
|
||||||
color:#f1f1f1;
|
color:#f1f1f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +142,10 @@ body {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr.accordion-toggle{
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.table > tbody > tr > td,
|
.table > tbody > tr > td,
|
||||||
.table > tbody > tr > th,
|
.table > tbody > tr > th,
|
||||||
.table > tfoot > tr > td,
|
.table > tfoot > tr > td,
|
||||||
@@ -230,6 +239,23 @@ body {
|
|||||||
max-width: 50px;
|
max-width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.temp-detail {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*加快Agent详情下拉展示速度*/
|
||||||
|
.collapsing{
|
||||||
|
-webkit-transition-property:height,visibility;
|
||||||
|
-o-transition-property:height,visibility;
|
||||||
|
transition-property:height,visibility;
|
||||||
|
-webkit-transition-duration:.15s;
|
||||||
|
-o-transition-duration:.15s;
|
||||||
|
transition-duration:.15s;
|
||||||
|
-webkit-transition-timing-function: linear;
|
||||||
|
-o-transition-timing-function: linear;
|
||||||
|
transition-timing-function: linear
|
||||||
|
}
|
||||||
|
|
||||||
/*正文结束*/
|
/*正文结束*/
|
||||||
|
|
||||||
/* 服务页 正文*/
|
/* 服务页 正文*/
|
||||||
@@ -317,6 +343,15 @@ body {
|
|||||||
right: 13px;
|
right: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
footer{
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer p{
|
||||||
|
text-align: center;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 1200px) {
|
@media only screen and (max-width: 1200px) {
|
||||||
.accordian-body{
|
.accordian-body{
|
||||||
margin: 5px 0px 5px 10px;
|
margin: 5px 0px 5px 10px;
|
||||||
|
|||||||
+36
-51
@@ -7,16 +7,17 @@ const mixinsVue = {
|
|||||||
showGoTop: false,
|
showGoTop: false,
|
||||||
preferredTemplate: null,
|
preferredTemplate: null,
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
|
staticUrl: '/static/theme-server-status',
|
||||||
adaptedTemplates: [
|
adaptedTemplates: [
|
||||||
{ key: 'default', name: 'Default', icon: 'th large' },
|
{ key: 'default', name: 'Default', icon: 'th large' },
|
||||||
{ key: 'angel-kanade', name: 'AngelKanade', icon: 'square' },
|
{ key: 'angel-kanade', name: 'AngelKanade', icon: 'square' },
|
||||||
{ key: 'server-status', name: 'SeverStatus', icon: 'list' }
|
{ key: 'server-status', name: 'ServerStatus', icon: 'list' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.isMobile = this.checkIsMobile();
|
this.isMobile = this.checkIsMobile();
|
||||||
this.initTheme();
|
this.theme = this.initTheme();
|
||||||
this.storedShowGroup();
|
this.showGroup = this.initShowGroup();
|
||||||
this.preferredTemplate = this.getCookie('preferred_theme') ? this.getCookie('preferred_theme') : this.$root.defaultTemplate;
|
this.preferredTemplate = this.getCookie('preferred_theme') ? this.getCookie('preferred_theme') : this.$root.defaultTemplate;
|
||||||
window.addEventListener('scroll', this.handleScroll);
|
window.addEventListener('scroll', this.handleScroll);
|
||||||
},
|
},
|
||||||
@@ -24,17 +25,6 @@ const mixinsVue = {
|
|||||||
window.removeEventListener('scroll', this.handleScroll);
|
window.removeEventListener('scroll', this.handleScroll);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleView() {
|
|
||||||
this.showGroup = !this.showGroup;
|
|
||||||
localStorage.setItem("showGroup", JSON.stringify(this.showGroup));
|
|
||||||
return this.showGroup;
|
|
||||||
},
|
|
||||||
storedShowGroup() {
|
|
||||||
const storedShowGroup = localStorage.getItem("showGroup");
|
|
||||||
if (storedShowGroup !== null) {
|
|
||||||
this.showGroup = JSON.parse(storedShowGroup);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleTemplate(template) {
|
toggleTemplate(template) {
|
||||||
if( template != this.preferredTemplate){
|
if( template != this.preferredTemplate){
|
||||||
this.preferredTemplate = template;
|
this.preferredTemplate = template;
|
||||||
@@ -42,6 +32,38 @@ const mixinsVue = {
|
|||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
initTheme() {
|
||||||
|
const storedTheme = localStorage.getItem("theme");
|
||||||
|
const theme = (storedTheme === 'dark' || storedTheme === 'light') ? storedTheme : (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||||
|
this.setTheme(theme);
|
||||||
|
return theme;
|
||||||
|
},
|
||||||
|
setTheme(theme) {
|
||||||
|
document.body.setAttribute("theme", theme);
|
||||||
|
this.theme = theme;
|
||||||
|
localStorage.setItem("theme", theme);
|
||||||
|
// 重新赋值全局调色
|
||||||
|
this.colors = this.theme == "dark" ? this.colorsDark : this.colorsLight;
|
||||||
|
|
||||||
|
if(this.$root.page == 'index') {
|
||||||
|
this.reloadCharts(); // 重新载入echarts图表
|
||||||
|
}
|
||||||
|
},
|
||||||
|
initShowGroup() {
|
||||||
|
const storedShowGroup = localStorage.getItem("showGroup");
|
||||||
|
const showGroup = storedShowGroup !== null ? JSON.parse(storedShowGroup) : false;
|
||||||
|
if (storedShowGroup === null) {
|
||||||
|
localStorage.setItem("showGroup", showGroup);
|
||||||
|
}
|
||||||
|
return showGroup;
|
||||||
|
},
|
||||||
|
toggleShowGroup() {
|
||||||
|
this.showGroup = !this.showGroup;
|
||||||
|
localStorage.setItem("showGroup", this.showGroup);
|
||||||
|
if (this.$root.page == 'service') {
|
||||||
|
this.$root.initTooltip();
|
||||||
|
}
|
||||||
|
},
|
||||||
updateCookie(name, value) {
|
updateCookie(name, value) {
|
||||||
document.cookie = name + "=" + value +"; path=/";
|
document.cookie = name + "=" + value +"; path=/";
|
||||||
},
|
},
|
||||||
@@ -57,43 +79,6 @@ const mixinsVue = {
|
|||||||
}
|
}
|
||||||
return cookieValue;
|
return cookieValue;
|
||||||
},
|
},
|
||||||
setTheme(title, store = false) {
|
|
||||||
this.theme = title;
|
|
||||||
document.body.setAttribute("theme", title);
|
|
||||||
if (store) {
|
|
||||||
localStorage.setItem("theme", title);
|
|
||||||
this.isSystemTheme = false;
|
|
||||||
if(this.$root.page == 'index') {
|
|
||||||
this.$root.reloadCharts(); //重新载入echarts图表
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setSystemTheme() {
|
|
||||||
localStorage.removeItem("theme");
|
|
||||||
this.initTheme();
|
|
||||||
this.isSystemTheme = true;
|
|
||||||
},
|
|
||||||
initTheme() {
|
|
||||||
const storeTheme = localStorage.getItem("theme");
|
|
||||||
if (storeTheme === 'dark' || storeTheme === 'light') {
|
|
||||||
this.setTheme(storeTheme, true);
|
|
||||||
} else {
|
|
||||||
this.isSystemTheme = true
|
|
||||||
const handleChange = (mediaQueryListEvent) => {
|
|
||||||
if (localStorage.getItem("theme")) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (mediaQueryListEvent.matches) {
|
|
||||||
this.setTheme('dark');
|
|
||||||
} else {
|
|
||||||
this.setTheme('light');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const mediaQueryListDark = window.matchMedia('(prefers-color-scheme: dark)');
|
|
||||||
this.setTheme(mediaQueryListDark.matches ? 'dark' : 'light');
|
|
||||||
mediaQueryListDark.addEventListener("change", handleChange);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toFixed2(f) {
|
toFixed2(f) {
|
||||||
return f.toFixed(2)
|
return f.toFixed(2)
|
||||||
},
|
},
|
||||||
|
|||||||
+1277
File diff suppressed because it is too large
Load Diff
+243
File diff suppressed because one or more lines are too long
+242
File diff suppressed because one or more lines are too long
+245
File diff suppressed because one or more lines are too long
+244
File diff suppressed because one or more lines are too long
Vendored
+4
-5
@@ -6,17 +6,16 @@
|
|||||||
{{.Version}}</small>
|
{{.Version}}</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/jquery/3.6.0/jquery.min.js"></script>
|
<script src="https://unpkg.com/jquery@3.7.1/dist/jquery.min.js"></script>
|
||||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/semantic-ui/2.4.1/semantic.min.js"></script>
|
<script src="https://unpkg.com/semantic-ui@2.4.0/dist/semantic.min.js"></script>
|
||||||
<script src="/static/semantic-ui-alerts.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="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
|
||||||
<script src="/static/main.js?v20240330"></script>
|
<script src="/static/main.js?v20240714"></script>
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
updateLang({{.LANG }});
|
updateLang({{.LANG }});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
Vendored
+4
-8
@@ -1,21 +1,17 @@
|
|||||||
{{define "common/header"}}
|
{{define "common/header"}}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{{.Conf.Language}}">
|
<html lang="{{.Conf.Language}}">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<meta content="telephone=no" name="format-detection">
|
<meta content="telephone=no" name="format-detection">
|
||||||
<title>{{.Title}}</title>
|
<title>{{.Title}}</title>
|
||||||
<link rel="stylesheet" type="text/css"
|
<link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" />
|
||||||
href="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/semantic-ui/2.4.1/semantic.min.css">
|
<link rel="stylesheet" type="text/css" href="https://unpkg.com/semantic-ui@2.4.0/dist/semantic.min.css">
|
||||||
<link href="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/font-logos/0.17/font-logos.min.css" type="text/css"
|
<link rel="stylesheet" type="text/css" href="https://unpkg.com/font-logos@0.17.0/assets/font-logos.css">
|
||||||
rel="stylesheet" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
|
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/static/main.css?v2022042314">
|
<link rel="stylesheet" type="text/css" href="/static/main.css?v2022042314">
|
||||||
<link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" />
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
{{end}}
|
{{end}}
|
||||||
Vendored
+1
@@ -9,6 +9,7 @@
|
|||||||
<a class='item{{if eq .MatchedPath "/monitor"}} active{{end}}' href="/monitor"><i class="rss icon"></i>{{tr "Services"}}</a>
|
<a class='item{{if eq .MatchedPath "/monitor"}} active{{end}}' href="/monitor"><i class="rss icon"></i>{{tr "Services"}}</a>
|
||||||
<a class='item{{if eq .MatchedPath "/cron"}} active{{end}}' href="/cron"><i class="clock icon"></i>{{tr "Task"}}</a>
|
<a class='item{{if eq .MatchedPath "/cron"}} active{{end}}' href="/cron"><i class="clock icon"></i>{{tr "Task"}}</a>
|
||||||
<a class='item{{if eq .MatchedPath "/notification"}} active{{end}}' href="/notification"><i class="bell icon"></i>{{tr "Notification"}}</a>
|
<a class='item{{if eq .MatchedPath "/notification"}} active{{end}}' href="/notification"><i class="bell icon"></i>{{tr "Notification"}}</a>
|
||||||
|
<a class='item{{if eq .MatchedPath "/nat"}} active{{end}}' href="/nat"><i class="exchange icon"></i>{{tr "NAT"}}</a>
|
||||||
<a class='item{{if eq .MatchedPath "/setting"}} active{{end}}' href="/setting">
|
<a class='item{{if eq .MatchedPath "/setting"}} active{{end}}' href="/setting">
|
||||||
<i class="settings icon"></i>{{tr "Settings"}}
|
<i class="settings icon"></i>{{tr "Settings"}}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
Vendored
+31
@@ -0,0 +1,31 @@
|
|||||||
|
{{define "component/nat"}}
|
||||||
|
<div class="ui tiny nat modal transition hidden">
|
||||||
|
<div class="header">Add</div>
|
||||||
|
<div class="content">
|
||||||
|
<form id="natForm" class="ui form">
|
||||||
|
<input type="hidden" name="ID">
|
||||||
|
<div class="field">
|
||||||
|
<label>{{tr "Name"}}</label>
|
||||||
|
<input type="text" name="Name">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Agent ID</label>
|
||||||
|
<input type="number" name="ServerID" placeholder="1">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>内网服务</label>
|
||||||
|
<input type="text" name="Host" placeholder="192.168.1.1:80(带端口)">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>绑定域名</label>
|
||||||
|
<input type="text" name="Domain" placeholder="router.app.yourdomain.com">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<div class="ui negative button">{{tr "Cancel"}}</div>
|
||||||
|
<button class="ui positive nezha-primary-btn right labeled icon button">{{tr "Confirm"}}<i class="checkmark icon"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
+1
-1
@@ -61,7 +61,7 @@
|
|||||||
<div class="ui message">
|
<div class="ui message">
|
||||||
{{if .Conf.GRPCHost}}
|
{{if .Conf.GRPCHost}}
|
||||||
curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.sh -o nezha.sh && chmod
|
curl -L https://raw.githubusercontent.com/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">{{if .Conf.ProxyGRPCPort}}{{.Conf.ProxyGRPCPort}}{{else}}{{.Conf.GRPCPort}}{{end}}</code> <code
|
||||||
class="command hostSecret"></code> <code class="command">{{if .Conf.TLS}}--tls{{end}}</code>
|
class="command hostSecret"></code> <code class="command">{{if .Conf.TLS}}--tls{{end}}</code>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
{{define "dashboard-default/nat"}}
|
||||||
|
{{template "common/header" .}}
|
||||||
|
{{template "common/menu" .}}
|
||||||
|
<div class="nb-container">
|
||||||
|
<div class="ui container">
|
||||||
|
<div class="ui grid">
|
||||||
|
<div class="right floated right aligned twelve wide column">
|
||||||
|
<button class="ui right labeled nezha-primary-btn icon button" onclick="addOrEditNAT()"><i
|
||||||
|
class="add icon"></i> Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="ui very basic table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>{{tr "Name"}}</th>
|
||||||
|
<th>Agent ID</th>
|
||||||
|
<th>内网服务</th>
|
||||||
|
<th>绑定域名</th>
|
||||||
|
<th>{{tr "Administration"}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range $item := .NAT}}
|
||||||
|
<tr>
|
||||||
|
<td>{{$item.ID}}</td>
|
||||||
|
<td>{{$item.Name}}</td>
|
||||||
|
<td>{{$item.ServerID}}</td>
|
||||||
|
<td>{{$item.Host}}</td>
|
||||||
|
<td>{{$item.Domain}}</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui mini icon buttons">
|
||||||
|
<button class="ui button" onclick="addOrEditNAT({{$item}})">
|
||||||
|
<i class="edit icon"></i>
|
||||||
|
</button>
|
||||||
|
<button class="ui button"
|
||||||
|
onclick="showConfirm('确定删除NAT隧道?','确认删除',deleteRequest,'/api/nat/'+{{$item.ID}})">
|
||||||
|
<i class="trash alternate outline icon"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "component/nat"}}
|
||||||
|
{{template "common/footer" .}}
|
||||||
|
<script>
|
||||||
|
$('.checkbox').checkbox()
|
||||||
|
</script>
|
||||||
|
{{end}}
|
||||||
@@ -1,18 +1,15 @@
|
|||||||
{{define "dashboard-default/redirect"}}
|
{{define "dashboard-default/redirect"}}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{{.Conf.Language}}">
|
<html lang="{{.Conf.Language}}">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Redirecting..</title>
|
<title>Redirecting..</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<p>If you are not redirected, please click <a href="{{.URL}}">here</a>.</p>
|
<p>If you are not redirected, please click <a href="{{.URL}}">here</a>.</p>
|
||||||
<script>window.location.href = "{{.URL}}"</script>
|
<script>window.location.href = "{{.URL}}"</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
+2
-2
@@ -60,7 +60,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="ui icon green mini button"
|
<button class="ui icon green mini button"
|
||||||
data-clipboard-text="{{if $.Conf.GRPCHost}}{{if eq $.Conf.Language "zh-CN"}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.sh{{else}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install_en.sh{{end}} -o nezha.sh && chmod +x nezha.sh && sudo ./nezha.sh install_agent {{$.Conf.GRPCHost}} {{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"
|
data-clipboard-text="{{if $.Conf.GRPCHost}}{{if eq $.Conf.Language "zh-CN"}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.sh{{else}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install_en.sh{{end}} -o nezha.sh && chmod +x nezha.sh && ./nezha.sh install_agent {{$.Conf.GRPCHost}} {{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"
|
||||||
data-tooltip="{{tr "ClickToCopy"}}">
|
data-tooltip="{{tr "ClickToCopy"}}">
|
||||||
<i class="linux icon"></i>
|
<i class="linux icon"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "component/server" .}}
|
{{template "component/server" .}}
|
||||||
{{template "common/footer" .}}
|
{{template "common/footer" .}}
|
||||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/clipboard.js/2.0.10/clipboard.min.js" type="application/javascript"></script>
|
<script src="https://unpkg.com/clipboard@2.0.11/dist/clipboard.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var clipboard = new ClipboardJS('.ui.icon.green.mini.button');
|
var clipboard = new ClipboardJS('.ui.icon.green.mini.button');
|
||||||
const checkBoxList = document.querySelectorAll('tbody > tr > td > input.nezha-servers[type=checkbox]')
|
const checkBoxList = document.querySelectorAll('tbody > tr > td > input.nezha-servers[type=checkbox]')
|
||||||
|
|||||||
+4
-8
@@ -1,16 +1,14 @@
|
|||||||
{{define "dashboard-default/terminal"}}
|
{{define "dashboard-default/terminal"}}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{{.Conf.Language}}">
|
<html lang="{{.Conf.Language}}">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>tty@{{.ServerName}} - {{.Title}}</title>
|
<title>tty@{{.ServerName}} - {{.Title}}</title>
|
||||||
<link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" />
|
<link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" />
|
||||||
<link href="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/xterm/4.11.0/xterm.css" type="text/css" rel="stylesheet"/>
|
<link type="text/css" rel="stylesheet" href="https://unpkg.com/[email protected]/css/xterm.css" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
html,
|
html,
|
||||||
body,
|
body,
|
||||||
@@ -25,12 +23,11 @@
|
|||||||
background-color: black;
|
background-color: black;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<body onresize="onResize()">
|
<body onresize="onResize()">
|
||||||
<div id="terminal-container"></div>
|
<div id="terminal-container"></div>
|
||||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/xterm/4.11.0/xterm.js" type="application/javascript"></script>
|
<script src="https://unpkg.com/[email protected]/lib/xterm.js"></script>
|
||||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/xterm/4.11.0/addons/attach/xterm-addon-attach.js"></script>
|
<script src="https://unpkg.com/@xterm/addon-attach@0.11.0/lib/addon-attach.js"></script>
|
||||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/xterm/4.11.0/addons/fit/xterm-addon-fit.js"></script>
|
<script src="https://unpkg.com/@xterm/addon-fit@0.10.0/lib/addon-fit.js"></script>
|
||||||
<script>
|
<script>
|
||||||
let sendResizing = false;
|
let sendResizing = false;
|
||||||
|
|
||||||
@@ -93,6 +90,5 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -24,6 +24,9 @@
|
|||||||
[<span
|
[<span
|
||||||
v-if="server.Host.Virtualization">@#server.Host.Virtualization#@:</span>@#server.Host.Arch#@]<br />
|
v-if="server.Host.Virtualization">@#server.Host.Virtualization#@:</span>@#server.Host.Arch#@]<br />
|
||||||
CPU: @#server.Host.CPU#@<br />
|
CPU: @#server.Host.CPU#@<br />
|
||||||
|
<template v-if="server.Host.GPU">
|
||||||
|
GPU: @#server.Host.GPU#@
|
||||||
|
</template>
|
||||||
{{tr "DiskUsed"}}:
|
{{tr "DiskUsed"}}:
|
||||||
@#formatByteSize(server.State.DiskUsed)#@/@#formatByteSize(server.Host.DiskTotal)#@<br />
|
@#formatByteSize(server.State.DiskUsed)#@/@#formatByteSize(server.Host.DiskTotal)#@<br />
|
||||||
{{tr "MemUsed"}}:
|
{{tr "MemUsed"}}:
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
<i :class="item.icon + ' icon'"></i>@#item.name#@
|
<i :class="item.icon + ' icon'"></i>@#item.name#@
|
||||||
<i class="check icon" v-if="preferredTemplate === item.key"></i>
|
<i class="check icon" v-if="preferredTemplate === item.key"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<a v-if="defaultTemplate === 'custom'" @click="toggleTemplate('custom')" class="item">
|
||||||
|
<i class="expand icon"></i>Custom
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
+12
-11
@@ -7,19 +7,20 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<meta content="telephone=no" name="format-detection">
|
<meta content="telephone=no" name="format-detection">
|
||||||
<title>{{.Title}}</title>
|
<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" />
|
<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>
|
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/semantic.min.css">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.js"></script>
|
<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="/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>
|
<script src="/static/theme-default/js/mixin.js?v20240302"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|||||||
+612
-512
File diff suppressed because it is too large
Load Diff
+3
@@ -27,6 +27,9 @@
|
|||||||
<i :class="item.icon + ' icon'"></i>@#item.name#@
|
<i :class="item.icon + ' icon'"></i>@#item.name#@
|
||||||
<i class="check icon" v-if="preferredTemplate === item.key"></i>
|
<i class="check icon" v-if="preferredTemplate === item.key"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<a v-if="defaultTemplate === 'custom'" @click="toggleTemplate('custom')" class="item">
|
||||||
|
<i class="expand icon"></i>Custom
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
+1
-1
@@ -221,7 +221,7 @@
|
|||||||
var disk = this.formatByteSize(server.State.DiskUsed) + '/' + this.formatByteSize(server.Host.DiskTotal);
|
var disk = this.formatByteSize(server.State.DiskUsed) + '/' + this.formatByteSize(server.Host.DiskTotal);
|
||||||
var upTime = this.secondToDate(server.State.Uptime);
|
var upTime = this.secondToDate(server.State.Uptime);
|
||||||
var tooltip =
|
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
|
return tooltip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
{{define "theme-server-status/content-footer"}}
|
{{define "theme-server-status/content-footer"}}
|
||||||
<footer class="container" style="padding-bottom: 2rem;">
|
<footer>
|
||||||
<p style="text-align: center; font-size: 10px;">
|
<p>{{ .Conf.Site.Brand }} | Theme ServerStatus | Powered by <a target="_blank" href="https://github.com/naiba/nezha">{{tr "NezhaMonitoring"}}</a> {{.Version}}</p>
|
||||||
{{ .Conf.Site.Brand }} | Theme ServerStatus | Powered by <a target="_blank" href="https://github.com/naiba/nezha">{{tr "NezhaMonitoring"}}</a> {{.Version}}
|
|
||||||
</p>
|
|
||||||
</footer>
|
</footer>
|
||||||
<aside class="toolbox">
|
<aside class="toolbox">
|
||||||
<span v-if="page=='index' && countryMapChartData.length!=0" class="showMapChart">
|
<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>
|
<i @click="showMapChart" data-toggle="modal" data-target="#mapChartBox" class="bi bi-geo-alt"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="toggleView">
|
<span class="toggleView">
|
||||||
<i v-if="showGroup" @click="toggleView" class="show-nogroup bi bi-justify"></i>
|
<i v-if="showGroup" @click="toggleShowGroup" class="show-nogroup bi bi-justify"></i>
|
||||||
<i v-else @click="toggleView" class="show-group bi bi-view-stacked"></i>
|
<i v-else @click="toggleShowGroup" class="show-group bi bi-view-stacked"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="setTheme">
|
<span class="setTheme">
|
||||||
<i v-if="theme === 'light'" @click="setTheme('dark', true)" class="setTheme-dark bi bi-moon-fill"></i>
|
<i v-if="theme === 'light'" @click="setTheme('dark')" class="setTheme-dark bi bi-moon-fill"></i>
|
||||||
<i v-else @click="setTheme('light', true)" class="setTheme-light bi bi-brightness-high-fill"></i>
|
<i v-else @click="setTheme('light')" class="setTheme-light bi bi-brightness-high-fill"></i>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="showGoTop" class="showGoTop">
|
<span v-if="showGoTop" class="showGoTop">
|
||||||
<i @click="goTop" class="goTop bi bi-arrow-up"></i>
|
<i @click="goTop" class="goTop bi bi-arrow-up"></i>
|
||||||
|
|||||||
@@ -39,6 +39,11 @@
|
|||||||
<i class="check icon" v-if="preferredTemplate === item.key"></i>
|
<i class="check icon" v-if="preferredTemplate === item.key"></i>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</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>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
+21
-15
@@ -6,16 +6,21 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<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?v20240407">
|
|
||||||
<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://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="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?v20240724">
|
||||||
|
<link rel="stylesheet" href="/static/theme-server-status/css/dark.css?v20240724">
|
||||||
|
<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="/static/theme-server-status/js/mixin.js?v20240711"></script>
|
||||||
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="/static/theme-server-status/js/html5shiv.js"></script>
|
<script src="/static/theme-server-status/js/html5shiv.js"></script>
|
||||||
@@ -24,12 +29,13 @@
|
|||||||
{{if ts .CustomCode}}
|
{{if ts .CustomCode}}
|
||||||
{{.CustomCode|safe}}
|
{{.CustomCode|safe}}
|
||||||
{{end}}
|
{{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="https://cdn.jsdelivr.net/npm/echarts/map/js/world.js"></script>
|
|
||||||
<script src="/static/theme-server-status/js/mixin.js?v20240302"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+29
-8
@@ -27,10 +27,10 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="node-cell name center">@#node.name#@</td>
|
<td class="node-cell name center">@#node.name#@</td>
|
||||||
<td class="node-cell os center">
|
<td class="node-cell os center">
|
||||||
<i v-if='node.os == "darwin"' class="apple icon"></i>
|
<i v-if='isWindowsPlatform(node.host.Platform)' class="windows icon"></i>
|
||||||
<i v-else-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>
|
<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>
|
||||||
<td style="text-align: center;" class="node-cell location">
|
<td style="text-align: center;" class="node-cell location">
|
||||||
<i :class="'fi fi-' + node.location"></i>
|
<i :class="'fi fi-' + node.location"></i>
|
||||||
@@ -71,20 +71,28 @@
|
|||||||
</span>
|
</span>
|
||||||
<span class="node-cell-expand" v-if="node.host.CPU">
|
<span class="node-cell-expand" v-if="node.host.CPU">
|
||||||
<span class="node-cell-expand-label">CPU:</span>
|
<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>
|
||||||
<span class="node-cell-expand">
|
<span class="node-cell-expand">
|
||||||
<span class="node-cell-expand-label">{{tr "DiskUsed"}}:</span>
|
<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>
|
||||||
<span class="node-cell-expand">
|
<span class="node-cell-expand">
|
||||||
<span class="node-cell-expand-label">{{tr "MemUsed"}}:</span>
|
<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>
|
||||||
<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>
|
<span class="node-cell-expand-label">{{tr "SwapUsed"}}:</span>
|
||||||
@#formatByteSize(node.state.SwapUsed)#@ / @#formatByteSize(node.host.SwapTotal)#@
|
@#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>
|
||||||
<span class="node-cell-expand">
|
<span class="node-cell-expand">
|
||||||
<span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span>
|
<span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span>
|
||||||
@@ -117,6 +125,19 @@
|
|||||||
<span class="node-cell-expand-label">{{tr "Uptime"}}:</span>
|
<span class="node-cell-expand-label">{{tr "Uptime"}}:</span>
|
||||||
@#node.uptime#@
|
@#node.uptime#@
|
||||||
</span>
|
</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">
|
||||||
<span class="node-cell-expand-label">{{tr "Version"}}:</span>
|
<span class="node-cell-expand-label">{{tr "Version"}}:</span>
|
||||||
@#node.host.Version#@
|
@#node.host.Version#@
|
||||||
|
|||||||
+29
-8
@@ -30,10 +30,10 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="node-cell name center">@#node.name#@</td>
|
<td class="node-cell name center">@#node.name#@</td>
|
||||||
<td class="node-cell os center">
|
<td class="node-cell os center">
|
||||||
<i v-if='node.os == "darwin"' class="apple icon"></i>
|
<i v-if='isWindowsPlatform(node.host.Platform)' class="windows icon"></i>
|
||||||
<i v-else-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>
|
<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>
|
||||||
<td style="text-align: center;" class="node-cell location">
|
<td style="text-align: center;" class="node-cell location">
|
||||||
<i :class="'fi fi-' + node.location"></i>
|
<i :class="'fi fi-' + node.location"></i>
|
||||||
@@ -74,20 +74,28 @@
|
|||||||
</span>
|
</span>
|
||||||
<span class="node-cell-expand" v-if="node.host.CPU">
|
<span class="node-cell-expand" v-if="node.host.CPU">
|
||||||
<span class="node-cell-expand-label">CPU:</span>
|
<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>
|
||||||
<span class="node-cell-expand">
|
<span class="node-cell-expand">
|
||||||
<span class="node-cell-expand-label">{{tr "DiskUsed"}}:</span>
|
<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>
|
||||||
<span class="node-cell-expand">
|
<span class="node-cell-expand">
|
||||||
<span class="node-cell-expand-label">{{tr "MemUsed"}}:</span>
|
<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>
|
||||||
<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>
|
<span class="node-cell-expand-label">{{tr "SwapUsed"}}:</span>
|
||||||
@#formatByteSize(node.state.SwapUsed)#@ / @#formatByteSize(node.host.SwapTotal)#@
|
@#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>
|
||||||
<span class="node-cell-expand">
|
<span class="node-cell-expand">
|
||||||
<span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span>
|
<span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span>
|
||||||
@@ -120,6 +128,19 @@
|
|||||||
<span class="node-cell-expand-label">{{tr "Uptime"}}:</span>
|
<span class="node-cell-expand-label">{{tr "Uptime"}}:</span>
|
||||||
@#node.uptime#@
|
@#node.uptime#@
|
||||||
</span>
|
</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">
|
||||||
<span class="node-cell-expand-label">{{tr "Version"}}:</span>
|
<span class="node-cell-expand-label">{{tr "Version"}}:</span>
|
||||||
@#node.host.Version#@
|
@#node.host.Version#@
|
||||||
|
|||||||
+170
-61
File diff suppressed because one or more lines are too long
+117
-98
@@ -4,74 +4,74 @@
|
|||||||
{{template "theme-server-status/content-nav" .}}
|
{{template "theme-server-status/content-nav" .}}
|
||||||
<!-- showGroup true -->
|
<!-- showGroup true -->
|
||||||
<template v-if="showGroup">
|
<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" .}}
|
{{template "theme-server-status/service-group-true" .}}
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<!-- showGroup false -->
|
<!-- showGroup false -->
|
||||||
<template v-else>
|
<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" .}}
|
{{template "theme-server-status/service-group-false" .}}
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<section class="container content table-responsive" style="max-width: 95vw">
|
{{if .CycleTransferStats}}
|
||||||
{{if .CycleTransferStats}}
|
<section class="container content table-responsive" style="max-width: 95vw">
|
||||||
<table class="table table-striped table-condensed table-hover">
|
<table class="table table-striped table-condensed table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="node-group-tag">
|
<tr class="node-group-tag">
|
||||||
<th colspan="16" style="border:none;">
|
<th colspan="16" style="border:none;">
|
||||||
{{tr "CycleTransferStats"}}
|
{{tr "CycleTransferStats"}}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="node-group-cell">
|
<tr class="node-group-cell">
|
||||||
<th class="node-cell center">ID</th>
|
<th class="node-cell center">ID</th>
|
||||||
<th class="node-cell center">{{tr "Rules"}}</th>
|
<th class="node-cell center">{{tr "Rules"}}</th>
|
||||||
<th class="node-cell center">{{tr "Server"}}</th>
|
<th class="node-cell center">{{tr "Server"}}</th>
|
||||||
<th class="node-cell center">{{tr "From"}}</th>
|
<th class="node-cell center">{{tr "From"}}</th>
|
||||||
<th class="node-cell center">{{tr "To"}}</th>
|
<th class="node-cell center">{{tr "To"}}</th>
|
||||||
<th class="node-cell center">MAX</th>
|
<th class="node-cell center">MAX</th>
|
||||||
<th class="node-cell center">MIN</th>
|
<th class="node-cell center">MIN</th>
|
||||||
<th class="node-cell center">{{tr "NextCheck"}}</th>
|
<th class="node-cell center">{{tr "NextCheck"}}</th>
|
||||||
<th class="node-cell center">{{tr "CurrentUsage"}}</th>
|
<th class="node-cell center">{{tr "CurrentUsage"}}</th>
|
||||||
<th class="node-cell center">{{tr "Transleft"}}</th>
|
<th class="node-cell center">{{tr "Transleft"}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{range $id, $stats := .CycleTransferStats}}
|
{{range $id, $stats := .CycleTransferStats}}
|
||||||
{{range $innerId, $transfer := $stats.Transfer}}
|
{{range $innerId, $transfer := $stats.Transfer}}
|
||||||
{{$TransLeftPercent := TransLeftPercent (UintToFloat $transfer) (UintToFloat $stats.Max)}}
|
{{$TransLeftPercent := TransLeftPercent (UintToFloat $transfer) (UintToFloat $stats.Max)}}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="node-cell center">{{$id}}</td>
|
<td class="node-cell center">{{$id}}</td>
|
||||||
<td class="node-cell center">{{$stats.Name}}</td>
|
<td class="node-cell center">{{$stats.Name}}</td>
|
||||||
<td class="node-cell center">{{index $stats.ServerName $innerId}}</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.From|tf}}</td>
|
||||||
<td class="node-cell center">{{$stats.To|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.Max|bf}}</td>
|
||||||
<td class="node-cell center">{{$stats.Min|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">{{(index $stats.NextUpdate $innerId)|sft}}</td>
|
||||||
<td class="node-cell center">{{$transfer|bf}}</td>
|
<td class="node-cell center">{{$transfer|bf}}</td>
|
||||||
<td class="node-cell center">
|
<td class="node-cell center">
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<div style="width: {{$TransLeftPercent}}%" :class="'progress-bar progress-bar-' + toSSBar('{{TransClassName $TransLeftPercent}}')">
|
<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>
|
<small style="display: inline-block;width: max-content;">{{TransLeft $stats.Max $transfer}} / {{$TransLeftPercent}} %</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{{end}}
|
</section>
|
||||||
</section>
|
{{end}}
|
||||||
{{template "theme-server-status/content-footer" .}}
|
{{template "theme-server-status/content-footer" .}}
|
||||||
</div>
|
</div>
|
||||||
<script>
|
|
||||||
// 初始化 Tooltip
|
|
||||||
$(document).ready(function(){
|
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<script>
|
<script>
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
@@ -80,13 +80,16 @@
|
|||||||
page: 'service',
|
page: 'service',
|
||||||
defaultTemplate: {{.Conf.Site.Theme}},
|
defaultTemplate: {{.Conf.Site.Theme}},
|
||||||
templates: {{.Themes}},
|
templates: {{.Themes}},
|
||||||
|
services: {{.Services}},
|
||||||
servicesTag: [],
|
servicesTag: [],
|
||||||
servicesNoTag: [],
|
servicesNoTag: []
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.initData();
|
this.servicesTag = this.groupingData(this.initData(this.services),"type");
|
||||||
|
this.servicesNoTag = this.initData(this.services);
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.initTooltip();
|
||||||
},
|
},
|
||||||
mixins: [mixinsVue],
|
mixins: [mixinsVue],
|
||||||
methods: {
|
methods: {
|
||||||
@@ -103,32 +106,36 @@
|
|||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
},
|
},
|
||||||
initData() {
|
initData(services) {
|
||||||
// @formatter:off
|
let nodes = [];
|
||||||
const services = []
|
for (let key in services) {
|
||||||
{{range $service := .Services}}
|
const service = services[key];
|
||||||
services.push({
|
let node = {
|
||||||
type: '{{$service.Monitor.Type}}',
|
type: service.Monitor.Type,
|
||||||
name: '{{$service.Monitor.Name}}',
|
name: service.Monitor.Name,
|
||||||
currentUp: parseInt('{{$service.CurrentUp}}'),
|
currentUp: parseInt(service.CurrentUp),
|
||||||
currentDown: parseInt('{{$service.CurrentDown}}'),
|
currentDown: parseInt(service.CurrentDown),
|
||||||
totalUp: parseInt('{{$service.TotalUp}}'),
|
totalUp: parseInt(service.TotalUp),
|
||||||
totalDown: parseInt('{{$service.TotalDown}}'),
|
totalDown: parseInt(service.TotalDown),
|
||||||
delay: '{{$service.Delay}}'.replaceAll("[","").replaceAll("]","").split(" "),
|
up: service.Up,
|
||||||
up: '{{$service.Up}}'.replaceAll("[","").replaceAll("]","").split(" "),
|
down: service.Down,
|
||||||
down: '{{$service.Down}}'.replaceAll("[","").replaceAll("]","").split(" "),
|
delay: service.Delay,
|
||||||
})
|
avgDelay: parseInt(this.getAvgDelay(service.Delay)) + "ms",
|
||||||
{{end}}
|
health: this.getStateInfo(this.getPercent(service.CurrentUp, service.CurrentDown)),
|
||||||
// @formatter:on
|
totalUpTime: this.getProgressInfo(this.getPercent(service.TotalUp, service.TotalDown))
|
||||||
for (let i = 0; i < services.length; i++) {
|
};
|
||||||
const service = services[i];
|
nodes.push(node);
|
||||||
service.avgDelay = parseInt(service.delay[service.delay.length - 1]) + "ms"
|
};
|
||||||
service.health = this.getStateInfo(this.getPercent(service.currentUp, service.currentDown))
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
service.dayDetail = this.getDayTails(service)
|
const node = nodes[i];
|
||||||
service.totalUpTime = this.getProgressInfo(this.getPercent(service.totalUp, service.totalDown))
|
node.dayDetail = this.getDayTails(node)
|
||||||
}
|
}
|
||||||
this.servicesTag = this.groupingData(services,"type");
|
return nodes
|
||||||
this.servicesNoTag = services;
|
},
|
||||||
|
initTooltip() {
|
||||||
|
$(document).ready(function(){
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
getPercent(up, down) {
|
getPercent(up, down) {
|
||||||
if (!up) {
|
if (!up) {
|
||||||
@@ -151,24 +158,24 @@
|
|||||||
return this.toFixed2(currentUp / total * 100)
|
return this.toFixed2(currentUp / total * 100)
|
||||||
},
|
},
|
||||||
getDayTails(service) {
|
getDayTails(service) {
|
||||||
const result = []
|
const result = [];
|
||||||
for (let i = 0; i < service.up.length; i++) {
|
for (let i = 0; i < service.up.length; i++) {
|
||||||
const up = service.up[i]
|
const up = service.up[i];
|
||||||
const down = service.down[i]
|
const down = service.down[i];
|
||||||
const delay = service.delay[i]
|
let delay = Number(service.delay[i]);
|
||||||
let percent = this.getPercent(up, down)
|
let percent = this.getPercent(up, down);
|
||||||
if (percent <= 0) {
|
if (percent <= 0) {
|
||||||
percent = 0;
|
percent = 0;
|
||||||
}
|
}
|
||||||
let className = this.getStateInfo(percent).className
|
let className = this.getStateInfo(percent).className;
|
||||||
let available = '{{tr "Availability"}}'
|
let available = '{{tr "Availability"}}';
|
||||||
let averageLatency = '{{tr "AverageLatency"}}'
|
let averageLatency = '{{tr "AverageLatency"}}';
|
||||||
const text = `${this.beforeDay(service.up.length - i - 1)},${available}:${percent}%,${averageLatency}:${delay}ms`
|
const text = `${this.beforeDay(service.up.length - i - 1)},${available}:${Number(percent).toFixed(3)}%,${averageLatency}:${Number(delay).toFixed(3)}ms`;
|
||||||
result.push({
|
result.push({
|
||||||
text, className
|
text, className
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
return result
|
return result;
|
||||||
},
|
},
|
||||||
beforeDay(days) {
|
beforeDay(days) {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
@@ -203,8 +210,9 @@
|
|||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
getProgressInfo(percent) {
|
getProgressInfo(percent) {
|
||||||
const result = this.getStateInfo(percent)
|
const result = this.getStateInfo(percent);
|
||||||
result.style = `width: ${parseInt(percent)}%`;
|
result.style = `width: ${parseInt(percent)}%`;
|
||||||
|
result.percent = Number(percent).toFixed(2);
|
||||||
const className = result.className;
|
const className = result.className;
|
||||||
if (className === "good") {
|
if (className === "good") {
|
||||||
result.className = 'progress-bar progress-bar-success'
|
result.className = 'progress-bar progress-bar-success'
|
||||||
@@ -218,8 +226,19 @@
|
|||||||
}
|
}
|
||||||
return result
|
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>
|
</script>
|
||||||
{{template "theme-server-status/footer" .}}
|
{{template "theme-server-status/footer" .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
+12
-10
@@ -28,8 +28,8 @@ pre_check() {
|
|||||||
|
|
||||||
## China_IP
|
## China_IP
|
||||||
if [[ -z "${CN}" ]]; then
|
if [[ -z "${CN}" ]]; then
|
||||||
if [[ $(curl -m 10 -s https://ipapi.co/json | grep 'China') != "" ]]; then
|
if [[ $(curl -m 10 -s http://ip-api.com/json |grep 'country' |grep -q 'China') != "" ]]; then
|
||||||
echo "According to the information provided by ipapi.co, the current IP may be in China"
|
echo "According to the information provided by ip-api.com, 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
|
read -e -r -p "Is the installation done with a Chinese Mirror? [Y/n] (Custom Mirror Input 3):" input
|
||||||
case $input in
|
case $input in
|
||||||
[yY][eE][sS] | [yY])
|
[yY][eE][sS] | [yY])
|
||||||
@@ -65,15 +65,9 @@ pre_check() {
|
|||||||
if [[ -z "${CN}" ]]; then
|
if [[ -z "${CN}" ]]; then
|
||||||
GITHUB_RAW_URL="raw.githubusercontent.com/naiba/nezha/master"
|
GITHUB_RAW_URL="raw.githubusercontent.com/naiba/nezha/master"
|
||||||
GITHUB_URL="github.com"
|
GITHUB_URL="github.com"
|
||||||
Get_Docker_URL="get.docker.com"
|
|
||||||
Get_Docker_Argu=" "
|
|
||||||
Docker_IMG="ghcr.io\/naiba\/nezha-dashboard"
|
|
||||||
else
|
else
|
||||||
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
|
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
|
||||||
GITHUB_URL="github.com"
|
GITHUB_URL="gitee.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
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -89,6 +83,9 @@ install_agent() {
|
|||||||
echo -e "Obtaining Agent version"
|
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')
|
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://gitee.com/api/v5/repos/naibahq/agent/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}')
|
||||||
|
fi
|
||||||
if [ ! -n "$version" ]; then
|
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')
|
version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
|
||||||
fi
|
fi
|
||||||
@@ -108,7 +105,12 @@ install_agent() {
|
|||||||
chmod -R 777 $NZ_AGENT_PATH
|
chmod -R 777 $NZ_AGENT_PATH
|
||||||
|
|
||||||
echo -e "Downloading Agent"
|
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 [[ -z $CN ]]; then
|
||||||
|
NZ_AGENT_URL="https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_darwin_${os_arch}.zip"
|
||||||
|
else
|
||||||
|
NZ_AGENT_URL="https://${GITHUB_URL}/naibahq/agent/releases/download/${version}/nezha-agent_darwin_${os_arch}.zip"
|
||||||
|
fi
|
||||||
|
curl -o nezha-agent_darwin_${os_arch}.zip -L -f --retry 2 --retry-max-time 60 $NZ_AGENT_URL >/dev/null 2>&1
|
||||||
if [[ $? != 0 ]]; then
|
if [[ $? != 0 ]]; then
|
||||||
echo -e "${red}Fail to download agent, please check if the network can link ${GITHUB_URL}${plain}"
|
echo -e "${red}Fail to download agent, please check if the network can link ${GITHUB_URL}${plain}"
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
+15
-3
@@ -49,14 +49,26 @@ if ([string]::IsNullOrWhiteSpace($agenttag)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#Region判断
|
#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"
|
$ipapi = ""
|
||||||
$region=$ipapi.cc
|
$region = "Unknown"
|
||||||
|
foreach ($url in ("https://dash.cloudflare.com/cdn-cgi/trace","https://cf-ns.com/cdn-cgi/trace","https://1.0.0.1/cdn-cgi/trace")) {
|
||||||
|
try {
|
||||||
|
$ipapi = Invoke-RestMethod -Uri $url -TimeoutSec 5 -UseBasicParsing
|
||||||
|
if ($ipapi -match "loc=(\w+)" ) {
|
||||||
|
$region = $Matches[1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "Error occurred while querying $url : $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
echo $ipapi
|
echo $ipapi
|
||||||
if($region -ne "CN"){
|
if($region -ne "CN"){
|
||||||
$download = "https://github.com/$agentrepo/releases/download/$agenttag/$file"
|
$download = "https://github.com/$agentrepo/releases/download/$agenttag/$file"
|
||||||
Write-Host "Location:$region,connect directly!" -BackgroundColor DarkRed -ForegroundColor Green
|
Write-Host "Location:$region,connect directly!" -BackgroundColor DarkRed -ForegroundColor Green
|
||||||
}else{
|
}else{
|
||||||
$download = "https://github.com/$agentrepo/releases/download/$agenttag/$file"
|
$download = "https://gitee.com/naibahq/agent/releases/download/$agenttag/$file"
|
||||||
Write-Host "Location:CN,use mirror address" -BackgroundColor DarkRed -ForegroundColor Green
|
Write-Host "Location:CN,use mirror address" -BackgroundColor DarkRed -ForegroundColor Green
|
||||||
}
|
}
|
||||||
echo $download
|
echo $download
|
||||||
|
|||||||
+298
-216
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
#========================================================
|
#========================================================
|
||||||
# System Required: CentOS 7+ / Debian 8+ / Ubuntu 16+ / Alpine 3+ /
|
# System Required: CentOS 7+ / Debian 8+ / Ubuntu 16+ / Alpine 3+ /
|
||||||
@@ -12,7 +12,7 @@ NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard"
|
|||||||
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
|
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
|
||||||
NZ_DASHBOARD_SERVICE="/etc/systemd/system/nezha-dashboard.service"
|
NZ_DASHBOARD_SERVICE="/etc/systemd/system/nezha-dashboard.service"
|
||||||
NZ_DASHBOARD_SERVICERC="/etc/init.d/nezha-dashboard"
|
NZ_DASHBOARD_SERVICERC="/etc/init.d/nezha-dashboard"
|
||||||
NZ_VERSION="v0.16.3"
|
NZ_VERSION="v0.18.2"
|
||||||
|
|
||||||
red='\033[0;31m'
|
red='\033[0;31m'
|
||||||
green='\033[0;32m'
|
green='\033[0;32m'
|
||||||
@@ -21,34 +21,69 @@ plain='\033[0m'
|
|||||||
export PATH=$PATH:/usr/local/bin
|
export PATH=$PATH:/usr/local/bin
|
||||||
|
|
||||||
os_arch=""
|
os_arch=""
|
||||||
[ -e /etc/os-release ] && cat /etc/os-release | grep -i "PRETTY_NAME" | grep -qi "alpine" && os_alpine='1'
|
[ -e /etc/os-release ] && grep -i "PRETTY_NAME" /etc/os-release | grep -qi "alpine" && os_alpine='1'
|
||||||
|
|
||||||
|
sudo() {
|
||||||
|
myEUID=$(id -ru)
|
||||||
|
if [ "$myEUID" -ne 0 ]; then
|
||||||
|
if command -v sudo > /dev/null 2>&1; then
|
||||||
|
command sudo "$@"
|
||||||
|
else
|
||||||
|
err "错误: 您的系统未安装 sudo,因此无法进行该项操作。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_systemd() {
|
||||||
|
if [ "$os_alpine" != 1 ] && ! command -v systemctl >/dev/null 2>&1; then
|
||||||
|
echo "不支持此系统:未找到 systemctl 命令"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
err() {
|
||||||
|
printf "${red}$*${plain}\n" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
geo_check() {
|
||||||
|
api_list="https://blog.cloudflare.com/cdn-cgi/trace https://dash.cloudflare.com/cdn-cgi/trace https://cf-ns.com/cdn-cgi/trace"
|
||||||
|
ua="Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"
|
||||||
|
set -- $api_list
|
||||||
|
for url in $api_list; do
|
||||||
|
text="$(curl -A $ua -m 10 -s $url)"
|
||||||
|
if echo $text | grep -qw 'CN'; then
|
||||||
|
isCN=true
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
pre_check() {
|
pre_check() {
|
||||||
[ "$os_alpine" != 1 ] && ! command -v systemctl >/dev/null 2>&1 && echo "不支持此系统:未找到 systemctl 命令" && exit 1
|
|
||||||
|
|
||||||
# check root
|
|
||||||
[[ $EUID -ne 0 ]] && echo -e "${red}错误: ${plain} 必须使用root用户运行此脚本!\n" && exit 1
|
|
||||||
|
|
||||||
## os_arch
|
## os_arch
|
||||||
if [[ $(uname -m | grep 'x86_64') != "" ]]; then
|
if uname -m | grep -q 'x86_64'; then
|
||||||
os_arch="amd64"
|
os_arch="amd64"
|
||||||
elif [[ $(uname -m | grep 'i386\|i686') != "" ]]; then
|
elif uname -m | grep -q 'i386\|i686'; then
|
||||||
os_arch="386"
|
os_arch="386"
|
||||||
elif [[ $(uname -m | grep 'aarch64\|armv8b\|armv8l') != "" ]]; then
|
elif uname -m | grep -q 'aarch64\|armv8b\|armv8l'; then
|
||||||
os_arch="arm64"
|
os_arch="arm64"
|
||||||
elif [[ $(uname -m | grep 'arm') != "" ]]; then
|
elif uname -m | grep -q 'arm'; then
|
||||||
os_arch="arm"
|
os_arch="arm"
|
||||||
elif [[ $(uname -m | grep 's390x') != "" ]]; then
|
elif uname -m | grep -q 's390x'; then
|
||||||
os_arch="s390x"
|
os_arch="s390x"
|
||||||
elif [[ $(uname -m | grep 'riscv64') != "" ]]; then
|
elif uname -m | grep -q 'riscv64'; then
|
||||||
os_arch="riscv64"
|
os_arch="riscv64"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
## China_IP
|
## China_IP
|
||||||
if [[ -z "${CN}" ]]; then
|
if [ -z "$CN" ]; then
|
||||||
if [[ $(curl -m 10 -s https://ipapi.co/json | grep 'China') != "" ]]; then
|
geo_check
|
||||||
echo "根据ipapi.co提供的信息,当前IP可能在中国"
|
if [ ! -z "$isCN" ]; then
|
||||||
read -e -r -p "是否选用中国镜像完成安装? [Y/n] (自定义镜像输入 3):" input
|
echo "根据geoip api提供的信息,当前IP可能在中国"
|
||||||
|
printf "是否选用中国镜像完成安装? [Y/n] (自定义镜像输入 3):"
|
||||||
|
read -r input
|
||||||
case $input in
|
case $input in
|
||||||
[yY][eE][sS] | [yY])
|
[yY][eE][sS] | [yY])
|
||||||
echo "使用中国镜像"
|
echo "使用中国镜像"
|
||||||
@@ -61,7 +96,8 @@ pre_check() {
|
|||||||
|
|
||||||
[3])
|
[3])
|
||||||
echo "使用自定义镜像"
|
echo "使用自定义镜像"
|
||||||
read -e -r -p "请输入自定义镜像 (例如:dn-dao-github-mirror.daocloud.io),留空为不使用: " input
|
printf "请输入自定义镜像 (例如:dn-dao-github-mirror.daocloud.io),留空为不使用: "
|
||||||
|
read -r input
|
||||||
case $input in
|
case $input in
|
||||||
*)
|
*)
|
||||||
CUSTOM_MIRROR=$input
|
CUSTOM_MIRROR=$input
|
||||||
@@ -77,14 +113,14 @@ pre_check() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${CUSTOM_MIRROR}" ]]; then
|
if [ -n "$CUSTOM_MIRROR" ]; then
|
||||||
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
|
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
|
||||||
GITHUB_URL=$CUSTOM_MIRROR
|
GITHUB_URL=$CUSTOM_MIRROR
|
||||||
Get_Docker_URL="get.docker.com"
|
Get_Docker_URL="get.docker.com"
|
||||||
Get_Docker_Argu=" -s docker --mirror Aliyun"
|
Get_Docker_Argu=" -s docker --mirror Aliyun"
|
||||||
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
|
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
|
||||||
else
|
else
|
||||||
if [[ -z "${CN}" ]]; then
|
if [ -z "$CN" ]; then
|
||||||
GITHUB_RAW_URL="raw.githubusercontent.com/naiba/nezha/master"
|
GITHUB_RAW_URL="raw.githubusercontent.com/naiba/nezha/master"
|
||||||
GITHUB_URL="github.com"
|
GITHUB_URL="github.com"
|
||||||
Get_Docker_URL="get.docker.com"
|
Get_Docker_URL="get.docker.com"
|
||||||
@@ -92,7 +128,7 @@ pre_check() {
|
|||||||
Docker_IMG="ghcr.io\/naiba\/nezha-dashboard"
|
Docker_IMG="ghcr.io\/naiba\/nezha-dashboard"
|
||||||
else
|
else
|
||||||
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
|
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
|
||||||
GITHUB_URL="github.com"
|
GITHUB_URL="gitee.com"
|
||||||
Get_Docker_URL="get.docker.com"
|
Get_Docker_URL="get.docker.com"
|
||||||
Get_Docker_Argu=" -s docker --mirror Aliyun"
|
Get_Docker_Argu=" -s docker --mirror Aliyun"
|
||||||
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
|
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
|
||||||
@@ -103,8 +139,8 @@ pre_check() {
|
|||||||
installation_check() {
|
installation_check() {
|
||||||
if docker compose version >/dev/null 2>&1; then
|
if docker compose version >/dev/null 2>&1; then
|
||||||
DOCKER_COMPOSE_COMMAND="docker compose"
|
DOCKER_COMPOSE_COMMAND="docker compose"
|
||||||
if $DOCKER_COMPOSE_COMMAND ls | grep -qw "$NZ_DASHBOARD_PATH/docker-compose.yaml" >/dev/null 2>&1; then
|
if sudo $DOCKER_COMPOSE_COMMAND ls | grep -qw "$NZ_DASHBOARD_PATH/docker-compose.yaml" >/dev/null 2>&1; then
|
||||||
NEZHA_IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -w "nezha-dashboard")
|
NEZHA_IMAGES=$(sudo docker images --format "{{.Repository}}:{{.Tag}}" | grep -w "nezha-dashboard")
|
||||||
if [ -n "$NEZHA_IMAGES" ]; then
|
if [ -n "$NEZHA_IMAGES" ]; then
|
||||||
echo "存在带有 nezha-dashboard 仓库的 Docker 镜像:"
|
echo "存在带有 nezha-dashboard 仓库的 Docker 镜像:"
|
||||||
echo "$NEZHA_IMAGES"
|
echo "$NEZHA_IMAGES"
|
||||||
@@ -117,8 +153,8 @@ installation_check() {
|
|||||||
fi
|
fi
|
||||||
elif command -v docker-compose >/dev/null 2>&1; then
|
elif command -v docker-compose >/dev/null 2>&1; then
|
||||||
DOCKER_COMPOSE_COMMAND="docker-compose"
|
DOCKER_COMPOSE_COMMAND="docker-compose"
|
||||||
if $DOCKER_COMPOSE_COMMAND -f "$NZ_DASHBOARD_PATH/docker-compose.yaml" config >/dev/null 2>&1; then
|
if sudo $DOCKER_COMPOSE_COMMAND -f "$NZ_DASHBOARD_PATH/docker-compose.yaml" config >/dev/null 2>&1; then
|
||||||
NEZHA_IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -w "nezha-dashboard")
|
NEZHA_IMAGES=$(sudo docker images --format "{{.Repository}}:{{.Tag}}" | grep -w "nezha-dashboard")
|
||||||
if [ -n "$NEZHA_IMAGES" ]; then
|
if [ -n "$NEZHA_IMAGES" ]; then
|
||||||
echo "存在带有 nezha-dashboard 仓库的 Docker 镜像:"
|
echo "存在带有 nezha-dashboard 仓库的 Docker 镜像:"
|
||||||
echo "$NEZHA_IMAGES"
|
echo "$NEZHA_IMAGES"
|
||||||
@@ -131,17 +167,18 @@ installation_check() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f $NZ_DASHBOARD_PATH/app ]]; then
|
if [ -f "$NZ_DASHBOARD_PATH/app" ]; then
|
||||||
IS_DOCKER_NEZHA=0
|
IS_DOCKER_NEZHA=0
|
||||||
FRESH_INSTALL=0
|
FRESH_INSTALL=0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
select_version() {
|
select_version() {
|
||||||
if [[ -z $IS_DOCKER_NEZHA ]]; then
|
if [ -z "$IS_DOCKER_NEZHA" ]; then
|
||||||
echo -e "${yellow}请自行选择您的安装方式(如果你是安装Agent,输入哪个都是一样的):\n1. Docker\n2. 独立安装${plain}"
|
printf "${yellow}请自行选择您的安装方式(如果你是安装Agent,输入哪个都是一样的):\n1. Docker\n2. 独立安装${plain}\n"
|
||||||
while true; do
|
while true; do
|
||||||
read -e -r -p "请输入选择 [1-2]:" option
|
printf "请输入选择 [1-2]:"
|
||||||
|
read -r option
|
||||||
case "${option}" in
|
case "${option}" in
|
||||||
1)
|
1)
|
||||||
IS_DOCKER_NEZHA=1
|
IS_DOCKER_NEZHA=1
|
||||||
@@ -152,7 +189,7 @@ select_version() {
|
|||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "${red}请输入正确的数字 [1-2]${plain}"
|
err "请输入正确的选择 [1-2]"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@@ -160,18 +197,18 @@ select_version() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_script() {
|
update_script() {
|
||||||
echo -e "> 更新脚本"
|
echo "> 更新脚本"
|
||||||
|
|
||||||
curl -sL https://${GITHUB_RAW_URL}/script/install.sh -o /tmp/nezha.sh
|
curl -sL https://${GITHUB_RAW_URL}/script/install.sh -o /tmp/nezha.sh
|
||||||
new_version=$(cat /tmp/nezha.sh | grep "NZ_VERSION" | head -n 1 | awk -F "=" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
|
new_version=$(grep "NZ_VERSION" /tmp/nezha.sh | head -n 1 | awk -F "=" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
|
||||||
if [ ! -n "$new_version" ]; then
|
if [ ! -n "$new_version" ]; then
|
||||||
echo -e "脚本获取失败,请检查本机能否链接 https://${GITHUB_RAW_URL}/script/install.sh"
|
echo "脚本获取失败,请检查本机能否链接 https://${GITHUB_RAW_URL}/script/install.sh"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
echo -e "当前最新版本为: ${new_version}"
|
echo "当前最新版本为: ${new_version}"
|
||||||
mv -f /tmp/nezha.sh ./nezha.sh && chmod a+x ./nezha.sh
|
mv -f /tmp/nezha.sh ./nezha.sh && chmod a+x ./nezha.sh
|
||||||
|
|
||||||
echo -e "3s后执行新脚本"
|
echo "3s后执行新脚本"
|
||||||
sleep 3s
|
sleep 3s
|
||||||
clear
|
clear
|
||||||
exec ./nezha.sh
|
exec ./nezha.sh
|
||||||
@@ -179,23 +216,23 @@ update_script() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
before_show_menu() {
|
before_show_menu() {
|
||||||
echo && echo -n -e "${yellow}* 按回车返回主菜单 *${plain}" && read temp
|
echo && printf "${yellow}* 按回车返回主菜单 *${plain}" && read temp
|
||||||
show_menu
|
show_menu
|
||||||
}
|
}
|
||||||
|
|
||||||
install_base() {
|
install_base() {
|
||||||
(command -v git >/dev/null 2>&1 && command -v curl >/dev/null 2>&1 && command -v wget >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1 && command -v getenforce >/dev/null 2>&1) ||
|
(command -v curl >/dev/null 2>&1 && command -v wget >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1 && command -v getenforce >/dev/null 2>&1) ||
|
||||||
(install_soft curl wget git unzip)
|
(install_soft curl wget unzip)
|
||||||
}
|
}
|
||||||
|
|
||||||
install_arch() {
|
install_arch() {
|
||||||
echo -e "${green}提示: ${plain} Arch安装libselinux需添加nezha-agent用户,安装完会自动删除,建议手动检查一次\n"
|
printf "${green}提示: ${plain} Arch安装libselinux需添加nezha-agent用户,安装完会自动删除,建议手动检查一次\n"
|
||||||
read -e -r -p "是否安装libselinux? [Y/n] " input
|
read -r -p "是否安装libselinux? [Y/n] " input
|
||||||
case $input in
|
case $input in
|
||||||
[yY][eE][sS] | [yY])
|
[yY][eE][sS] | [yY])
|
||||||
useradd -m nezha-agent
|
useradd -m nezha-agent
|
||||||
sed -i "$ a\nezha-agent ALL=(ALL ) NOPASSWD:ALL" /etc/sudoers
|
sed -i "$ a\nezha-agent ALL=(ALL ) NOPASSWD:ALL" /etc/sudoers
|
||||||
sudo -iu nezha-agent bash -c 'gpg --keyserver keys.gnupg.net --recv-keys BE22091E3EF62275;
|
sudo -iu nezha-agent bash -c 'gpg --keyserver keys.gnupg.net --recv-keys 4695881C254508D1;
|
||||||
cd /tmp; git clone https://aur.archlinux.org/libsepol.git; cd libsepol; makepkg -si --noconfirm --asdeps; cd ..;
|
cd /tmp; git clone https://aur.archlinux.org/libsepol.git; cd libsepol; makepkg -si --noconfirm --asdeps; cd ..;
|
||||||
git clone https://aur.archlinux.org/libselinux.git; cd libselinux; makepkg -si --noconfirm; cd ..;
|
git clone https://aur.archlinux.org/libselinux.git; cd libselinux; makepkg -si --noconfirm; cd ..;
|
||||||
rm -rf libsepol libselinux'
|
rm -rf libsepol libselinux'
|
||||||
@@ -213,24 +250,26 @@ install_arch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_soft() {
|
install_soft() {
|
||||||
(command -v yum >/dev/null 2>&1 && yum makecache && yum install $* selinux-policy -y) ||
|
(command -v yum >/dev/null 2>&1 && sudo yum makecache && sudo yum install $* selinux-policy -y) ||
|
||||||
(command -v apt >/dev/null 2>&1 && apt update && apt install $* selinux-utils -y) ||
|
(command -v apt >/dev/null 2>&1 && sudo apt update && sudo apt install $* selinux-utils -y) ||
|
||||||
(command -v pacman >/dev/null 2>&1 && pacman -Syu $* base-devel --noconfirm && install_arch) ||
|
(command -v pacman >/dev/null 2>&1 && sudo pacman -Syu $* base-devel --noconfirm && install_arch) ||
|
||||||
(command -v apt-get >/dev/null 2>&1 && apt-get update && apt-get install $* selinux-utils -y) ||
|
(command -v apt-get >/dev/null 2>&1 && sudo apt-get update && sudo apt-get install $* selinux-utils -y) ||
|
||||||
(command -v apk >/dev/null 2>&1 && apk update && apk add $* -f)
|
(command -v apk >/dev/null 2>&1 && sudo apk update && sudo apk add $* -f)
|
||||||
}
|
}
|
||||||
|
|
||||||
install_dashboard() {
|
install_dashboard() {
|
||||||
|
check_systemd
|
||||||
install_base
|
install_base
|
||||||
|
|
||||||
echo -e "> 安装面板"
|
echo "> 安装面板"
|
||||||
|
|
||||||
# 哪吒监控文件夹
|
# 哪吒监控文件夹
|
||||||
if [[ ! $FRESH_INSTALL == 0 ]]; then
|
if [ ! "$FRESH_INSTALL" = 0 ]; then
|
||||||
mkdir -p $NZ_DASHBOARD_PATH
|
sudo mkdir -p $NZ_DASHBOARD_PATH
|
||||||
else
|
else
|
||||||
echo "您可能已经安装过面板端,重复安装会覆盖数据,请注意备份。"
|
echo "您可能已经安装过面板端,重复安装会覆盖数据,请注意备份。"
|
||||||
read -e -r -p "是否退出安装? [Y/n] " input
|
printf "是否退出安装? [Y/n] "
|
||||||
|
read -r input
|
||||||
case $input in
|
case $input in
|
||||||
[yY][eE][sS] | [yY])
|
[yY][eE][sS] | [yY])
|
||||||
echo "退出安装"
|
echo "退出安装"
|
||||||
@@ -246,40 +285,40 @@ install_dashboard() {
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
chmod 777 -R $NZ_DASHBOARD_PATH
|
sudo chmod -R 700 $NZ_DASHBOARD_PATH
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
install_dashboard_docker
|
install_dashboard_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
install_dashboard_standalone
|
install_dashboard_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
modify_dashboard_config 0
|
modify_dashboard_config 0
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_dashboard_docker() {
|
install_dashboard_docker() {
|
||||||
if [[ ! $FRESH_INSTALL == 0 ]]; then
|
if [ ! "$FRESH_INSTALL" = 0 ]; then
|
||||||
command -v docker >/dev/null 2>&1
|
command -v docker >/dev/null 2>&1
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "正在安装 Docker"
|
echo "正在安装 Docker"
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
bash <(curl -sL https://${Get_Docker_URL}) ${Get_Docker_Argu} >/dev/null 2>&1
|
curl -sL https://${Get_Docker_URL} | sudo bash -s ${Get_Docker_Argu}
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "${red}下载脚本失败,请检查本机能否连接 ${Get_Docker_URL}${plain}"
|
err "下载脚本失败,请检查本机能否连接 ${Get_Docker_URL}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
systemctl enable docker.service
|
sudo systemctl enable docker.service
|
||||||
systemctl start docker.service
|
sudo systemctl start docker.service
|
||||||
else
|
else
|
||||||
apk add docker docker-compose >/dev/null 2>&1
|
sudo apk add docker docker-compose
|
||||||
rc-update add docker
|
sudo rc-update add docker
|
||||||
rc-service docker start
|
sudo rc-service docker start
|
||||||
fi
|
fi
|
||||||
echo -e "${green}Docker${plain} 安装成功"
|
printf "${green}Docker${plain} 安装成功\n"
|
||||||
installation_check
|
installation_check
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -287,7 +326,7 @@ install_dashboard_docker() {
|
|||||||
|
|
||||||
install_dashboard_standalone() {
|
install_dashboard_standalone() {
|
||||||
if [ ! -d "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" ] || [ ! -d "${NZ_DASHBOARD_PATH}/resource/static/custom" ]; then
|
if [ ! -d "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" ] || [ ! -d "${NZ_DASHBOARD_PATH}/resource/static/custom" ]; then
|
||||||
mkdir -p "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" "${NZ_DASHBOARD_PATH}/resource/static/custom" >/dev/null 2>&1
|
sudo mkdir -p "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" "${NZ_DASHBOARD_PATH}/resource/static/custom" >/dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,10 +336,10 @@ selinux() {
|
|||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
getenforce | grep '[Ee]nfor'
|
getenforce | grep '[Ee]nfor'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo -e "SELinux是开启状态,正在关闭!"
|
echo "SELinux是开启状态,正在关闭!"
|
||||||
setenforce 0 &>/dev/null
|
sudo setenforce 0 &>/dev/null
|
||||||
find_key="SELINUX="
|
find_key="SELINUX="
|
||||||
sed -ri "/^$find_key/c${find_key}disabled" /etc/selinux/config
|
sudo sed -ri "/^$find_key/c${find_key}disabled" /etc/selinux/config
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -309,11 +348,14 @@ install_agent() {
|
|||||||
install_base
|
install_base
|
||||||
selinux
|
selinux
|
||||||
|
|
||||||
echo -e "> 安装监控Agent"
|
echo "> 安装监控Agent"
|
||||||
|
|
||||||
echo -e "正在获取监控Agent版本号"
|
echo "正在获取监控Agent版本号"
|
||||||
|
|
||||||
local version=$(curl -m 10 -sL "https://api.github.com/repos/nezhahq/agent/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
|
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://gitee.com/api/v5/repos/naibahq/agent/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}')
|
||||||
|
fi
|
||||||
if [ ! -n "$version" ]; then
|
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')
|
version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
|
||||||
fi
|
fi
|
||||||
@@ -322,26 +364,31 @@ install_agent() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -n "$version" ]; then
|
if [ ! -n "$version" ]; then
|
||||||
echo -e "获取版本号失败,请检查本机能否链接 https://api.github.com/repos/nezhahq/agent/releases/latest"
|
err "获取版本号失败,请检查本机能否链接 https://api.github.com/repos/nezhahq/agent/releases/latest"
|
||||||
return 0
|
return 1
|
||||||
else
|
else
|
||||||
echo -e "当前最新版本为: ${version}"
|
echo "当前最新版本为: ${version}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 哪吒监控文件夹
|
# 哪吒监控文件夹
|
||||||
mkdir -p $NZ_AGENT_PATH
|
sudo mkdir -p $NZ_AGENT_PATH
|
||||||
chmod 777 -R $NZ_AGENT_PATH
|
sudo chmod -R 700 $NZ_AGENT_PATH
|
||||||
|
|
||||||
echo -e "正在下载监控端"
|
echo "正在下载监控端"
|
||||||
wget -t 2 -T 60 -O nezha-agent_linux_${os_arch}.zip https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_linux_${os_arch}.zip >/dev/null 2>&1
|
if [ -z "$CN" ]; then
|
||||||
if [[ $? != 0 ]]; then
|
NZ_AGENT_URL="https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_linux_${os_arch}.zip"
|
||||||
echo -e "${red}Release 下载失败,请检查本机能否连接 ${GITHUB_URL}${plain}"
|
else
|
||||||
return 0
|
NZ_AGENT_URL="https://${GITHUB_URL}/naibahq/agent/releases/download/${version}/nezha-agent_linux_${os_arch}.zip"
|
||||||
|
fi
|
||||||
|
wget -t 2 -T 60 -O nezha-agent_linux_${os_arch}.zip $NZ_AGENT_URL >/dev/null 2>&1
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
err "Release 下载失败,请检查本机能否连接 ${GITHUB_URL}"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
unzip -qo nezha-agent_linux_${os_arch}.zip &&
|
sudo unzip -qo nezha-agent_linux_${os_arch}.zip &&
|
||||||
mv nezha-agent $NZ_AGENT_PATH &&
|
sudo mv nezha-agent $NZ_AGENT_PATH &&
|
||||||
rm -rf nezha-agent_linux_${os_arch}.zip README.md
|
sudo rm -rf nezha-agent_linux_${os_arch}.zip README.md
|
||||||
|
|
||||||
if [ $# -ge 3 ]; then
|
if [ $# -ge 3 ]; then
|
||||||
modify_agent_config "$@"
|
modify_agent_config "$@"
|
||||||
@@ -349,27 +396,31 @@ install_agent() {
|
|||||||
modify_agent_config 0
|
modify_agent_config 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
modify_agent_config() {
|
modify_agent_config() {
|
||||||
echo -e "> 修改Agent配置"
|
echo "> 修改Agent配置"
|
||||||
|
|
||||||
if [ $# -lt 3 ]; then
|
if [ $# -lt 3 ]; then
|
||||||
echo "请先在管理面板上添加Agent,记录下密钥" &&
|
echo "请先在管理面板上添加Agent,记录下密钥"
|
||||||
read -ep "请输入一个解析到面板所在IP的域名(不可套CDN): " nz_grpc_host &&
|
printf "请输入一个解析到面板所在IP的域名(不可套CDN): "
|
||||||
read -ep "请输入面板RPC端口 (默认值 5555): " nz_grpc_port &&
|
read -r nz_grpc_host
|
||||||
read -ep "请输入Agent 密钥: " nz_client_secret &&
|
printf "请输入面板RPC端口 (默认值 5555): "
|
||||||
read -ep "是否启用针对 gRPC 端口的 SSL/TLS加密 (--tls),需要请按 [y],默认是不需要,不理解用户可回车跳过: " nz_grpc_proxy
|
read -r nz_grpc_port
|
||||||
grep -qiw 'Y' <<<"${nz_grpc_proxy}" && args='--tls'
|
printf "请输入Agent 密钥: "
|
||||||
if [[ -z "${nz_grpc_host}" || -z "${nz_client_secret}" ]]; then
|
read -r nz_client_secret
|
||||||
echo -e "${red}所有选项都不能为空${plain}"
|
printf "是否启用针对 gRPC 端口的 SSL/TLS加密 (--tls),需要请按 [y],默认是不需要,不理解用户可回车跳过: "
|
||||||
|
read -r nz_grpc_proxy
|
||||||
|
echo "${nz_grpc_proxy}" | grep -qiw 'Y' && args='--tls'
|
||||||
|
if [ -z "$nz_grpc_host" ] || [ -z "$nz_client_secret" ]; then
|
||||||
|
err "所有选项都不能为空"
|
||||||
before_show_menu
|
before_show_menu
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if [[ -z "${nz_grpc_port}" ]]; then
|
if [ -z "$nz_grpc_port" ]; then
|
||||||
nz_grpc_port=5555
|
nz_grpc_port=5555
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -382,14 +433,14 @@ modify_agent_config() {
|
|||||||
fi
|
fi
|
||||||
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
|
sudo ${NZ_AGENT_PATH}/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p $nz_client_secret $args >/dev/null 2>&1
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
${NZ_AGENT_PATH}/nezha-agent service uninstall >/dev/null 2>&1
|
sudo ${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
|
sudo ${NZ_AGENT_PATH}/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p $nz_client_secret $args >/dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "Agent配置 ${green}修改成功,请稍等重启生效${plain}"
|
printf "Agent配置 ${green}修改成功,请稍等重启生效${plain}\n"
|
||||||
|
|
||||||
#if [[ $# == 0 ]]; then
|
#if [[ $# == 0 ]]; then
|
||||||
# before_show_menu
|
# before_show_menu
|
||||||
@@ -397,46 +448,53 @@ modify_agent_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
modify_dashboard_config() {
|
modify_dashboard_config() {
|
||||||
echo -e "> 修改面板配置"
|
echo "> 修改面板配置"
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
echo -e "正在下载 Docker 脚本"
|
echo "正在下载 Docker 脚本"
|
||||||
wget -t 2 -T 60 -O /tmp/nezha-docker-compose.yaml https://${GITHUB_RAW_URL}/script/docker-compose.yaml >/dev/null 2>&1
|
wget -t 2 -T 60 -O /tmp/nezha-docker-compose.yaml https://${GITHUB_RAW_URL}/script/docker-compose.yaml >/dev/null 2>&1
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "${red}下载脚本失败,请检查本机能否连接 ${GITHUB_RAW_URL}${plain}"
|
err "下载脚本失败,请检查本机能否连接 ${GITHUB_RAW_URL}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
wget -t 2 -T 60 -O /tmp/nezha-config.yaml https://${GITHUB_RAW_URL}/script/config.yaml >/dev/null 2>&1
|
wget -t 2 -T 60 -O /tmp/nezha-config.yaml https://${GITHUB_RAW_URL}/script/config.yaml >/dev/null 2>&1
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "${red}下载脚本失败,请检查本机能否连接 ${GITHUB_RAW_URL}${plain}"
|
err "下载脚本失败,请检查本机能否连接 ${GITHUB_RAW_URL}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "关于 GitHub Oauth2 应用:在 https://github.com/settings/developers 创建,无需审核,Callback 填 http(s)://域名或IP/oauth2/callback" &&
|
echo "关于 GitHub Oauth2 应用:在 https://github.com/settings/developers 创建,无需审核,Callback 填 http(s)://域名或IP/oauth2/callback"
|
||||||
echo "关于 Gitee Oauth2 应用:在 https://gitee.com/oauth/applications 创建,无需审核,Callback 填 http(s)://域名或IP/oauth2/callback" &&
|
echo "关于 Gitee Oauth2 应用:在 https://gitee.com/oauth/applications 创建,无需审核,Callback 填 http(s)://域名或IP/oauth2/callback"
|
||||||
read -ep "请输入 OAuth2 提供商(github/gitlab/jihulab/gitee,默认 github): " nz_oauth2_type &&
|
printf "请输入 OAuth2 提供商(github/gitlab/jihulab/gitee,默认 github): "
|
||||||
read -ep "请输入 Oauth2 应用的 Client ID: " nz_github_oauth_client_id &&
|
read -r nz_oauth2_type
|
||||||
read -ep "请输入 Oauth2 应用的 Client Secret: " nz_github_oauth_client_secret &&
|
printf "请输入 Oauth2 应用的 Client ID: "
|
||||||
read -ep "请输入 GitHub/Gitee 登录名作为管理员,多个以逗号隔开: " nz_admin_logins &&
|
read -r nz_github_oauth_client_id
|
||||||
read -ep "请输入站点标题: " nz_site_title &&
|
printf "请输入 Oauth2 应用的 Client Secret: "
|
||||||
read -ep "请输入站点访问端口: (默认 8008)" nz_site_port &&
|
read -r nz_github_oauth_client_secret
|
||||||
read -ep "请输入用于 Agent 接入的 RPC 端口: (默认 5555)" nz_grpc_port
|
printf "请输入 GitHub/Gitee 登录名作为管理员,多个以逗号隔开: "
|
||||||
|
read -r nz_admin_logins
|
||||||
|
printf "请输入站点标题: "
|
||||||
|
read -r nz_site_title
|
||||||
|
printf "请输入站点访问端口: (默认 8008)"
|
||||||
|
read -r nz_site_port
|
||||||
|
printf "请输入用于 Agent 接入的 RPC 端口: (默认 5555)"
|
||||||
|
read -r nz_grpc_port
|
||||||
|
|
||||||
if [[ -z "${nz_admin_logins}" || -z "${nz_github_oauth_client_id}" || -z "${nz_github_oauth_client_secret}" || -z "${nz_site_title}" ]]; then
|
if [ -z "$nz_admin_logins" ] || [ -z "$nz_github_oauth_client_id" ] || [ -z "$nz_github_oauth_client_secret" ] || [ -z "$nz_site_title" ]; then
|
||||||
echo -e "${red}所有选项都不能为空${plain}"
|
err "所有选项都不能为空"
|
||||||
before_show_menu
|
before_show_menu
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "${nz_site_port}" ]]; then
|
if [ -z "$nz_site_port" ]; then
|
||||||
nz_site_port=8008
|
nz_site_port=8008
|
||||||
fi
|
fi
|
||||||
if [[ -z "${nz_grpc_port}" ]]; then
|
if [ -z "$nz_grpc_port" ]; then
|
||||||
nz_grpc_port=5555
|
nz_grpc_port=5555
|
||||||
fi
|
fi
|
||||||
if [[ -z "${nz_oauth2_type}" ]]; then
|
if [ -z "$nz_oauth2_type" ]; then
|
||||||
nz_oauth2_type=github
|
nz_oauth2_type=github
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -447,260 +505,284 @@ modify_dashboard_config() {
|
|||||||
sed -i "s/nz_github_oauth_client_secret/${nz_github_oauth_client_secret}/" /tmp/nezha-config.yaml
|
sed -i "s/nz_github_oauth_client_secret/${nz_github_oauth_client_secret}/" /tmp/nezha-config.yaml
|
||||||
sed -i "s/nz_language/zh-CN/" /tmp/nezha-config.yaml
|
sed -i "s/nz_language/zh-CN/" /tmp/nezha-config.yaml
|
||||||
sed -i "s/nz_site_title/${nz_site_title}/" /tmp/nezha-config.yaml
|
sed -i "s/nz_site_title/${nz_site_title}/" /tmp/nezha-config.yaml
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
sed -i "s/nz_site_port/${nz_site_port}/" /tmp/nezha-docker-compose.yaml
|
sed -i "s/nz_site_port/${nz_site_port}/" /tmp/nezha-docker-compose.yaml
|
||||||
sed -i "s/nz_grpc_port/${nz_grpc_port}/g" /tmp/nezha-docker-compose.yaml
|
sed -i "s/nz_grpc_port/${nz_grpc_port}/g" /tmp/nezha-docker-compose.yaml
|
||||||
sed -i "s/nz_image_url/${Docker_IMG}/" /tmp/nezha-docker-compose.yaml
|
sed -i "s/nz_image_url/${Docker_IMG}/" /tmp/nezha-docker-compose.yaml
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
sed -i "s/80/${nz_site_port}/" /tmp/nezha-config.yaml
|
sed -i "s/80/${nz_site_port}/" /tmp/nezha-config.yaml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p $NZ_DASHBOARD_PATH/data
|
sudo mkdir -p $NZ_DASHBOARD_PATH/data
|
||||||
mv -f /tmp/nezha-config.yaml ${NZ_DASHBOARD_PATH}/data/config.yaml
|
sudo mv -f /tmp/nezha-config.yaml ${NZ_DASHBOARD_PATH}/data/config.yaml
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
mv -f /tmp/nezha-docker-compose.yaml ${NZ_DASHBOARD_PATH}/docker-compose.yaml
|
sudo mv -f /tmp/nezha-docker-compose.yaml ${NZ_DASHBOARD_PATH}/docker-compose.yaml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
echo -e "正在下载服务文件"
|
echo "正在下载服务文件"
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICE https://${GITHUB_RAW_URL}/script/nezha-dashboard.service >/dev/null 2>&1
|
sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICE https://${GITHUB_RAW_URL}/script/nezha-dashboard.service >/dev/null 2>&1
|
||||||
else
|
else
|
||||||
wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-dashboard >/dev/null 2>&1
|
sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-dashboard >/dev/null 2>&1
|
||||||
chmod +x $NZ_DASHBOARD_SERVICERC
|
sudo chmod +x $NZ_DASHBOARD_SERVICERC
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "${red}文件下载失败,请检查本机能否连接 ${GITHUB_RAW_URL}${plain}"
|
err "文件下载失败,请检查本机能否连接 ${GITHUB_RAW_URL}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "面板配置 ${green}修改成功,请稍等重启生效${plain}"
|
printf "面板配置 ${green}修改成功,请稍等重启生效${plain}\n"
|
||||||
|
|
||||||
restart_and_update
|
restart_and_update
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_and_update() {
|
restart_and_update() {
|
||||||
echo -e "> 重启并更新面板"
|
echo "> 重启并更新面板"
|
||||||
|
|
||||||
cd $NZ_DASHBOARD_PATH
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
|
||||||
restart_and_update_docker
|
restart_and_update_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
restart_and_update_standalone
|
restart_and_update_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $? == 0 ]]; then
|
if [ $? = 0 ]; then
|
||||||
echo -e "${green}哪吒监控 重启成功${plain}"
|
printf "${green}哪吒监控 重启成功${plain}\n"
|
||||||
echo -e "默认管理面板地址:${yellow}域名:站点访问端口${plain}"
|
printf "默认管理面板地址:${yellow}域名:站点访问端口${plain}\n"
|
||||||
else
|
else
|
||||||
echo -e "${red}重启失败,可能是因为启动时间超过了两秒,请稍后查看日志信息${plain}"
|
err "重启失败,可能是因为启动时间超过了两秒,请稍后查看日志信息"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_and_update_docker() {
|
restart_and_update_docker() {
|
||||||
$DOCKER_COMPOSE_COMMAND pull
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml pull
|
||||||
$DOCKER_COMPOSE_COMMAND down
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml down
|
||||||
$DOCKER_COMPOSE_COMMAND up -d
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml up -d
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_and_update_standalone() {
|
restart_and_update_standalone() {
|
||||||
if [ "$os_alpine" != 1 ]; then
|
local version=$(curl -m 10 -sL "https://api.github.com/repos/naiba/nezha/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
|
||||||
systemctl stop nezha-dashboard
|
if [ ! -n "$version" ]; then
|
||||||
else
|
version=$(curl -m 10 -sL "https://gitee.com/api/v5/repos/naibahq/nezha/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}')
|
||||||
rc-service nezha-dashboard stop
|
fi
|
||||||
|
if [ ! -n "$version" ]; then
|
||||||
|
version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g')
|
||||||
|
fi
|
||||||
|
if [ ! -n "$version" ]; then
|
||||||
|
version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
wget -qO app.zip https://${GITHUB_URL}/naiba/nezha/releases/latest/download/dashboard-linux-$os_arch.zip >/dev/null 2>&1 && unzip -qq app.zip && mv dist/dashboard-linux-$os_arch app && rm -r app.zip dist
|
if [ "$os_alpine" != 1 ]; then
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl stop nezha-dashboard
|
||||||
|
else
|
||||||
|
sudo rc-service nezha-dashboard stop
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -n "$version" ]; then
|
||||||
|
err "获取版本号失败,请检查本机能否链接 https://api.github.com/repos/naiba/nezha/releases/latest"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
echo "当前最新版本为: ${version}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$CN" ]; then
|
||||||
|
NZ_DASHBOARD_URL="https://${GITHUB_URL}/naiba/nezha/releases/download/$version/dashboard-linux-$os_arch.zip"
|
||||||
|
else
|
||||||
|
NZ_DASHBOARD_URL="https://${GITHUB_URL}/naibahq/nezha/releases/download/$version/dashboard-linux-$os_arch.zip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo wget -qO $NZ_DASHBOARD_PATH/app.zip $NZ_DASHBOARD_URL >/dev/null 2>&1 && sudo unzip -qq $NZ_DASHBOARD_PATH/app.zip -d $NZ_DASHBOARD_PATH && sudo mv $NZ_DASHBOARD_PATH/dist/dashboard-linux-$os_arch $NZ_DASHBOARD_PATH/app && sudo rm -r $NZ_DASHBOARD_PATH/app.zip $NZ_DASHBOARD_PATH/dist
|
||||||
|
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
systemctl daemon-reload
|
sudo systemctl enable nezha-dashboard
|
||||||
systemctl enable nezha-dashboard
|
sudo systemctl restart nezha-dashboard
|
||||||
systemctl restart nezha-dashboard
|
|
||||||
else
|
else
|
||||||
rc-update add nezha-dashboard
|
sudo rc-update add nezha-dashboard
|
||||||
rc-service nezha-dashboard restart
|
sudo rc-service nezha-dashboard restart
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
start_dashboard() {
|
start_dashboard() {
|
||||||
echo -e "> 启动面板"
|
echo "> 启动面板"
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
start_dashboard_docker
|
start_dashboard_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
start_dashboard_standalone
|
start_dashboard_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $? == 0 ]]; then
|
if [ $? = 0 ]; then
|
||||||
echo -e "${green}哪吒监控 启动成功${plain}"
|
printf "${green}哪吒监控 启动成功${plain}\n"
|
||||||
else
|
else
|
||||||
echo -e "${red}启动失败,请稍后查看日志信息${plain}"
|
err "启动失败,请稍后查看日志信息"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
start_dashboard_docker() {
|
start_dashboard_docker() {
|
||||||
cd $NZ_DASHBOARD_PATH && $DOCKER_COMPOSE_COMMAND up -d
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml up -d
|
||||||
}
|
}
|
||||||
|
|
||||||
start_dashboard_standalone() {
|
start_dashboard_standalone() {
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
systemctl start nezha-dashboard
|
sudo systemctl start nezha-dashboard
|
||||||
else
|
else
|
||||||
rc-service nezha-dashboard start
|
sudo rc-service nezha-dashboard start
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_dashboard() {
|
stop_dashboard() {
|
||||||
echo -e "> 停止面板"
|
echo "> 停止面板"
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
stop_dashboard_docker
|
stop_dashboard_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
stop_dashboard_standalone
|
stop_dashboard_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $? == 0 ]]; then
|
if [ $? = 0 ]; then
|
||||||
echo -e "${green}哪吒监控 停止成功${plain}"
|
printf "${green}哪吒监控 停止成功${plain}\n"
|
||||||
else
|
else
|
||||||
echo -e "${red}停止失败,请稍后查看日志信息${plain}"
|
err "停止失败,请稍后查看日志信息"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_dashboard_docker() {
|
stop_dashboard_docker() {
|
||||||
cd $NZ_DASHBOARD_PATH && $DOCKER_COMPOSE_COMMAND down
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml down
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_dashboard_standalone() {
|
stop_dashboard_standalone() {
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
systemctl stop nezha-dashboard
|
sudo systemctl stop nezha-dashboard
|
||||||
else
|
else
|
||||||
rc-service nezha-dashboard stop
|
sudo rc-service nezha-dashboard stop
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
show_dashboard_log() {
|
show_dashboard_log() {
|
||||||
echo -e "> 获取面板日志"
|
echo "> 获取面板日志"
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
show_dashboard_log_docker
|
show_dashboard_log_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
show_dashboard_log_standalone
|
show_dashboard_log_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
show_dashboard_log_docker() {
|
show_dashboard_log_docker() {
|
||||||
cd $NZ_DASHBOARD_PATH && $DOCKER_COMPOSE_COMMAND logs -f
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml logs -f
|
||||||
}
|
}
|
||||||
|
|
||||||
show_dashboard_log_standalone() {
|
show_dashboard_log_standalone() {
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
journalctl -xf -u nezha-dashboard.service
|
sudo journalctl -xf -u nezha-dashboard.service
|
||||||
else
|
else
|
||||||
tail -n 10 /var/log/nezha-dashboard.err
|
sudo tail -n 10 /var/log/nezha-dashboard.err
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_dashboard() {
|
uninstall_dashboard() {
|
||||||
echo -e "> 卸载管理面板"
|
echo "> 卸载管理面板"
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
uninstall_dashboard_docker
|
uninstall_dashboard_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
uninstall_dashboard_standalone
|
uninstall_dashboard_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
clean_all
|
clean_all
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_dashboard_docker() {
|
uninstall_dashboard_docker() {
|
||||||
cd $NZ_DASHBOARD_PATH && $DOCKER_COMPOSE_COMMAND down
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml down
|
||||||
rm -rf $NZ_DASHBOARD_PATH
|
sudo rm -rf $NZ_DASHBOARD_PATH
|
||||||
docker rmi -f ghcr.io/naiba/nezha-dashboard >/dev/null 2>&1
|
sudo docker rmi -f ghcr.io/naiba/nezha-dashboard >/dev/null 2>&1
|
||||||
docker rmi -f registry.cn-shanghai.aliyuncs.com/naibahq/nezha-dashboard >/dev/null 2>&1
|
sudo docker rmi -f registry.cn-shanghai.aliyuncs.com/naibahq/nezha-dashboard >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_dashboard_standalone() {
|
uninstall_dashboard_standalone() {
|
||||||
rm -rf $NZ_DASHBOARD_PATH
|
sudo rm -rf $NZ_DASHBOARD_PATH
|
||||||
|
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
systemctl stop nezha-dashboard
|
sudo systemctl disable nezha-dashboard
|
||||||
|
sudo systemctl stop nezha-dashboard
|
||||||
else
|
else
|
||||||
rc-service nezha-dashboard stop
|
sudo rc-update del nezha-dashboard
|
||||||
|
sudo rc-service nezha-dashboard stop
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
rm $NZ_DASHBOARD_SERVICE
|
sudo rm $NZ_DASHBOARD_SERVICE
|
||||||
else
|
else
|
||||||
rm $NZ_DASHBOARD_SERVICERC
|
sudo rm $NZ_DASHBOARD_SERVICERC
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
show_agent_log() {
|
show_agent_log() {
|
||||||
echo -e "> 获取Agent日志"
|
echo "> 获取Agent日志"
|
||||||
|
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
journalctl -xf -u nezha-agent.service
|
sudo journalctl -xf -u nezha-agent.service
|
||||||
else
|
else
|
||||||
tail -n 10 /var/log/nezha-agent.err
|
sudo tail -n 10 /var/log/nezha-agent.err
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_agent() {
|
uninstall_agent() {
|
||||||
echo -e "> 卸载Agent"
|
echo "> 卸载Agent"
|
||||||
|
|
||||||
${NZ_AGENT_PATH}/nezha-agent service uninstall
|
sudo ${NZ_AGENT_PATH}/nezha-agent service uninstall
|
||||||
|
|
||||||
rm -rf $NZ_AGENT_PATH
|
sudo rm -rf $NZ_AGENT_PATH
|
||||||
clean_all
|
clean_all
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_agent() {
|
restart_agent() {
|
||||||
echo -e "> 重启Agent"
|
echo "> 重启Agent"
|
||||||
|
|
||||||
${NZ_AGENT_PATH}/nezha-agent service restart
|
sudo ${NZ_AGENT_PATH}/nezha-agent service restart
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
clean_all() {
|
clean_all() {
|
||||||
if [ -z "$(ls -A ${NZ_BASE_PATH})" ]; then
|
if [ -z "$(ls -A ${NZ_BASE_PATH})" ]; then
|
||||||
rm -rf ${NZ_BASE_PATH}
|
sudo rm -rf ${NZ_BASE_PATH}
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -726,7 +808,7 @@ show_usage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
show_menu() {
|
show_menu() {
|
||||||
echo -e "
|
printf "
|
||||||
${green}哪吒监控管理脚本${plain} ${red}${NZ_VERSION}${plain}
|
${green}哪吒监控管理脚本${plain} ${red}${NZ_VERSION}${plain}
|
||||||
--- https://github.com/naiba/nezha ---
|
--- https://github.com/naiba/nezha ---
|
||||||
${green}1.${plain} 安装面板端
|
${green}1.${plain} 安装面板端
|
||||||
@@ -747,7 +829,7 @@ show_menu() {
|
|||||||
————————————————-
|
————————————————-
|
||||||
${green}0.${plain} 退出脚本
|
${green}0.${plain} 退出脚本
|
||||||
"
|
"
|
||||||
echo && read -ep "请输入选择 [0-13]: " num
|
echo && printf "请输入选择 [0-13]: " && read -r num
|
||||||
case "${num}" in
|
case "${num}" in
|
||||||
0)
|
0)
|
||||||
exit 0
|
exit 0
|
||||||
@@ -792,7 +874,7 @@ show_menu() {
|
|||||||
update_script
|
update_script
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo -e "${red}请输入正确的数字 [0-13]${plain}"
|
err "请输入正确的数字 [0-13]"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -800,7 +882,7 @@ show_menu() {
|
|||||||
pre_check
|
pre_check
|
||||||
installation_check
|
installation_check
|
||||||
|
|
||||||
if [[ $# > 0 ]]; then
|
if [ $# -gt 0 ]; then
|
||||||
case $1 in
|
case $1 in
|
||||||
"install_dashboard")
|
"install_dashboard")
|
||||||
install_dashboard 0
|
install_dashboard 0
|
||||||
|
|||||||
+299
-219
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
#========================================================
|
#========================================================
|
||||||
# System Required: CentOS 7+ / Debian 8+ / Ubuntu 16+ / Alpine 3+ /
|
# System Required: CentOS 7+ / Debian 8+ / Ubuntu 16+ / Alpine 3+ /
|
||||||
@@ -12,7 +12,7 @@ NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard"
|
|||||||
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
|
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
|
||||||
NZ_DASHBOARD_SERVICE="/etc/systemd/system/nezha-dashboard.service"
|
NZ_DASHBOARD_SERVICE="/etc/systemd/system/nezha-dashboard.service"
|
||||||
NZ_DASHBOARD_SERVICERC="/etc/init.d/nezha-dashboard"
|
NZ_DASHBOARD_SERVICERC="/etc/init.d/nezha-dashboard"
|
||||||
NZ_VERSION="v0.16.3"
|
NZ_VERSION="v0.18.2"
|
||||||
|
|
||||||
red='\033[0;31m'
|
red='\033[0;31m'
|
||||||
green='\033[0;32m'
|
green='\033[0;32m'
|
||||||
@@ -21,34 +21,69 @@ plain='\033[0m'
|
|||||||
export PATH=$PATH:/usr/local/bin
|
export PATH=$PATH:/usr/local/bin
|
||||||
|
|
||||||
os_arch=""
|
os_arch=""
|
||||||
[ -e /etc/os-release ] && cat /etc/os-release | grep -i "PRETTY_NAME" | grep -qi "alpine" && os_alpine='1'
|
[ -e /etc/os-release ] && grep -i "PRETTY_NAME" /etc/os-release | grep -qi "alpine" && os_alpine='1'
|
||||||
|
|
||||||
|
sudo() {
|
||||||
|
myEUID=$(id -ru)
|
||||||
|
if [ "$myEUID" -ne 0 ]; then
|
||||||
|
if command -v sudo > /dev/null 2>&1; then
|
||||||
|
command sudo "$@"
|
||||||
|
else
|
||||||
|
err "ERROR: sudo is not installed on the system, the action cannot be proceeded."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_systemd() {
|
||||||
|
if [ "$os_alpine" != 1 ] && ! command -v systemctl >/dev/null 2>&1; then
|
||||||
|
echo "System not supported: systemctl not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
err() {
|
||||||
|
printf "${red}$*${plain}\n" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
geo_check() {
|
||||||
|
api_list="https://blog.cloudflare.com/cdn-cgi/trace https://dash.cloudflare.com/cdn-cgi/trace https://cf-ns.com/cdn-cgi/trace"
|
||||||
|
ua="Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"
|
||||||
|
set -- $api_list
|
||||||
|
for url in $api_list; do
|
||||||
|
text="$(curl -A $ua -m 10 -s $url)"
|
||||||
|
if echo $text | grep -qw 'CN'; then
|
||||||
|
isCN=true
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
pre_check() {
|
pre_check() {
|
||||||
[ "$os_alpine" != 1 ] && ! command -v systemctl >/dev/null 2>&1 && echo "This system is not supported: systemctl not found" && exit 1
|
|
||||||
|
|
||||||
# check root
|
|
||||||
[[ $EUID -ne 0 ]] && echo -e "${red}ERROR: ${plain} This script must be run with the root user!\n" && exit 1
|
|
||||||
|
|
||||||
## os_arch
|
## os_arch
|
||||||
if [[ $(uname -m | grep 'x86_64') != "" ]]; then
|
if uname -m | grep -q 'x86_64'; then
|
||||||
os_arch="amd64"
|
os_arch="amd64"
|
||||||
elif [[ $(uname -m | grep 'i386\|i686') != "" ]]; then
|
elif uname -m | grep -q 'i386\|i686'; then
|
||||||
os_arch="386"
|
os_arch="386"
|
||||||
elif [[ $(uname -m | grep 'aarch64\|armv8b\|armv8l') != "" ]]; then
|
elif uname -m | grep -q 'aarch64\|armv8b\|armv8l'; then
|
||||||
os_arch="arm64"
|
os_arch="arm64"
|
||||||
elif [[ $(uname -m | grep 'arm') != "" ]]; then
|
elif uname -m | grep -q 'arm'; then
|
||||||
os_arch="arm"
|
os_arch="arm"
|
||||||
elif [[ $(uname -m | grep 's390x') != "" ]]; then
|
elif uname -m | grep -q 's390x'; then
|
||||||
os_arch="s390x"
|
os_arch="s390x"
|
||||||
elif [[ $(uname -m | grep 'riscv64') != "" ]]; then
|
elif uname -m | grep -q 'riscv64'; then
|
||||||
os_arch="riscv64"
|
os_arch="riscv64"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
## China_IP
|
## China_IP
|
||||||
if [[ -z "${CN}" ]]; then
|
if [ -z "$CN" ]; then
|
||||||
if [[ $(curl -m 10 -s https://ipapi.co/json | grep 'China') != "" ]]; then
|
geo_check
|
||||||
echo "According to the information provided by ipapi.co, the current IP may be in China"
|
if [ ! -z "$isCN" ]; then
|
||||||
read -e -r -p "Is the installation done with a Chinese Mirror? [Y/n] (Custom Mirror Input 3):" input
|
echo "According to the information provided by various geoip api, the current IP may be in China"
|
||||||
|
printf "Will the installation be done with a Chinese Mirror? [Y/n] (Custom Mirror Input 3): "
|
||||||
|
read -r input
|
||||||
case $input in
|
case $input in
|
||||||
[yY][eE][sS] | [yY])
|
[yY][eE][sS] | [yY])
|
||||||
echo "Use Chinese Mirror"
|
echo "Use Chinese Mirror"
|
||||||
@@ -56,12 +91,13 @@ pre_check() {
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
[nN][oO] | [nN])
|
[nN][oO] | [nN])
|
||||||
echo "No Use Chinese Mirror"
|
echo "Do Not Use Chinese Mirror"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
[3])
|
[3])
|
||||||
echo "Use Custom Mirror"
|
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
|
printf "Please enter a custom image (e.g. :dn-dao-github-mirror.daocloud.io). If left blank, it won't be used: "
|
||||||
|
read -r input
|
||||||
case $input in
|
case $input in
|
||||||
*)
|
*)
|
||||||
CUSTOM_MIRROR=$input
|
CUSTOM_MIRROR=$input
|
||||||
@@ -70,20 +106,20 @@ pre_check() {
|
|||||||
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "No Use Chinese Mirror"
|
echo "Do Not Use Chinese Mirror"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${CUSTOM_MIRROR}" ]]; then
|
if [ -n "$CUSTOM_MIRROR" ]; then
|
||||||
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
|
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
|
||||||
GITHUB_URL=$CUSTOM_MIRROR
|
GITHUB_URL=$CUSTOM_MIRROR
|
||||||
Get_Docker_URL="get.docker.com"
|
Get_Docker_URL="get.docker.com"
|
||||||
Get_Docker_Argu=" -s docker --mirror Aliyun"
|
Get_Docker_Argu=" -s docker --mirror Aliyun"
|
||||||
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
|
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
|
||||||
else
|
else
|
||||||
if [[ -z "${CN}" ]]; then
|
if [ -z "$CN" ]; then
|
||||||
GITHUB_RAW_URL="raw.githubusercontent.com/naiba/nezha/master"
|
GITHUB_RAW_URL="raw.githubusercontent.com/naiba/nezha/master"
|
||||||
GITHUB_URL="github.com"
|
GITHUB_URL="github.com"
|
||||||
Get_Docker_URL="get.docker.com"
|
Get_Docker_URL="get.docker.com"
|
||||||
@@ -91,7 +127,7 @@ pre_check() {
|
|||||||
Docker_IMG="ghcr.io\/naiba\/nezha-dashboard"
|
Docker_IMG="ghcr.io\/naiba\/nezha-dashboard"
|
||||||
else
|
else
|
||||||
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
|
GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
|
||||||
GITHUB_URL="github.com"
|
GITHUB_URL="gitee.com"
|
||||||
Get_Docker_URL="get.docker.com"
|
Get_Docker_URL="get.docker.com"
|
||||||
Get_Docker_Argu=" -s docker --mirror Aliyun"
|
Get_Docker_Argu=" -s docker --mirror Aliyun"
|
||||||
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
|
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
|
||||||
@@ -102,12 +138,13 @@ pre_check() {
|
|||||||
installation_check() {
|
installation_check() {
|
||||||
if docker compose version >/dev/null 2>&1; then
|
if docker compose version >/dev/null 2>&1; then
|
||||||
DOCKER_COMPOSE_COMMAND="docker compose"
|
DOCKER_COMPOSE_COMMAND="docker compose"
|
||||||
if $DOCKER_COMPOSE_COMMAND ls | grep -qw "$NZ_DASHBOARD_PATH/docker-compose.yaml" >/dev/null 2>&1; then
|
if sudo $DOCKER_COMPOSE_COMMAND ls | grep -qw "$NZ_DASHBOARD_PATH/docker-compose.yaml" >/dev/null 2>&1; then
|
||||||
NEZHA_IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -w "nezha-dashboard")
|
NEZHA_IMAGES=$(sudo docker images --format "{{.Repository}}:{{.Tag}}" | grep -w "nezha-dashboard")
|
||||||
if [ -n "$NEZHA_IMAGES" ]; then
|
if [ -n "$NEZHA_IMAGES" ]; then
|
||||||
echo "Docker image with nezha-dashboard repository exists:"
|
echo "Docker image with nezha-dashboard repository exists:"
|
||||||
echo "$NEZHA_IMAGES"
|
echo "$NEZHA_IMAGES"
|
||||||
IS_DOCKER_NEZHA=1
|
IS_DOCKER_NEZHA=1
|
||||||
|
FRESH_INSTALL=0
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
echo "No Docker images with the nezha-dashboard repository were found."
|
echo "No Docker images with the nezha-dashboard repository were found."
|
||||||
@@ -115,12 +152,13 @@ installation_check() {
|
|||||||
fi
|
fi
|
||||||
elif command -v docker-compose >/dev/null 2>&1; then
|
elif command -v docker-compose >/dev/null 2>&1; then
|
||||||
DOCKER_COMPOSE_COMMAND="docker-compose"
|
DOCKER_COMPOSE_COMMAND="docker-compose"
|
||||||
if $DOCKER_COMPOSE_COMMAND -f "$NZ_DASHBOARD_PATH/docker-compose.yaml" config >/dev/null 2>&1; then
|
if sudo $DOCKER_COMPOSE_COMMAND -f "$NZ_DASHBOARD_PATH/docker-compose.yaml" config >/dev/null 2>&1; then
|
||||||
NEZHA_IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -w "nezha-dashboard")
|
NEZHA_IMAGES=$(sudo docker images --format "{{.Repository}}:{{.Tag}}" | grep -w "nezha-dashboard")
|
||||||
if [ -n "$NEZHA_IMAGES" ]; then
|
if [ -n "$NEZHA_IMAGES" ]; then
|
||||||
echo "Docker image with nezha-dashboard repository exists:"
|
echo "Docker image with nezha-dashboard repository exists:"
|
||||||
echo "$NEZHA_IMAGES"
|
echo "$NEZHA_IMAGES"
|
||||||
IS_DOCKER_NEZHA=1
|
IS_DOCKER_NEZHA=1
|
||||||
|
FRESH_INSTALL=0
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
echo "No Docker images with the nezha-dashboard repository were found."
|
echo "No Docker images with the nezha-dashboard repository were found."
|
||||||
@@ -128,17 +166,18 @@ installation_check() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f $NZ_DASHBOARD_PATH/app ]]; then
|
if [ -f "$NZ_DASHBOARD_PATH/app" ]; then
|
||||||
IS_DOCKER_NEZHA=0
|
IS_DOCKER_NEZHA=0
|
||||||
FRESH_INSTALL=0
|
FRESH_INSTALL=0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
select_version() {
|
select_version() {
|
||||||
if [[ -z $IS_DOCKER_NEZHA ]]; then
|
if [ -z "$IS_DOCKER_NEZHA" ]; then
|
||||||
echo -e "${yellow}Select your installation method(Input anything is ok if you are installing agent):\n1. Docker\n2. Standalone${plain}"
|
printf "${yellow}Select your installation method(Input anything is ok if you are installing agent):\n1. Docker\n2. Standalone${plain}\n"
|
||||||
while true; do
|
while true; do
|
||||||
read -e -r -p "Please enter [1-2]: " option
|
printf "Please enter [1-2]: "
|
||||||
|
read -r option
|
||||||
case "${option}" in
|
case "${option}" in
|
||||||
1)
|
1)
|
||||||
IS_DOCKER_NEZHA=1
|
IS_DOCKER_NEZHA=1
|
||||||
@@ -149,7 +188,7 @@ select_version() {
|
|||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "${red}Please enter the correct number [1-2]${plain}"
|
err "Please enter the correct number [1-2]"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@@ -157,18 +196,18 @@ select_version() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_script() {
|
update_script() {
|
||||||
echo -e "> Update Script"
|
echo "> Update Script"
|
||||||
|
|
||||||
curl -sL https://${GITHUB_RAW_URL}/script/install_en.sh -o /tmp/nezha.sh
|
curl -sL https://${GITHUB_RAW_URL}/script/install_en.sh -o /tmp/nezha.sh
|
||||||
new_version=$(cat /tmp/nezha.sh | grep "NZ_VERSION" | head -n 1 | awk -F "=" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
|
new_version=$(grep "NZ_VERSION" /tmp/nezha.sh | head -n 1 | awk -F "=" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
|
||||||
if [ ! -n "$new_version" ]; then
|
if [ ! -n "$new_version" ]; then
|
||||||
echo -e "Script failed to get, please check if the network can link https://${GITHUB_RAW_URL}/script/install.sh"
|
echo "Script failed to get, please check if the network can link https://${GITHUB_RAW_URL}/script/install.sh"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
echo -e "The current latest version is: ${new_version}"
|
echo "The current latest version is: ${new_version}"
|
||||||
mv -f /tmp/nezha.sh ./nezha.sh && chmod a+x ./nezha.sh
|
mv -f /tmp/nezha.sh ./nezha.sh && chmod a+x ./nezha.sh
|
||||||
|
|
||||||
echo -e "Execute new script after 3s"
|
echo "Execute new script after 3s"
|
||||||
sleep 3s
|
sleep 3s
|
||||||
clear
|
clear
|
||||||
exec ./nezha.sh
|
exec ./nezha.sh
|
||||||
@@ -176,23 +215,23 @@ update_script() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
before_show_menu() {
|
before_show_menu() {
|
||||||
echo && echo -n -e "${yellow}* Press Enter to return to the main menu *${plain}" && read temp
|
echo && printf "${yellow}* Press Enter to return to the main menu *${plain}" && read temp
|
||||||
show_menu
|
show_menu
|
||||||
}
|
}
|
||||||
|
|
||||||
install_base() {
|
install_base() {
|
||||||
(command -v git >/dev/null 2>&1 && command -v curl >/dev/null 2>&1 && command -v wget >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1 && command -v getenforce >/dev/null 2>&1) ||
|
(command -v curl >/dev/null 2>&1 && command -v wget >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1 && command -v getenforce >/dev/null 2>&1) ||
|
||||||
(install_soft curl wget git unzip tzdata)
|
(install_soft curl wget unzip)
|
||||||
}
|
}
|
||||||
|
|
||||||
install_arch() {
|
install_arch() {
|
||||||
echo -e "${green}Info: ${plain} Archlinux needs to add nezha-agent user to install libselinux. It will be deleted automatically after installation. It is recommended to check manually\n"
|
printf "${green}Info: ${plain} Archlinux needs to add nezha-agent user to install libselinux. It will be deleted automatically after installation. It is recommended to check manually\n"
|
||||||
read -e -r -p "Do you need to install libselinux? [Y/n] " input
|
read -r -p "Do you need to install libselinux? [Y/n] " input
|
||||||
case $input in
|
case $input in
|
||||||
[yY][eE][sS] | [yY])
|
[yY][eE][sS] | [yY])
|
||||||
useradd -m nezha-agent
|
useradd -m nezha-agent
|
||||||
sed -i "$ a\nezha-agent ALL=(ALL ) NOPASSWD:ALL" /etc/sudoers
|
sed -i "$ a\nezha-agent ALL=(ALL ) NOPASSWD:ALL" /etc/sudoers
|
||||||
sudo -iu nezha-agent bash -c 'gpg --keyserver keys.gnupg.net --recv-keys BE22091E3EF62275;
|
sudo -iu nezha-agent bash -c 'gpg --keyserver keys.gnupg.net --recv-keys 4695881C254508D1;
|
||||||
cd /tmp; git clone https://aur.archlinux.org/libsepol.git; cd libsepol; makepkg -si --noconfirm --asdeps; cd ..;
|
cd /tmp; git clone https://aur.archlinux.org/libsepol.git; cd libsepol; makepkg -si --noconfirm --asdeps; cd ..;
|
||||||
git clone https://aur.archlinux.org/libselinux.git; cd libselinux; makepkg -si --noconfirm; cd ..;
|
git clone https://aur.archlinux.org/libselinux.git; cd libselinux; makepkg -si --noconfirm; cd ..;
|
||||||
rm -rf libsepol libselinux'
|
rm -rf libsepol libselinux'
|
||||||
@@ -210,24 +249,26 @@ install_arch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_soft() {
|
install_soft() {
|
||||||
(command -v yum >/dev/null 2>&1 && yum makecache && yum install $* selinux-policy -y) ||
|
(command -v yum >/dev/null 2>&1 && sudo yum makecache && sudo yum install $* selinux-policy -y) ||
|
||||||
(command -v apt >/dev/null 2>&1 && apt update && apt install $* selinux-utils -y) ||
|
(command -v apt >/dev/null 2>&1 && sudo apt update && sudo apt install $* selinux-utils -y) ||
|
||||||
(command -v pacman >/dev/null 2>&1 && pacman -Syu $* base-devel --noconfirm && install_arch) ||
|
(command -v pacman >/dev/null 2>&1 && sudo pacman -Syu $* base-devel --noconfirm && install_arch) ||
|
||||||
(command -v apt-get >/dev/null 2>&1 && apt-get update && apt-get install $* selinux-utils -y) ||
|
(command -v apt-get >/dev/null 2>&1 && sudo apt-get update && sudo apt-get install $* selinux-utils -y) ||
|
||||||
(command -v apk >/dev/null 2>&1 && apk update && apk add $* -f)
|
(command -v apk >/dev/null 2>&1 && sudo apk update && sudo apk add $* -f)
|
||||||
}
|
}
|
||||||
|
|
||||||
install_dashboard() {
|
install_dashboard() {
|
||||||
|
check_systemd
|
||||||
install_base
|
install_base
|
||||||
|
|
||||||
echo -e "> Install Panel"
|
echo "> Install Dashboard"
|
||||||
|
|
||||||
# Nezha Monitoring Folder
|
# Nezha Monitoring Folder
|
||||||
if [[ ! $FRESH_INSTALL == 0 ]]; then
|
if [ ! "$FRESH_INSTALL" = 0 ]; then
|
||||||
mkdir -p $NZ_DASHBOARD_PATH
|
sudo mkdir -p $NZ_DASHBOARD_PATH
|
||||||
else
|
else
|
||||||
echo "You may have already installed the dashboard, repeated installation will overwrite the data, please pay attention to backup."
|
echo "You may have already installed the dashboard, repeated installation will overwrite the data, please pay attention to backup."
|
||||||
read -e -r -p "Exit the installation? [Y/n] " input
|
printf "Exit the installation? [Y/n] "
|
||||||
|
read -r input
|
||||||
case $input in
|
case $input in
|
||||||
[yY][eE][sS] | [yY])
|
[yY][eE][sS] | [yY])
|
||||||
echo "Exit the installation."
|
echo "Exit the installation."
|
||||||
@@ -242,40 +283,41 @@ install_dashboard() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
chmod 777 -R $NZ_DASHBOARD_PATH
|
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
sudo chmod -R 700 $NZ_DASHBOARD_PATH
|
||||||
|
|
||||||
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
install_dashboard_docker
|
install_dashboard_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
install_dashboard_standalone
|
install_dashboard_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
modify_dashboard_config 0
|
modify_dashboard_config 0
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_dashboard_docker() {
|
install_dashboard_docker() {
|
||||||
if [[ ! $FRESH_INSTALL == 0 ]]; then
|
if [ ! "$FRESH_INSTALL" = 0 ]; then
|
||||||
command -v docker >/dev/null 2>&1
|
command -v docker >/dev/null 2>&1
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "Installing Docker"
|
echo "Installing Docker"
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
bash <(curl -sL https://${Get_Docker_URL}) ${Get_Docker_Argu} >/dev/null 2>&1
|
curl -sL https://${Get_Docker_URL} | sudo bash -s ${Get_Docker_Argu}
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "${red}Script failed to get, please check if the network can link ${Get_Docker_URL}${plain}"
|
err "Script failed to get, please check if the network can link ${Get_Docker_URL}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
systemctl enable docker.service
|
sudo systemctl enable docker.service
|
||||||
systemctl start docker.service
|
sudo systemctl start docker.service
|
||||||
else
|
else
|
||||||
apk add docker docker-compose >/dev/null 2>&1
|
sudo apk add docker docker-compose
|
||||||
rc-update add docker
|
sudo rc-update add docker
|
||||||
rc-service docker start
|
sudo rc-service docker start
|
||||||
fi
|
fi
|
||||||
echo -e "${green}Docker${plain} installed successfully"
|
printf "${green}Docker${plain} installed successfully\n"
|
||||||
installation_check
|
installation_check
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -283,7 +325,7 @@ install_dashboard_docker() {
|
|||||||
|
|
||||||
install_dashboard_standalone() {
|
install_dashboard_standalone() {
|
||||||
if [ ! -d "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" ] || [ ! -d "${NZ_DASHBOARD_PATH}/resource/static/custom" ]; then
|
if [ ! -d "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" ] || [ ! -d "${NZ_DASHBOARD_PATH}/resource/static/custom" ]; then
|
||||||
mkdir -p "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" "${NZ_DASHBOARD_PATH}/resource/static/custom" >/dev/null 2>&1
|
sudo mkdir -p "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" "${NZ_DASHBOARD_PATH}/resource/static/custom" >/dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,10 +335,10 @@ selinux() {
|
|||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
getenforce | grep '[Ee]nfor'
|
getenforce | grep '[Ee]nfor'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo -e "SELinux running,closing now!"
|
echo "SELinux running, closing now!"
|
||||||
setenforce 0 &>/dev/null
|
sudo setenforce 0 &>/dev/null
|
||||||
find_key="SELINUX="
|
find_key="SELINUX="
|
||||||
sed -ri "/^$find_key/c${find_key}disabled" /etc/selinux/config
|
sudo sed -ri "/^$find_key/c${find_key}disabled" /etc/selinux/config
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -305,11 +347,14 @@ install_agent() {
|
|||||||
install_base
|
install_base
|
||||||
selinux
|
selinux
|
||||||
|
|
||||||
echo -e "> Install Nezha Agent"
|
echo "> Install Agent"
|
||||||
|
|
||||||
echo -e "Obtaining Agent version"
|
echo "Obtaining Agent version number"
|
||||||
|
|
||||||
local version=$(curl -m 10 -sL "https://api.github.com/repos/nezhahq/agent/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
|
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://gitee.com/api/v5/repos/naibahq/agent/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}')
|
||||||
|
fi
|
||||||
if [ ! -n "$version" ]; then
|
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')
|
version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
|
||||||
fi
|
fi
|
||||||
@@ -318,26 +363,26 @@ install_agent() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -n "$version" ]; then
|
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"
|
err "Fail to obtaine agent version, please check if the network can link https://api.github.com/repos/nezhahq/agent/releases/latest"
|
||||||
return 0
|
return 1
|
||||||
else
|
else
|
||||||
echo -e "The current latest version is: ${version}"
|
echo "The current latest version is: ${version}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Nezha Monitoring Folder
|
# Nezha Monitoring Folder
|
||||||
mkdir -p $NZ_AGENT_PATH
|
sudo mkdir -p $NZ_AGENT_PATH
|
||||||
chmod 777 -R $NZ_AGENT_PATH
|
sudo chmod -R 700 $NZ_AGENT_PATH
|
||||||
|
|
||||||
echo -e "Downloading Agent"
|
echo "Downloading Agent"
|
||||||
wget -t 2 -T 60 -O nezha-agent_linux_${os_arch}.zip https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_linux_${os_arch}.zip >/dev/null 2>&1
|
wget -t 2 -T 60 -O nezha-agent_linux_${os_arch}.zip https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_linux_${os_arch}.zip >/dev/null 2>&1
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "${red}Fail to download agent, please check if the network can link ${GITHUB_URL}${plain}"
|
err "Fail to download agent, please check if the network can link ${GITHUB_URL}"
|
||||||
return 0
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
unzip -qo nezha-agent_linux_${os_arch}.zip &&
|
sudo unzip -qo nezha-agent_linux_${os_arch}.zip &&
|
||||||
mv nezha-agent $NZ_AGENT_PATH &&
|
sudo mv nezha-agent $NZ_AGENT_PATH &&
|
||||||
rm -rf nezha-agent_linux_${os_arch}.zip README.md
|
sudo rm -rf nezha-agent_linux_${os_arch}.zip README.md
|
||||||
|
|
||||||
if [ $# -ge 3 ]; then
|
if [ $# -ge 3 ]; then
|
||||||
modify_agent_config "$@"
|
modify_agent_config "$@"
|
||||||
@@ -345,27 +390,31 @@ install_agent() {
|
|||||||
modify_agent_config 0
|
modify_agent_config 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
modify_agent_config() {
|
modify_agent_config() {
|
||||||
echo -e "> Modify Agent Configuration"
|
echo "> Modify Agent Configuration"
|
||||||
|
|
||||||
if [ $# -lt 3 ]; then
|
if [ $# -lt 3 ]; then
|
||||||
echo "Please add Agent in the admin panel first, record the secret" &&
|
echo "Please add Agent in the 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 &&
|
printf "Please enter a domain that resolves to the IP where the panel is located (no CDN): "
|
||||||
read -ep "Please enter the panel RPC port (default 5555): " nz_grpc_port &&
|
read -r nz_grpc_host
|
||||||
read -ep "Please enter the Agent secret: " nz_client_secret &&
|
printf "Please enter the panel RPC port (default 5555): "
|
||||||
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
|
read -r nz_grpc_port
|
||||||
grep -qiw 'Y' <<<"${nz_grpc_proxy}" && args='--tls'
|
printf "Please enter the Agent secret: "
|
||||||
if [[ -z "${nz_grpc_host}" || -z "${nz_client_secret}" ]]; then
|
read -r nz_client_secret
|
||||||
echo -e "${red}All options cannot be empty${plain}"
|
printf "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: "
|
||||||
|
read -r nz_grpc_proxy
|
||||||
|
echo "${nz_grpc_proxy}" | grep -qiw 'Y' && args='--tls'
|
||||||
|
if [ -z "$nz_grpc_host" ] || [ -z "$nz_client_secret" ]; then
|
||||||
|
err "All options cannot be empty"
|
||||||
before_show_menu
|
before_show_menu
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if [[ -z "${nz_grpc_port}" ]]; then
|
if [ -z "$nz_grpc_port" ]; then
|
||||||
nz_grpc_port=5555
|
nz_grpc_port=5555
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -378,14 +427,14 @@ modify_agent_config() {
|
|||||||
fi
|
fi
|
||||||
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
|
sudo ${NZ_AGENT_PATH}/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p $nz_client_secret $args >/dev/null 2>&1
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
${NZ_AGENT_PATH}/nezha-agent service uninstall >/dev/null 2>&1
|
sudo ${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
|
sudo ${NZ_AGENT_PATH}/nezha-agent service install -s "$nz_grpc_host:$nz_grpc_port" -p $nz_client_secret $args >/dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "Agent configuration ${green} modified successfully, please wait for agent self-restart to take effect${plain}"
|
printf "Agent configuration ${green} modified successfully, please wait for agent self-restart to take effect${plain}\n"
|
||||||
|
|
||||||
#if [[ $# == 0 ]]; then
|
#if [[ $# == 0 ]]; then
|
||||||
# before_show_menu
|
# before_show_menu
|
||||||
@@ -393,46 +442,53 @@ modify_agent_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
modify_dashboard_config() {
|
modify_dashboard_config() {
|
||||||
echo -e "> Modify Panel Configuration"
|
echo "> Modify Dashboard Configuration"
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
echo -e "Download Docker Script"
|
echo "Download Docker Script"
|
||||||
wget -t 2 -T 60 -O /tmp/nezha-docker-compose.yaml https://${GITHUB_RAW_URL}/script/docker-compose.yaml >/dev/null 2>&1
|
wget -t 2 -T 60 -O /tmp/nezha-docker-compose.yaml https://${GITHUB_RAW_URL}/script/docker-compose.yaml >/dev/null 2>&1
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "${red}Script failed to get, please check if the network can link ${GITHUB_RAW_URL}${plain}"
|
err "Script failed to get, please check if the network can link ${GITHUB_RAW_URL}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
wget -t 2 -T 60 -O /tmp/nezha-config.yaml https://${GITHUB_RAW_URL}/script/config.yaml >/dev/null 2>&1
|
wget -t 2 -T 60 -O /tmp/nezha-config.yaml https://${GITHUB_RAW_URL}/script/config.yaml >/dev/null 2>&1
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "${red}Script failed to get, please check if the network can link ${GITHUB_RAW_URL}${plain}"
|
err "Script failed to get, please check if the network can link ${GITHUB_RAW_URL}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "About the GitHub Oauth2 application: create it at https://github.com/settings/developers, no review required, and fill in the http(s)://domain_or_IP/oauth2/callback" &&
|
echo "About the GitHub Oauth2 application: create it at https://github.com/settings/developers, no review required, and fill in the http(s)://domain_or_IP/oauth2/callback"
|
||||||
echo "(Not recommended) About the Gitee Oauth2 application: create it at https://gitee.com/oauth/applications, no auditing required, and fill in the http(s)://domain_or_IP/oauth2/callback" &&
|
echo "(Not recommended) About the Gitee Oauth2 application: create it at https://gitee.com/oauth/applications, no auditing required, and fill in the http(s)://domain_or_IP/oauth2/callback"
|
||||||
read -ep "Please enter the OAuth2 provider (github/gitlab/jihulab/gitee, default github): " nz_oauth2_type &&
|
printf "Please enter the OAuth2 provider (github/gitlab/jihulab/gitee, default github): "
|
||||||
read -ep "Please enter the Client ID of the Oauth2 application: " nz_github_oauth_client_id &&
|
read -r nz_oauth2_type
|
||||||
read -ep "Please enter the Client Secret of the Oauth2 application: " nz_github_oauth_client_secret &&
|
printf "Please enter the Client ID of the Oauth2 application: "
|
||||||
read -ep "Please enter your GitHub/Gitee login name as the administrator, separated by commas: " nz_admin_logins &&
|
read -r nz_github_oauth_client_id
|
||||||
read -ep "Please enter the site title: " nz_site_title &&
|
printf "Please enter the Client Secret of the Oauth2 application: "
|
||||||
read -ep "Please enter the site access port: (default 8008)" nz_site_port &&
|
read -r nz_github_oauth_client_secret
|
||||||
read -ep "Please enter the RPC port to be used for Agent access: (default 5555)" nz_grpc_port
|
printf "Please enter your GitHub/Gitee login name as the administrator, separated by commas: "
|
||||||
|
read -r nz_admin_logins
|
||||||
|
printf "Please enter the site title: "
|
||||||
|
read -r nz_site_title
|
||||||
|
printf "Please enter the site access port: (default 8008)"
|
||||||
|
read -r nz_site_port
|
||||||
|
printf "Please enter the RPC port to be used for Agent access: (default 5555)"
|
||||||
|
read -r nz_grpc_port
|
||||||
|
|
||||||
if [[ -z "${nz_admin_logins}" || -z "${nz_github_oauth_client_id}" || -z "${nz_github_oauth_client_secret}" || -z "${nz_site_title}" ]]; then
|
if [ -z "$nz_admin_logins" ] || [ -z "$nz_github_oauth_client_id" ] || [ -z "$nz_github_oauth_client_secret" ] || [ -z "$nz_site_title" ]; then
|
||||||
echo -e "${red}All options cannot be empty${plain}"
|
err "All options cannot be empty"
|
||||||
before_show_menu
|
before_show_menu
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "${nz_site_port}" ]]; then
|
if [ -z "$nz_site_port" ]; then
|
||||||
nz_site_port=8008
|
nz_site_port=8008
|
||||||
fi
|
fi
|
||||||
if [[ -z "${nz_grpc_port}" ]]; then
|
if [ -z "$nz_grpc_port" ]; then
|
||||||
nz_grpc_port=5555
|
nz_grpc_port=5555
|
||||||
fi
|
fi
|
||||||
if [[ -z "${nz_oauth2_type}" ]]; then
|
if [ -z "$nz_oauth2_type" ]; then
|
||||||
nz_oauth2_type=github
|
nz_oauth2_type=github
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -441,262 +497,286 @@ modify_dashboard_config() {
|
|||||||
sed -i "s/nz_grpc_port/${nz_grpc_port}/" /tmp/nezha-config.yaml
|
sed -i "s/nz_grpc_port/${nz_grpc_port}/" /tmp/nezha-config.yaml
|
||||||
sed -i "s/nz_github_oauth_client_id/${nz_github_oauth_client_id}/" /tmp/nezha-config.yaml
|
sed -i "s/nz_github_oauth_client_id/${nz_github_oauth_client_id}/" /tmp/nezha-config.yaml
|
||||||
sed -i "s/nz_github_oauth_client_secret/${nz_github_oauth_client_secret}/" /tmp/nezha-config.yaml
|
sed -i "s/nz_github_oauth_client_secret/${nz_github_oauth_client_secret}/" /tmp/nezha-config.yaml
|
||||||
|
sed -i "s/nz_language/zh-CN/" /tmp/nezha-config.yaml
|
||||||
sed -i "s/nz_site_title/${nz_site_title}/" /tmp/nezha-config.yaml
|
sed -i "s/nz_site_title/${nz_site_title}/" /tmp/nezha-config.yaml
|
||||||
sed -i "s/nz_language/en-US/" /tmp/nezha-config.yaml
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
|
||||||
sed -i "s/nz_site_port/${nz_site_port}/" /tmp/nezha-docker-compose.yaml
|
sed -i "s/nz_site_port/${nz_site_port}/" /tmp/nezha-docker-compose.yaml
|
||||||
sed -i "s/nz_grpc_port/${nz_grpc_port}/g" /tmp/nezha-docker-compose.yaml
|
sed -i "s/nz_grpc_port/${nz_grpc_port}/g" /tmp/nezha-docker-compose.yaml
|
||||||
sed -i "s/nz_image_url/${Docker_IMG}/" /tmp/nezha-docker-compose.yaml
|
sed -i "s/nz_image_url/${Docker_IMG}/" /tmp/nezha-docker-compose.yaml
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
sed -i "s/80/${nz_site_port}/" /tmp/nezha-config.yaml
|
sed -i "s/80/${nz_site_port}/" /tmp/nezha-config.yaml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p $NZ_DASHBOARD_PATH/data
|
sudo mkdir -p $NZ_DASHBOARD_PATH/data
|
||||||
mv -f /tmp/nezha-config.yaml ${NZ_DASHBOARD_PATH}/data/config.yaml
|
sudo mv -f /tmp/nezha-config.yaml ${NZ_DASHBOARD_PATH}/data/config.yaml
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
mv -f /tmp/nezha-docker-compose.yaml ${NZ_DASHBOARD_PATH}/docker-compose.yaml
|
sudo mv -f /tmp/nezha-docker-compose.yaml ${NZ_DASHBOARD_PATH}/docker-compose.yaml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
echo -e "Downloading service file"
|
echo "Downloading service file"
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICE https://${GITHUB_RAW_URL}/script/nezha-dashboard.service >/dev/null 2>&1
|
sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICE https://${GITHUB_RAW_URL}/script/nezha-dashboard.service >/dev/null 2>&1
|
||||||
else
|
else
|
||||||
wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-dashboard >/dev/null 2>&1
|
sudo wget -t 2 -T 60 -O $NZ_DASHBOARD_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-dashboard >/dev/null 2>&1
|
||||||
chmod +x $NZ_DASHBOARD_SERVICERC
|
sudo chmod +x $NZ_DASHBOARD_SERVICERC
|
||||||
if [[ $? != 0 ]]; then
|
if [ $? != 0 ]; then
|
||||||
echo -e "${red}File failed to get, please check if the network can link ${GITHUB_RAW_URL}${plain}"
|
err "File failed to get, please check if the network can link ${GITHUB_RAW_URL}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "Dashboard configuration ${green} modified successfully, please wait for Dashboard self-restart to take effect${plain}"
|
printf "Dashboard configuration ${green} modified successfully, please wait for Dashboard self-restart to take effect${plain}\n"
|
||||||
|
|
||||||
restart_and_update
|
restart_and_update
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_and_update() {
|
restart_and_update() {
|
||||||
echo -e "> Restart and Update the Panel"
|
echo "> Restart and Update the Panel"
|
||||||
|
|
||||||
cd $NZ_DASHBOARD_PATH
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
|
||||||
restart_and_update_docker
|
restart_and_update_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
restart_and_update_standalone
|
restart_and_update_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $? == 0 ]]; then
|
if [ $? = 0 ]; then
|
||||||
echo -e "${green}Nezha Monitoring Restart Successful${plain}"
|
printf "${green}Nezha Monitoring Restart Successful${plain}\n"
|
||||||
echo -e "Default panel address: ${yellow}domain:Site_access_port${plain}"
|
printf "Default panel address: ${yellow}domain:Site_access_port${plain}\n"
|
||||||
else
|
else
|
||||||
echo -e "${red}The restart failed, probably because the boot time exceeded two seconds, please check the log information later${plain}"
|
err "The restart failed, probably because the boot time exceeded two seconds, please check the log information later"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_and_update_docker() {
|
restart_and_update_docker() {
|
||||||
$DOCKER_COMPOSE_COMMAND pull
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml pull
|
||||||
$DOCKER_COMPOSE_COMMAND down
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml down
|
||||||
$DOCKER_COMPOSE_COMMAND up -d
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml up -d
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_and_update_standalone() {
|
restart_and_update_standalone() {
|
||||||
if [ "$os_alpine" != 1 ]; then
|
local version=$(curl -m 10 -sL "https://api.github.com/repos/naiba/nezha/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
|
||||||
systemctl stop nezha-dashboard
|
if [ ! -n "$version" ]; then
|
||||||
else
|
version=$(curl -m 10 -sL "https://gitee.com/api/v5/repos/naibahq/nezha/releases/latest" | awk -F '"' '{for(i=1;i<=NF;i++){if($i=="tag_name"){print $(i+2)}}}')
|
||||||
rc-service nezha-dashboard stop
|
fi
|
||||||
|
if [ ! -n "$version" ]; then
|
||||||
|
version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g')
|
||||||
|
fi
|
||||||
|
if [ ! -n "$version" ]; then
|
||||||
|
version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/naiba/nezha/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/naiba\/nezha@/v/g')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
wget -qO app.zip https://${GITHUB_URL}/naiba/nezha/releases/latest/download/dashboard-linux-$os_arch.zip >/dev/null 2>&1 && unzip -qq app.zip && mv dist/dashboard-linux-$os_arch app && rm -r app.zip dist
|
if [ ! -n "$version" ]; then
|
||||||
|
err "Fail to obtaine agent version, please check if the network can link https://api.github.com/repos/nezhahq/agent/releases/latest"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
echo "The current latest version is: ${version}"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
systemctl enable nezha-dashboard
|
sudo systemctl stop nezha-dashboard
|
||||||
systemctl restart nezha-dashboard
|
|
||||||
else
|
else
|
||||||
rc-update add nezha-dashboard
|
sudo rc-service nezha-dashboard stop
|
||||||
rc-service nezha-dashboard restart
|
fi
|
||||||
|
|
||||||
|
if [ -z "$CN" ]; then
|
||||||
|
NZ_DASHBOARD_URL="https://${GITHUB_URL}/naiba/nezha/releases/download/$version/dashboard-linux-$os_arch.zip"
|
||||||
|
else
|
||||||
|
NZ_DASHBOARD_URL="https://${GITHUB_URL}/naibahq/nezha/releases/download/$version/dashboard-linux-$os_arch.zip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo wget -qO $NZ_DASHBOARD_PATH/app.zip $NZ_DASHBOARD_URL >/dev/null 2>&1 && sudo unzip -qq $NZ_DASHBOARD_PATH/app.zip -d $NZ_DASHBOARD_PATH && sudo mv $NZ_DASHBOARD_PATH/dist/dashboard-linux-$os_arch $NZ_DASHBOARD_PATH/app && sudo rm -r $NZ_DASHBOARD_PATH/app.zip $NZ_DASHBOARD_PATH/dist
|
||||||
|
|
||||||
|
if [ "$os_alpine" != 1 ]; then
|
||||||
|
sudo systemctl enable nezha-dashboard
|
||||||
|
sudo systemctl restart nezha-dashboard
|
||||||
|
else
|
||||||
|
sudo rc-update add nezha-dashboard
|
||||||
|
sudo rc-service nezha-dashboard restart
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
start_dashboard() {
|
start_dashboard() {
|
||||||
echo -e "> Start Panel"
|
echo "> Start Panel"
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
start_dashboard_docker
|
start_dashboard_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
start_dashboard_standalone
|
start_dashboard_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $? == 0 ]]; then
|
if [ $? = 0 ]; then
|
||||||
echo -e "${green}Nezha Monitoring Start Successful${plain}"
|
printf "${green}Nezha Monitoring Start Successful${plain}\n"
|
||||||
else
|
else
|
||||||
echo -e "${red}Failed to start, please check the log message later${plain}"
|
err "Failed to start, please check the log message later"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
start_dashboard_docker() {
|
start_dashboard_docker() {
|
||||||
cd $NZ_DASHBOARD_PATH && $DOCKER_COMPOSE_COMMAND up -d
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml up -d
|
||||||
}
|
}
|
||||||
|
|
||||||
start_dashboard_standalone() {
|
start_dashboard_standalone() {
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
systemctl start nezha-dashboard
|
sudo systemctl start nezha-dashboard
|
||||||
else
|
else
|
||||||
rc-service nezha-dashboard start
|
sudo rc-service nezha-dashboard start
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_dashboard() {
|
stop_dashboard() {
|
||||||
echo -e "> Stop Panel"
|
echo "> Stop Panel"
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
stop_dashboard_docker
|
stop_dashboard_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
stop_dashboard_standalone
|
stop_dashboard_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $? == 0 ]]; then
|
if [ $? = 0 ]; then
|
||||||
echo -e "${green}Nezha Monitoring Stop Successful${plain}"
|
printf "${green}Nezha Monitoring Stop Successful${plain}\n"
|
||||||
else
|
else
|
||||||
echo -e "${red}Failed to stop, please check the log message later${plain}"
|
err "Failed to stop, please check the log message later"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_dashboard_docker() {
|
stop_dashboard_docker() {
|
||||||
cd $NZ_DASHBOARD_PATH && $DOCKER_COMPOSE_COMMAND down
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml down
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_dashboard_standalone() {
|
stop_dashboard_standalone() {
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
systemctl stop nezha-dashboard
|
sudo systemctl stop nezha-dashboard
|
||||||
else
|
else
|
||||||
rc-service nezha-dashboard stop
|
sudo rc-service nezha-dashboard stop
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
show_dashboard_log() {
|
show_dashboard_log() {
|
||||||
echo -e "> View Panel Log"
|
echo "> View Panel Log"
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
show_dashboard_log_docker
|
show_dashboard_log_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
show_dashboard_log_standalone
|
show_dashboard_log_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
show_dashboard_log_docker() {
|
show_dashboard_log_docker() {
|
||||||
cd $NZ_DASHBOARD_PATH && $DOCKER_COMPOSE_COMMAND logs -f
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml logs -f
|
||||||
}
|
}
|
||||||
|
|
||||||
show_dashboard_log_standalone() {
|
show_dashboard_log_standalone() {
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
journalctl -xf -u nezha-dashboard.service
|
sudo journalctl -xf -u nezha-dashboard.service
|
||||||
else
|
else
|
||||||
tail -n 10 /var/log/nezha-dashboard.err
|
sudo tail -n 10 /var/log/nezha-dashboard.err
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_dashboard() {
|
uninstall_dashboard() {
|
||||||
echo -e "> Uninstall Panel"
|
echo "> Uninstall Panel"
|
||||||
|
|
||||||
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
|
if [ "$IS_DOCKER_NEZHA" = 1 ]; then
|
||||||
uninstall_dashboard_docker
|
uninstall_dashboard_docker
|
||||||
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
|
elif [ "$IS_DOCKER_NEZHA" = 0 ]; then
|
||||||
uninstall_dashboard_standalone
|
uninstall_dashboard_standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
clean_all
|
clean_all
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_dashboard_docker() {
|
uninstall_dashboard_docker() {
|
||||||
cd $NZ_DASHBOARD_PATH && $DOCKER_COMPOSE_COMMAND down
|
sudo $DOCKER_COMPOSE_COMMAND -f ${NZ_DASHBOARD_PATH}/docker-compose.yaml down
|
||||||
rm -rf $NZ_DASHBOARD_PATH
|
sudo rm -rf $NZ_DASHBOARD_PATH
|
||||||
docker rmi -f ghcr.io/naiba/nezha-dashboard >/dev/null 2>&1
|
sudo docker rmi -f ghcr.io/naiba/nezha-dashboard >/dev/null 2>&1
|
||||||
docker rmi -f registry.cn-shanghai.aliyuncs.com/naibahq/nezha-dashboard >/dev/null 2>&1
|
sudo docker rmi -f registry.cn-shanghai.aliyuncs.com/naibahq/nezha-dashboard >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_dashboard_standalone() {
|
uninstall_dashboard_standalone() {
|
||||||
rm -rf $NZ_DASHBOARD_PATH
|
sudo rm -rf $NZ_DASHBOARD_PATH
|
||||||
|
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
systemctl stop nezha-dashboard
|
sudo systemctl disable nezha-dashboard
|
||||||
|
sudo systemctl stop nezha-dashboard
|
||||||
else
|
else
|
||||||
rc-service nezha-dashboard stop
|
sudo rc-update del nezha-dashboard
|
||||||
|
sudo rc-service nezha-dashboard stop
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
rm $NZ_DASHBOARD_SERVICE
|
sudo rm $NZ_DASHBOARD_SERVICE
|
||||||
else
|
else
|
||||||
rm $NZ_DASHBOARD_SERVICERC
|
sudo rm $NZ_DASHBOARD_SERVICERC
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
show_agent_log() {
|
show_agent_log() {
|
||||||
echo -e "> > View Agent Log"
|
echo "> View Agent Log"
|
||||||
|
|
||||||
if [ "$os_alpine" != 1 ]; then
|
if [ "$os_alpine" != 1 ]; then
|
||||||
journalctl -xf -u nezha-agent.service
|
sudo journalctl -xf -u nezha-agent.service
|
||||||
else
|
else
|
||||||
tail -n 10 /var/log/nezha-agent.err
|
sudo tail -n 10 /var/log/nezha-agent.err
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_agent() {
|
uninstall_agent() {
|
||||||
echo -e "> Uninstall Agent"
|
echo "> Uninstall Agent"
|
||||||
|
|
||||||
${NZ_AGENT_PATH}/nezha-agent service uninstall
|
sudo ${NZ_AGENT_PATH}/nezha-agent service uninstall
|
||||||
|
|
||||||
rm -rf $NZ_AGENT_PATH
|
sudo rm -rf $NZ_AGENT_PATH
|
||||||
clean_all
|
clean_all
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_agent() {
|
restart_agent() {
|
||||||
echo -e "> Restart Agent"
|
echo "> Restart Agent"
|
||||||
|
|
||||||
${NZ_AGENT_PATH}/nezha-agent service restart
|
sudo ${NZ_AGENT_PATH}/nezha-agent service restart
|
||||||
|
|
||||||
if [[ $# == 0 ]]; then
|
if [ $# = 0 ]; then
|
||||||
before_show_menu
|
before_show_menu
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
clean_all() {
|
clean_all() {
|
||||||
if [ -z "$(ls -A ${NZ_BASE_PATH})" ]; then
|
if [ -z "$(ls -A ${NZ_BASE_PATH})" ]; then
|
||||||
rm -rf ${NZ_BASE_PATH}
|
sudo rm -rf ${NZ_BASE_PATH}
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,7 +802,7 @@ show_usage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
show_menu() {
|
show_menu() {
|
||||||
echo -e "
|
printf "
|
||||||
${green}Nezha Monitor Management Script${plain} ${red}${NZ_VERSION}${plain}
|
${green}Nezha Monitor Management Script${plain} ${red}${NZ_VERSION}${plain}
|
||||||
--- https://github.com/naiba/nezha ---
|
--- https://github.com/naiba/nezha ---
|
||||||
${green}1.${plain} Install Panel
|
${green}1.${plain} Install Panel
|
||||||
@@ -743,7 +823,7 @@ show_menu() {
|
|||||||
————————————————-
|
————————————————-
|
||||||
${green}0.${plain} Exit Script
|
${green}0.${plain} Exit Script
|
||||||
"
|
"
|
||||||
echo && read -ep "Please enter [0-13]: " num
|
echo && printf "Please enter [0-13]: " && read -r num
|
||||||
case "${num}" in
|
case "${num}" in
|
||||||
0)
|
0)
|
||||||
exit 0
|
exit 0
|
||||||
@@ -788,7 +868,7 @@ show_menu() {
|
|||||||
update_script
|
update_script
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo -e "${red}Please enter the correct number [0-13]${plain}"
|
err "Please enter the correct number [0-13]"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -796,7 +876,7 @@ show_menu() {
|
|||||||
pre_check
|
pre_check
|
||||||
installation_check
|
installation_check
|
||||||
|
|
||||||
if [[ $# > 0 ]]; then
|
if [ $# -gt 0 ]; then
|
||||||
case $1 in
|
case $1 in
|
||||||
"install_dashboard")
|
"install_dashboard")
|
||||||
install_dashboard 0
|
install_dashboard 0
|
||||||
|
|||||||
+3
-1
@@ -1 +1,3 @@
|
|||||||
protoc --go-grpc_out="require_unimplemented_servers=false:." --go_out="." proto/*.proto
|
protoc --go-grpc_out="require_unimplemented_servers=false:." --go_out="." proto/*.proto
|
||||||
|
rm -rf ../agent/proto
|
||||||
|
cp -r proto ../agent
|
||||||
+4
-4
@@ -10,19 +10,19 @@ import (
|
|||||||
"github.com/naiba/nezha/service/singleton"
|
"github.com/naiba/nezha/service/singleton"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthHandler struct {
|
type authHandler struct {
|
||||||
ClientSecret string
|
ClientSecret string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AuthHandler) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
func (a *authHandler) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
||||||
return map[string]string{"client_secret": a.ClientSecret}, nil
|
return map[string]string{"client_secret": a.ClientSecret}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AuthHandler) RequireTransportSecurity() bool {
|
func (a *authHandler) RequireTransportSecurity() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AuthHandler) Check(ctx context.Context) (uint64, error) {
|
func (a *authHandler) Check(ctx context.Context) (uint64, error) {
|
||||||
md, ok := metadata.FromIncomingContext(ctx)
|
md, ok := metadata.FromIncomingContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, status.Errorf(codes.Unauthenticated, "获取 metaData 失败")
|
return 0, status.Errorf(codes.Unauthenticated, "获取 metaData 失败")
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ioStreamContext struct {
|
||||||
|
userIo io.ReadWriteCloser
|
||||||
|
agentIo io.ReadWriteCloser
|
||||||
|
userIoConnectCh chan struct{}
|
||||||
|
agentIoConnectCh chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NezhaHandler) CreateStream(streamId string) {
|
||||||
|
s.ioStreamMutex.Lock()
|
||||||
|
defer s.ioStreamMutex.Unlock()
|
||||||
|
|
||||||
|
s.ioStreams[streamId] = &ioStreamContext{
|
||||||
|
userIoConnectCh: make(chan struct{}),
|
||||||
|
agentIoConnectCh: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NezhaHandler) GetStream(streamId string) (*ioStreamContext, error) {
|
||||||
|
s.ioStreamMutex.RLock()
|
||||||
|
defer s.ioStreamMutex.RUnlock()
|
||||||
|
|
||||||
|
if ctx, ok := s.ioStreams[streamId]; ok {
|
||||||
|
return ctx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("stream not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NezhaHandler) CloseStream(streamId string) error {
|
||||||
|
s.ioStreamMutex.Lock()
|
||||||
|
defer s.ioStreamMutex.Unlock()
|
||||||
|
|
||||||
|
if ctx, ok := s.ioStreams[streamId]; ok {
|
||||||
|
if ctx.userIo != nil {
|
||||||
|
ctx.userIo.Close()
|
||||||
|
}
|
||||||
|
if ctx.agentIo != nil {
|
||||||
|
ctx.agentIo.Close()
|
||||||
|
}
|
||||||
|
delete(s.ioStreams, streamId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NezhaHandler) UserConnected(streamId string, userIo io.ReadWriteCloser) error {
|
||||||
|
stream, err := s.GetStream(streamId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.userIo = userIo
|
||||||
|
close(stream.userIoConnectCh)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NezhaHandler) AgentConnected(streamId string, agentIo io.ReadWriteCloser) error {
|
||||||
|
stream, err := s.GetStream(streamId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.agentIo = agentIo
|
||||||
|
close(stream.agentIoConnectCh)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NezhaHandler) StartStream(streamId string, timeout time.Duration) error {
|
||||||
|
stream, err := s.GetStream(streamId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutTimer := time.NewTimer(timeout)
|
||||||
|
|
||||||
|
LOOP:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-stream.userIoConnectCh:
|
||||||
|
if stream.agentIo != nil {
|
||||||
|
timeoutTimer.Stop()
|
||||||
|
break LOOP
|
||||||
|
}
|
||||||
|
case <-stream.agentIoConnectCh:
|
||||||
|
if stream.userIo != nil {
|
||||||
|
timeoutTimer.Stop()
|
||||||
|
break LOOP
|
||||||
|
}
|
||||||
|
case <-time.After(timeout):
|
||||||
|
break LOOP
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
if stream.userIo == nil && stream.agentIo == nil {
|
||||||
|
return errors.New("timeout: no connection established")
|
||||||
|
}
|
||||||
|
if stream.userIo == nil {
|
||||||
|
return errors.New("timeout: user connection not established")
|
||||||
|
}
|
||||||
|
if stream.agentIo == nil {
|
||||||
|
return errors.New("timeout: agent connection not established")
|
||||||
|
}
|
||||||
|
|
||||||
|
isDone := new(atomic.Bool)
|
||||||
|
endCh := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
_, innerErr := io.Copy(stream.userIo, stream.agentIo)
|
||||||
|
if innerErr != nil {
|
||||||
|
err = innerErr
|
||||||
|
}
|
||||||
|
if isDone.CompareAndSwap(false, true) {
|
||||||
|
close(endCh)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
_, innerErr := io.Copy(stream.agentIo, stream.userIo)
|
||||||
|
if innerErr != nil {
|
||||||
|
err = innerErr
|
||||||
|
}
|
||||||
|
if isDone.CompareAndSwap(false, true) {
|
||||||
|
close(endCh)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-endCh
|
||||||
|
return err
|
||||||
|
}
|
||||||
+77
-4
@@ -3,11 +3,16 @@ package rpc
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/naiba/nezha/pkg/ddns"
|
|
||||||
"github.com/naiba/nezha/pkg/utils"
|
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/naiba/nezha/pkg/ddns"
|
||||||
|
"github.com/naiba/nezha/pkg/geoip"
|
||||||
|
"github.com/naiba/nezha/pkg/grpcx"
|
||||||
|
"github.com/naiba/nezha/pkg/utils"
|
||||||
|
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
|
|
||||||
@@ -16,8 +21,20 @@ import (
|
|||||||
"github.com/naiba/nezha/service/singleton"
|
"github.com/naiba/nezha/service/singleton"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var NezhaHandlerSingleton *NezhaHandler
|
||||||
|
|
||||||
type NezhaHandler struct {
|
type NezhaHandler struct {
|
||||||
Auth *AuthHandler
|
Auth *authHandler
|
||||||
|
ioStreams map[string]*ioStreamContext
|
||||||
|
ioStreamMutex *sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNezhaHandler() *NezhaHandler {
|
||||||
|
return &NezhaHandler{
|
||||||
|
Auth: &authHandler{},
|
||||||
|
ioStreamMutex: new(sync.RWMutex),
|
||||||
|
ioStreams: make(map[string]*ioStreamContext),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NezhaHandler) ReportTask(c context.Context, r *pb.TaskResult) (*pb.Receipt, error) {
|
func (s *NezhaHandler) ReportTask(c context.Context, r *pb.TaskResult) (*pb.Receipt, error) {
|
||||||
@@ -121,7 +138,6 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece
|
|||||||
singleton.ServerList[clientID].Host != nil &&
|
singleton.ServerList[clientID].Host != nil &&
|
||||||
host.IP != "" &&
|
host.IP != "" &&
|
||||||
singleton.ServerList[clientID].Host.IP != host.IP {
|
singleton.ServerList[clientID].Host.IP != host.IP {
|
||||||
|
|
||||||
serverDomain := singleton.ServerList[clientID].DDNSDomain
|
serverDomain := singleton.ServerList[clientID].DDNSDomain
|
||||||
if singleton.Conf.DDNS.Provider == "" {
|
if singleton.Conf.DDNS.Provider == "" {
|
||||||
provider, err = singleton.GetDDNSProviderFromProfile(singleton.ServerList[clientID].DDNSProfile)
|
provider, err = singleton.GetDDNSProviderFromProfile(singleton.ServerList[clientID].DDNSProfile)
|
||||||
@@ -174,6 +190,63 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece
|
|||||||
singleton.ServerList[clientID].PrevHourlyTransferOut = singleton.ServerList[clientID].PrevHourlyTransferOut - int64(singleton.ServerList[clientID].State.NetOutTransfer)
|
singleton.ServerList[clientID].PrevHourlyTransferOut = singleton.ServerList[clientID].PrevHourlyTransferOut - int64(singleton.ServerList[clientID].State.NetOutTransfer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 不要冲掉国家码
|
||||||
|
if singleton.ServerList[clientID].Host != nil {
|
||||||
|
host.CountryCode = singleton.ServerList[clientID].Host.CountryCode
|
||||||
|
}
|
||||||
|
|
||||||
singleton.ServerList[clientID].Host = &host
|
singleton.ServerList[clientID].Host = &host
|
||||||
return &pb.Receipt{Proced: true}, nil
|
return &pb.Receipt{Proced: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *NezhaHandler) IOStream(stream pb.NezhaService_IOStreamServer) error {
|
||||||
|
if _, err := s.Auth.Check(stream.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id, err := stream.Recv()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if id == nil || len(id.Data) < 4 || (id.Data[0] != 0xff && id.Data[1] != 0x05 && id.Data[2] != 0xff && id.Data[3] == 0x05) {
|
||||||
|
return fmt.Errorf("invalid stream id")
|
||||||
|
}
|
||||||
|
|
||||||
|
streamId := string(id.Data[4:])
|
||||||
|
|
||||||
|
if _, err := s.GetStream(streamId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iw := grpcx.NewIOStreamWrapper(stream)
|
||||||
|
if err := s.AgentConnected(streamId, iw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iw.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NezhaHandler) LookupGeoIP(c context.Context, r *pb.GeoIP) (*pb.GeoIP, error) {
|
||||||
|
var clientID uint64
|
||||||
|
var err error
|
||||||
|
if clientID, err = s.Auth.Check(c); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据内置数据库查询 IP 地理位置
|
||||||
|
record := &geoip.IPInfo{}
|
||||||
|
ip := r.GetIp()
|
||||||
|
netIP := net.ParseIP(ip)
|
||||||
|
location, err := geoip.Lookup(netIP, record)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将地区码写入到 Host
|
||||||
|
singleton.ServerLock.RLock()
|
||||||
|
defer singleton.ServerLock.RUnlock()
|
||||||
|
if singleton.ServerList[clientID].Host == nil {
|
||||||
|
return nil, fmt.Errorf("host not found")
|
||||||
|
}
|
||||||
|
singleton.ServerList[clientID].Host.CountryCode = location
|
||||||
|
|
||||||
|
return &pb.GeoIP{Ip: ip, CountryCode: location}, nil
|
||||||
|
}
|
||||||
|
|||||||
+17
-17
@@ -15,8 +15,6 @@ var (
|
|||||||
|
|
||||||
ServerAPI = &ServerAPIService{}
|
ServerAPI = &ServerAPIService{}
|
||||||
MonitorAPI = &MonitorAPIService{}
|
MonitorAPI = &MonitorAPIService{}
|
||||||
|
|
||||||
once = &sync.Once{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerAPIService struct{}
|
type ServerAPIService struct{}
|
||||||
@@ -28,13 +26,14 @@ type CommonResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CommonServerInfo struct {
|
type CommonServerInfo struct {
|
||||||
ID uint64 `json:"id"`
|
ID uint64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
LastActive int64 `json:"last_active"`
|
LastActive int64 `json:"last_active"`
|
||||||
IPV4 string `json:"ipv4"`
|
IPV4 string `json:"ipv4"`
|
||||||
IPV6 string `json:"ipv6"`
|
IPV6 string `json:"ipv6"`
|
||||||
ValidIP string `json:"valid_ip"`
|
ValidIP string `json:"valid_ip"`
|
||||||
|
DisplayIndex int `json:"display_index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatusResponse 服务器状态子结构 包含服务器信息与状态信息
|
// StatusResponse 服务器状态子结构 包含服务器信息与状态信息
|
||||||
@@ -78,7 +77,7 @@ func InitAPI() {
|
|||||||
UserIDToApiTokenList = make(map[uint64][]string)
|
UserIDToApiTokenList = make(map[uint64][]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadAPI() {
|
func loadAPI() {
|
||||||
InitAPI()
|
InitAPI()
|
||||||
var tokenList []*model.ApiToken
|
var tokenList []*model.ApiToken
|
||||||
DB.Find(&tokenList)
|
DB.Find(&tokenList)
|
||||||
@@ -143,13 +142,14 @@ func (s *ServerAPIService) GetAllStatus() *ServerStatusResponse {
|
|||||||
}
|
}
|
||||||
ipv4, ipv6, validIP := utils.SplitIPAddr(host.IP)
|
ipv4, ipv6, validIP := utils.SplitIPAddr(host.IP)
|
||||||
info := CommonServerInfo{
|
info := CommonServerInfo{
|
||||||
ID: v.ID,
|
ID: v.ID,
|
||||||
Name: v.Name,
|
Name: v.Name,
|
||||||
Tag: v.Tag,
|
Tag: v.Tag,
|
||||||
LastActive: v.LastActive.Unix(),
|
LastActive: v.LastActive.Unix(),
|
||||||
IPV4: ipv4,
|
IPV4: ipv4,
|
||||||
IPV6: ipv6,
|
IPV6: ipv6,
|
||||||
ValidIP: validIP,
|
ValidIP: validIP,
|
||||||
|
DisplayIndex: v.DisplayIndex,
|
||||||
}
|
}
|
||||||
res.Result = append(res.Result, &StatusResponse{
|
res.Result = append(res.Result, &StatusResponse{
|
||||||
CommonServerInfo: info,
|
CommonServerInfo: info,
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ func InitCronTask() {
|
|||||||
Crons = make(map[uint64]*model.Cron)
|
Crons = make(map[uint64]*model.Cron)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadCronTasks 加载计划任务
|
// loadCronTasks 加载计划任务
|
||||||
func LoadCronTasks() {
|
func loadCronTasks() {
|
||||||
InitCronTask()
|
InitCronTask()
|
||||||
var crons []model.Cron
|
var crons []model.Cron
|
||||||
DB.Find(&crons)
|
DB.Find(&crons)
|
||||||
|
|||||||
+14
-14
@@ -1,10 +1,10 @@
|
|||||||
package singleton
|
package singleton
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
ddns2 "github.com/naiba/nezha/pkg/ddns"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
ddns2 "github.com/naiba/nezha/pkg/ddns"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RetryableUpdateDomain(provider ddns2.Provider, config *ddns2.DomainConfig, maxRetries int) bool {
|
func RetryableUpdateDomain(provider ddns2.Provider, config *ddns2.DomainConfig, maxRetries int) bool {
|
||||||
@@ -25,54 +25,54 @@ func RetryableUpdateDomain(provider ddns2.Provider, config *ddns2.DomainConfig,
|
|||||||
func GetDDNSProviderFromString(provider string) (ddns2.Provider, error) {
|
func GetDDNSProviderFromString(provider string) (ddns2.Provider, error) {
|
||||||
switch provider {
|
switch provider {
|
||||||
case "webhook":
|
case "webhook":
|
||||||
return ddns2.ProviderWebHook{
|
return &ddns2.ProviderWebHook{
|
||||||
URL: Conf.DDNS.WebhookURL,
|
URL: Conf.DDNS.WebhookURL,
|
||||||
RequestMethod: Conf.DDNS.WebhookMethod,
|
RequestMethod: Conf.DDNS.WebhookMethod,
|
||||||
RequestBody: Conf.DDNS.WebhookRequestBody,
|
RequestBody: Conf.DDNS.WebhookRequestBody,
|
||||||
RequestHeader: Conf.DDNS.WebhookHeaders,
|
RequestHeader: Conf.DDNS.WebhookHeaders,
|
||||||
}, nil
|
}, nil
|
||||||
case "dummy":
|
case "dummy":
|
||||||
return ddns2.ProviderDummy{}, nil
|
return &ddns2.ProviderDummy{}, nil
|
||||||
case "cloudflare":
|
case "cloudflare":
|
||||||
return ddns2.ProviderCloudflare{
|
return &ddns2.ProviderCloudflare{
|
||||||
Secret: Conf.DDNS.AccessSecret,
|
Secret: Conf.DDNS.AccessSecret,
|
||||||
}, nil
|
}, nil
|
||||||
case "tencentcloud":
|
case "tencentcloud":
|
||||||
return ddns2.ProviderTencentCloud{
|
return &ddns2.ProviderTencentCloud{
|
||||||
SecretID: Conf.DDNS.AccessID,
|
SecretID: Conf.DDNS.AccessID,
|
||||||
SecretKey: Conf.DDNS.AccessSecret,
|
SecretKey: Conf.DDNS.AccessSecret,
|
||||||
}, nil
|
}, 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) {
|
func GetDDNSProviderFromProfile(profileName string) (ddns2.Provider, error) {
|
||||||
profile, ok := Conf.DDNS.Profiles[profileName]
|
profile, ok := Conf.DDNS.Profiles[profileName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return ddns2.ProviderDummy{}, errors.New(fmt.Sprintf("未找到配置项 %s", profileName))
|
return &ddns2.ProviderDummy{}, fmt.Errorf("未找到配置项 %s", profileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch profile.Provider {
|
switch profile.Provider {
|
||||||
case "webhook":
|
case "webhook":
|
||||||
return ddns2.ProviderWebHook{
|
return &ddns2.ProviderWebHook{
|
||||||
URL: profile.WebhookURL,
|
URL: profile.WebhookURL,
|
||||||
RequestMethod: profile.WebhookMethod,
|
RequestMethod: profile.WebhookMethod,
|
||||||
RequestBody: profile.WebhookRequestBody,
|
RequestBody: profile.WebhookRequestBody,
|
||||||
RequestHeader: profile.WebhookHeaders,
|
RequestHeader: profile.WebhookHeaders,
|
||||||
}, nil
|
}, nil
|
||||||
case "dummy":
|
case "dummy":
|
||||||
return ddns2.ProviderDummy{}, nil
|
return &ddns2.ProviderDummy{}, nil
|
||||||
case "cloudflare":
|
case "cloudflare":
|
||||||
return ddns2.ProviderCloudflare{
|
return &ddns2.ProviderCloudflare{
|
||||||
Secret: profile.AccessSecret,
|
Secret: profile.AccessSecret,
|
||||||
}, nil
|
}, nil
|
||||||
case "tencentcloud":
|
case "tencentcloud":
|
||||||
return ddns2.ProviderTencentCloud{
|
return &ddns2.ProviderTencentCloud{
|
||||||
SecretID: profile.AccessID,
|
SecretID: profile.AccessID,
|
||||||
SecretKey: profile.AccessSecret,
|
SecretKey: profile.AccessSecret,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return ddns2.ProviderDummy{}, errors.New(fmt.Sprintf("无法找到配置的DDNS提供者%s", profile.Provider))
|
return &ddns2.ProviderDummy{}, fmt.Errorf("无法找到配置的DDNS提供者%s", profile.Provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateDDNSProvidersFromProfiles() error {
|
func ValidateDDNSProvidersFromProfiles() error {
|
||||||
@@ -80,7 +80,7 @@ func ValidateDDNSProvidersFromProfiles() error {
|
|||||||
providers := make(map[string]string)
|
providers := make(map[string]string)
|
||||||
for profileName, profile := range Conf.DDNS.Profiles {
|
for profileName, profile := range Conf.DDNS.Profiles {
|
||||||
if _, ok := validProviders[profile.Provider]; !ok {
|
if _, ok := validProviders[profile.Provider]; !ok {
|
||||||
return errors.New(fmt.Sprintf("无法找到配置的DDNS提供者%s", profile.Provider))
|
return fmt.Errorf("无法找到配置的DDNS提供者%s", profile.Provider)
|
||||||
}
|
}
|
||||||
providers[profileName] = profile.Provider
|
providers[profileName] = profile.Provider
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package singleton
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/naiba/nezha/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
var natCache = make(map[string]*model.NAT)
|
||||||
|
var natCacheRwLock = new(sync.RWMutex)
|
||||||
|
|
||||||
|
func initNAT() {
|
||||||
|
OnNATUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func OnNATUpdate() {
|
||||||
|
natCacheRwLock.Lock()
|
||||||
|
defer natCacheRwLock.Unlock()
|
||||||
|
var nats []*model.NAT
|
||||||
|
DB.Find(&nats)
|
||||||
|
natCache = make(map[string]*model.NAT)
|
||||||
|
for i := 0; i < len(nats); i++ {
|
||||||
|
natCache[nats[i].Domain] = nats[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNATConfigByDomain(domain string) *model.NAT {
|
||||||
|
natCacheRwLock.RLock()
|
||||||
|
defer natCacheRwLock.RUnlock()
|
||||||
|
return natCache[domain]
|
||||||
|
}
|
||||||
@@ -24,8 +24,8 @@ func InitNotification() {
|
|||||||
NotificationIDToTag = make(map[uint64]string)
|
NotificationIDToTag = make(map[uint64]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadNotifications 从 DB 初始化通知方式相关参数
|
// loadNotifications 从 DB 初始化通知方式相关参数
|
||||||
func LoadNotifications() {
|
func loadNotifications() {
|
||||||
InitNotification()
|
InitNotification()
|
||||||
notificationsLock.Lock()
|
notificationsLock.Lock()
|
||||||
defer notificationsLock.Unlock()
|
defer notificationsLock.Unlock()
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ func InitServer() {
|
|||||||
ServerTagToIDList = make(map[string][]uint64)
|
ServerTagToIDList = make(map[string][]uint64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadServers 加载服务器列表并根据ID排序
|
// loadServers 加载服务器列表并根据ID排序
|
||||||
func LoadServers() {
|
func loadServers() {
|
||||||
InitServer()
|
InitServer()
|
||||||
var servers []model.Server
|
var servers []model.Server
|
||||||
DB.Find(&servers)
|
DB.Find(&servers)
|
||||||
|
|||||||
@@ -34,10 +34,11 @@ func InitTimezoneAndCache() {
|
|||||||
|
|
||||||
// LoadSingleton 加载子服务并执行
|
// LoadSingleton 加载子服务并执行
|
||||||
func LoadSingleton() {
|
func LoadSingleton() {
|
||||||
LoadNotifications() // 加载通知服务
|
loadNotifications() // 加载通知服务
|
||||||
LoadServers() // 加载服务器列表
|
loadServers() // 加载服务器列表
|
||||||
LoadCronTasks() // 加载定时任务
|
loadCronTasks() // 加载定时任务
|
||||||
LoadAPI()
|
loadAPI()
|
||||||
|
initNAT()
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitConfigFromPath 从给出的文件路径中加载配置
|
// InitConfigFromPath 从给出的文件路径中加载配置
|
||||||
@@ -47,11 +48,11 @@ func InitConfigFromPath(path string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
ValidateConfig()
|
validateConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateConfig 验证配置文件有效性
|
// validateConfig 验证配置文件有效性
|
||||||
func ValidateConfig() {
|
func validateConfig() {
|
||||||
var err error
|
var err error
|
||||||
if Conf.DDNS.Provider == "" {
|
if Conf.DDNS.Provider == "" {
|
||||||
err = ValidateDDNSProvidersFromProfiles()
|
err = ValidateDDNSProvidersFromProfiles()
|
||||||
@@ -82,7 +83,8 @@ func InitDBFromPath(path string) {
|
|||||||
}
|
}
|
||||||
err = DB.AutoMigrate(model.Server{}, model.User{},
|
err = DB.AutoMigrate(model.Server{}, model.User{},
|
||||||
model.Notification{}, model.AlertRule{}, model.Monitor{},
|
model.Notification{}, model.AlertRule{}, model.Monitor{},
|
||||||
model.MonitorHistory{}, model.Cron{}, model.Transfer{}, model.ApiToken{})
|
model.MonitorHistory{}, model.Cron{}, model.Transfer{},
|
||||||
|
model.ApiToken{}, model.NAT{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -93,7 +95,7 @@ func RecordTransferHourlyUsage() {
|
|||||||
ServerLock.Lock()
|
ServerLock.Lock()
|
||||||
defer ServerLock.Unlock()
|
defer ServerLock.Unlock()
|
||||||
now := time.Now()
|
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
|
var txs []model.Transfer
|
||||||
for id, server := range ServerList {
|
for id, server := range ServerList {
|
||||||
tx := model.Transfer{
|
tx := model.Transfer{
|
||||||
@@ -136,7 +138,7 @@ func CleanMonitorHistory() {
|
|||||||
if !rule.IsTransferDurationRule() {
|
if !rule.IsTransferDurationRule() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dataCouldRemoveBefore := rule.GetTransferDurationStart()
|
dataCouldRemoveBefore := rule.GetTransferDurationStart().UTC()
|
||||||
// 判断规则影响的机器范围
|
// 判断规则影响的机器范围
|
||||||
if rule.Cover == model.RuleCoverAll {
|
if rule.Cover == model.RuleCoverAll {
|
||||||
// 更新全局可以清理的数据点
|
// 更新全局可以清理的数据点
|
||||||
@@ -155,12 +157,12 @@ func CleanMonitorHistory() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for id, couldRemove := range specialServerKeep {
|
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() {
|
if allServerKeep.IsZero() {
|
||||||
DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?)", specialServerIDs)
|
DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?)", specialServerIDs)
|
||||||
} else {
|
} 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user