357 lines
10 KiB
Bash
Executable File
357 lines
10 KiB
Bash
Executable File
#!/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=""
|
||
# 尝试读取一行 STDIN,1 秒超时以避免在无输入场景下阻塞
|
||
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
|