Files
openwrt_packages/luci-app-bandix/root/usr/libexec/rpcd/luci.bandix
2025-11-02 14:26:26 +08:00

357 lines
10 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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