mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-27 12:42:51 +08:00
259 lines
5.9 KiB
Bash
Executable File
259 lines
5.9 KiB
Bash
Executable File
#!/bin/sh
|
|
# shellcheck shell=ash
|
|
|
|
# Variables below are populated by sourced helpers and ss_load_config()
|
|
# shellcheck disable=SC2154
|
|
|
|
LC_ALL=C
|
|
IPKG_INSTROOT="${IPKG_INSTROOT:-}"
|
|
export IPKG_INSTROOT
|
|
|
|
# shellcheck disable=SC1091
|
|
. /lib/functions.sh
|
|
# shellcheck disable=SC1091
|
|
. /usr/lib/safeshield/core.sh
|
|
|
|
readonly SS_REFRESHD_LOCK='/var/lock/safeshield-refreshd.lock'
|
|
readonly SS_REFRESHD_LOCK_FD=308
|
|
|
|
ss_should_terminate=0
|
|
ss_sleep_pid=''
|
|
|
|
refreshd_lock() {
|
|
mkdir -p "${SS_REFRESHD_LOCK%/*}" || return 1
|
|
eval "exec ${SS_REFRESHD_LOCK_FD}>\"${SS_REFRESHD_LOCK}\"" || return 1
|
|
flock -n "${SS_REFRESHD_LOCK_FD}" || return 1
|
|
}
|
|
|
|
refreshd_unlock() {
|
|
flock -u "${SS_REFRESHD_LOCK_FD}" 2>/dev/null || true
|
|
eval "exec ${SS_REFRESHD_LOCK_FD}>&-" 2>/dev/null || true
|
|
}
|
|
|
|
handle_term() {
|
|
ss_should_terminate=1
|
|
if [ -n "$ss_sleep_pid" ]; then
|
|
kill "$ss_sleep_pid" 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
sleep_seconds() {
|
|
local seconds="$1"
|
|
local rc=0
|
|
|
|
[ "$ss_should_terminate" -eq 1 ] && return 1
|
|
[ "$seconds" -gt 0 ] 2>/dev/null || return 0
|
|
|
|
sleep "$seconds" &
|
|
ss_sleep_pid=$!
|
|
wait "$ss_sleep_pid" 2>/dev/null || rc=$?
|
|
ss_sleep_pid=''
|
|
|
|
[ "$ss_should_terminate" -eq 1 ] && return 1
|
|
[ "$rc" -eq 0 ]
|
|
}
|
|
|
|
wait_for_wan_if_needed() {
|
|
local require_wan
|
|
|
|
require_wan="$(ss_config_get config require_wan 1)"
|
|
|
|
case "$require_wan" in
|
|
1)
|
|
ubus -t 30 wait_for network.interface.wan 2>/dev/null || true
|
|
;;
|
|
esac
|
|
}
|
|
|
|
status_epoch() {
|
|
local key="$1"
|
|
local value
|
|
|
|
value="$(json get "$key" 2>/dev/null)"
|
|
is_valid_integer "$value" || value=0
|
|
printf '%s\n' "$value"
|
|
}
|
|
|
|
schedule_base_epoch() {
|
|
local now="$1"
|
|
local last_success last_attempt base=0
|
|
|
|
last_success="$(status_epoch last_success)"
|
|
last_attempt="$(status_epoch last_attempt)"
|
|
|
|
if [ "$last_success" -gt 0 ] 2>/dev/null && [ "$last_success" -le "$now" ] 2>/dev/null; then
|
|
base="$last_success"
|
|
fi
|
|
|
|
# A failed or currently-running refresh must also move the retry window
|
|
# forward so refreshd cannot enter an immediate retry loop. A successful
|
|
# refresh is naturally newer than its attempt timestamp and wins here.
|
|
if [ "$last_attempt" -gt "$base" ] 2>/dev/null && [ "$last_attempt" -le "$now" ] 2>/dev/null; then
|
|
base="$last_attempt"
|
|
fi
|
|
|
|
printf '%s\n' "$base"
|
|
}
|
|
|
|
has_recent_success() {
|
|
local interval="$1"
|
|
local now last_success age
|
|
|
|
now="$(date +%s)"
|
|
last_success="$(status_epoch last_success)"
|
|
|
|
[ "$last_success" -gt 0 ] 2>/dev/null || return 1
|
|
[ "$last_success" -le "$now" ] 2>/dev/null || return 1
|
|
|
|
age=$((now - last_success))
|
|
[ "$age" -lt "$interval" ] 2>/dev/null
|
|
}
|
|
|
|
set_next_refresh_epoch() {
|
|
local epoch="$1"
|
|
|
|
is_valid_integer "$epoch" || epoch=0
|
|
ss_status_set next_refresh_at "$epoch"
|
|
}
|
|
|
|
clear_next_refresh_at() {
|
|
ss_status_set next_refresh_at "0"
|
|
}
|
|
|
|
wait_until_refresh_due() {
|
|
local interval="$1"
|
|
local fallback_epoch="$2"
|
|
local now base due remaining
|
|
|
|
while :; do
|
|
[ "$ss_should_terminate" -eq 1 ] && return 1
|
|
|
|
now="$(date +%s)"
|
|
base="$(schedule_base_epoch "$now")"
|
|
if [ "$base" -le 0 ] 2>/dev/null; then
|
|
base="$fallback_epoch"
|
|
fi
|
|
|
|
due=$((base + interval))
|
|
remaining=$((due - now))
|
|
|
|
if [ "$remaining" -le 0 ] 2>/dev/null; then
|
|
clear_next_refresh_at
|
|
return 0
|
|
fi
|
|
|
|
set_next_refresh_epoch "$due"
|
|
sleep_seconds "$remaining" || return 1
|
|
|
|
# A manual refresh may have completed while refreshd was sleeping.
|
|
# Recalculate from the latest last_success/last_attempt before running.
|
|
done
|
|
}
|
|
|
|
main() {
|
|
local interval
|
|
local boot_delay
|
|
local refresh_on_boot
|
|
local schedule_anchor
|
|
|
|
refreshd_lock || exit 0
|
|
|
|
ss_load_config || exit 1
|
|
if [ ! -s "${RUNNING_STATUS_FILE}" ]; then
|
|
ss_status_reset || true
|
|
fi
|
|
ss_sync_blocklist_status
|
|
ss_status_set status "idle"
|
|
ss_status_set stage "starting"
|
|
|
|
interval="$(ss_config_get config refresh_interval_s 28800)"
|
|
boot_delay="$(ss_config_get config boot_start_delay_s 30)"
|
|
refresh_on_boot="$(ss_config_get config refresh_on_boot 1)"
|
|
|
|
is_valid_integer "$interval" || interval=28800
|
|
[ "$interval" -gt 0 ] 2>/dev/null || interval=28800
|
|
|
|
is_valid_integer "$boot_delay" || boot_delay=30
|
|
|
|
wait_for_wan_if_needed
|
|
ss_status_set stage "boot_delay"
|
|
set_next_refresh_epoch "$(($(date +%s) + boot_delay))"
|
|
sleep_seconds "$boot_delay" || exit 0
|
|
|
|
if [ "$refresh_on_boot" = "1" ] && [ "${ss_enabled}" = "1" ]; then
|
|
if has_recent_success "$interval"; then
|
|
log_info "Skipping boot refresh because a recent refresh already succeeded"
|
|
ss_status_set status "idle"
|
|
ss_status_set stage "boot_refresh_skipped"
|
|
else
|
|
ss_status_set status "running"
|
|
ss_status_set stage "boot_refresh"
|
|
clear_next_refresh_at
|
|
safeshield_force_download
|
|
fi
|
|
fi
|
|
|
|
schedule_anchor="$(date +%s)"
|
|
|
|
while :; do
|
|
ss_load_config || {
|
|
schedule_anchor="$(date +%s)"
|
|
sleep_seconds 5 || break
|
|
continue
|
|
}
|
|
|
|
interval="$(ss_config_get config refresh_interval_s 28800)"
|
|
is_valid_integer "$interval" || interval=28800
|
|
[ "$interval" -gt 0 ] 2>/dev/null || interval=28800
|
|
|
|
if [ "${ss_enabled}" != "1" ]; then
|
|
ss_status_set status "disabled"
|
|
ss_status_set stage "disabled"
|
|
clear_next_refresh_at
|
|
sleep_seconds "$interval" || break
|
|
schedule_anchor="$(date +%s)"
|
|
continue
|
|
fi
|
|
|
|
ss_status_set status "idle"
|
|
ss_status_set stage "scheduled_wait"
|
|
wait_until_refresh_due "$interval" "$schedule_anchor" || break
|
|
|
|
ss_load_config || {
|
|
schedule_anchor="$(date +%s)"
|
|
continue
|
|
}
|
|
|
|
if [ "${ss_enabled}" != "1" ]; then
|
|
ss_status_set status "disabled"
|
|
ss_status_set stage "disabled"
|
|
clear_next_refresh_at
|
|
schedule_anchor="$(date +%s)"
|
|
continue
|
|
fi
|
|
|
|
wait_for_wan_if_needed || true
|
|
|
|
ss_status_set status "running"
|
|
ss_status_set stage "scheduled_refresh"
|
|
clear_next_refresh_at
|
|
safeshield_force_download
|
|
schedule_anchor="$(date +%s)"
|
|
done
|
|
|
|
ss_load_config >/dev/null 2>&1 || true
|
|
if [ "${ss_enabled:-0}" = "1" ]; then
|
|
ss_status_set status "idle"
|
|
ss_status_set stage "stopped"
|
|
else
|
|
ss_status_set status "disabled"
|
|
ss_status_set stage "disabled"
|
|
fi
|
|
clear_next_refresh_at
|
|
}
|
|
|
|
trap "handle_term" TERM INT
|
|
trap "refreshd_unlock; clear_next_refresh_at" EXIT
|
|
|
|
main "$@"
|