24 Commits

Author SHA1 Message Date
87418edeea 修复脚本执行错误
Some checks failed
Compile / build (x64, ubuntu-latest) (push) Failing after 15s
Compile / build (x64, windows-latest) (push) Failing after 21s
2024-10-05 23:01:17 +08:00
5c089873ca 修复脚本执行错误
Some checks failed
Compile / build (x64, windows-latest) (push) Failing after 14s
Compile / build (x64, ubuntu-latest) (push) Failing after 1m35s
2024-10-05 22:56:04 +08:00
79242f9dd6 修复脚本执行错误 2024-10-05 22:54:33 +08:00
22feee38ee 修复脚本执行错误
Some checks failed
Compile / build (x64, windows-latest) (push) Failing after 13s
Compile / build (x64, ubuntu-latest) (push) Failing after 3m6s
2024-10-05 22:50:41 +08:00
e0aa6adbeb 修复脚本执行错误 2024-10-05 22:48:40 +08:00
87859a58f8 修复脚本执行错误 2024-10-05 22:46:31 +08:00
d1098cf735 Merge remote-tracking branch 'origin/main' 2024-10-05 22:25:32 +08:00
62096e5f4d 修复脚本执行错误 2024-10-05 22:25:17 +08:00
26db6fe7d0 Create LICENSE 2024-10-05 22:04:50 +08:00
3b09c0650d 修复脚本执行错误 2024-10-05 22:02:53 +08:00
fb7e3144d3 修复脚本执行错误 2024-10-05 21:57:48 +08:00
c271378c71 修复脚本执行错误
Some checks failed
Compile / build (x64, windows-latest) (push) Failing after 38s
Compile / build (x64, ubuntu-latest) (push) Failing after 3m7s
2024-10-05 21:52:39 +08:00
5834abcd33 修复脚本执行错误 2024-10-05 21:50:12 +08:00
67475ef499 修复脚本执行错误 2024-10-05 21:20:22 +08:00
42c4db6c01 修复脚本执行错误 2024-10-05 21:02:50 +08:00
4af3579d70 新增Linux安装脚本 2024-10-05 20:53:58 +08:00
cd56065e32 os字段新增版本和发行版
Some checks failed
Compile / build (x64, windows-latest) (push) Failing after 19s
Compile / build (x64, ubuntu-latest) (push) Failing after 35s
2024-10-05 05:34:26 +08:00
3c960896f4 修复运行时间错误的问题
Some checks failed
Compile / build (x64, windows-latest) (push) Failing after 36s
Compile / build (x64, ubuntu-latest) (push) Failing after 1m27s
2024-10-05 03:21:33 +08:00
c2a3966f37 修复运行时间错误的问题 2024-10-05 03:21:01 +08:00
3fa94f653d 修复运行时间错误的问题
Some checks failed
Compile / build (x64, windows-latest) (push) Failing after 39s
Compile / build (x64, ubuntu-latest) (push) Failing after 2m24s
2024-10-04 08:29:49 +08:00
4cb1fcdb21 添加系统启动时间 2024-10-04 07:46:00 +08:00
657cd1a80f 添加系统启动时间 2024-10-04 07:34:28 +08:00
3d14b5a18e 添加系统启动时间 2024-10-04 07:33:16 +08:00
2c3cda6e46 排除linux下无关分区
Some checks failed
Compile / build (x64, windows-latest) (push) Failing after 20s
Compile / build (x64, ubuntu-latest) (push) Failing after 35s
2024-10-03 18:49:28 +08:00
8 changed files with 399 additions and 39 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Snowykami
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -19,20 +19,39 @@ _✨ 服务器状态 - 客户端 ✨_
服务器状态的客户端命令行工具
- 跨平台支持
- 自动上报服务器状态
- 支持自定义标签、地域、链接等信息
## 💿 安装
- 先决条件:`curl` `python3` `pip` `venv` `git`
使用 pip 安装(确保包路径在环境变量下)
- Linux 可使用脚本安装,带自动部署和自启动
pip install server-status
```shell
sudo bash -c "$(curl -sSL https://raw.githubusercontent.com/snowykami/server-status-client/refs/heads/main/deploy.sh)"
```
如果位于中国大陆无法访问GitHub可使用中国版脚本
```shell
sudo bash -c "$(curl -sSL https://git.liteyuki.icu/snowykami/server-status-client/raw/branch/main/deploy-cn.sh)"
```
Debian系请使用pipx安装
- 或手动部署
```bash
sudo apt install pipx
sudo pipx install server-status
```
若出现环境问题,请从 Actions 下载构建好的二进制文件
```shell
# 克隆仓库
git clone https://github.com/snowykami/server-status-client
cd server-status-client
# 配置环境
python3 -m venv venv
source venv/bin/activate
# 安装依赖
pip install pdm
pdm install
# 如需自启动请自行添加到系统服务
```
## 🎉 使用
@@ -59,40 +78,13 @@ server_status https://status.liteyuki.icu 114514 myhost run -n "MyHost" --labels
### 开机启动
执行以下命令
```shell
sudo pipx ensurepath # 确保pipx路径在环境变量下
sudo touch /etc/systemd/system/server-status-client.service
sudo bash -c 'cat <<EOF > /etc/systemd/system/server-status-client.service
[Unit]
Description=Server Status Client
After=network-online.target
[Service]
Type=simple
ExecStart=server-status <server> <token> <id> run # 请替换为实际参数
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF'
sudo systemctl enable server-status-client
sudo systemctl start server-status-client
```
- 安装脚本已自动添加到系统服务
### 更新
```shell
git pull
sudo systemctl restart server-status-client
#
git pull
systemctl restart server-status-client
```
### 服务端

