release: 1.3.26 — Watchdog proxy restart protection, WAN monitor debounce, and subscription bootstrap resilience
- Fix #52: Watchdog proxy restart on single URL failure: * Validate failure against secondary independent probe URL before declaring proxy down * Skip restart when direct WAN is also degraded or down (!direct_ok) * Implement 120s cooldown between automated proxy restarts * Fix Telegram notification to accurately state 'Перезапуск sing-box' instead of 'Перезапуск роутера' - Fix #51: Telegram bot spamming WAN up/down notifications: * Filter hotplug events strictly by badwan_monitored_interfaces (defaults to wan) * Add atomic directory lock with debounce delay and real ubus state query * Prevent repeated notifications when interface state has not transitioned - Feat: 2-VPN deadlock elimination & self-download subscription proxy: * Isolate unbootstrapped dependent subscription sections on initial boot (deferred_sections) * Allow self-download proxy target for subscriptions with explicit UI hint '(текущее правило при активности)' * Enable automatic local proxy fallback for subscription refresh when direct WAN download fails while sing-box is active * Add regression test in tests/subscription_bootstrap_deadlock.sh - Fix: Parental control quota enforcement: * Correct route rule filtering when daily quota minutes are exhausted without a fixed time interval - i18n & Version bump: * Bump fe-app-tachyon to 1.3.26 and update Russian PO/POT translations
This commit is contained in:
@@ -780,7 +780,7 @@ function createParentalContent(section) {
|
||||
o.rawhtml = true;
|
||||
o.modalonly = false;
|
||||
o.cfgvalue = function (sectionId) {
|
||||
const target = uci.get(UCI_PACKAGE, sectionId, "target") || "all";
|
||||
const target = uci.get(UCI_PACKAGE, sectionId, "target") || "domains";
|
||||
if (target === "all") {
|
||||
return (
|
||||
'<span style="color:var(--error-color-medium, #e53e3e);font-weight:600;">🚫 ' +
|
||||
@@ -788,11 +788,20 @@ function createParentalContent(section) {
|
||||
"</span>"
|
||||
);
|
||||
}
|
||||
if (target === "domains") {
|
||||
const rawDomains = normalizeListValues(
|
||||
uci.get(UCI_PACKAGE, sectionId, "blocked_domains"),
|
||||
);
|
||||
const count = rawDomains.length;
|
||||
return (
|
||||
'<span class="badge" style="background:var(--background-color-low, rgba(0,0,0,0.06));padding:2px 6px;border-radius:4px;font-size:11px;margin-right:4px;border:1px solid var(--border-color-low, rgba(0,0,0,0.12));display:inline-flex;align-items:center;margin-bottom:2px;">🌐 ' +
|
||||
_("Blocked Sites") +
|
||||
(count > 0 ? " (" + count + ")" : "") +
|
||||
"</span>"
|
||||
);
|
||||
}
|
||||
const rawSecs = uci.get(UCI_PACKAGE, sectionId, "sections");
|
||||
const secNames = normalizeListValues(rawSecs);
|
||||
if (secNames.length === 0 && target !== "sections") {
|
||||
secNames.push(target);
|
||||
}
|
||||
if (secNames.length === 0) {
|
||||
return (
|
||||
'<span style="opacity:0.6;">' + _("No sections selected") + "</span>"
|
||||
@@ -814,8 +823,17 @@ function createParentalContent(section) {
|
||||
);
|
||||
};
|
||||
o.textvalue = function (sectionId) {
|
||||
const target = uci.get(UCI_PACKAGE, sectionId, "target") || "all";
|
||||
const target = uci.get(UCI_PACKAGE, sectionId, "target") || "domains";
|
||||
if (target === "all") return _("All Internet");
|
||||
if (target === "domains") {
|
||||
const rawDomains = normalizeListValues(
|
||||
uci.get(UCI_PACKAGE, sectionId, "blocked_domains"),
|
||||
);
|
||||
return (
|
||||
_("Blocked Sites") +
|
||||
(rawDomains.length > 0 ? " (" + rawDomains.length + ")" : "")
|
||||
);
|
||||
}
|
||||
const secNames = normalizeListValues(
|
||||
uci.get(UCI_PACKAGE, sectionId, "sections"),
|
||||
);
|
||||
@@ -1081,6 +1099,7 @@ function createParentalContent(section) {
|
||||
),
|
||||
);
|
||||
o.modalonly = true;
|
||||
o.rmempty = false;
|
||||
o.default = "domains";
|
||||
o.value("domains", _("Blocked Sites (Only block domains specified below)"));
|
||||
o.value("all", _("All Internet (Complete internet cutoff)"));
|
||||
@@ -1222,6 +1241,7 @@ function createParentalContent(section) {
|
||||
),
|
||||
);
|
||||
o.modalonly = true;
|
||||
o.depends("target", "domains");
|
||||
o.rmempty = true;
|
||||
o.rows = 6;
|
||||
o.wrap = "soft";
|
||||
|
||||
@@ -2083,7 +2083,6 @@ function isDownloadThroughTargetSection(section, currentSectionId) {
|
||||
|
||||
if (
|
||||
!sectionName ||
|
||||
sectionName === currentSectionId ||
|
||||
section.enabled === "0"
|
||||
) {
|
||||
return false;
|
||||
@@ -2134,10 +2133,17 @@ function isDownloadThroughTargetSection(section, currentSectionId) {
|
||||
function subscriptionDownloadTargetChoices(section_id) {
|
||||
return (uci.sections(UCI_PACKAGE, "section") || [])
|
||||
.filter((section) => isDownloadThroughTargetSection(section, section_id))
|
||||
.map((section) => ({
|
||||
value: getUciSectionName(section),
|
||||
label: getUciSectionLabel(section),
|
||||
}));
|
||||
.map((section) => {
|
||||
const name = getUciSectionName(section);
|
||||
let label = getUciSectionLabel(section);
|
||||
if (name === section_id) {
|
||||
label += " " + _("(this rule, when active)");
|
||||
}
|
||||
return {
|
||||
value: name,
|
||||
label: label,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function dnsTypeChoices() {
|
||||
@@ -2745,9 +2751,6 @@ function addSubscriptionUrlItemOptions(itemSection, options = {}) {
|
||||
if (!value) {
|
||||
return _("Select a section for downloading this subscription");
|
||||
}
|
||||
if (value === sectionId) {
|
||||
return _("Current section cannot download its own subscription");
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1586,6 +1586,9 @@ msgstr "Скачивать эту подписку без проверки се
|
||||
msgid "Download through"
|
||||
msgstr "Загружать через"
|
||||
|
||||
msgid "(this rule, when active)"
|
||||
msgstr "(эта же секция, при активном VPN)"
|
||||
|
||||
msgid "Downloaded"
|
||||
msgstr "Загружено"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user