diff --git a/containers/gluetun/gluetun.config b/containers/gluetun/gluetun.config index 6631c84..d80a8a5 100644 --- a/containers/gluetun/gluetun.config +++ b/containers/gluetun/gluetun.config @@ -49,6 +49,13 @@ CFG_GLUETUN_CONTROL_SERVER_API_KEY=RANDOMIZEDPASSWORD1 # CFG_GLUETUN_HEALTH_TARGETS="mullvad.net:443,eff.org:443" CFG_GLUETUN_HEALTH_ICMP_IPS="9.9.9.9" +# PROVIDERS_REFRESH_HOURS = how often (hours) to re-fetch gluetun's upstream +# server list, which powers the provider/country pickers. It's a few MB and +# rarely changes, so we don't pull it on every WebUI update. Lower it for a +# fresher list, raise it on a slow/metered link, or set 0 to never auto-fetch +# (refresh on demand from the Tools tab instead). Default 24. +# +CFG_GLUETUN_PROVIDERS_REFRESH_HOURS=24 # # ============================================================================= # METADATA diff --git a/containers/gluetun/scripts/gluetun_install_hooks.sh b/containers/gluetun/scripts/gluetun_install_hooks.sh index 3068167..8f14252 100644 --- a/containers/gluetun/scripts/gluetun_install_hooks.sh +++ b/containers/gluetun/scripts/gluetun_install_hooks.sh @@ -14,7 +14,7 @@ gluetun_install_post_start() echo "---- $menu_number. Refreshing Gluetun provider snapshot." echo "" - appWebuiRefresh_gluetun + GLUETUN_PROVIDERS_FORCE=1 appWebuiRefresh_gluetun ((menu_number++)) echo "" diff --git a/containers/gluetun/scripts/gluetun_providers.sh b/containers/gluetun/scripts/gluetun_providers.sh index f1f0462..efba1d7 100644 --- a/containers/gluetun/scripts/gluetun_providers.sh +++ b/containers/gluetun/scripts/gluetun_providers.sh @@ -22,20 +22,51 @@ appWebuiRefresh_gluetun() { return 0 fi + # Refresh throttle. The WebUI updater calls this hook on every routine + # update (the task processor fires it repeatedly), but the upstream server + # list is a few MB and changes rarely — re-fetching it each time adds a + # silent, slow-on-a-bad-link stall to every update. So only reach upstream + # once per refresh window. Direct callers that want a guaranteed pull (the + # Tools "refresh" button, the install hook) set GLUETUN_PROVIDERS_FORCE=1. + # CFG_GLUETUN_PROVIDERS_REFRESH_HOURS=0 disables auto-fetch (manual only). + local refresh_hours="${CFG_GLUETUN_PROVIDERS_REFRESH_HOURS:-24}" + local stamp="/tmp/libreportal_gluetun_providers_checked" + if [[ "${GLUETUN_PROVIDERS_FORCE:-0}" != "1" ]]; then + if [[ "$refresh_hours" == "0" ]]; then + return 0 + fi + if [[ -s "$output_file" ]]; then + local _now _last + _now=$(date +%s) + _last=$(stat -c '%Y' "$stamp" 2>/dev/null || echo 0) + if (( _now - _last < refresh_hours * 3600 )); then + return 0 + fi + fi + fi + # GitHub raw only sends ETag (no Last-Modified), so use If-None-Match - # via a sidecar to skip the 7MB body when nothing has changed upstream. + # via a sidecar to skip the multi-MB body when nothing has changed + # upstream. --compressed asks for gzip too (this JSON shrinks ~7x), and + # --connect-timeout fails fast on a dead link instead of hanging. local etag_file="${output_file}.etag" local etag="" [[ -s "$etag_file" ]] && etag=$(<"$etag_file") local headers="${output_file}.hdr.$$" local http_code - http_code=$(curl -sSL \ + http_code=$(curl -sSL --compressed \ ${etag:+-H "If-None-Match: $etag"} \ + --connect-timeout 15 \ --speed-limit 1000 --speed-time 30 \ --retry 2 --retry-delay 2 --retry-all-errors \ -D "$headers" -o "$raw" \ -w '%{http_code}' "$upstream") || http_code="" + # Whatever the outcome (fresh copy, 304, or a failed/slow link), record + # that we just checked so the throttle window restarts — a persistent + # outage then can't re-stall every subsequent update. + touch "$stamp" 2>/dev/null || true + # $raw and $headers live next to $output_file (under containers_dir/ # libreportal/frontend/data/, dockerinstall-owned in rootless). The # manager can't `rm` them directly without a Permission denied — same diff --git a/containers/gluetun/tools/gluetun_refresh_providers.sh b/containers/gluetun/tools/gluetun_refresh_providers.sh index 533be33..d4bcc56 100644 --- a/containers/gluetun/tools/gluetun_refresh_providers.sh +++ b/containers/gluetun/tools/gluetun_refresh_providers.sh @@ -11,6 +11,6 @@ appGluetunRefreshProviders() local tool_args="$1" isNotice "Refreshing Gluetun provider snapshot..." - appWebuiRefresh_gluetun + GLUETUN_PROVIDERS_FORCE=1 appWebuiRefresh_gluetun isSuccessful "Provider snapshot regenerated." } diff --git a/scripts/webui/webui_updater.sh b/scripts/webui/webui_updater.sh index f1ad245..1972558 100755 --- a/scripts/webui/webui_updater.sh +++ b/scripts/webui/webui_updater.sh @@ -81,6 +81,10 @@ webuiLibrePortalUpdate() { [[ -f "${containers_dir}${_app}/docker-compose.yml" ]] || continue _hook="appWebuiRefresh_${_app}" declare -F "$_hook" >/dev/null 2>&1 || continue + # Announce before running: a hook may reach upstream (e.g. + # gluetun's provider list), and its own output is captured + # below, so without this the update looks frozen mid-fetch. + isNotice "Refreshing ${_app} WebUI data..." local result; result=$($_hook) checkSuccess "Refreshed ${_app} WebUI data..." done