🚀 Sync 2026-11-03 05:32:30

This commit is contained in:
github-actions[bot] committed 2026-11-03 05:32:30 +08:00
1 parent 981b1dc64d
commit e37cccd846
15 files changed
+2 -225

No files matched your search

@@ -0,0 +1,9 @@
config pingpacket 'config'
option enabled '0'
option domestic_target 'www.baidu.com'
option foreign_target 'https://www.google.com/generate_204'
option foreign_proxy_type 'socks5h'
option foreign_proxy_host '127.0.0.1'
option foreign_proxy_port '7891'
option domestic_interval '1'
option foreign_interval '5'
+103
View File
@@ -0,0 +1,103 @@
#!/bin/sh /etc/rc.common
START=90
STOP=10
USE_PROCD=1
PROG=/usr/bin/pingpacket.sh
RUN_DIR=/var/run/pingpacket
STATUS_FILE=/tmp/pingpacket_status.json
CONFIG_FILE=$RUN_DIR/config
LOG_FILE=/tmp/pingpacket.log
LOG_MAX_LINES=500
log_rotate() {
[ -f "$LOG_FILE" ] || return 0
tail -n "$LOG_MAX_LINES" "$LOG_FILE" > "${LOG_FILE}.tmp" 2>/dev/null && \
mv -f "${LOG_FILE}.tmp" "$LOG_FILE"
}
log_event() {
local event_type="$1"
local message="$2"
local timestamp
timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
printf '[%s] [%s] %s\n' "$timestamp" "$event_type" "$message" >> "$LOG_FILE"
log_rotate
}
format_foreign_summary() {
local target="$1"
local proxy_type="$2"
local proxy_host="$3"
local proxy_port="$4"
[ -n "$target" ] || {
echo "未配置"
return
}
if [ -n "$proxy_port" ]; then
echo "${target}(代理 ${proxy_type} 本机端口 ${proxy_port})"
else
echo "${target}(代理端口未配置)"
fi
}
start_service() {
local enabled domestic foreign proxy_type proxy_host proxy_port domestic_interval foreign_interval foreign_summary
config_load pingpacket
config_get enabled config enabled "0"
config_get domestic config domestic_target ""
config_get foreign config foreign_target ""
config_get proxy_type config foreign_proxy_type "socks5h"
config_get proxy_host config foreign_proxy_host "127.0.0.1"
config_get proxy_port config foreign_proxy_port "7891"
config_get domestic_interval config domestic_interval "1"
config_get foreign_interval config foreign_interval "5"
proxy_type="socks5h"
[ "$enabled" = "1" ] || return 0
[ -n "$domestic" ] || [ -n "$foreign" ] || return 0
rm -rf "$RUN_DIR"
rm -f "$STATUS_FILE"
mkdir -p "$RUN_DIR"
printf '%s\n' "$domestic" > "$CONFIG_FILE"
printf '%s\n' "$foreign" >> "$CONFIG_FILE"
printf '%s\n' "$proxy_type" >> "$CONFIG_FILE"
printf '%s\n' "${proxy_host:-127.0.0.1}" >> "$CONFIG_FILE"
printf '%s\n' "$proxy_port" >> "$CONFIG_FILE"
printf '%s\n' "$domestic_interval" >> "$CONFIG_FILE"
printf '%s\n' "$foreign_interval" >> "$CONFIG_FILE"
foreign_summary="$(format_foreign_summary "$foreign" "$proxy_type" "$proxy_host" "$proxy_port")"
log_event "启动" "监控服务已启动,国内目标:${domestic:-未配置},国外目标:${foreign_summary}"
procd_open_instance
procd_set_param command /bin/sh "$PROG"
procd_set_param respawn 3600 10 5
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}
stop_service() {
if [ -d "$RUN_DIR" ] || [ -f "$STATUS_FILE" ]; then
log_event "停止" "监控服务已停止。"
fi
rm -rf "$RUN_DIR"
rm -f "$STATUS_FILE"
}
reload_service() {
stop
start
}
service_triggers() {
procd_add_reload_trigger "pingpacket"
}
+805
View File
@@ -0,0 +1,805 @@
#!/bin/sh
STATUS_FILE="/tmp/pingpacket_status.json"
STATUS_TMP="${STATUS_FILE}.tmp"
LOG_FILE="/tmp/pingpacket.log"
LOG_MAX_LINES=500
RUN_DIR="/var/run/pingpacket"
START_TIME_FILE="$RUN_DIR/start_time"
HIST_DIR="/etc/pingpacket/history"
HIST_RETENTION_DAYS=35
child_pids=""
probe_seq=0
log_line_count=0
current_minute=""
domestic_fail_count=0
foreign_fail_count=0
domestic_fault_open=0
foreign_fault_open=0
domestic_total_samples=0
foreign_total_samples=0
domestic_success_count=0
foreign_success_count=0
domestic_loss_count=0
foreign_loss_count=0
domestic_rtt_sum="0"
foreign_rtt_sum="0"
domestic_min_rtt=""
foreign_min_rtt=""
domestic_max_rtt=""
foreign_max_rtt=""
domestic_last_probe_at=0
foreign_last_probe_at=0
domestic_last_fault_seq=0
foreign_last_fault_seq=0
domestic_last_stats_seq=0
foreign_last_stats_seq=0
hist_bucket_key=""
hist_flush_count=0
hist_d_samples=0
hist_d_loss=0
hist_d_rtt_sum="0"
hist_f_samples=0
hist_f_loss=0
hist_f_rtt_sum="0"
log_rotate() {
[ -f "$LOG_FILE" ] || return 0
tail -n "$LOG_MAX_LINES" "$LOG_FILE" > "${LOG_FILE}.tmp" 2>/dev/null && \
mv -f "${LOG_FILE}.tmp" "$LOG_FILE"
log_line_count="$LOG_MAX_LINES"
}
log_event() {
local event_type="$1"
local scope="$2"
local message="$3"
local timestamp
# 日志被页面手动清除后,行数计数需要重新开始
if [ ! -f "$LOG_FILE" ]; then
log_line_count=0
fi
timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
if [ -n "$scope" ]; then
printf '[%s] [%s] [%s] %s\n' "$timestamp" "$event_type" "$scope" "$message" >> "$LOG_FILE"
else
printf '[%s] [%s] %s\n' "$timestamp" "$event_type" "$message" >> "$LOG_FILE"
fi
log_line_count=$((log_line_count + 1))
if [ "$log_line_count" -gt "$LOG_MAX_LINES" ]; then
log_rotate
fi
}
prune_history() {
[ -d "$HIST_DIR" ] || return 0
find "$HIST_DIR" -type f -name '*.tsv' -mtime +"$HIST_RETENTION_DAYS" 2>/dev/null | while IFS= read -r stale_file; do
rm -f "$stale_file" 2>/dev/null
done
}
flush_history_bucket() {
[ -n "$hist_bucket_key" ] || return 0
if [ "$hist_d_samples" -le 0 ] && [ "$hist_f_samples" -le 0 ]; then
hist_bucket_key=""
return 0
fi
local bucket_day="${hist_bucket_key% *}"
local bucket_clock="${hist_bucket_key#* }"
mkdir -p "$HIST_DIR" 2>/dev/null
printf '%s\t%d\t%d\t%s\t%d\t%d\t%s\n' \
"$bucket_clock" \
"$hist_d_samples" "$hist_d_loss" "$hist_d_rtt_sum" \
"$hist_f_samples" "$hist_f_loss" "$hist_f_rtt_sum" \
>> "$HIST_DIR/${bucket_day}.tsv" 2>/dev/null
hist_bucket_key=""
hist_d_samples=0
hist_d_loss=0
hist_d_rtt_sum="0"
hist_f_samples=0
hist_f_loss=0
hist_f_rtt_sum="0"
hist_flush_count=$((hist_flush_count + 1))
if [ "$hist_flush_count" -ge 60 ]; then
hist_flush_count=0
prune_history
fi
}
accumulate_history() {
local name="$1"
local success="$2"
local rtt="${3:-0}"
[ -n "$current_minute" ] || return 0
if [ "$hist_bucket_key" != "$current_minute" ]; then
flush_history_bucket
hist_bucket_key="$current_minute"
fi
case "$name" in
domestic)
hist_d_samples=$((hist_d_samples + 1))
if [ "$success" = "1" ]; then
hist_d_rtt_sum="$(awk -v sum="$hist_d_rtt_sum" -v value="$rtt" 'BEGIN { printf "%.3f", (sum + 0) + (value + 0) }')"
else
hist_d_loss=$((hist_d_loss + 1))
fi
;;
foreign)
hist_f_samples=$((hist_f_samples + 1))
if [ "$success" = "1" ]; then
hist_f_rtt_sum="$(awk -v sum="$hist_f_rtt_sum" -v value="$rtt" 'BEGIN { printf "%.3f", (sum + 0) + (value + 0) }')"
else
hist_f_loss=$((hist_f_loss + 1))
fi
;;
esac
}
kill_children() {
[ -n "$child_pids" ] || return 0
kill $child_pids 2>/dev/null
wait $child_pids 2>/dev/null
child_pids=""
}
cleanup() {
flush_history_bucket
kill_children
exit 0
}
trap cleanup INT TERM
mkdir -p "$RUN_DIR"
date '+%Y-%m-%d %H:%M:%S' > "$START_TIME_FILE"
if [ -f "$LOG_FILE" ]; then
log_line_count="$(wc -l < "$LOG_FILE" 2>/dev/null | tr -d ' ')"
case "$log_line_count" in
""|*[!0-9]*) log_line_count=0 ;;
esac
fi
write_result_file() {
local path="$1"
local success="$2"
local rtt="$3"
local detail="$4"
local probe_at="$5"
local seq="$6"
[ -n "$probe_at" ] || probe_at="$(date '+%s' 2>/dev/null || echo 0)"
[ -n "$seq" ] || seq="0"
mkdir -p "$(dirname "$path")"
printf '%s\n%s\n%s\n%s\n%s\n' "$success" "$rtt" "$detail" "$probe_at" "$seq" > "$path"
}
normalize_foreign_url() {
case "$1" in
http://*|https://*)
printf '%s\n' "$1"
;;
*)
printf 'https://%s\n' "$1"
;;
esac
}
ensure_runtime_state() {
local domestic
local foreign
local proxy_type
local proxy_host
local proxy_port
local domestic_interval
local foreign_interval
mkdir -p "$RUN_DIR"
if [ ! -s "$START_TIME_FILE" ]; then
date '+%Y-%m-%d %H:%M:%S' > "$START_TIME_FILE"
fi
if [ -f "$RUN_DIR/config" ]; then
return 0
fi
if ! command -v uci >/dev/null 2>&1; then
return 0
fi
domestic="$(uci -q get pingpacket.config.domestic_target)"
foreign="$(uci -q get pingpacket.config.foreign_target)"
proxy_type="$(uci -q get pingpacket.config.foreign_proxy_type)"
proxy_host="$(uci -q get pingpacket.config.foreign_proxy_host)"
proxy_port="$(uci -q get pingpacket.config.foreign_proxy_port)"
domestic_interval="$(uci -q get pingpacket.config.domestic_interval)"
foreign_interval="$(uci -q get pingpacket.config.foreign_interval)"
proxy_type="socks5h"
[ -n "$proxy_host" ] || proxy_host="127.0.0.1"
[ -n "$proxy_port" ] || proxy_port="7891"
[ -n "$domestic_interval" ] || domestic_interval="1"
[ -n "$foreign_interval" ] || foreign_interval="5"
printf '%s\n' "$domestic" > "$RUN_DIR/config"
printf '%s\n' "$foreign" >> "$RUN_DIR/config"
printf '%s\n' "$proxy_type" >> "$RUN_DIR/config"
printf '%s\n' "$proxy_host" >> "$RUN_DIR/config"
printf '%s\n' "$proxy_port" >> "$RUN_DIR/config"
printf '%s\n' "$domestic_interval" >> "$RUN_DIR/config"
printf '%s\n' "$foreign_interval" >> "$RUN_DIR/config"
}
normalize_interval() {
local value="$1"
case "$value" in
""|*[!0-9]*)
printf '1\n'
return 0
;;
esac
if [ "$value" -ge 1 ] 2>/dev/null; then
printf '%s\n' "$value"
else
printf '1\n'
fi
}
should_probe_now() {
local last_probe_at="${1:-0}"
local interval="${2:-1}"
local now_ts="${3:-0}"
if [ "$last_probe_at" -le 0 ] 2>/dev/null; then
return 0
fi
if [ $((now_ts - last_probe_at)) -ge "$interval" ] 2>/dev/null; then
return 0
fi
return 1
}
is_ip_literal() {
case "$1" in
*:*|*.*)
printf '%s\n' "$1" | awk '
/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ { found=1 }
/^[0-9A-Fa-f:]+$/ { found=1 }
END { exit(found ? 0 : 1) }
'
;;
*)
return 1
;;
esac
}
resolve_target_ip() {
local target="$1"
local name="$2"
local cache_target_file="$RUN_DIR/${name}_resolved_target"
local cache_ip_file="$RUN_DIR/${name}_resolved_ip"
local cache_time_file="$RUN_DIR/${name}_resolved_at"
local cached_target
local cached_ip
local cached_time
local now
local resolved_ip=""
if is_ip_literal "$target"; then
printf '%s\n' "$target"
return 0
fi
cached_target="$(cat "$cache_target_file" 2>/dev/null || echo "")"
cached_ip="$(cat "$cache_ip_file" 2>/dev/null || echo "")"
cached_time="$(cat "$cache_time_file" 2>/dev/null || echo "")"
now="$(date '+%s' 2>/dev/null || echo 0)"
if [ "$cached_target" = "$target" ] && [ -n "$cached_ip" ] && [ -n "$cached_time" ]; then
if [ $((now - cached_time)) -lt 300 ] 2>/dev/null; then
printf '%s\n' "$cached_ip"
return 0
fi
fi
if command -v resolveip >/dev/null 2>&1; then
resolved_ip="$(
resolveip -4 -t 3 "$target" 2>/dev/null | awk '
{
for (i = 1; i <= NF; i++) {
if ($i ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) {
print $i
exit
}
}
}
'
)"
fi
if [ -z "$resolved_ip" ] && command -v nslookup >/dev/null 2>&1; then
resolved_ip="$(
nslookup "$target" 2>/dev/null | awk '
{
for (i = 1; i <= NF; i++) {
if ($i ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) {
print $i
exit
}
}
}
'
)"
fi
if [ -n "$resolved_ip" ]; then
printf '%s\n' "$target" > "$cache_target_file"
printf '%s\n' "$resolved_ip" > "$cache_ip_file"
printf '%s\n' "$now" > "$cache_time_file"
printf '%s\n' "$resolved_ip"
return 0
fi
if [ "$cached_target" = "$target" ] && [ -n "$cached_ip" ]; then
printf '%s\n' "$cached_ip"
return 0
fi
printf '%s\n' "$target"
}
do_ping() {
local target="$1"
local name="$2"
local seq="$3"
local result_file="$RUN_DIR/${name}_last_result"
local ping_target
local result
local rtt
ping_target="$(resolve_target_ip "$target" "$name")"
result="$(ping -n -c 1 -W 2 "$ping_target" 2>/dev/null)"
if echo "$result" | grep -q "bytes from"; then
rtt="$(echo "$result" | sed -n 's/.*time=\([0-9.]*\).*/\1/p')"
write_result_file "$result_file" "1" "${rtt:-0}" "" "" "$seq"
else
write_result_file "$result_file" "0" "" "ping 无响应" "" "$seq"
fi
}
do_proxy_curl() {
local target="$1"
local proxy_type="$2"
local proxy_host="${3:-127.0.0.1}"
local proxy_port="$4"
local name="$5"
local seq="$6"
local result_file="$RUN_DIR/${name}_last_result"
local error_file="$RUN_DIR/${name}_curl_error"
local url
local proxy_addr
local curl_result
local http_code
local time_pretransfer
local rtt_ms
local detail
local rc
if ! command -v curl >/dev/null 2>&1; then
write_result_file "$result_file" "0" "" "系统未安装 curl" "" "$seq"
return 0
fi
if [ -z "$proxy_port" ]; then
write_result_file "$result_file" "0" "" "代理端口未配置" "" "$seq"
return 0
fi
url="$(normalize_foreign_url "$target")"
proxy_addr="${proxy_host}:${proxy_port}"
curl_result="$(
curl -k -I -L -sS --noproxy "" \
--connect-timeout 5 --max-time 10 \
--socks5-hostname "$proxy_addr" \
-o /dev/null -w '%{http_code}:%{time_pretransfer}' \
"$url" 2>"$error_file"
)"
rc=$?
http_code="$(printf '%s' "$curl_result" | awk -F ':' 'NR==1 { print $1 }')"
time_pretransfer="$(printf '%s' "$curl_result" | awk -F ':' 'NR==1 { print $2 }')"
if [ "$rc" -eq 0 ] && [ -n "$http_code" ] && [ -n "$time_pretransfer" ] && { [ "$http_code" = "200" ] || [ "$http_code" = "204" ]; }; then
rtt_ms="$(awk -v sec="$time_pretransfer" 'BEGIN { printf "%.1f", (sec + 0) * 1000 }')"
write_result_file "$result_file" "1" "$rtt_ms" "curl 连接探测成功,HTTP ${http_code}" "" "$seq"
else
detail="$(sed -n '1p' "$error_file" 2>/dev/null)"
[ -n "$detail" ] || detail="curl 退出码 ${rc},HTTP ${http_code:-000}"
write_result_file "$result_file" "0" "" "$detail" "" "$seq"
fi
rm -f "$error_file"
}
get_target_state() {
local name="$1"
case "$name" in
domestic)
fail_count="$domestic_fail_count"
fault_open="$domestic_fault_open"
;;
foreign)
fail_count="$foreign_fail_count"
fault_open="$foreign_fault_open"
;;
*)
fail_count=0
fault_open=0
;;
esac
}
set_target_state() {
local name="$1"
local next_fail_count="$2"
local next_fault_open="$3"
case "$name" in
domestic)
domestic_fail_count="$next_fail_count"
domestic_fault_open="$next_fault_open"
;;
foreign)
foreign_fail_count="$next_fail_count"
foreign_fault_open="$next_fault_open"
;;
esac
}
get_processed_seq() {
local name="$1"
local kind="$2"
case "${name}:${kind}" in
domestic:fault)
processed_seq="$domestic_last_fault_seq"
;;
foreign:fault)
processed_seq="$foreign_last_fault_seq"
;;
domestic:stats)
processed_seq="$domestic_last_stats_seq"
;;
foreign:stats)
processed_seq="$foreign_last_stats_seq"
;;
*)
processed_seq=0
;;
esac
}
set_processed_seq() {
local name="$1"
local kind="$2"
local value="${3:-0}"
case "${name}:${kind}" in
domestic:fault)
domestic_last_fault_seq="$value"
;;
foreign:fault)
foreign_last_fault_seq="$value"
;;
domestic:stats)
domestic_last_stats_seq="$value"
;;
foreign:stats)
foreign_last_stats_seq="$value"
;;
esac
}
reset_target_state() {
local name="$1"
rm -f "$RUN_DIR/${name}_last_result"
set_target_state "$name" 0 0
set_processed_seq "$name" "fault" 0
set_processed_seq "$name" "stats" 0
}
update_target_faults() {
local name="$1"
local label="$2"
local target="$3"
local result_file="$RUN_DIR/${name}_last_result"
local success="0"
local rtt=""
local detail=""
local seq=""
[ -n "$target" ] || {
reset_target_state "$name"
return 0
}
get_target_state "$name"
if [ -f "$result_file" ]; then
success="$(sed -n '1p' "$result_file" 2>/dev/null)"
rtt="$(sed -n '2p' "$result_file" 2>/dev/null)"
detail="$(sed -n '3p' "$result_file" 2>/dev/null)"
seq="$(sed -n '5p' "$result_file" 2>/dev/null)"
fi
[ -n "$seq" ] || return 0
get_processed_seq "$name" "fault"
if [ "$seq" = "$processed_seq" ]; then
return 0
fi
if [ "$success" = "1" ]; then
if [ "$fault_open" = "1" ]; then
log_event "恢复" "$label" "目标 ${target} 已恢复响应,当前延迟 ${rtt:-0} ms"
fi
set_target_state "$name" 0 0
set_processed_seq "$name" "fault" "$seq"
return 0
fi
fail_count=$((fail_count + 1))
if [ -n "$detail" ]; then
log_event "丢包" "$label" "目标 ${target} 本次探测失败(连续第 ${fail_count} 次):${detail}"
else
log_event "丢包" "$label" "目标 ${target} 本次探测失败(连续第 ${fail_count} 次)"
fi
fault_open=1
set_target_state "$name" "$fail_count" "$fault_open"
set_processed_seq "$name" "fault" "$seq"
}
calc_stats() {
local name="$1"
local total_samples=0
local success_count=0
local loss_count=0
local rtt_sum="0"
local min_rtt=""
local max_rtt=""
local avg="0.0"
local min="0.0"
local max="0.0"
local loss_rate="0.0"
case "$name" in
domestic)
total_samples="$domestic_total_samples"
success_count="$domestic_success_count"
loss_count="$domestic_loss_count"
rtt_sum="$domestic_rtt_sum"
min_rtt="$domestic_min_rtt"
max_rtt="$domestic_max_rtt"
;;
foreign)
total_samples="$foreign_total_samples"
success_count="$foreign_success_count"
loss_count="$foreign_loss_count"
rtt_sum="$foreign_rtt_sum"
min_rtt="$foreign_min_rtt"
max_rtt="$foreign_max_rtt"
;;
esac
if [ "$success_count" -gt 0 ]; then
avg="$(awk -v sum="$rtt_sum" -v count="$success_count" 'BEGIN { printf "%.1f", (sum + 0) / count }')"
min="$(awk -v value="${min_rtt:-0}" 'BEGIN { printf "%.1f", value + 0 }')"
max="$(awk -v value="${max_rtt:-0}" 'BEGIN { printf "%.1f", value + 0 }')"
fi
if [ "$total_samples" -gt 0 ]; then
loss_rate="$(awk -v loss="$loss_count" -v total="$total_samples" 'BEGIN { printf "%.1f", loss * 100.0 / total }')"
fi
printf '{"avg":"%s","min":"%s","max":"%s","loss_rate":"%s","loss_count":%d,"count":%d,"samples":%d}' \
"$avg" "$min" "$max" "$loss_rate" "$loss_count" "$success_count" "$total_samples"
}
update_cumulative_stats() {
local name="$1"
local target="$2"
local result_file="$RUN_DIR/${name}_last_result"
local success="0"
local rtt=""
local seq=""
local total_samples=0
local success_count=0
local loss_count=0
local rtt_sum="0"
local min_rtt=""
local max_rtt=""
[ -n "$target" ] || return 0
if [ -f "$result_file" ]; then
success="$(sed -n '1p' "$result_file" 2>/dev/null)"
rtt="$(sed -n '2p' "$result_file" 2>/dev/null)"
seq="$(sed -n '5p' "$result_file" 2>/dev/null)"
fi
[ -n "$seq" ] || return 0
get_processed_seq "$name" "stats"
if [ "$seq" = "$processed_seq" ]; then
return 0
fi
case "$name" in
domestic)
total_samples="$domestic_total_samples"
success_count="$domestic_success_count"
loss_count="$domestic_loss_count"
rtt_sum="$domestic_rtt_sum"
min_rtt="$domestic_min_rtt"
max_rtt="$domestic_max_rtt"
;;
foreign)
total_samples="$foreign_total_samples"
success_count="$foreign_success_count"
loss_count="$foreign_loss_count"
rtt_sum="$foreign_rtt_sum"
min_rtt="$foreign_min_rtt"
max_rtt="$foreign_max_rtt"
;;
esac
total_samples=$((total_samples + 1))
if [ "$success" = "1" ]; then
rtt="${rtt:-0}"
success_count=$((success_count + 1))
rtt_sum="$(awk -v sum="$rtt_sum" -v value="$rtt" 'BEGIN { printf "%.3f", (sum + 0) + (value + 0) }')"
if [ -z "$min_rtt" ]; then
min_rtt="$rtt"
else
min_rtt="$(awk -v current="$min_rtt" -v value="$rtt" 'BEGIN { printf "%.3f", ((value + 0) < (current + 0)) ? (value + 0) : (current + 0) }')"
fi
if [ -z "$max_rtt" ]; then
max_rtt="$rtt"
else
max_rtt="$(awk -v current="$max_rtt" -v value="$rtt" 'BEGIN { printf "%.3f", ((value + 0) > (current + 0)) ? (value + 0) : (current + 0) }')"
fi
else
loss_count=$((loss_count + 1))
fi
case "$name" in
domestic)
domestic_total_samples="$total_samples"
domestic_success_count="$success_count"
domestic_loss_count="$loss_count"
domestic_rtt_sum="$rtt_sum"
domestic_min_rtt="$min_rtt"
domestic_max_rtt="$max_rtt"
;;
foreign)
foreign_total_samples="$total_samples"
foreign_success_count="$success_count"
foreign_loss_count="$loss_count"
foreign_rtt_sum="$rtt_sum"
foreign_min_rtt="$min_rtt"
foreign_max_rtt="$max_rtt"
;;
esac
set_processed_seq "$name" "stats" "$seq"
if [ "$success" = "1" ]; then
accumulate_history "$name" "1" "${rtt:-0}"
else
accumulate_history "$name" "0" ""
fi
}
while true; do
ensure_runtime_state
START_TIME="$(cat "$START_TIME_FILE" 2>/dev/null || echo "")"
UPDATED_AT="$(date '+%Y-%m-%d %H:%M:%S')"
NOW_TS="$(date '+%s' 2>/dev/null || echo 0)"
current_minute="$(date '+%Y-%m-%d %H:%M')"
DOMESTIC_TARGET=""
FOREIGN_TARGET=""
FOREIGN_PROXY_TYPE="socks5h"
FOREIGN_PROXY_HOST="127.0.0.1"
FOREIGN_PROXY_PORT="7891"
DOMESTIC_INTERVAL="1"
FOREIGN_INTERVAL="5"
if [ -f "$RUN_DIR/config" ]; then
DOMESTIC_TARGET="$(sed -n '1p' "$RUN_DIR/config")"
FOREIGN_TARGET="$(sed -n '2p' "$RUN_DIR/config")"
FOREIGN_PROXY_TYPE="$(sed -n '3p' "$RUN_DIR/config")"
FOREIGN_PROXY_HOST="$(sed -n '4p' "$RUN_DIR/config")"
FOREIGN_PROXY_PORT="$(sed -n '5p' "$RUN_DIR/config")"
DOMESTIC_INTERVAL="$(sed -n '6p' "$RUN_DIR/config")"
FOREIGN_INTERVAL="$(sed -n '7p' "$RUN_DIR/config")"
fi
FOREIGN_PROXY_TYPE="socks5h"
[ -n "$FOREIGN_PROXY_HOST" ] || FOREIGN_PROXY_HOST="127.0.0.1"
[ -n "$FOREIGN_PROXY_PORT" ] || FOREIGN_PROXY_PORT="7891"
[ -n "$FOREIGN_INTERVAL" ] || FOREIGN_INTERVAL="5"
DOMESTIC_INTERVAL="$(normalize_interval "$DOMESTIC_INTERVAL")"
FOREIGN_INTERVAL="$(normalize_interval "$FOREIGN_INTERVAL")"
child_pids=""
if [ -n "$DOMESTIC_TARGET" ]; then
if should_probe_now "$domestic_last_probe_at" "$DOMESTIC_INTERVAL" "$NOW_TS"; then
probe_seq=$((probe_seq + 1))
do_ping "$DOMESTIC_TARGET" "domestic" "$probe_seq" &
child_pids="$!"
domestic_last_probe_at="$NOW_TS"
fi
else
domestic_last_probe_at=0
reset_target_state "domestic"
fi
if [ -n "$FOREIGN_TARGET" ]; then
if should_probe_now "$foreign_last_probe_at" "$FOREIGN_INTERVAL" "$NOW_TS"; then
probe_seq=$((probe_seq + 1))
do_proxy_curl "$FOREIGN_TARGET" "$FOREIGN_PROXY_TYPE" "$FOREIGN_PROXY_HOST" "$FOREIGN_PROXY_PORT" "foreign" "$probe_seq" &
child_pids="${child_pids:+$child_pids }$!"
foreign_last_probe_at="$NOW_TS"
fi
else
foreign_last_probe_at=0
reset_target_state "foreign"
fi
[ -n "$child_pids" ] && wait $child_pids 2>/dev/null
child_pids=""
update_target_faults "domestic" "国内" "$DOMESTIC_TARGET"
update_target_faults "foreign" "国外" "$FOREIGN_TARGET"
update_cumulative_stats "domestic" "$DOMESTIC_TARGET"
update_cumulative_stats "foreign" "$FOREIGN_TARGET"
DOMESTIC_STATS="$(calc_stats "domestic")"
FOREIGN_STATS="$(calc_stats "foreign")"
printf '{"start_time":"%s","updated_at":"%s","domestic":%s,"foreign":%s}\n' \
"$START_TIME" "$UPDATED_AT" "$DOMESTIC_STATS" "$FOREIGN_STATS" > "$STATUS_TMP" && \
mv -f "$STATUS_TMP" "$STATUS_FILE"
sleep 1
done
@@ -0,0 +1,15 @@
{
"luci-app-pingpacket": {
"description": "Grant access to luci-app-pingpacket",
"read": {
"uci": [
"pingpacket"
]
},
"write": {
"uci": [
"pingpacket"
]
}
}
}