🐶 Sync 2025-11-02 14:26:26

This commit is contained in:
actions-user
2025-11-02 14:26:26 +08:00
parent 64bcc56c2a
commit ac011db799
1557 changed files with 746465 additions and 0 deletions

View File

@@ -0,0 +1,356 @@
#!/bin/sh
# Copyright 2025 timsaya
. /usr/share/libubox/jshn.sh
# 从UCI配置读取端口号如果读取失败则使用默认端口8686
BANDIX_PORT=$(uci get bandix.general.port 2>/dev/null || echo "8686")
readonly BANDIX_API_BASE="http://127.0.0.1:$BANDIX_PORT"
readonly BANDIX_DEVICES_API="$BANDIX_API_BASE/api/traffic/devices"
readonly BANDIX_LIMITS_API="$BANDIX_API_BASE/api/traffic/limits"
readonly BANDIX_METRICS_API="$BANDIX_API_BASE/api/traffic/metrics"
readonly BANDIX_CONNECTION_API="$BANDIX_API_BASE/api/connection/devices"
# 通用函数创建简单的JSON响应
make_value() {
json_init
json_add_string "$1" "$2"
json_dump
json_cleanup
}
# 通用函数:创建错误响应
make_error() {
json_init
json_add_boolean "success" 0
json_add_string "error" "$1"
json_dump
json_cleanup
}
# 通用函数:创建成功响应
make_success() {
json_init
json_add_boolean "success" 1
[ -n "$1" ] && json_add_string "message" "$1"
json_dump
json_cleanup
}
# 转义JSON字符串
escape_json_string() {
echo "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\n/\\n/g; s/\r/\\r/g; s/\t/\\t/g'
}
# 获取设备状态
get_device_status() {
local api_result=$(curl -s --connect-timeout 2 --max-time 5 "$BANDIX_DEVICES_API" 2>/dev/null)
# 检查API调用是否成功
if [ $? -ne 0 ] || [ -z "$api_result" ]; then
echo '{"devices":[]}'
return
fi
# 提取 data 部分并返回
local data_part=$(echo "$api_result" | jsonfilter -e '$.data' 2>/dev/null)
if [ -n "$data_part" ]; then
echo "$data_part"
else
echo '{"devices":[]}'
fi
}
# 获取历史指标可选MAC
get_metrics() {
local mac="$1"
local url="$BANDIX_METRICS_API"
if [ -n "$mac" ]; then
# 转义MAC
local mac_escaped=$(echo "$mac" | sed 's/\//\\\//g')
url="$url?mac=$mac_escaped"
fi
# logger "luci.bandix.metrics: entering mac=$mac url=$url"
local api_result=$(curl -s --connect-timeout 1 --max-time 3 "$url" 2>/dev/null)
local curl_exit_code=$?
# logger "luci.bandix.metrics: curl finished with exit code: $curl_exit_code"
if [ $curl_exit_code -ne 0 ] || [ -z "$api_result" ]; then
# logger "luci.bandix.metrics: curl failed or empty response, returning empty metrics"
# 返回空结果(原始格式)
echo '{"retention_seconds":600,"mac":"","metrics":[]}'
return
fi
# 使用 jsonfilter 提取 data 部分根据文档这是处理大JSON的推荐方式
local data_part=$(echo "$api_result" | jsonfilter -e '$.data' 2>/dev/null)
if [ -n "$data_part" ]; then
local data_size=${#data_part}
# logger "luci.bandix.metrics: extracted data part using jsonfilter, size: $data_size bytes"
echo "$data_part"
return
else
# logger "luci.bandix.metrics: jsonfilter failed to extract data part"
echo '{"retention_seconds":600,"mac":"","metrics":[]}'
fi
}
# 设置设备限速
set_device_rate_limit() {
local mac="$1"
local wide_tx_rate_limit="$2"
local wide_rx_rate_limit="$3"
# logger "luci.bandix: set_device_rate_limit 参数: mac=$mac tx=$wide_tx_rate_limit rx=$wide_rx_rate_limit"
# 验证参数
if [ -z "$mac" ]; then
make_error "MAC address is required"
return
fi
# 转义MAC地址中的特殊字符
local mac_escaped=$(escape_json_string "$mac")
# 构建请求数据
local request_data="{
\"mac\": \"$mac\",
\"wide_tx_rate_limit\": $wide_tx_rate_limit,
\"wide_rx_rate_limit\": $wide_rx_rate_limit
}"
# 记录请求数据(用于调试)
# logger "luci.bandix: request_data=$request_data"
# 发送请求到bandix API
local response=$(curl -s --connect-timeout 3 --max-time 10 -X POST -H "Content-Type: application/json" -d "$request_data" "$BANDIX_LIMITS_API" 2>/dev/null)
# logger "luci.bandix: API response=$response"
if [ $? -eq 0 ] && [ -n "$response" ]; then
# 检查API响应是否包含success状态
if echo "$response" | grep -q '"status":\s*"success"'; then
make_success "Rate limit set successfully"
else
# API返回了响应但不是success状态
json_init
json_add_boolean "success" 0
json_add_string "error" "API returned error response"
json_add_string "response" "$response"
json_dump
json_cleanup
fi
else
make_error "Failed to set rate limit"
fi
}
# 设置设备主机名绑定
set_device_hostname() {
local mac="$1"
local hostname="$2"
# logger "luci.bandix: set_device_hostname 参数: mac=$mac hostname=$hostname"
# 验证参数
if [ -z "$mac" ]; then
make_error "MAC address is required"
return
fi
# hostname可以为空表示删除绑定
if [ -z "$hostname" ]; then
hostname=""
fi
# 转义特殊字符
local mac_escaped=$(escape_json_string "$mac")
local hostname_escaped=$(escape_json_string "$hostname")
# 构建请求数据
local request_data="{
\"mac\": \"$mac\",
\"hostname\": \"$hostname\"
}"
# 记录请求数据(用于调试)
# logger "luci.bandix: hostname request_data=$request_data"
# 发送请求到bandix API
local bindings_api="$BANDIX_API_BASE/api/traffic/bindings"
local response=$(curl -s --connect-timeout 3 --max-time 10 -X POST -H "Content-Type: application/json" -d "$request_data" "$bindings_api" 2>/dev/null)
# logger "luci.bandix: hostname API response=$response"
if [ $? -eq 0 ] && [ -n "$response" ]; then
# 检查API响应是否包含success状态
if echo "$response" | grep -q '"status":\s*"success"'; then
make_success "Hostname binding set successfully"
else
# API返回了响应但不是success状态
json_init
json_add_boolean "success" 0
json_add_string "error" "API returned error response"
json_add_string "response" "$response"
json_dump
json_cleanup
fi
else
make_error "Failed to set hostname binding"
fi
}
# 获取连接监控数据
get_connection_devices() {
# 检查连接监控是否启用
local connection_enabled=$(uci get bandix.connections.enabled 2>/dev/null)
if [ "$connection_enabled" != "1" ]; then
make_error "Connection monitoring is not enabled"
return
fi
# 从 Bandix API 获取连接数据
local response=$(curl -s --connect-timeout 2 --max-time 5 -X GET "$BANDIX_CONNECTION_API" 2>/dev/null)
# 检查API调用是否成功
if [ $? -ne 0 ] || [ -z "$response" ]; then
make_error "Failed to connect to Bandix service"
return
fi
# 直接返回API结果
echo "$response"
}
case "$1" in
list)
json_init
json_add_object "getStatus"
json_close_object
json_add_object "getMetrics"
json_add_string "mac"
json_close_object
json_add_object "setRateLimit"
json_add_string "mac"
json_add_int "wide_rx_rate_limit"
json_add_int "wide_tx_rate_limit"
json_close_object
json_add_object "setHostname"
json_add_string "mac"
json_add_string "hostname"
json_close_object
json_add_object "getConnection"
json_close_object
json_dump
json_cleanup
;;
call)
case "$2" in
getStatus)
get_device_status
;;
getMetrics)
# logger "luci.bandix: getMetrics called"
# 读取参数:优先 STDIN带超时避免阻塞其次位置参数$3
# 很奇怪收到的是 received input: {"mac":"70:e2:84:2b:9f:42","ubus_rpc_session":"4b0c5dcd9baf9963e4f13647fa71228a"}
mac=""
input=""
# 尝试读取一行 STDIN1 秒超时以避免在无输入场景下阻塞
if read -t 1 -r input; then
:
fi
if [ -n "$input" ]; then
# logger "luci.bandix: received input: $input"
# 支持数组或对象两种风格
mac="$(echo "$input" | jsonfilter -e '$[0]' 2>/dev/null)"
[ -z "$mac" ] && mac="$(echo "$input" | jsonfilter -e '$.mac' 2>/dev/null)"
else
# 某些环境不会通过 STDIN 传参,改为读取位置参数
[ -n "$3" ] && mac="$3"
# logger "luci.bandix: received argv mac: $mac"
fi
get_metrics "$mac"
;;
setRateLimit)
# logger "luci.bandix: setRateLimit called"
# 从 stdin 读取 JSON 参数
read input
# logger "luci.bandix: received input: $input"
if [ -n "$input" ]; then
# 尝试解析数组格式的 JSON 参数 (LuCI RPC 通常使用数组格式)
# 参数格式: ["mac", wide_tx_rate_limit, wide_rx_rate_limit]
mac=$(echo "$input" | jsonfilter -e '$[0]' 2>/dev/null)
wide_tx_rate_limit=$(echo "$input" | jsonfilter -e '$[1]' 2>/dev/null)
wide_rx_rate_limit=$(echo "$input" | jsonfilter -e '$[2]' 2>/dev/null)
# 如果数组格式解析失败,尝试对象格式
if [ -z "$mac" ]; then
mac=$(echo "$input" | jsonfilter -e '$.mac' 2>/dev/null)
wide_tx_rate_limit=$(echo "$input" | jsonfilter -e '$.wide_tx_rate_limit' 2>/dev/null)
wide_rx_rate_limit=$(echo "$input" | jsonfilter -e '$.wide_rx_rate_limit' 2>/dev/null)
fi
# logger "luci.bandix: parsed - mac=$mac tx=$wide_tx_rate_limit rx=$wide_rx_rate_limit"
# 验证参数
if [ -n "$mac" ] && [ -n "$wide_tx_rate_limit" ] && [ -n "$wide_rx_rate_limit" ]; then
# 调用限速设置函数
set_device_rate_limit "$mac" "$wide_tx_rate_limit" "$wide_rx_rate_limit"
else
# logger "luci.bandix: setRateLimit 参数缺失或无效"
make_error "Missing or invalid parameters"
fi
else
# logger "luci.bandix: setRateLimit 没有接收到输入"
make_error "No input received"
fi
;;
setHostname)
# logger "luci.bandix: setHostname called"
# 从 stdin 读取 JSON 参数
read input
# logger "luci.bandix: received input: $input"
if [ -n "$input" ]; then
# 尝试解析数组格式的 JSON 参数 (LuCI RPC 通常使用数组格式)
# 参数格式: ["mac", "hostname"]
mac=$(echo "$input" | jsonfilter -e '$[0]' 2>/dev/null)
hostname=$(echo "$input" | jsonfilter -e '$[1]' 2>/dev/null)
# 如果数组格式解析失败,尝试对象格式
if [ -z "$mac" ]; then
mac=$(echo "$input" | jsonfilter -e '$.mac' 2>/dev/null)
hostname=$(echo "$input" | jsonfilter -e '$.hostname' 2>/dev/null)
fi
# logger "luci.bandix: parsed - mac=$mac hostname=$hostname"
# 验证参数hostname可以为空
if [ -n "$mac" ]; then
# 调用主机名设置函数
set_device_hostname "$mac" "$hostname"
else
# logger "luci.bandix: setHostname MAC参数缺失"
make_error "Missing MAC address parameter"
fi
else
# logger "luci.bandix: setHostname 没有接收到输入"
make_error "No input received"
fi
;;
getConnection)
# logger "luci.bandix: getConnection called"
get_connection_devices
;;
esac
;;
esac

