🚀 Sync 2026-03-08 00:54:34

This commit is contained in:
github-actions[bot] committed 2026-03-08 00:54:34 +08:00
1 parent 97d524986e
commit 5997aee442
22 files changed
+3954 -28

No files matched your search

@@ -0,0 +1,2 @@
config netspeedtest 'config'
@@ -0,0 +1,6 @@
#!/bin/sh
chmod +x /usr/bin/netspeedtest.sh /usr/bin/speedtest /usr/libexec/rpcd/luci.netspeedtest
rm -f /tmp/luci-indexcache
exit 0
+338
View File
@@ -0,0 +1,338 @@
#!/bin/bash
# Copyright (C) 2019-2026 sirpdboy
# Fixed version - correct image URL handling
RESULT_FILE='/tmp/netspeedtest_result'
LOG_FILE='/tmp/netspeedtest.log'
LOCK_FILE='/var/run/netspeedtest.lock'
PID_FILE='/var/run/netspeedtest.pid'
TIMEOUT=120
# 默认设置
PREFERRED_VERSION="auto"
SELECTED_SERVER="auto"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
# 检查进程锁
check_running() {
if [ -f "$PID_FILE" ]; then
local old_pid=$(cat "$PID_FILE" 2>/dev/null)
if kill -0 "$old_pid" 2>/dev/null; then
log "Another speedtest is already running (PID: $old_pid)"
echo "Testing" > "$RESULT_FILE"
exit 1
else
rm -f "$PID_FILE"
fi
fi
exec 200>"$LOCK_FILE"
if ! flock -n 200; then
log "Another speedtest is already running (flock)"
echo "Testing" > "$RESULT_FILE"
exit 1
fi
echo $$ > "$PID_FILE"
}
# 清理函数
cleanup() {
rm -f "$PID_FILE"
flock -u 200 2>/dev/null
exec 200>&-
}
trap cleanup EXIT INT TERM
# 检测可用的speedtest版本
detect_speedtest() {
local preferred="$1"
local available_versions=""
# 检查Ookla官方版
if [ -f '/usr/bin/ookla-speedtest' ] && [ -x '/usr/bin/ookla-speedtest' ]; then
available_versions="ookla:/usr/bin/ookla-speedtest"
fi
# 检查Python版
if [ -f '/usr/bin/speedtest' ] && [ -x '/usr/bin/speedtest' ]; then
if [ -n "$available_versions" ]; then
available_versions="$available_versions|python:/usr/bin/speedtest"
else
available_versions="python:/usr/bin/speedtest"
fi
fi
# 如果没有找到任何版本
if [ -z "$available_versions" ]; then
log "No speedtest versions found"
return 1
fi
# 如果指定了偏好版本
if [ "$preferred" != "auto" ]; then
IFS='|' read -ra versions <<< "$available_versions"
for ver in "${versions[@]}"; do
if [[ "$ver" == "$preferred:"* ]]; then
echo "$ver"
return 0
fi
done
fi
echo "$available_versions" | cut -d'|' -f1
return 0
}
# 运行Ookla版测试
run_ookla_test() {
local speedtest_bin=$1
local server_id=$2
local cmd="$speedtest_bin --accept-gdpr --accept-license --progress=no"
[ -n "$server_id" ] && [ "$server_id" != "auto" ] && cmd="$cmd --server-id=$server_id"
# 使用临时文件存储输出
local tmp_output=$(mktemp)
if command -v timeout >/dev/null 2>&1; then
timeout $TIMEOUT $cmd > "$tmp_output" 2>&1
local exit_code=$?
if [ $exit_code -eq 124 ]; then
log "Error: Test timed out"
rm -f "$tmp_output"
return 1
fi
else
$cmd > "$tmp_output" 2>&1
fi
cat "$tmp_output"
rm -f "$tmp_output"
return 0
}
# 运行Python版测试
run_python_test() {
local speedtest_bin=$1
local server_id=$2
local cmd="$speedtest_bin --share --simple"
if [ -n "$server_id" ] && [ "$server_id" != "auto" ]; then
cmd="$speedtest_bin --server $server_id --share --simple"
fi
local tmp_output=$(mktemp)
if command -v timeout >/dev/null 2>&1; then
timeout 90 $cmd > "$tmp_output" 2>&1
local exit_code=$?
if [ $exit_code -eq 124 ]; then
log "Error: Python test timed out"
# 尝试使用常用服务器
timeout 90 $speedtest_bin --server 59016 --share --simple > "$tmp_output" 2>&1
if [ $? -eq 124 ]; then
log "Error: Second attempt also timed out"
rm -f "$tmp_output"
return 1
fi
fi
else
$cmd > "$tmp_output" 2>&1
fi
cat "$tmp_output"
rm -f "$tmp_output"
return 0
}
# 解析Python版结果
parse_python_result() {
local result="$1"
# 检查是否包含错误信息
if echo "$result" | grep -q -i "error\|failed\|cannot\|timeout"; then
return 1
fi
# 提取分享链接
local share_url=$(echo "$result" | grep -o 'http://www.speedtest.net/result/[0-9]*\.png' | head -1)
if [ -n "$share_url" ]; then
echo "$share_url"
return 0
fi
# 提取速度数据
local download=$(echo "$result" | grep -i "download" | head -1)
local upload=$(echo "$result" | grep -i "upload" | head -1)
local latency=$(echo "$result" | grep -i "latency" | head -1)
if [ -n "$download" ] && [ -n "$upload" ]; then
{
echo "$download"
echo "$upload"
[ -n "$latency" ] && echo "$latency"
}
return 0
fi
return 1
}
parse_ookla_result() {
local result="$1"
# 提取结果URL
local result_url=$(echo "$result" | grep -i "result url" | grep -o 'https\?://[^ ]*' | head -1)
if [ -n "$result_url" ]; then
echo "$result_url.png"
return 0
fi
local download=$(echo "$result" | grep -i "download" | grep -o "[0-9.]\+ [Mk]bits" | head -1)
local upload=$(echo "$result" | grep -i "upload" | grep -o "[0-9.]\+ [Mk]bits" | head -1)
local latency=$(echo "$result" | grep -i "latency" | grep -o "[0-9.]\+ ms" | head -1)
if [ -n "$download" ] && [ -n "$upload" ]; then
{
echo "Download: $download"
echo "Upload: $upload"
[ -n "$latency" ] && echo "Latency: $latency"
}
return 0
fi
return 1
}
# 主测试函数
main_test() {
log "=== Speedtest started (PID: $$) ==="
# 检测可用的speedtest版本
local version_info=$(detect_speedtest "$PREFERRED_VERSION")
if [ -z "$version_info" ]; then
log "Error: No speedtest version found"
echo "Test failed" > "$RESULT_FILE"
exit 1
fi
local version_type=${version_info%:*}
local speedtest_bin=${version_info#*:}
log "Using $version_type version: $speedtest_bin"
TEST_SUCCESS=0
# 运行测试
case $version_type in
ookla)
RUNTEST=$(run_ookla_test "$speedtest_bin" "$SELECTED_SERVER")
;;
python)
RUNTEST=$(run_python_test "$speedtest_bin" "$SELECTED_SERVER")
;;
esac
echo "$RUNTEST" >> "$LOG_FILE"
# 解析结果
case $version_type in
ookla) RESULT=$(parse_ookla_result "$RUNTEST") ;;
python) RESULT=$(parse_python_result "$RUNTEST") ;;
esac
if [ -n "$RESULT" ]; then
echo "$RESULT" > "$RESULT_FILE"
TEST_SUCCESS=1
log "Test successful"
fi
# 如果失败,尝试自动选择
if [ $TEST_SUCCESS -eq 0 ] && [ "$SELECTED_SERVER" != "auto" ]; then
log "Test failed with selected server, trying automatic server selection"
SELECTED_SERVER="auto"
case $version_type in
ookla)
RUNTEST=$(run_ookla_test "$speedtest_bin" "auto")
;;
python)
RUNTEST=$(run_python_test "$speedtest_bin" "auto")
;;
esac
echo "$RUNTEST" >> "$LOG_FILE"
case $version_type in
ookla) RESULT=$(parse_ookla_result "$RUNTEST") ;;
python) RESULT=$(parse_python_result "$RUNTEST") ;;
esac
if [ -n "$RESULT" ]; then
echo "$RESULT" > "$RESULT_FILE"
log "Test successful with automatic server selection"
TEST_SUCCESS=1
fi
fi
# 最终检查
if [ $TEST_SUCCESS -eq 0 ]; then
echo "Test failed" > "$RESULT_FILE"
log "All tests failed"
fi
log "=== Speedtest completed (PID: $$) ==="
echo "" >> "$LOG_FILE"
}
# 显示帮助信息
show_help() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " --version VERSION Preferred version (ookla/python/auto)"
echo " --server SERVER_ID Server ID to test with"
echo " --help Show this help message"
}
# 命令行参数处理
while [ $# -gt 0 ]; do
case "$1" in
--version)
if [ -n "$2" ]; then
PREFERRED_VERSION="$2"
shift 2
else
echo "Error: --version requires an argument"
exit 1
fi
;;
--server)
if [ -n "$2" ]; then
SELECTED_SERVER="$2"
shift 2
else
echo "Error: --server requires an argument"
exit 1
fi
;;
--help)
show_help
exit 0
;;
*)
echo "Unknown option: $1"
show_help
exit 1
;;
esac
done
# 运行测试
check_running
main_test
exit 0
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,88 @@
#!/bin/sh
# Copyright (C) 2019-2026 sirpdboy
# RPC plugin for netspeedtest
. /usr/share/libubox/jshn.sh
get_ookla_servers() {
local servers="[]"
if [ -f '/usr/bin/ookla-speedtest' ] && [ -x '/usr/bin/ookla-speedtest' ]; then
local json_output=$(/usr/bin/ookla-speedtest --servers --format=json 2>/dev/null)
if [ -n "$json_output" ]; then
servers=$(echo "$json_output" | sed -n 's/.*"servers":\(\[.*\]\).*/\1/p')
[ -z "$servers" ] && servers="[]"
fi
fi
echo "$servers"
}
get_python_servers() {
local servers="[]"
local temp_file="/tmp/python_servers.tmp"
if [ -f '/usr/bin/speedtest' ] && [ -x '/usr/bin/speedtest' ]; then
/usr/bin/speedtest --list > "$temp_file" 2>/dev/null
if [ -s "$temp_file" ]; then
local json=""
local count=0
while IFS= read -r line; do
if echo "$line" | grep -qE '^[0-9]+\)'; then
local id=$(echo "$line" | sed -E 's/^([0-9]+)\).*/\1/')
local sponsor=$(echo "$line" | sed -E 's/^[0-9]+\)[[:space:]]+([^(]+).*/\1/' | sed -e 's/[[:space:]]*$//' -e 's/"/\\"/g')
local city_country=$(echo "$line" | grep -o '([^)]*)' | head -1 | sed 's/[()]//g')
local city=$(echo "$city_country" | cut -d',' -f1 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/"/\\"/g')
local country=$(echo "$city_country" | cut -d',' -f2 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/"/\\"/g')
local distance=$(echo "$line" | grep -o '\[[0-9.]* km\]' | sed 's/\[//g' | sed 's/ km\]//g')
[ -z "$distance" ] && distance="0"
if [ $count -gt 0 ]; then
json="$json,"
fi
json="$json{\"id\":$id,\"sponsor\":\"$sponsor\",\"city\":\"$city\",\"country\":\"$country\",\"distance\":$distance}"
count=$((count + 1))
[ $count -ge 10 ] && break
fi
done < "$temp_file"
[ -n "$json" ] && servers="[$json]"
fi
rm -f "$temp_file"
fi
echo "$servers"
}
case "$1" in
list)
echo '{
"get_servers": {
"signature": [],
"help": "Get speedtest servers"
}
}'
;;
call)
case "$2" in
get_servers)
json_init
json_add_string "ookla" "$(get_ookla_servers)"
json_add_string "python" "$(get_python_servers)"
json_dump
;;
*)
echo '{"error": "Method not found"}'
;;
esac
;;
*)
echo '{"error": "Invalid command"}'
;;
esac
@@ -0,0 +1,53 @@
{
"admin/network/netspeedtest": {
"title": "NetSpeedtest",
"order": 90,
"action": {
"type": "firstchild"
},
"depends": {
"acl": [ "luci-app-netspeedtest" ],
"uci": { "netspeedtest": true }
}
},
"admin/network/netspeedtest/iperf3": {
"title": "Throughput speedtest Iperf3",
"order": 10,
"action": {
"type": "view",
"path": "netspeedtest/iperf3"
}
},
"admin/network/netspeedtest/homebox": {
"title": "Throughput speedtest Homebox",
"order": 20,
"action": {
"type": "view",
"path": "netspeedtest/homebox"
}
},
"admin/network/netspeedtest/wanspeedtest": {
"title": "Wan SpeedTest",
"order": 40,
"action": {
"type": "view",
"path": "netspeedtest/wanspeedtest"
}
},
"admin/network/netspeedtest/onlinespeedtest": {
"title": "Online SpeedTest",
"order": 50,
"action": {
"type": "view",
"path": "netspeedtest/onlinespeedtest"
}
},
"admin/network/netspeedtest/logs": {
"title": "Log",
"order": 60,
"action": {
"type": "view",
"path": "netspeedtest/logs"
}
}
}
@@ -0,0 +1,38 @@
{
"luci-app-netspeedtest": {
"description": "Grant access to netspeedtest procedures",
"read": {
"file": {
"/usr/bin/netspeedtest.sh": [ "exec" ],
"/usr/bin/pgrep": [ "exec" ],
"/bin/ps": [ "exec" ],
"/usr/bin/homebox": [ "exec" ],
"/usr/bin/killall": [ "exec" ],
"/bin/sh": [ "exec" ],
"/bin/cat": [ "exec" ],
"/usr/bin/iperf3": [ "exec" ],
"/usr/bin/nohup": [ "exec" ],
"/usr/bin/speedtest": [ "exec" ],
"/usr/bin/ookla-speedtest": [ "exec" ],
"/tmp/netspeedtest_result": [ "read" ],
"/tmp/netspeedtest_progress": [ "read" ],
"/var/run/netspeedtest.pid": [ "read" ],
"/tmp/netspeedtest.log": [ "read" ]
},
"ubus": {
"luci.netspeedtest": [ "get_servers" ]
}
},
"write": {
"file": {
"/tmp/netspeedtest_result": [ "write" ],
"/tmp/netspeedtest_progress": [ "write" ],
"/var/run/netspeedtest.pid": [ "write" ],
"/tmp/netspeedtest.log": [ "write" ]
},
"ubus": {
"luci.netspeedtest": [ "get_servers" ]
}
}
}
}