From 9c5c48e5f2f53a187f0efc364deccc5511038dae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 30 Jun 2026 20:43:37 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=88=20Sync=202026-06-30=2020:43:37?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bitsrunlogin-go/Makefile | 2 +- bitsrunlogin-go/files/bitsrunlogin-go.config | 3 + bitsrunlogin-go/files/bitsrunlogin-go.init | 2 + daed/Makefile | 2 +- ...0003-raise-latency-probe-concurrency.patch | 19 + .../htdocs/luci-static/resources/fchomo.js | 534 +++++++++++++++--- .../luci-static/resources/fchomo/listeners.js | 14 +- .../resources/view/fchomo/client.js | 85 ++- .../luci-static/resources/view/fchomo/node.js | 53 +- .../resources/view/fchomo/ruleset.js | 9 +- smartdns/Makefile | 7 +- 11 files changed, 599 insertions(+), 131 deletions(-) create mode 100644 daed/patches/0003-raise-latency-probe-concurrency.patch diff --git a/bitsrunlogin-go/Makefile b/bitsrunlogin-go/Makefile index d9fa224f..fe433521 100644 --- a/bitsrunlogin-go/Makefile +++ b/bitsrunlogin-go/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=BitSrunLoginGo PKG_VERSION:=1.6.7 -PKG_RELEASE:=5 +PKG_RELEASE:=6 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/Mmx233/BitSrunLoginGo/tar.gz/v$(PKG_VERSION)? diff --git a/bitsrunlogin-go/files/bitsrunlogin-go.config b/bitsrunlogin-go/files/bitsrunlogin-go.config index 10c0800b..696a0a19 100644 --- a/bitsrunlogin-go/files/bitsrunlogin-go.config +++ b/bitsrunlogin-go/files/bitsrunlogin-go.config @@ -27,6 +27,9 @@ config bitsrunlogin-go 'config' # Interface name in regex, e.g. "eth0\.[2-3]" # Multi-interfaces mode will be enabled if not empty option interfaces '' + option interfaces_interval '' + # Custom DNS server. System DNS will be used if empty + option dns_server '' # Enable debug log option debug '0' diff --git a/bitsrunlogin-go/files/bitsrunlogin-go.init b/bitsrunlogin-go/files/bitsrunlogin-go.init index 8f4113b9..81b2a88c 100755 --- a/bitsrunlogin-go/files/bitsrunlogin-go.init +++ b/bitsrunlogin-go/files/bitsrunlogin-go.init @@ -69,6 +69,8 @@ start_service() { uci_json_add_boolean "skip_cert_verify" "skip_cert_verify" uci_json_add_int "timeout" "timeout" "5" uci_json_add_string "interfaces" "interfaces" + uci_json_add_int "interfaces_interval" "interfaces_interval" + uci_json_add_string "dns_server" "dns_server" json_close_object json_add_object "guardian" json_add_boolean "enable" "1" diff --git a/daed/Makefile b/daed/Makefile index 0905bd78..3200a758 100644 --- a/daed/Makefile +++ b/daed/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=daed PKG_VERSION:=2026.06.14 -PKG_RELEASE:=15 +PKG_RELEASE:=16 PKG_SOURCE:=daed-src-2026.06.14-4e215048068a.tar.gz PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src diff --git a/daed/patches/0003-raise-latency-probe-concurrency.patch b/daed/patches/0003-raise-latency-probe-concurrency.patch new file mode 100644 index 00000000..3d0f6ff4 --- /dev/null +++ b/daed/patches/0003-raise-latency-probe-concurrency.patch @@ -0,0 +1,19 @@ +From: kenzok8 +Date: 2026-06-30 +Subject: [PATCH] daed: raise manual latency probe concurrency to 16 + +Raise concurrent probes 8->16 so manual latency tests finish faster +when many nodes (incl. dead/timeout ones) are present. +Reported: https://github.com/kenzok8/openwrt-daede/issues/20 +--- +--- a/graphql/service/node/latency_mutation_utils.go ++++ b/graphql/service/node/latency_mutation_utils.go +@@ -19,7 +19,7 @@ + "github.com/sirupsen/logrus" + ) + +-const latencyProbeConcurrency = 8 ++const latencyProbeConcurrency = 16 + + func TestLatencies(ctx context.Context, ids *[]graphql.ID) ([]*LatencyResolver, error) { + option, err := latencyProbeOption(ctx) diff --git a/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js b/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js index 80cc1464..68da2e02 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js @@ -2,6 +2,7 @@ 'require baseclass'; 'require form'; 'require fs'; +'require dom'; 'require rpc'; 'require uci'; 'require ui'; @@ -495,6 +496,31 @@ const CBIDynamicList = form.DynamicList.extend({ // @less_25_12 } }); +const CBIMultiValue = form.MultiValue.extend({ // @pr8758_merged + __name__: 'CBI.MultiValue', + + renderWidget(section_id, option_index, cfgvalue) { + const value = (cfgvalue != null) ? cfgvalue : this.default; + const choices = this.transformChoices(); + + const widget = new UIDropdown(L.toArray(value), choices, { + id: this.cbid(section_id), + sort: this.keylist, + multiple: true, + keep_order: this.keep_order, + optional: this.optional || this.rmempty, + select_placeholder: this.placeholder, + create: this.create, + display_items: this.display_size ?? this.size ?? 3, + dropdown_items: this.dropdown_size ?? this.size ?? -1, + validate: this.getValidator(section_id), + disabled: (this.readonly != null) ? this.readonly : this.map.readonly + }); + + return widget.render(); + } +}); + const CBIStaticList = form.DynamicList.extend({ __name__: 'CBI.StaticList', @@ -786,6 +812,360 @@ const UIDynamicList = ui.DynamicList.extend({ // @less_25_12 } }); +// keep selected order for multiple selection +const UIDropdown = ui.Dropdown.extend({ // @pr8758_merged + __init__(value, choices, options) { + if (typeof(choices) != 'object') + choices = {}; + + if (!Array.isArray(value)) + this.values = (value != null && value != '') ? [ value ] : []; + else + this.values = value; + + this.orderCounter = this.values.length; + this.choices = choices; + this.options = Object.assign({ + sort: true, + multiple: Array.isArray(value), + keep_order: false, + optional: true, + select_placeholder: _('-- Please choose --'), + custom_placeholder: _('-- custom --'), + display_items: 3, + dropdown_items: -1, + create: false, + create_query: '.create-item-input', + create_template: 'script[type="item-template"]' + }, options); + }, + + render() { + const sb = E('div', { + 'id': this.options.id, + 'class': 'cbi-dropdown', + 'multiple': this.options.multiple ? '' : null, + 'keep_order': this.options.keep_order ? '' : null, + 'optional': this.options.optional ? '' : null, + 'disabled': this.options.disabled ? '' : null, + 'tabindex': -1 + }, E('ul')); + + let keys = Object.keys(this.choices); + + if (this.options.sort === true) + keys.sort(L.naturalCompare); + else if (Array.isArray(this.options.sort)) + keys = this.options.sort; + + if (this.options.create) + for (let i = 0; i < this.values.length; i++) + if (!this.choices.hasOwnProperty(this.values[i])) + keys.push(this.values[i]); + + for (let i = 0; i < keys.length; i++) { + let label = this.choices[keys[i]]; + + if (dom.elem(label)) + label = label.cloneNode(true); + + sb.lastElementChild.appendChild(E('li', { + 'data-value': keys[i], + 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null + }, [ label ?? keys[i] ])); + } + + if (this.options.create) { + const createEl = E('input', { + 'type': 'text', + 'class': 'create-item-input', + 'readonly': this.options.readonly ? '' : null, + 'maxlength': this.options.maxlength, + 'placeholder': this.options.custom_placeholder ?? this.options.placeholder, + 'inputmode': 'text', + 'enterkeyhint': 'done' + }); + + if (this.options.datatype || this.options.validate) + UI.prototype.addValidator(createEl, this.options.datatype ?? 'string', + true, this.options.validate, 'blur', 'keyup'); + + sb.lastElementChild.appendChild(E('li', { 'data-value': '-' }, createEl)); + } + + if (this.options.create_markup) + sb.appendChild(E('script', { type: 'item-template' }, + this.options.create_markup)); + + return this.bind(sb); + }, + + bind(sb) { + const o = this.options; + + o.multiple = sb.hasAttribute('multiple'); + o.keep_order = sb.hasAttribute('keep_order'); + o.optional = sb.hasAttribute('optional'); + o.placeholder = sb.getAttribute('placeholder') ?? o.placeholder; + o.display_items = parseInt(sb.getAttribute('display-items') ?? o.display_items); + o.dropdown_items = parseInt(sb.getAttribute('dropdown-items') ?? o.dropdown_items); + o.create_query = sb.getAttribute('item-create') ?? o.create_query; + o.create_template = sb.getAttribute('item-template') ?? o.create_template; + + const ul = sb.querySelector('ul'); + const more = sb.appendChild(E('span', { class: 'more', tabindex: -1 }, '···')); + sb.appendChild(E('span', { class: 'open', tabindex: -1 }, '▾')); + const canary = sb.appendChild(E('div')); + const create = sb.querySelector(this.options.create_query); + let ndisplay = this.options.display_items; + let n = 0; + + if (this.options.multiple) { + let items = ul.querySelectorAll('li'); + + for (let i = 0; i < items.length; i++) { + this.transformItem(sb, items[i]); + + if (items[i].hasAttribute('selected')) { + if (ndisplay-- > 0) + items[i].setAttribute('display', n++); + + if (this.options.keep_order) { + const value = items[i].getAttribute('data-value'); + if (this.values.includes(value)) + items[i].setAttribute('data-order', this.values.indexOf(value) + 1); + } + } + } + } + else { + if (this.options.optional && !ul.querySelector('li[data-value=""]')) { + const placeholder = E('li', { placeholder: '' }, + this.options.select_placeholder ?? this.options.placeholder); + + ul.firstChild + ? ul.insertBefore(placeholder, ul.firstChild) + : ul.appendChild(placeholder); + } + + let items = ul.querySelectorAll('li'); + const sel = sb.querySelectorAll('[selected]'); + + sel.forEach(s => { + s.removeAttribute('selected'); + }); + + const s = sel[0] ?? items[0]; + if (s) { + s.setAttribute('selected', ''); + s.setAttribute('display', n++); + } + + ndisplay--; + } + + this.saveValues(sb, ul); + + ul.setAttribute('tabindex', -1); + sb.setAttribute('tabindex', 0); + + if (ndisplay < 0) + sb.setAttribute('more', '') + else + sb.removeAttribute('more'); + + if (ndisplay == this.options.display_items) + sb.setAttribute('empty', '') + else + sb.removeAttribute('empty'); + + dom.content(more, (ndisplay == this.options.display_items) + ? (this.options.select_placeholder ?? this.options.placeholder) : '···'); + + + sb.addEventListener('click', this.handleClick.bind(this)); + sb.addEventListener('keydown', this.handleKeydown.bind(this)); + sb.addEventListener('cbi-dropdown-close', this.handleDropdownClose.bind(this)); + sb.addEventListener('cbi-dropdown-select', this.handleDropdownSelect.bind(this)); + + if ('ontouchstart' in window) { + sb.addEventListener('touchstart', ev => ev.stopPropagation()); + window.addEventListener('touchstart', this.closeAllDropdowns); + } + else { + sb.addEventListener('focus', this.handleFocus.bind(this)); + + canary.addEventListener('focus', this.handleCanaryFocus.bind(this)); + + window.addEventListener('click', this.closeAllDropdowns); + } + + if (create) { + create.addEventListener('keydown', this.handleCreateKeydown.bind(this)); + create.addEventListener('focus', this.handleCreateFocus.bind(this)); + create.addEventListener('blur', this.handleCreateBlur.bind(this)); + + const li = findParent(create, 'li'); + + li.setAttribute('unselectable', ''); + li.addEventListener('click', this.handleCreateClick.bind(this)); + } + + this.node = sb; + + this.setUpdateEvents(sb, 'cbi-dropdown-open', 'cbi-dropdown-close'); + this.setChangeEvents(sb, 'cbi-dropdown-change', 'cbi-dropdown-close'); + + dom.bindClassInstance(sb, this); + + return sb; + }, + + toggleItem(sb, li, force_state) { + const ul = li.parentNode; + + if (li.hasAttribute('unselectable')) + return; + + if (this.options.multiple) { + const cbox = li.querySelector('input[type="checkbox"]'); + const items = li.parentNode.querySelectorAll('li'); + const label = sb.querySelector('ul.preview'); + let sel = li.parentNode.querySelectorAll('[selected]').length; + const more = sb.querySelector('.more'); + let ndisplay = this.options.display_items; + let n = 0; + + if (li.hasAttribute('selected')) { + if (force_state !== true) { + if (sel > 1 || this.options.optional) { + li.removeAttribute('selected'); + cbox.checked = cbox.disabled = false; + sel--; + + if (this.options.keep_order) + li.removeAttribute('data-order'); + } + else { + cbox.disabled = true; + } + } + } + else { + if (force_state !== false) { + li.setAttribute('selected', ''); + cbox.checked = true; + cbox.disabled = false; + sel++; + + if (this.options.keep_order) + li.setAttribute('data-order', ++this.orderCounter); + } + } + + while (label && label.firstElementChild) + label.removeChild(label.firstElementChild); + + for (let i = 0; i < items.length; i++) { + items[i].removeAttribute('display'); + if (items[i].hasAttribute('selected')) { + if (ndisplay-- > 0) { + items[i].setAttribute('display', n++); + if (label) + label.appendChild(items[i].cloneNode(true)); + } + const c = items[i].querySelector('input[type="checkbox"]'); + if (c) + c.disabled = (sel == 1 && !this.options.optional); + } + } + + if (ndisplay < 0) + sb.setAttribute('more', ''); + else + sb.removeAttribute('more'); + + if (ndisplay === this.options.display_items) + sb.setAttribute('empty', ''); + else + sb.removeAttribute('empty'); + + dom.content(more, (ndisplay === this.options.display_items) + ? (this.options.select_placeholder ?? this.options.placeholder) : '···'); + } + else { + let sel = li.parentNode.querySelector('[selected]'); + if (sel) { + sel.removeAttribute('display'); + sel.removeAttribute('selected'); + } + + li.setAttribute('display', 0); + li.setAttribute('selected', ''); + + this.closeDropdown(sb); + } + + this.saveValues(sb, ul); + }, + + saveValues(sb, ul) { + const sel = Array.from(ul.querySelectorAll('li[selected]')); + const div = sb.lastElementChild; + const name = this.options.name; + let strval = ''; + const values = []; + + if (this.options.keep_order) { + sel.sort((a, b) => + (+a.getAttribute('data-order') || 0) - + (+b.getAttribute('data-order') || 0) + ); + } + + while (div.lastElementChild) + div.removeChild(div.lastElementChild); + + sel.forEach(s => { + if (s.hasAttribute('placeholder')) + return; + + const v = { + text: s.innerText, + value: s.hasAttribute('data-value') ? s.getAttribute('data-value') : s.innerText, + element: s + }; + + div.appendChild(E('input', { + type: 'hidden', + name: name, + value: v.value + })); + + values.push(v); + + strval += strval.length ? ` ${v.value}` : v.value; + }); + + const detail = { + instance: this, + element: sb + }; + + if (this.options.multiple) + detail.values = values; + else + detail.value = values.length ? values[0] : null; + + sb.value = strval; + + sb.dispatchEvent(new CustomEvent('cbi-dropdown-change', { + bubbles: true, + detail: detail + })); + } +}); + /* Method */ /* thanks to homeproxy */ function calcStringMD5(e) { @@ -1114,109 +1494,80 @@ function loadModalTitle(title, addtitle, section_id) { return label ? title + ' » ' + label : addtitle; } -function loadProxyGroupLabel(preadds, section_id) { +function loadLabel(preadds, section_id) { delete this.keylist; delete this.vallist; - preadds?.forEach((arr) => { - this.value.apply(this, arr); - }); - uci.sections(this.config, 'proxy_group', (res) => { - if (res.enabled !== '0') - this.value(res['.name'], res.label); - }); + for (const arr of preadds || []) + this.value(...arr); return this.super('load', section_id); } -function loadNodeLabel(preadds, section_id) { - delete this.keylist; - delete this.vallist; +function loadLabelValues(uciconfig, sectiontype, options = {}) { + const values = []; - preadds?.forEach((arr) => { - this.value.apply(this, arr); - }); - uci.sections(this.config, 'node', (res) => { - if (res.enabled !== '0') - this.value(res['.name'], res.label); - }); + switch (sectiontype) { + case 'proxy_group': + case 'node': + case 'provider': + uci.sections(uciconfig, sectiontype, (res) => { + if (res.enabled !== '0') + values.push([res['.name'], res.label]); + }); + break; + case 'ruleset': + uci.sections(uciconfig, sectiontype, (res) => { + if ( + res.enabled !== '0' && + (!options.behaviors || + options.behaviors.includes(res.behavior)) + ) { + values.push([res['.name'], res.label]); + } + }); + break; + case 'subrule-group': { + const groups = new Set(); - return this.super('load', section_id); -} + uci.sections(uciconfig, 'subrules', (res) => { + if (res.enabled !== '0') + groups.add(res.group); + }); -function loadProviderLabel(preadds, section_id) { - delete this.keylist; - delete this.vallist; + for (const group of groups) + values.push([group, group]); + break; + } + case 'rematch-name': { + const names = new Set(); - preadds?.forEach((arr) => { - this.value.apply(this, arr); - }); - uci.sections(this.config, 'provider', (res) => { - if (res.enabled !== '0') - this.value(res['.name'], res.label); - }); + for (const type of ['rules', 'subrules']) { + uci.sections(uciconfig, type, (res) => { + if (res.enabled === '0') + return; - return this.super('load', section_id); -} + try { + const payload = + JSON.parse(res?.entry?.trim() || '{}').payload || []; -function loadRulesetLabel(preadds, behaviors, section_id) { - delete this.keylist; - delete this.vallist; + for (const p of payload) + if (p.type === 'REMATCH-NAME') + names.add(p.factor); + } catch {} + }); + } - preadds?.forEach((arr) => { - this.value.apply(this, arr); - }); - uci.sections(this.config, 'ruleset', (res) => { - if (res.enabled !== '0') - if (behaviors ? behaviors.includes(res.behavior) : true) - this.value(res['.name'], res.label); - }); + for (const name of names) + values.push([name, name]); - return this.super('load', section_id); -} + break; + } + default: + break; + } -function loadSubRuleGroup(preadds, section_id) { - delete this.keylist; - delete this.vallist; - - preadds?.forEach((arr) => { - this.value.apply(this, arr); - }); - let groups = {}; - uci.sections(this.config, 'subrules', (res) => { - if (res.enabled !== '0') - groups[res.group] = res.group; - }); - Object.keys(groups).forEach((group) => { - this.value(group, group); - }); - - return this.super('load', section_id); -} - -function loadRematchName(preadds, section_id) { - delete this.keylist; - delete this.vallist; - - preadds?.forEach((arr) => { - this.value.apply(this, arr); - }); - let names = {}; - for (const section_type of ['rules', 'subrules']) - uci.sections(this.config, section_type, (res) => { - if (res.enabled !== '0') - try { - const obj = JSON.parse(res?.entry?.trim() || '{}'); - for (const p of obj.payload || []) - if (p.type === 'REMATCH-NAME') - names[p.factor] = p.factor; - } catch {} - }); - Object.keys(names).forEach((name) => { - this.value(name, name); - }); - - return this.super('load', section_id); + return values; } function renderStatus(ElId, isRunning, instance, noGlobal) { @@ -1790,6 +2141,7 @@ return baseclass.extend({ /* Prototype */ GridSection: CBIGridSection, DynamicList: CBIDynamicList, + MultiValue: CBIMultiValue, StaticList: CBIStaticList, ListValue: CBIListValue, RichValue: CBIRichValue, @@ -1819,12 +2171,8 @@ return baseclass.extend({ // load loadDefaultLabel, loadModalTitle, - loadProxyGroupLabel, - loadNodeLabel, - loadProviderLabel, - loadRulesetLabel, - loadSubRuleGroup, - loadRematchName, + loadLabel, + loadLabelValues, // render renderStatus, updateStatus, diff --git a/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js b/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js index 7d7c3778..b32d7701 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js @@ -609,7 +609,12 @@ function renderListeners(s, uciconfig, isClient) { o = s.taboption('field_general', hm.ListValue, 'rule', _('Sub rule'), _('Name of the Sub rule used for inbound matching.')); o.value.apply(o, ['', _('null')]); - o.load = L.bind(hm.loadSubRuleGroup, o, [['', _('null')]]); + o.load = function(section_id) { + return hm.loadLabel.call(this, [ + ['', _('null')], + ...hm.loadLabelValues(this.config, 'subrule-group') + ], section_id); + } o.editable = true; o = s.taboption('field_general', hm.ListValue, 'proxy', _('Proxy group'), @@ -618,7 +623,12 @@ function renderListeners(s, uciconfig, isClient) { hm.preset_outbound.direct.forEach((res) => { o.value.apply(o, res); }) - o.load = L.bind(hm.loadProxyGroupLabel, o, hm.preset_outbound.direct); + o.load = function(section_id) { + return hm.loadLabel.call(this, [ + ...hm.preset_outbound.direct, + ...hm.loadLabelValues(this.config, 'proxy_group') + ], section_id); + } o.editable = true; } diff --git a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/client.js b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/client.js index 902af06e..f4e13961 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/client.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/client.js @@ -18,12 +18,12 @@ const parseProxyGroupYaml = hm.parseYaml.extend({ id: this.id, label: this.label, type: cfg.type, - groups: cfg.proxies ? cfg.proxies.map((grop) => hm.preset_outbound.full.map(([key, label]) => key).includes(grop) ? grop : this.calcID(hm.glossary["proxy_group"].field, grop)) : null, // array + groups: cfg.proxies ? cfg.proxies.map((grop) => hm.preset_outbound.proxy.map(([key, label]) => key).includes(grop) ? grop : this.calcID(hm.glossary["proxy_group"].field, grop)) : null, // array use: cfg.use ? cfg.use.map((prov) => this.calcID(hm.glossary["provider"].field, prov)) : null, // array include_all: this.bool2str(cfg["include-all"]), // bool include_all_proxies: this.bool2str(cfg["include-all-proxies"]), // bool include_all_providers: this.bool2str(cfg["include-all-providers"]), // bool - empty_fallback: cfg["empty-fallback"] ? hm.preset_outbound.full.map(([key, label]) => key).includes(cfg["empty-fallback"]) ? cfg["empty-fallback"] : this.calcID(hm.glossary["proxy_group"].field, cfg["empty-fallback"]) : null, // string + empty_fallback: cfg["empty-fallback"] ? hm.preset_outbound.proxy.map(([key, label]) => key).includes(cfg["empty-fallback"]) ? cfg["empty-fallback"] : this.calcID(hm.glossary["proxy_group"].field, cfg["empty-fallback"]) : null, // string // Url-test fields tolerance: cfg.tolerance, // Load-balance fields @@ -255,7 +255,7 @@ const parseDNSYaml = hm.parseYaml.extend({ let detour = addr.parseParam('detour'); if (detour) - addr.setParam('detour', hm.preset_outbound.full.map(([key, label]) => key).includes(detour) ? detour : this.calcID(hm.glossary["proxy_group"].field, detour)); + addr.setParam('detour', hm.preset_outbound.dns.map(([key, label]) => key).includes(detour) ? detour : detour === 'RULES' ? '' : this.calcID(hm.glossary["proxy_group"].field, detour)); // key mapping // 2026/01/17 let config = { @@ -614,7 +614,7 @@ function renderPayload(s, total, uciconfig) { o.depends(prefix + 'type', 'RULE-SET'); initPayload(o, n, 'factor', uciconfig); o.load = L.bind(function(n, key, uciconfig, section_id) { - hm.loadRulesetLabel.call(this, [], null, section_id); + hm.loadLabel.call(this, hm.loadLabelValues(this.config, 'ruleset'), section_id); return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayload(n)[key]; }, o, n, 'factor', uciconfig) @@ -688,8 +688,11 @@ function renderPayload(s, total, uciconfig) { ['tcp', _('TCP')], ['RULESET', '-- RULE-SET --'] ]; - hm.loadRulesetLabel.call(this, fusedval, null, section_id); - this.super('load', section_id); + + hm.loadLabel.call(this, [ + ...fusedval, + ...hm.loadLabelValues(this.config, 'ruleset') + ], section_id); return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayloads().slice(n).map(e => e[key] ?? ''); }, o, n, 'factor', uciconfig) @@ -791,7 +794,10 @@ function renderRules(s, uciconfig) { o = s.option(hm.ListValue, 'detour', _('Proxy group')); o.load = function(section_id) { - hm.loadProxyGroupLabel.call(this, hm.preset_outbound.full, section_id); + hm.loadLabel.call(this, [ + ...hm.preset_outbound.full, + ...hm.loadLabelValues(this.config, 'proxy_group') + ], section_id); return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).detour; } @@ -867,7 +873,12 @@ function renderPolicies(s, uciconfig) { o = s.option(form.MultiValue, 'rule_set', _('Rule set'), _('Match rule set.')); o.value('', _('-- Please choose --')); - o.load = L.bind(hm.loadRulesetLabel, o, [['', _('-- Please choose --')]], ['domain', 'classical']); + o.load = function(section_id) { + return hm.loadLabel.call(this, [ + ['', _('-- Please choose --')], + ...hm.loadLabelValues(this.config, 'ruleset', {behaviors: ['domain', 'classical']}) + ], section_id); + } o.depends('type', 'rule_set'); o.modalonly = true; @@ -893,7 +904,12 @@ function renderPolicies(s, uciconfig) { hm.preset_outbound.direct.forEach((res) => { o.value.apply(o, res); }) - o.load = L.bind(hm.loadProxyGroupLabel, o, hm.preset_outbound.direct); + o.load = function(section_id) { + return hm.loadLabel.call(this, [ + ...hm.preset_outbound.direct, + ...hm.loadLabelValues(this.config, 'proxy_group') + ], section_id); + } o.editable = true; } @@ -1041,16 +1057,28 @@ return view.extend({ so.value.apply(so, res); }) - so = ss.taboption('field_general', form.MultiValue, 'groups', _('Group')); - hm.preset_outbound.full.forEach((res) => { + so = ss.taboption('field_general', hm.MultiValue, 'groups', _('Group')); // @pr8758_merged + hm.preset_outbound.proxy.forEach((res) => { so.value.apply(so, res); }) - so.load = L.bind(hm.loadProxyGroupLabel, so, hm.preset_outbound.full); + so.keep_order = true; + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ...hm.preset_outbound.proxy, + ...hm.loadLabelValues(this.config, 'proxy_group') + ], section_id); + } so.editable = true; - so = ss.taboption('field_general', form.MultiValue, 'proxies', _('Node')); + so = ss.taboption('field_general', hm.MultiValue, 'proxies', _('Node')); // @pr8758_merged so.value('', _('-- Please choose --')); - so.load = L.bind(hm.loadNodeLabel, so, [['', _('-- Please choose --')]]); + so.keep_order = true; + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ['', _('-- Please choose --')], + ...hm.loadLabelValues(this.config, 'node') + ], section_id); + } so.validate = function(section_id, value) { if (this.section.getOption('include_all').formvalue(section_id) === '1' || this.section.getOption('include_all_proxies').formvalue(section_id) === '1') @@ -1062,9 +1090,15 @@ return view.extend({ } so.editable = true; - so = ss.taboption('field_general', form.MultiValue, 'use', _('Provider')); + so = ss.taboption('field_general', hm.MultiValue, 'use', _('Provider')); // @pr8758_merged so.value('', _('-- Please choose --')); - so.load = L.bind(hm.loadProviderLabel, so, [['', _('-- Please choose --')]]); + so.keep_order = true; + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ['', _('-- Please choose --')], + ...hm.loadLabelValues(this.config, 'provider') + ], section_id); + } so.validate = function(section_id, value) { if (this.section.getOption('include_all').formvalue(section_id) === '1' || this.section.getOption('include_all_providers').formvalue(section_id) === '1') @@ -1096,8 +1130,13 @@ return view.extend({ hm.preset_outbound.proxy.forEach((res) => { so.value.apply(so, res); }) - so.load = L.bind(hm.loadNodeLabel, so, hm.preset_outbound.proxy); - so.modalonly = true; + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ...hm.preset_outbound.proxy, + ...hm.loadLabelValues(this.config, 'node') + ], section_id); + } + so.textvalue = hm.textvalue2Value; /* Override fields */ so = ss.taboption('field_override', form.Flag, 'disable_udp', _('Disable UDP')); @@ -1293,7 +1332,10 @@ return view.extend({ so = ss.option(form.ListValue, 'SUB-RULE', _('SUB-RULE')); so.load = function(section_id) { - hm.loadSubRuleGroup.call(this, [['', _('-- Please choose --')]], section_id); + hm.loadLabel.call(this, [ + ['', _('-- Please choose --')], + ...hm.loadLabelValues(this.config, 'subrule-group') + ], section_id); return new RulesEntry(uci.get(data[0], section_id, 'entry')).subrule || ''; } @@ -1563,7 +1605,10 @@ return view.extend({ so = ss.option(hm.ListValue, 'detour', _('Proxy group')); so.load = function(section_id) { - hm.loadProxyGroupLabel.call(this, hm.preset_outbound.dns, section_id); + hm.loadLabel.call(this, [ + ...hm.preset_outbound.dns, + ...hm.loadLabelValues(this.config, 'proxy_group') + ], section_id); return new DNSAddress(uci.get(data[0], section_id, 'address')).parseParam('detour'); } diff --git a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js index e51e3882..eddff1ba 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js @@ -28,7 +28,7 @@ const CBIBubblesValue = form.DummyValue.extend({ __name__: 'CBI.BubblesValue', load(section_id) { - const uciconfig = this.config || this.section.configthis.config || this.map.config; + const uciconfig = this.config || this.section.config || this.map.config; const type = uci.get(uciconfig, section_id, 'type'); const detour = uci.get(uciconfig, section_id, 'chain_tail_group') || uci.get(uciconfig, section_id, 'chain_tail'); @@ -116,7 +116,7 @@ const parseProviderYaml = hm.parseYaml.extend({ url: cfg.url, size_limit: cfg["size-limit"], interval: cfg.interval, - proxy: cfg.proxy ? hm.preset_outbound.full.map(([key, label]) => key).includes(cfg.proxy) ? cfg.proxy : this.calcID(hm.glossary["proxy_group"].field, cfg.proxy) : null, + proxy: cfg.proxy ? hm.preset_outbound.direct.map(([key, label]) => key).includes(cfg.proxy) ? cfg.proxy : this.calcID(hm.glossary["proxy_group"].field, cfg.proxy) : null, age_private_key: cfg["age-secret-key"], header: cfg.header ? JSON.stringify(cfg.header, null, 2) : null, // string: object /* Health fields */ @@ -265,13 +265,23 @@ return view.extend({ /* Rematch fields */ so = ss.taboption('field_general', form.ListValue, 'target_rematch_name', _('REMATCH-NAME marking')); - so.load = L.bind(hm.loadRematchName, so, [['', _('-- Please choose --')]]); + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ['', _('-- Please choose --')], + ...hm.loadLabelValues(this.config, 'rematch-name') + ], section_id); + } so.rmempty = false; so.depends('type', 'rematch'); so.modalonly = true; so = ss.taboption('field_general', form.ListValue, 'target_sub_rule', _('Use sub rule')); - so.load = L.bind(hm.loadSubRuleGroup, so, [['', _('-- Please choose --')]]); + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ['', _('-- Please choose --')], + ...hm.loadLabelValues(this.config, 'subrule-group') + ], section_id); + } so.depends('type', 'rematch'); so.modalonly = true; @@ -1750,7 +1760,12 @@ return view.extend({ hm.preset_outbound.direct.forEach((res) => { so.value.apply(so, res); }) - so.load = L.bind(hm.loadProxyGroupLabel, so, hm.preset_outbound.direct); + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ...hm.preset_outbound.direct, + ...hm.loadLabelValues(this.config, 'proxy_group') + ], section_id); + } so.textvalue = hm.textvalue2Value; //so.editable = true; so.depends('type', 'http'); @@ -2032,13 +2047,23 @@ return view.extend({ so.modalonly = false; so = ss.option(form.ListValue, 'chain_head_sub', _('Destination provider')); - so.load = L.bind(hm.loadProviderLabel, so, [['', _('-- Please choose --')]]); + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ['', _('-- Please choose --')], + ...hm.loadLabelValues(this.config, 'provider') + ], section_id); + } so.rmempty = false; so.depends('type', 'provider'); so.modalonly = true; so = ss.option(form.ListValue, 'chain_head', _('Destination proxy node')); - so.load = L.bind(hm.loadNodeLabel, so, [['', _('-- Please choose --')]]); + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ['', _('-- Please choose --')], + ...hm.loadLabelValues(this.config, 'node') + ], section_id); + } so.rmempty = false; so.validate = function(section_id, value) { const chain_tail = this.section.getUIElement(section_id, 'chain_tail').getValue(); @@ -2052,13 +2077,23 @@ return view.extend({ so.modalonly = true; so = ss.option(form.ListValue, 'chain_tail_group', _('Transit proxy group')); - so.load = L.bind(hm.loadProxyGroupLabel, so, [['', _('-- Please choose --')]]); + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ['', _('-- Please choose --')], + ...hm.loadLabelValues(this.config, 'proxy_group') + ], section_id); + } so.rmempty = false; so.depends({chain_tail: /.+/, '!reverse': true}); so.modalonly = true; so = ss.option(form.ListValue, 'chain_tail', _('Transit proxy node')); - so.load = L.bind(hm.loadNodeLabel, so, [['', _('-- Please choose --')]]); + so.load = function(section_id) { + return hm.loadLabel.call(this, [ + ['', _('-- Please choose --')], + ...hm.loadLabelValues(this.config, 'node') + ], section_id); + } so.rmempty = false; so.validate = function(section_id, value) { const chain_head = this.section.getUIElement(section_id, 'chain_head').getValue(); diff --git a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/ruleset.js b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/ruleset.js index 3a40ca4f..aca2e06f 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/ruleset.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/ruleset.js @@ -25,7 +25,7 @@ const parseRulesetYaml = hm.parseYaml.extend({ path_in_bundle: cfg["path-in-bundle"], size_limit: cfg["size-limit"], interval: cfg.interval, - proxy: cfg.proxy ? hm.preset_outbound.full.map(([key, label]) => key).includes(cfg.proxy) ? cfg.proxy : this.calcID(hm.glossary["proxy_group"].field, cfg.proxy) : null, + proxy: cfg.proxy ? hm.preset_outbound.direct.map(([key, label]) => key).includes(cfg.proxy) ? cfg.proxy : this.calcID(hm.glossary["proxy_group"].field, cfg.proxy) : null, header: cfg.header ? JSON.stringify(cfg.header, null, 2) : null, // string: object }) }); @@ -406,7 +406,12 @@ return view.extend({ hm.preset_outbound.direct.forEach((res) => { o.value.apply(o, res); }) - o.load = L.bind(hm.loadProxyGroupLabel, o, hm.preset_outbound.direct); + o.load = function(section_id) { + return hm.loadLabel.call(this, [ + ...hm.preset_outbound.direct, + ...hm.loadLabelValues(this.config, 'proxy_group') + ], section_id); + } o.textvalue = hm.textvalue2Value; //o.editable = true; o.depends('type', 'http'); diff --git a/smartdns/Makefile b/smartdns/Makefile index c26cd2a4..6e1abf45 100644 --- a/smartdns/Makefile +++ b/smartdns/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=smartdns -PKG_VERSION:=48 -PKG_RELEASE:=3 +PKG_VERSION:=48.2 +PKG_RELEASE:=4 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/pymumu/smartdns/tar.gz/Release$(PKG_VERSION)? @@ -29,7 +29,7 @@ include $(INCLUDE_DIR)/package.mk include $(TOPDIR)/feeds/packages/lang/rust/rust-package.mk MAKE_PATH:=src -MAKE_VARS+= VER=$(PKG_VERSION) +MAKE_VARS+= VER=$(PKG_VERSION) WITH_ZLIB=0 define Package/smartdns/Default SECTION:=net @@ -104,6 +104,7 @@ ifneq ($(CONFIG_PACKAGE_smartdns-ui),) pushd plugin/smartdns-ui ; \ $(CARGO_PKG_CONFIG_VARS) \ MAKEFLAGS="$(PKG_JOBS)" \ + WITH_ZLIB=0 \ TARGET_CFLAGS="$(filter-out -O%,$(TARGET_CFLAGS)) $(RUSTC_CFLAGS)" \ BINDGEN_EXTRA_CLANG_ARGS="--sysroot=$(TOOLCHAIN_ROOT_DIR)" \ cargo build -v --profile $(CARGO_PKG_PROFILE) \