100
deploy-cn.sh Executable file
View File

@@ -0,0 +1,100 @@
#!/bin/bash
# 部署脚本中国大陆可用版本
# check if sudo is used
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi
# check install dir
install_dir="/opt"
echo -n "Install directory? (default: $install_dir/server-status-client): " && read -r install_dir_input
if [ -n "$install_dir_input" ]; then
install_dir="$install_dir_input"
fi
# check server
echo -n "Server? (required): " && read -r server
if [ -z "$server" ]; then
echo "Server is required"
exit 1
fi
# check token
echo -n "Token? (required): " && read -r token
if [ -z "$token" ]; then
echo "Token is required"
exit 1
fi
# check hostname
hostname=$(hostname)
echo -n "Hostname? (default: $hostname): " && read -r hostname_input
if [ -n "$hostname_input" ]; then
hostname="$hostname_input"
fi
# labels
echo -n "Labels? (space separated): " && read -r labels_input
if [ -n "$labels_input" ]; then
labels="$labels_input"
fi
# location
echo -n "Location? (optional): " && read -r location_input
if [ -n "$location_input" ]; then
location="$location_input"
fi
repo2="https://git.liteyuki.icu/snowykami/server-status-client"
# try 1 if failed try 2
git clone "$repo2" "$install_dir/server-status-client"
cd "$install_dir/server-status-client" || { echo "Failed to clone repo"; exit 1; }
# create venv
python3 -m venv venv
python_exe="./venv/bin/python"
# check if venv is created
if [ ! -f "$python_exe" ]; then
echo "Failed to create venv"
exit 1
fi
echo "venv created successfully"
# install the required packages
echo "Installing the required packages"
$python_exe -m pip install pdm -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
$python_exe -m pdm install
# create the systemd service
echo "Creating the systemd service"
# generate random id
# shellcheck disable=SC2002
id=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
bash -c "cat <<EOF > /etc/systemd/system/server-status-client.service
[Unit]
Description=Server Status Client
After=network-online.target
[Service]
Type=simple
ExecStart=$install_dir/server-status-client/venv/bin/python main.py $server $token $id run -n $hostname --labels $labels --location $location
WorkingDirectory=$install_dir/server-status-client
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF"
# enable and start the service
systemctl enable server-status-client
systemctl start server-status-client
echo "server-status-client installed successfully"

