mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-29 06:25:13 +08:00
🐤 Sync 2026-03-30 12:52:58
This commit is contained in:
1 parent
238cb2aa39
commit
9941499a61
63 files changed
+3456
-4029
No files matched your search
@@ -1,41 +1,60 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 2006 OpenWrt.org
|
||||
# Copyright 2022-2025 sirpdboy <herboy2008@gmail.com>
|
||||
# Copyright 2022-2026 sirpdboy <herboy2008@gmail.com>
|
||||
|
||||
NAME=timecontrol
|
||||
LOG_FILE="/var/log/timecontrol.log"
|
||||
DEBUG=1
|
||||
|
||||
# 时长数据库目录
|
||||
DURATION_DIR="/var/lib/timecontrol"
|
||||
DURATION_DB="$DURATION_DIR/duration.db"
|
||||
CONNECTION_LOG="$DURATION_DIR/connections.log"
|
||||
|
||||
# 状态文件
|
||||
IDLIST="/var/$NAME.idlist"
|
||||
TMPID="/var/$NAME.tmpid"
|
||||
STATUS_DB="$DURATION_DIR/status.db"
|
||||
|
||||
idlist=$(uci show $NAME | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]')
|
||||
|
||||
config_get_type() {
|
||||
local ret=$(uci -q get "${NAME}.${1}")
|
||||
echo "${ret:=$2}"
|
||||
# 初始化目录
|
||||
init_dirs() {
|
||||
mkdir -p "$DURATION_DIR"
|
||||
touch "$DURATION_DB" "$CONNECTION_LOG" "$STATUS_DB" 2>/dev/null
|
||||
}
|
||||
|
||||
config_n_get() {
|
||||
local ret=$(uci -q get "${NAME}.${1}.${2}")
|
||||
echo "${ret:=$3}"
|
||||
# 日志函数
|
||||
dbg() {
|
||||
[ "$DEBUG" -eq 1 ] && {
|
||||
local d="$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "[$d] CTRL-DEBUG: $@" >> "$LOG_FILE"
|
||||
}
|
||||
}
|
||||
|
||||
info() {
|
||||
local d="$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "[$d] CTRL-INFO: $@" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# 配置文件读取
|
||||
config_t_get() {
|
||||
local index=${3:-0}
|
||||
local ret=$(uci -q get "${NAME}.@${1}[${index}].${2}")
|
||||
echo "${ret:=${4}}"
|
||||
local index=${3:-0}
|
||||
local ret=$(uci -q get "${NAME}.@${1}[${index}].${2}")
|
||||
echo "${ret:=${4}}"
|
||||
}
|
||||
|
||||
config_t_set() {
|
||||
local index=${4:-0}
|
||||
local ret=$(uci -q set "${NAME}.@${1}[${index}].${2}=${3}")
|
||||
# 获取启用设备
|
||||
get_enabled_devices() {
|
||||
uci show $NAME 2>/dev/null | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]' | sort -n
|
||||
}
|
||||
|
||||
# 时间检查函数
|
||||
is_time_in_range() {
|
||||
local start_time=$1
|
||||
local end_time=$2
|
||||
local current_time=$(date +%H:%M)
|
||||
|
||||
if [ "$start_time" = "$end_time" ]; then
|
||||
return 0
|
||||
return 0
|
||||
elif [ "$start_time" \< "$end_time" ]; then
|
||||
[ "$current_time" \> "$start_time" ] && [ "$current_time" \< "$end_time" ] && return 0
|
||||
else
|
||||
@@ -48,60 +67,269 @@ is_weekday_in_range() {
|
||||
local configured_weekdays=$1
|
||||
local current_weekday=$(date +%u)
|
||||
|
||||
[ "$configured_weekdays" = "0" ] && return 0
|
||||
|
||||
for ww in $(echo $configured_weekdays | sed 's/,/ /g'); do
|
||||
if [ "$current_weekday" = "$ww" ] || [ "$ww" = "0" ]; then
|
||||
return 0
|
||||
fi
|
||||
[ "$current_weekday" = "$ww" ] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
check_device() {
|
||||
local id=$1
|
||||
local start_time=$(config_t_get device timestart $id )
|
||||
local end_time=$(config_t_get device timeend $id )
|
||||
local weekdays=$(config_t_get device week $id )
|
||||
|
||||
if is_weekday_in_range "$weekdays" && is_time_in_range "$start_time" "$end_time"; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
update_device_status() {
|
||||
local id=$1
|
||||
local action=$2
|
||||
|
||||
if [ "$action" = "add" ]; then
|
||||
timecontrol add $id
|
||||
echo "!${id}!" >> $IDLIST
|
||||
elif [ "$action" = "del" ]; then
|
||||
timecontrol del $id
|
||||
sed -i "/!$id!/d" $IDLIST >/dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
process_devices() {
|
||||
[ -s $IDLIST ] || touch $IDLIST
|
||||
|
||||
for id in $idlist; do
|
||||
if check_device $id; then
|
||||
if ! grep -q "!${id}!" $IDLIST; then
|
||||
update_device_status $id "add"
|
||||
fi
|
||||
else
|
||||
if grep -q "!${id}!" $IDLIST; then
|
||||
update_device_status $id "del"
|
||||
fi
|
||||
# 时长管理
|
||||
record_connection_time() {
|
||||
local target="$1"
|
||||
local action="$2"
|
||||
local timestamp=$(date +%s)
|
||||
|
||||
echo "$timestamp,$target,$action" >> "$CONNECTION_LOG"
|
||||
|
||||
if [ "$action" = "connect" ]; then
|
||||
if ! grep -q "^$target," "$DURATION_DB" 2>/dev/null; then
|
||||
echo "$target,$timestamp,0,0" >> "$DURATION_DB"
|
||||
dbg "初始化时长: $target"
|
||||
fi
|
||||
done
|
||||
|
||||
cat $IDLIST | sort | uniq > $TMPID
|
||||
mv $TMPID $IDLIST
|
||||
elif [ "$action" = "disconnect" ]; then
|
||||
if grep -q "^$target," "$DURATION_DB" 2>/dev/null; then
|
||||
local last_connect=$(grep "^$target," "$DURATION_DB" | cut -d',' -f2)
|
||||
local total_used=$(grep "^$target," "$DURATION_DB" | cut -d',' -f3)
|
||||
local last_reset=$(grep "^$target," "$DURATION_DB" | cut -d',' -f4)
|
||||
|
||||
local session_duration=$((timestamp - last_connect))
|
||||
local new_total=$((total_used + session_duration))
|
||||
|
||||
sed -i "/^$target,/d" "$DURATION_DB"
|
||||
echo "$target,$timestamp,$new_total,$last_reset" >> "$DURATION_DB"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
while :; do
|
||||
process_devices
|
||||
sleep 60
|
||||
done
|
||||
get_connection_time() {
|
||||
local target="$1"
|
||||
local current_time=$(date +%s)
|
||||
|
||||
if grep -q "^$target," "$DURATION_DB" 2>/dev/null; then
|
||||
local last_connect=$(grep "^$target," "$DURATION_DB" | cut -d',' -f2)
|
||||
local total_used=$(grep "^$target," "$DURATION_DB" | cut -d',' -f3)
|
||||
|
||||
if tail -n 5 "$CONNECTION_LOG" 2>/dev/null | grep -q "^[0-9]*,$target,connect$"; then
|
||||
local session_duration=$((current_time - last_connect))
|
||||
total_used=$((total_used + session_duration))
|
||||
fi
|
||||
|
||||
echo "$total_used"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
# 重置检查
|
||||
should_reset_duration() {
|
||||
local target="$1"
|
||||
local reset_cycle="$2"
|
||||
local last_reset_file="$DURATION_DIR/last_reset_$target"
|
||||
|
||||
[ ! -f "$last_reset_file" ] && return 0
|
||||
|
||||
local last_reset=$(cat "$last_reset_file" 2>/dev/null)
|
||||
local current_time=$(date +%s)
|
||||
|
||||
case "$reset_cycle" in
|
||||
"daily")
|
||||
local last_date=$(date -d "@$last_reset" +%Y%m%d 2>/dev/null || echo "0")
|
||||
local current_date=$(date +%Y%m%d)
|
||||
[ "$last_date" != "$current_date" ]
|
||||
;;
|
||||
"weekly")
|
||||
local last_week=$(date -d "@$last_reset" +%Y%W 2>/dev/null || echo "0")
|
||||
local current_week=$(date +%Y%W)
|
||||
[ "$last_week" != "$current_week" ]
|
||||
;;
|
||||
"monthly")
|
||||
local last_month=$(date -d "@$last_reset" +%Y%m 2>/dev/null || echo "0")
|
||||
local current_month=$(date +%Y%m)
|
||||
[ "$last_month" != "$current_month" ]
|
||||
;;
|
||||
*)
|
||||
false
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
reset_duration_counter() {
|
||||
local target="$1"
|
||||
local reset_cycle="$2"
|
||||
local current_time=$(date +%s)
|
||||
|
||||
if grep -q "^$target," "$DURATION_DB" 2>/dev/null; then
|
||||
sed -i "/^$target,/d" "$DURATION_DB"
|
||||
fi
|
||||
|
||||
echo "$target,$current_time,0,$current_time" >> "$DURATION_DB"
|
||||
echo "$current_time" > "$DURATION_DIR/last_reset_$target"
|
||||
|
||||
info "重置时长: $target (周期: $reset_cycle)"
|
||||
}
|
||||
|
||||
# 主检查函数
|
||||
check_device_control() {
|
||||
local id="$1"
|
||||
local target=$(config_t_get device mac "$id")
|
||||
local time_mode=$(config_t_get device time_mode "$id" "period")
|
||||
local weekdays=$(config_t_get device week "$id" "0")
|
||||
|
||||
# 检查星期
|
||||
is_weekday_in_range "$weekdays" || {
|
||||
dbg "星期不允许: $target"
|
||||
return 1
|
||||
}
|
||||
|
||||
case "$time_mode" in
|
||||
"period")
|
||||
local start_time=$(config_t_get device timestart "$id" "00:00")
|
||||
local end_time=$(config_t_get device timeend "$id" "00:00")
|
||||
is_time_in_range "$start_time" "$end_time" || {
|
||||
dbg "时间段外: $target ($start_time-$end_time)"
|
||||
return 1
|
||||
}
|
||||
dbg "时间段内: $target"
|
||||
return 0
|
||||
;;
|
||||
|
||||
"duration")
|
||||
local duration=$(config_t_get device duration "$id" "60")
|
||||
local reset_cycle=$(config_t_get device reset_cycle "$id" "daily")
|
||||
|
||||
# 重置检查
|
||||
if should_reset_duration "$target" "$reset_cycle"; then
|
||||
reset_duration_counter "$target" "$reset_cycle"
|
||||
fi
|
||||
|
||||
# 记录连接
|
||||
local last_action=$(grep ",$target," "$CONNECTION_LOG" 2>/dev/null | tail -1 | cut -d',' -f3)
|
||||
if [ "$last_action" != "connect" ]; then
|
||||
record_connection_time "$target" "connect"
|
||||
fi
|
||||
|
||||
# 检查时长
|
||||
local used_seconds=$(get_connection_time "$target")
|
||||
local used_minutes=$((used_seconds / 60))
|
||||
local max_minutes=$duration
|
||||
|
||||
dbg "时长检查: $target 已用=${used_minutes}分钟, 限制=${max_minutes}分钟"
|
||||
|
||||
if [ "$used_minutes" -ge "$max_minutes" ]; then
|
||||
dbg "已超时: $target"
|
||||
return 1
|
||||
fi
|
||||
dbg "未超时: $target"
|
||||
return 0
|
||||
;;
|
||||
|
||||
"combined")
|
||||
local start_time=$(config_t_get device timestart "$id" "00:00")
|
||||
local end_time=$(config_t_get device timeend "$id" "00:00")
|
||||
local use_duration=$(config_t_get device use_duration "$id" "0")
|
||||
|
||||
# 时间段检查
|
||||
is_time_in_range "$start_time" "$end_time" || {
|
||||
dbg "时间段外: $target"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 时长检查
|
||||
if [ "$use_duration" = "1" ]; then
|
||||
local duration=$(config_t_get device duration "$id" "60")
|
||||
local reset_cycle=$(config_t_get device reset_cycle "$id" "daily")
|
||||
|
||||
if should_reset_duration "$target" "$reset_cycle"; then
|
||||
reset_duration_counter "$target" "$reset_cycle"
|
||||
fi
|
||||
|
||||
local last_action=$(grep ",$target," "$CONNECTION_LOG" 2>/dev/null | tail -1 | cut -d',' -f3)
|
||||
if [ "$last_action" != "connect" ]; then
|
||||
record_connection_time "$target" "connect"
|
||||
fi
|
||||
|
||||
local used_seconds=$(get_connection_time "$target")
|
||||
local used_minutes=$((used_seconds / 60))
|
||||
local max_minutes=$duration
|
||||
|
||||
if [ "$used_minutes" -ge "$max_minutes" ]; then
|
||||
dbg "时间段内但已超时: $target"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
dbg "时间段内允许: $target"
|
||||
return 0
|
||||
;;
|
||||
|
||||
*)
|
||||
# 默认时间段控制
|
||||
local start_time=$(config_t_get device timestart "$id" "00:00")
|
||||
local end_time=$(config_t_get device timeend "$id" "00:00")
|
||||
is_time_in_range "$start_time" "$end_time"
|
||||
return $?
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 更新设备状态
|
||||
update_device_status() {
|
||||
local id="$1"
|
||||
local should_allow="$2" # 0=允许, 1=禁止
|
||||
local target=$(config_t_get device mac "$id")
|
||||
local comment=$(config_t_get device comment "$id" "设备$id")
|
||||
|
||||
# 检查当前状态
|
||||
local current_blocked=0
|
||||
if [ -f "$IDLIST" ] && grep -q "!${id}!" "$IDLIST" 2>/dev/null; then
|
||||
current_blocked=1
|
||||
fi
|
||||
|
||||
dbg "设备状态: $target, 应该允许=$should_allow, 当前阻止=$current_blocked"
|
||||
|
||||
if [ "$should_allow" -eq 0 ]; then
|
||||
# 应该允许
|
||||
if [ "$current_blocked" -eq 1 ]; then
|
||||
dbg "解除阻止: $target"
|
||||
timecontrol del "$id"
|
||||
sed -i "/!$id!/d" "$IDLIST" 2>/dev/null
|
||||
info "允许上网: $comment ($target)"
|
||||
record_connection_time "$target" "disconnect"
|
||||
fi
|
||||
else
|
||||
# 应该阻止
|
||||
if [ "$current_blocked" -eq 0 ]; then
|
||||
dbg "添加阻止: $target"
|
||||
timecontrol add "$id"
|
||||
if ! grep -q "!$id!" "$IDLIST" 2>/dev/null; then
|
||||
echo "!$id!" >> "$IDLIST"
|
||||
fi
|
||||
info "阻止上网: $comment ($target)"
|
||||
record_connection_time "$target" "disconnect"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 主处理循环
|
||||
main_loop() {
|
||||
info "时间控制守护进程启动"
|
||||
init_dirs
|
||||
while :; do
|
||||
dbg "开始检查设备"
|
||||
[ `uci show $NAME 2>/dev/null | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]' | sort -n | wc -l` eq 0 ] && timecontrol stop && break
|
||||
for id in $(get_enabled_devices); do
|
||||
if check_device_control "$id"; then
|
||||
update_device_status "$id" 0 # 允许
|
||||
else
|
||||
update_device_status "$id" 1 # 阻止
|
||||
fi
|
||||
done
|
||||
|
||||
sleep 60
|
||||
done
|
||||
}
|
||||
|
||||
# 启动
|
||||
main_loop
|
||||
Reference in new issue
Block a user