View File

@@ -0,0 +1,38 @@
{
"admin/network/bandix": {
"title": "Bandix",
"order": 90,
"action": {
"type": "alias",
"path": "admin/network/bandix/index"
},
"depends": {
"acl": [ "luci-app-bandix" ],
"uci": { "bandix": true }
}
},
"admin/network/bandix/index": {
"title": "Status",
"order": 10,
"action": {
"type": "view",
"path": "bandix/index"
}
},
"admin/network/bandix/connection": {
"title": "Connections",
"order": 15,
"action": {
"type": "view",
"path": "bandix/connection"
}
},
"admin/network/bandix/settings": {
"title": "Settings",
"order": 20,
"action": {
"type": "view",
"path": "bandix/settings"
}
}
}

View File

@@ -0,0 +1,12 @@
{
"bandix": {
"title": "Bandix 流量监控",
"description": "局域网设备流量监控和统计服务",
"instances": {
"instance": {
"type": "process",
"init": "bandix"
}
}
}
}

View File

@@ -0,0 +1,33 @@
{
"luci-app-bandix": {
"description": "Grant access to bandix traffic monitoring",
"read": {
"ubus": {
"luci.bandix": [
"getStatus",
"getMetrics",
"setRateLimit",
"getConnection",
"setHostname"
]
},
"uci": [
"bandix"
]
},
"write": {
"ubus": {
"luci.bandix": [
"setRateLimit",
"getStatus",
"getMetrics",
"getConnection",
"setHostname"
]
},
"uci": [
"bandix"
]
}
}
}