0
deploy.cmd Normal file
View File

99
deploy.sh Executable file
View File

@@ -0,0 +1,99 @@
#!/bin/bash
# check if sudo is used
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi
# check install dir
install_dir="/opt"
echo -n "Install directory? (default: $install_dir/server-status-client): " && read -r install_dir_input
if [ -n "$install_dir_input" ]; then
install_dir="$install_dir_input"
fi
# check server
echo -n "Server? (required): " && read -r server
if [ -z "$server" ]; then
echo "Server is required"
exit 1
fi
# check token
echo -n "Token? (required): " && read -r token
if [ -z "$token" ]; then
echo "Token is required"
exit 1
fi
# check hostname
hostname=$(hostname)
echo -n "Hostname? (default: $hostname): " && read -r hostname_input
if [ -n "$hostname_input" ]; then
hostname="$hostname_input"
fi
# labels
echo -n "Labels? (space separated): " && read -r labels_input
if [ -n "$labels_input" ]; then
labels="$labels_input"
fi
# location
echo -n "Location? (optional): " && read -r location_input
if [ -n "$location_input" ]; then
location="$location_input"
fi
# clone repo
repo1="https://github.com/snowykami/server-status-client"
repo2="https://git.liteyuki.icu/snowykami/server-status-client"
# try 1 if failed try 2
git clone "$repo1" "$install_dir/server-status-client" || git clone "$repo2" "$install_dir/server-status-client"
cd "$install_dir/server-status-client" || { echo "Failed to clone repo"; exit 1; }
# create venv
python3 -m venv venv
python_exe="./venv/bin/python"
# check if venv is created
if [ ! -f "$python_exe" ]; then
echo "Failed to create venv"
exit 1
fi
echo "venv created successfully"
# install the required packages
echo "Installing the required packages"
$python_exe -m pip install pdm
$python_exe -m pdm install
# create the systemd service
echo "Creating the systemd service"
# generate random id
# shellcheck disable=SC2002
id=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
bash -c "cat <<EOF > /etc/systemd/system/server-status-client.service
[Unit]
Description=Server Status Client
After=network-online.target
[Service]
Type=simple
ExecStart=$install_dir/server-status-client/venv/bin/python main.py $server $token $id run -n $hostname --labels $labels --location $location
WorkingDirectory=$install_dir/server-status-client
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF"
# enable and start the service
systemctl enable server-status-client
systemctl start server-status-client
echo "server-status-client installed successfully"

View File

@@ -9,6 +9,7 @@ dependencies = [
"requests>=2.32.3",
"psutil>=6.0.0",
"arclet-alconna>=1.8.30",
"pytz>=2024.2",
]
requires-python = ">=3.10"
readme = "README.md"
@@ -30,5 +31,5 @@ tag_filter = "v*"
tag_regex = '^v(?:\D*)?(?P<version>([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))*((a|b|c|rc)(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))?(\.dev(0|[1-9][0-9]*))?$)$'
[[tool.pdm.source]]
name = "tuna"
name = "pypi"
url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"

View File

@@ -6,6 +6,8 @@ from typing import Any
import psutil
import requests
from server_status.timezone import get_timezone
excluded_partition_prefix = ("/var", "/boot", "/run", "/proc", "/sys", "/dev", "/tmp", "/snap")
@@ -39,6 +41,8 @@ class Hardware:
disks: dict[str, dict[str, int]] = {}
timezone: str = get_timezone()
net_up: int = 0
net_down: int = 0
net_type: str = "ethernet"
@@ -136,13 +140,13 @@ class Client:
self.link = link
self.interval = interval
self.start_time = psutil.boot_time()
self.hardware = Hardware()
log("Client initialized",
f"Name: {self.name}({self.client_id}), Location: {self.location}, Labels: {self.labels}")
def start(self):
self.start_time = time.time()
self.observe()
while True:
@@ -183,12 +187,16 @@ class Client:
"os": {
"name": platform.system(),
"version": platform.version(),
"machine": platform.machine(),
"release": platform.release(),
},
"labels": self.labels,
"location": self.location,
"uptime": int(time.time() - self.start_time),
"start_time": int(self.start_time), # 系统启动的时间
"link": self.link,
"observed_at": int(time.time()),
"timezone": self.hardware.timezone,
},
"hardware": {
"mem": {
@@ -236,6 +244,9 @@ class Client:
continue
self.hardware.disks[part.device] = {
"mountpoint": part.mountpoint,
"device": part.device,
"fstype": part.fstype,
"total": usage.total,
"used": usage.used,
}

136
server_status/timezone.py Normal file
View File

@@ -0,0 +1,136 @@
import os
import platform
from zoneinfo import ZoneInfo
windows_timezone_map = {
"Dateline Standard Time": "Etc/GMT+12",
"UTC-11": "Etc/GMT+11",
"Aleutian Standard Time": "America/Adak",
"Hawaiian Standard Time": "Pacific/Honolulu",
"Marquesas Standard Time": "Pacific/Marquesas",
"Alaskan Standard Time": "America/Anchorage",
"UTC-09": "Etc/GMT+9",
"Pacific Standard Time (Mexico)": "America/Tijuana",
"UTC-08": "Etc/GMT+8",
"Pacific Standard Time": "America/Los_Angeles",
"US Mountain Standard Time": "America/Phoenix",
"Mountain Standard Time (Mexico)": "America/Chihuahua",
"Mountain Standard Time": "America/Denver",
"Central America Standard Time": "America/Guatemala",
"Central Standard Time": "America/Chicago",
"Easter Island Standard Time": "Pacific/Easter",
"Central Standard Time (Mexico)": "America/Mexico_City",
"Canada Central Standard Time": "America/Regina",
"SA Pacific Standard Time": "America/Bogota",
"Eastern Standard Time (Mexico)": "America/Cancun",
"Eastern Standard Time": "America/New_York",
"Haiti Standard Time": "America/Port-au-Prince",
"Cuba Standard Time": "America/Havana",
"US Eastern Standard Time": "America/Indianapolis",
"Turks And Caicos Standard Time": "America/Grand_Turk",
"Paraguay Standard Time": "America/Asuncion",
"Atlantic Standard Time": "America/Halifax",
"Venezuela Standard Time": "America/Caracas",
"Central Brazilian Standard Time": "America/Cuiaba",
"SA Western Standard Time": "America/La_Paz",
"Pacific SA Standard Time": "America/Santiago",
"SA Eastern Standard Time": "America/Cayenne",
"Argentina Standard Time": "America/Buenos_Aires",
"Greenland Standard Time": "America/Godthab",
"Montevideo Standard Time": "America/Montevideo",
"Bahia Standard Time": "America/Bahia",
"UTC-02": "Etc/GMT+2",
"Azores Standard Time": "Atlantic/Azores",
"Cape Verde Standard Time": "Atlantic/Cape_Verde",
"UTC": "Etc/GMT",
"GMT Standard Time": "Europe/London",
"Greenwich Standard Time": "Atlantic/Reykjavik",
"W. Europe Standard Time": "Europe/Berlin",
"Central Europe Standard Time": "Europe/Budapest",
"Romance Standard Time": "Europe/Paris",
"Central European Standard Time": "Europe/Warsaw",
"W. Central Africa Standard Time": "Africa/Lagos",
"Namibia Standard Time": "Africa/Windhoek",
"GTB Standard Time": "Europe/Bucharest",
"Middle East Standard Time": "Asia/Beirut",
"Egypt Standard Time": "Africa/Cairo",
"Syria Standard Time": "Asia/Damascus",
"E. Europe Standard Time": "Europe/Chisinau",
"South Africa Standard Time": "Africa/Johannesburg",
"FLE Standard Time": "Europe/Kiev",
"Turkey Standard Time": "Europe/Istanbul",
"Israel Standard Time": "Asia/Jerusalem",
"Jordan Standard Time": "Asia/Amman",
"Arabic Standard Time": "Asia/Riyadh",
"Kaliningrad Standard Time": "Europe/Kaliningrad",
"Arab Standard Time": "Asia/Riyadh",
"E. Africa Standard Time": "Africa/Nairobi",
"Iran Standard Time": "Asia/Tehran",
"Arabian Standard Time": "Asia/Dubai",
"Astrakhan Standard Time": "Europe/Astrakhan",
"Russian Standard Time": "Europe/Moscow",
"E. Europe Standard Time": "Europe/Chisinau",
"W. Australia Standard Time": "Australia/Perth",
"Moscow Standard Time": "Europe/Moscow",
"Pakistan Standard Time": "Asia/Karachi",
"India Standard Time": "Asia/Kolkata",
"Sri Lanka Standard Time": "Asia/Colombo",
"Nepal Standard Time": "Asia/Kathmandu",
"Bangladesh Standard Time": "Asia/Dhaka",
"Afghanistan Standard Time": "Asia/Kabul",
"Myanmar Standard Time": "Asia/Yangon",
"SE Asia Standard Time": "Asia/Bangkok",
"North Asia Standard Time": "Asia/Krasnoyarsk",
"China Standard Time": "Asia/Shanghai",
"Singapore Standard Time": "Asia/Singapore",
"W. Australia Standard Time": "Australia/Perth",
"Taipei Standard Time": "Asia/Taipei",
"Ulaanbaatar Standard Time": "Asia/Ulaanbaatar",
"North Asia East Standard Time": "Asia/Irkutsk",
"Korea Standard Time": "Asia/Seoul",
"Tokyo Standard Time": "Asia/Tokyo",
"Yakutsk Standard Time": "Asia/Yakutsk",
"Cen. Australia Standard Time": "Australia/Adelaide",
"AUS Central Standard Time": "Australia/Darwin",
"E. Australia Standard Time": "Australia/Brisbane",
"AUS Eastern Standard Time": "Australia/Sydney",
"West Pacific Standard Time": "Pacific/Port_Moresby",
"Tasmania Standard Time": "Australia/Hobart",
"Magadan Standard Time": "Asia/Magadan",
"Vladivostok Standard Time": "Asia/Vladivostok",
"Russia Time Zone 10": "Asia/Srednekolymsk",
"Central Pacific Standard Time": "Pacific/Guadalcanal",
"Fiji Standard Time": "Pacific/Fiji",
"New Zealand Standard Time": "Pacific/Auckland",
"UTC+12": "Etc/GMT-12",
"Kamchatka Standard Time": "Asia/Kamchatka",
"Tonga Standard Time": "Pacific/Tongatapu",
"Samoa Standard Time": "Pacific/Apia",
"Line Islands Standard Time": "Pacific/Kiritimati",
}
def get_timezone() -> str:
try:
# 尝试获取系统的本地时区
if 'TZ' in os.environ:
return os.environ['TZ']
# 如果环境变量中没有TZ尝试获取系统时区
if platform.system() == "Linux":
# Linux:
with open("/etc/timezone", "r") as f:
return f.read().strip()
elif platform.system() == "Darwin":
# macOS:
return ZoneInfo.from_file(open("/etc/localtime")).key
elif platform.system() == "Windows":
# Windows:
import winreg
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation") as key:
tz = winreg.QueryValueEx(key, "TimeZoneKeyName")[0]
return windows_timezone_map.get(tz) or tz
else:
return "UTC"
except Exception as e:
return "UTC"