🍕 Sync 2026-04-25 20:15:58

This commit is contained in:
github-actions[bot] 2026-04-25 20:15:58 +08:00
parent 80f09ddc21
commit 8a2eefa223
19 changed files with 438 additions and 39 deletions

View File

@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=3ginfo
PKG_VERSION:=20260404
PKG_RELEASE:=2
PKG_VERSION:=20260425
PKG_RELEASE:=3
include $(INCLUDE_DIR)/package.mk

View File

@ -365,7 +365,16 @@ function showmodemparams() {
}
if (data.cid_dec && data.cid_dec > 0 && data.operator_mcc == 260) {
document.getElementById('btsearch' + idx).setAttribute("href", "https://btsearch.pl/stations?q=" + data.cid_dec);
switch (data.operator_mnc) {
case '01':
case '02':
case '03':
case '06':
document.getElementById('btsearch' + idx).setAttribute('href', 'https://btsearch.pl/stations?mnc=260' + data.operator_mnc + '&q=' + data.cid_dec);
break;
default:
document.getElementById('btsearch' + idx).setAttribute('href', 'https://btsearch.pl/stations?q=' + data.cid_dec);
}
setDisplay('div_btsearch' + idx, true);
} else {
setDisplay('div_btsearch' + idx, false);

View File

@ -10,8 +10,8 @@ LUCI_DEPENDS:=+luci-base +luci-lib-jsonc +curl +bandix
PKG_MAINTAINER:=timsaya
PKG_VERSION:=0.12.6
PKG_RELEASE:=4
PKG_VERSION:=0.12.7
PKG_RELEASE:=5
include $(TOPDIR)/feeds/luci/luci.mk

View File

@ -150,7 +150,7 @@ var callGetConnection = rpc.declare({
var callGetConnectionFlows = rpc.declare({
object: 'luci.bandix',
method: 'getConnectionFlows',
params: ['ip', 'protocol', 'state'],
params: ['ip', 'protocol', 'state', 'page', 'page_size'],
expect: {}
});
@ -688,14 +688,16 @@ return view.extend({
flex-shrink: 0;
}
.flows-modal-content .flows-filters select {
.flows-modal-content .flows-filters select,
.flows-modal-content .flows-footer select {
padding: 6px 10px;
border-radius: 4px;
border: 1px solid rgba(0,0,0,0.2);
font-size: 0.875rem;
}
.flows-modal-content.theme-dark .flows-filters select {
.flows-modal-content.theme-dark .flows-filters select,
.flows-modal-content.theme-dark .flows-footer select {
background-color: #3a3a3a;
border-color: rgba(255,255,255,0.2);
color: #e5e5e5;
@ -778,6 +780,13 @@ return view.extend({
flex-shrink: 0;
display: flex;
justify-content: flex-end;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.flows-modal-content .flows-footer .flows-page-size-select {
min-width: 92px;
}
.flows-modal-content.theme-dark .flows-footer {
@ -1051,6 +1060,11 @@ return view.extend({
function showFlowsModal(deviceIp, deviceInfo) {
var currentTheme = getThemeMode();
var currentPage = 1;
var totalPages = 1;
var totalItems = 0;
var currentPageSize = 100;
var protocolSelect = E('select', { 'class': 'cbi-input-select', 'id': 'flows-protocol' }, [
E('option', { 'value': '' }, _('All')),
E('option', { 'value': 'tcp' }, 'TCP'),
@ -1068,6 +1082,15 @@ return view.extend({
E('option', { 'value': 'LAST_ACK' }, 'LAST_ACK'),
E('option', { 'value': 'CLOSE' }, 'CLOSE')
]);
var pageSizeSelect = E('select', { 'class': 'cbi-input-select flows-page-size-select', 'id': 'flows-page-size' }, [
E('option', { 'value': '50' }, '50'),
E('option', { 'value': '100', 'selected': 'selected' }, '100'),
E('option', { 'value': '200' }, '200'),
E('option', { 'value': '500' }, '500')
]);
var pageInfo = E('span', { 'style': 'font-size: 0.85rem; opacity: 0.85; margin: 0 14px;' }, '');
var prevPageBtn = E('button', { 'class': 'cbi-button cbi-button-action', 'style': 'margin-right: 8px;' }, _('Previous'));
var nextPageBtn = E('button', { 'class': 'cbi-button cbi-button-action' }, _('Next'));
var tableBody = E('tbody', { 'class': 'flows-table-body' });
var tableWrap = E('div', { 'class': 'flows-table-wrap' }, [
E('table', { 'class': 'flows-table' }, [
@ -1088,22 +1111,75 @@ return view.extend({
])
]);
function loadFlows() {
function updatePaginationUi() {
if (pageInfo) {
pageInfo.textContent = _('Page') + ' ' + currentPage + '/' + totalPages + ' · ' + _('Total') + ': ' + totalItems;
}
if (prevPageBtn) {
prevPageBtn.disabled = currentPage <= 1;
}
if (nextPageBtn) {
nextPageBtn.disabled = currentPage >= totalPages;
}
}
function normalizeFlowsResponse(res) {
if (!res || res.status !== 'success') {
return { items: [], total: 0, page: currentPage, page_size: currentPageSize, total_pages: 1 };
}
if (Array.isArray(res.data)) {
// 兼容旧后端data 直接是数组
return {
items: res.data,
total: res.data.length,
page: 1,
page_size: res.data.length || currentPageSize,
total_pages: 1
};
}
if (res.data && Array.isArray(res.data.items)) {
// 新后端:分页对象
return {
items: res.data.items,
total: res.data.total || 0,
page: res.data.page || currentPage,
page_size: res.data.page_size || currentPageSize,
total_pages: res.data.total_pages || 1
};
}
return { items: [], total: 0, page: currentPage, page_size: currentPageSize, total_pages: 1 };
}
function loadFlows(resetPage) {
if (resetPage) {
currentPage = 1;
}
var protocol = protocolSelect.value || '';
var state = stateSelect.value || '';
currentPageSize = parseInt(pageSizeSelect.value, 10) || 100;
tableBody.innerHTML = '';
tableBody.appendChild(E('tr', {}, [
E('td', { 'colspan': 9, 'class': 'loading-state' }, _('Loading…'))
]));
return callGetConnectionFlows(deviceIp, protocol || null, state || null).then(function (res) {
return callGetConnectionFlows(deviceIp, protocol || null, state || null, currentPage, currentPageSize).then(function (res) {
tableBody.innerHTML = '';
if (!res || res.status !== 'success' || !res.data || res.data.length === 0) {
var normalized = normalizeFlowsResponse(res);
var flows = normalized.items;
totalItems = normalized.total;
currentPage = normalized.page;
totalPages = Math.max(1, normalized.total_pages);
updatePaginationUi();
if (!flows || flows.length === 0) {
tableBody.appendChild(E('tr', {}, [
E('td', { 'colspan': 9, 'class': 'loading-state' }, _('No connections'))
]));
return;
}
res.data.forEach(function (f) {
flows.forEach(function (f) {
var stateCls = '';
if (f.state) {
if (f.state.indexOf('ESTABLISHED') >= 0) stateCls = 'flows-state-est';
@ -1131,15 +1207,19 @@ return view.extend({
]));
});
}).catch(function (err) {
totalItems = 0;
totalPages = 1;
currentPage = 1;
updatePaginationUi();
tableBody.innerHTML = '';
tableBody.appendChild(E('tr', {}, [
E('td', { 'colspan': 9, 'class': 'error-state' }, _('Failed to load') + ': ' + (err.message || err))
E('td', { 'colspan': 9, 'class': 'error-state' }, _('Failed to load') + ': ' + (err.message || err) + ' · ' + _('Try using filters or smaller page size'))
]));
});
}
function onFilterChange() {
loadFlows();
loadFlows(true);
}
function hideFlowsModal() {
@ -1147,6 +1227,22 @@ return view.extend({
if (overlay) overlay.classList.remove('show');
}
prevPageBtn.addEventListener('click', function () {
if (currentPage > 1) {
currentPage -= 1;
loadFlows(false);
}
});
nextPageBtn.addEventListener('click', function () {
if (currentPage < totalPages) {
currentPage += 1;
loadFlows(false);
}
});
pageSizeSelect.addEventListener('change', function () {
loadFlows(true);
});
var modalContent = E('div', { 'class': 'flows-modal-content theme-' + currentTheme }, [
E('div', { 'class': 'flows-modal-header' }, [
E('div', { 'class': 'flows-modal-title' }, _('Connection Details') + ' - ' + (deviceInfo.host || deviceInfo.ip4 || deviceIp)),
@ -1161,6 +1257,10 @@ return view.extend({
]),
tableWrap,
E('div', { 'class': 'flows-footer' }, [
pageSizeSelect,
prevPageBtn,
nextPageBtn,
pageInfo,
E('button', { 'class': 'cbi-button cbi-button-reset', 'click': hideFlowsModal }, _('Close'))
])
]);
@ -1181,7 +1281,8 @@ return view.extend({
overlay.appendChild(modalContent);
overlay.classList.add('show');
modalContent.addEventListener('click', function (e) { e.stopPropagation(); });
loadFlows();
updatePaginationUi();
loadFlows(true);
}
container.addEventListener('click', function (ev) {
@ -1260,4 +1361,4 @@ return view.extend({
return container;
}
});
});

View File

@ -6535,6 +6535,99 @@ return view.extend({
return increments.map(normalizeTrafficIncrementItem).filter(function (x) { return x; });
}
// 为了规避 ubus 1MB 响应限制,长时间范围按块分段请求
var TRAFFIC_INCREMENT_CHUNK_MS_HOURLY = 14 * 24 * 60 * 60 * 1000; // 14 天
var TRAFFIC_INCREMENT_CHUNK_MS_DAILY = 60 * 24 * 60 * 60 * 1000; // 60 天
function mergeIncrementsResponse(base, part) {
if (!part) return base;
if (Array.isArray(part.inc)) {
base.inc = base.inc.concat(part.inc);
}
if (part.start && (!base.start || part.start < base.start)) {
base.start = part.start;
}
if (part.end && (!base.end || part.end > base.end)) {
base.end = part.end;
}
base.t_rx_b = (base.t_rx_b || 0) + (part.t_rx_b || 0);
base.t_tx_b = (base.t_tx_b || 0) + (part.t_tx_b || 0);
base.t_b = (base.t_b || 0) + (part.t_b || 0);
if (!base.agg && part.agg) base.agg = part.agg;
if (!base.mac && part.mac) base.mac = part.mac;
if (!base.net && part.net) base.net = part.net;
if (!base.network_type && part.network_type) base.network_type = part.network_type;
return base;
}
function buildTrafficIncrementsChunks(startMs, endMs, aggregation) {
if (!startMs || !endMs || endMs <= startMs) {
return null;
}
var chunkMs = aggregation === 'daily' ? TRAFFIC_INCREMENT_CHUNK_MS_DAILY : TRAFFIC_INCREMENT_CHUNK_MS_HOURLY;
var totalRange = endMs - startMs;
if (totalRange <= chunkMs) {
return null;
}
var chunks = [];
for (var s = startMs; s < endMs; s += chunkMs) {
chunks.push({ start: s, end: Math.min(s + chunkMs, endMs) });
}
return chunks;
}
function fetchTrafficIncrementsChunked(startMs, endMs, aggregation, mac, networkType, onProgress) {
var chunks = buildTrafficIncrementsChunks(startMs, endMs, aggregation);
if (!chunks) {
return callGetTrafficUsageIncrements(startMs, endMs, aggregation, mac, networkType);
}
if (typeof onProgress === 'function') {
onProgress(0, chunks.length);
}
var merged = {
start: startMs,
end: endMs,
agg: aggregation,
inc: [],
t_rx_b: 0,
t_tx_b: 0,
t_b: 0
};
var chain = Promise.resolve(merged);
var finished = 0;
chunks.forEach(function (chunk) {
chain = chain.then(function (acc) {
return callGetTrafficUsageIncrements(chunk.start, chunk.end, aggregation, mac, networkType).then(function (part) {
finished += 1;
if (typeof onProgress === 'function') {
onProgress(finished, chunks.length);
}
return mergeIncrementsResponse(acc, part || {});
});
});
});
return chain.then(function (result) {
if (Array.isArray(result.inc)) {
result.inc.sort(function (a, b) {
var aTs = (a && (a.start || a.ts_ms || a.end)) || 0;
var bTs = (b && (b.start || b.ts_ms || b.end)) || 0;
return aTs - bTs;
});
}
return result;
});
}
// 更新时间序列增量数据(使用 Traffic Timeline 自己的时间范围)
// Traffic Timeline 缩放变量
var incrementsZoomEnabled = false;
@ -6568,7 +6661,29 @@ return view.extend({
selectedNetworkType = null;
}
callGetTrafficUsageIncrements(startMs, endMs, selectedAggregation, selectedMac, selectedNetworkType).then(function (result) {
var container = document.getElementById('traffic-increments-container');
var chunks = buildTrafficIncrementsChunks(startMs, endMs, selectedAggregation);
if (container) {
if (chunks && chunks.length > 1) {
container.innerHTML = '<div class="loading-state">' + _('Loading in chunks, please wait... (%d/%d)').format(0, chunks.length) + '</div>';
} else {
container.innerHTML = '<div class="loading-state">' + _('Loading...') + '</div>';
}
}
fetchTrafficIncrementsChunked(
startMs,
endMs,
selectedAggregation,
selectedMac,
selectedNetworkType,
function (done, total) {
var progressContainer = document.getElementById('traffic-increments-container');
if (progressContainer && total > 1) {
progressContainer.innerHTML = '<div class="loading-state">' + _('Loading in chunks, please wait... (%d/%d)').format(done, total) + '</div>';
}
}
).then(function (result) {
if (!result || !result.inc) {
var container = document.getElementById('traffic-increments-container');
if (container) {

View File

@ -860,6 +860,9 @@ msgstr "Aún no hay reglas programadas, haga clic en \"Agregar regla\" para come
msgid "Loading..."
msgstr "Cargando..."
msgid "Loading in chunks, please wait... (%d/%d)"
msgstr "Carga por fragmentos, espere... (%d/%d)"
msgid "No schedule rules"
msgstr "No hay reglas programadas"

View File

@ -860,6 +860,9 @@ msgstr "Aucune règle programmée pour le moment, cliquez sur \"Ajouter une règ
msgid "Loading..."
msgstr "Chargement..."
msgid "Loading in chunks, please wait... (%d/%d)"
msgstr "Chargement par morceaux, veuillez patienter... (%d/%d)"
msgid "No schedule rules"
msgstr "Aucune règle programmée"

View File

@ -860,6 +860,9 @@ msgstr "スケジュール制限ルールがまだありません。「ルール
msgid "Loading..."
msgstr "読み込み中..."
msgid "Loading in chunks, please wait... (%d/%d)"
msgstr "分割読み込み中です。しばらくお待ちください... (%d/%d)"
msgid "No schedule rules"
msgstr "スケジュール制限ルールなし"

View File

@ -860,6 +860,9 @@ msgstr "Brak jeszcze reguł limitu czasu, kliknij \"Dodaj regułę\", aby rozpoc
msgid "Loading..."
msgstr "Ładowanie..."
msgid "Loading in chunks, please wait... (%d/%d)"
msgstr "Ładowanie fragmentami, proszę czekać... (%d/%d)"
msgid "No schedule rules"
msgstr "Brak reguł limitu czasu"

View File

@ -860,6 +860,9 @@ msgstr "Правил расписания пока нет, нажмите \"До
msgid "Loading..."
msgstr "Загрузка..."
msgid "Loading in chunks, please wait... (%d/%d)"
msgstr "Поштучная загрузка, подождите... (%d/%d)"
msgid "No schedule rules"
msgstr "Нет правил расписания"

View File

@ -857,6 +857,9 @@ msgstr "还没有定时限速规则,点击"添加规则"开始设置"
msgid "Loading..."
msgstr "加载中..."
msgid "Loading in chunks, please wait... (%d/%d)"
msgstr "分段加载中,请稍等... (%d/%d)"
msgid "No schedule rules"
msgstr "没有定时限速规则"

View File

@ -860,6 +860,9 @@ msgstr "還沒有定時限速規則,點擊"新增規則"開始設定"
msgid "Loading..."
msgstr "載入中..."
msgid "Loading in chunks, please wait... (%d/%d)"
msgstr "分段載入中,請稍候... (%d/%d)"
msgid "No schedule rules"
msgstr "沒有定時限速規則"

View File

@ -346,11 +346,15 @@ get_connection_flows() {
local ip="$1"
local protocol="$2"
local state="$3"
local page="$4"
local page_size="$5"
local query_params=""
[ -n "$ip" ] && query_params="${query_params}ip=$(printf '%s' "$ip" | sed 's/ /%20/g')&"
[ -n "$protocol" ] && query_params="${query_params}protocol=$(printf '%s' "$protocol" | sed 's/ /%20/g')&"
[ -n "$state" ] && query_params="${query_params}state=$(printf '%s' "$state" | sed 's/ /%20/g')&"
[ -n "$page" ] && query_params="${query_params}page=$page&"
[ -n "$page_size" ] && query_params="${query_params}page_size=$page_size&"
query_params=$(echo "$query_params" | sed 's/&$//')
local url="$BANDIX_CONNECTION_FLOWS_API"
@ -1248,6 +1252,8 @@ case "$1" in
json_add_string "ip"
json_add_string "protocol"
json_add_string "state"
json_add_int "page"
json_add_int "page_size"
json_close_object
json_add_object "getDnsQueries"
@ -1444,6 +1450,8 @@ case "$1" in
ip=""
protocol=""
state=""
page=""
page_size=""
input=""
if read -t 1 -r input; then
:
@ -1455,12 +1463,18 @@ case "$1" in
[ -z "$protocol" ] && protocol="$(echo "$input" | jsonfilter -e '$.protocol' 2>/dev/null)"
state="$(echo "$input" | jsonfilter -e '$[2]' 2>/dev/null)"
[ -z "$state" ] && state="$(echo "$input" | jsonfilter -e '$.state' 2>/dev/null)"
page="$(echo "$input" | jsonfilter -e '$[3]' 2>/dev/null)"
[ -z "$page" ] && page="$(echo "$input" | jsonfilter -e '$.page' 2>/dev/null)"
page_size="$(echo "$input" | jsonfilter -e '$[4]' 2>/dev/null)"
[ -z "$page_size" ] && page_size="$(echo "$input" | jsonfilter -e '$.page_size' 2>/dev/null)"
else
[ -n "$3" ] && ip="$3"
[ -n "$4" ] && protocol="$4"
[ -n "$5" ] && state="$5"
[ -n "$6" ] && page="$6"
[ -n "$7" ] && page_size="$7"
fi
get_connection_flows "$ip" "$protocol" "$state"
get_connection_flows "$ip" "$protocol" "$state" "$page" "$page_size"
;;
getDnsQueries)
# logger "luci.bandix: getDnsQueries called"

View File

@ -4,9 +4,31 @@
-#}
{%
import { access } from 'fs';
import { cursor } from 'uci';
const wizard_request = ctx.request_path ?? [];
let wizard_pending = false;
if (ctx.authsession &&
wizard_request[0] == 'admin' &&
wizard_request[1] != 'wizard' &&
access('/etc/config/wizard') &&
!access('/usr/sbin/quickstart') &&
!access('/etc/config/finished')) {
let wizard_uci = cursor();
wizard_pending = (wizard_uci.get('wizard', 'config', 'finished') != '1');
}
include(`themes/${theme}/header`);
-%}
{% if (wizard_pending): %}
<script>
window.location.replace({{ sprintf('%J', dispatcher.build_url('admin/wizard')) }});
</script>
{% endif %}
<script src="{{ resource }}/luci.js?v={# PKG_VERSION #}-{{ pkgs_update_time }}"></script>
<script>
L = new LuCI({{ replace(`${ {

View File

@ -81,9 +81,13 @@ function getLegacyIwinfoProbeTargets() {
const targets = [];
for (const radio of uci.sections('wireless', 'wifi-device'))
pushUnique(targets, radio['.name']);
if (!isConfigWifiDeviceDisabled(radio['.name']))
pushUnique(targets, radio['.name']);
for (const iface of uci.sections('wireless', 'wifi-iface')) {
if (isConfigWifiIfaceDisabled(iface))
continue;
const device = iface.device;
const section = iface['.name'];
const configuredIfname = iface.ifname;
@ -98,6 +102,13 @@ function getLegacyIwinfoProbeTargets() {
return targets;
}
function parseIwDevInfoTxPower(stdout) {
const match = String(stdout || '').match(/\btxpower\s+([0-9]+(?:\.[0-9]+)?)\s*dBm\b/i);
const value = match ? parseFloat(match[1]) : NaN;
return (!isNaN(value) && value > 0) ? value : null;
}
function buildIwinfoResolver(devices) {
const deviceLookup = buildIwinfoDeviceLookup(devices);
const aliasMap = Object.create(null);
@ -115,6 +126,9 @@ function buildIwinfoResolver(devices) {
}
for (const iface of uci.sections('wireless', 'wifi-iface')) {
if (isConfigWifiIfaceDisabled(iface))
continue;
const device = iface.device;
const section = iface['.name'];
const configuredIfname = iface.ifname;
@ -142,6 +156,10 @@ function buildIwinfoResolver(devices) {
for (const radio of uci.sections('wireless', 'wifi-device')) {
const name = radio['.name'];
if (isConfigWifiDeviceDisabled(name))
continue;
const target = radioTargets[name] || (deviceLookup[name] ? name : null);
registerTarget(target);
@ -209,18 +227,35 @@ function loadIwinfoInfoMap(force) {
if (info != null)
nextMap[name] = info;
for (const alias in resolver.aliasMap) {
const target = resolver.aliasMap[alias];
const missingTxPowerTargets = queryTargets.filter((name) => {
const txpower = nextMap[name]?.txpower;
if (target && nextMap[target] != null)
nextMap[alias] = nextMap[target];
}
return (txpower == null || isNaN(txpower) || txpower <= 0);
});
if (Object.keys(nextMap).length > 0 || cachedIwinfoInfoMap == null)
cachedIwinfoInfoMap = nextMap;
return Promise.all(missingTxPowerTargets.map((name) =>
L.resolveDefault(fs.exec_direct('/usr/sbin/iw', [ 'dev', name, 'info' ]), '').then((stdout) => [ name, parseIwDevInfoTxPower(stdout) ])
)).then((fallbacks) => {
for (const [ name, txpower ] of fallbacks) {
if (txpower == null)
continue;
cachedIwinfoInfoPromise = null;
return cachedIwinfoInfoMap || nextMap;
nextMap[name] = Object.assign({}, nextMap[name] || {}, { txpower });
}
for (const alias in resolver.aliasMap) {
const target = resolver.aliasMap[alias];
if (target && nextMap[target] != null)
nextMap[alias] = nextMap[target];
}
if (Object.keys(nextMap).length > 0 || cachedIwinfoInfoMap == null)
cachedIwinfoInfoMap = nextMap;
cachedIwinfoInfoPromise = null;
return cachedIwinfoInfoMap || nextMap;
});
});
}).catch(() => {
cachedIwinfoInfoPromise = null;
@ -250,8 +285,19 @@ function isQcaWifiHwtype(hwtype) {
return (hwtype == 'qcawifi' || hwtype == 'qcawificfg80211');
}
function isConfigWifiDeviceDisabled(deviceName) {
return (uci.get('wireless', deviceName, 'disabled') == '1');
}
function isConfigWifiIfaceDisabled(ifaceSection) {
const iface = L.isObject(ifaceSection) ? ifaceSection : uci.get('wireless', ifaceSection);
return (iface != null && iface['.type'] == 'wifi-iface' &&
(iface.disabled == '1' || isConfigWifiDeviceDisabled(iface.device)));
}
function isNetworkDisabled(radioNet) {
return (radioNet.get('disabled') == '1' || uci.get('wireless', radioNet.getWifiDeviceName(), 'disabled') == '1');
return (radioNet.get('disabled') == '1' || isConfigWifiDeviceDisabled(radioNet.getWifiDeviceName()));
}
function isRadioDisplayUp(radioDev, wifiNets) {
@ -997,6 +1043,9 @@ function probeAssocListCandidates(candidates, probeFn) {
}
function getAssocListForNetwork(radioNet) {
if (isNetworkDisabled(radioNet))
return Promise.resolve([]);
const hwtype = uci.get('wireless', radioNet.getWifiDeviceName(), 'type');
const candidates = getAssocListCandidates(radioNet);
const resolvedIfname = candidates[0];
@ -1494,11 +1543,15 @@ var CBIWifiFrequencyValue = form.Value.extend({
return obj;
}, {});
const has_he_modes = !!(htmodelist.HE20 || htmodelist.HE40 || htmodelist.HE80 || htmodelist.HE160);
const has_eht_modes = !!(htmodelist.EHT20 || htmodelist.EHT40 || htmodelist.EHT80 || htmodelist.EHT160 || htmodelist.EHT320);
const has_5g_channels = this.channels['5g'].length > (allow_auto ? 3 : 0);
const has_ac = (hwmodelist.ac || ((hwmodelist.ax || hwmodelist.be || /^11ax|^11be/.test(hwval)) && has_5g_channels)) &&
(L.hasSystemFeature('hostapd', '11ac') || htmodelist.VHT20 || htmodelist.VHT40 || htmodelist.VHT80 || htmodelist.VHT160);
const has_ax = hwmodelist.ax && (L.hasSystemFeature('hostapd', '11ax') || htmodelist.HE20 || htmodelist.HE40 || htmodelist.HE80 || htmodelist.HE160);
const has_be = hwmodelist.be && (L.hasSystemFeature('hostapd', '11be') || htmodelist.EHT20 || htmodelist.EHT40 || htmodelist.EHT80 || htmodelist.EHT160 || htmodelist.EHT320);
const has_ax = (hwmodelist.ax || has_eht_modes) &&
(L.hasSystemFeature('hostapd', '11ax') || has_he_modes || has_eht_modes);
const has_be = (hwmodelist.be || has_eht_modes) &&
(L.hasSystemFeature('hostapd', '11be') || has_eht_modes);
if (isQcaWifiHwtype(hwtype)) {
const qca_has_be = has_be || /^11be/.test(hwval);
@ -2034,6 +2087,15 @@ var CBIWifiTxPowerValue = form.ListValue.extend({
}),
load: function(section_id) {
const device_section = this.getDeviceSection ? this.getDeviceSection(section_id) : section_id;
if (isConfigWifiDeviceDisabled(device_section)) {
this.powerval = this.wifiNetwork ? getDisplayTxPower(this.wifiNetwork) : null;
this.poweroff = this.wifiNetwork ? this.wifiNetwork.getTXPowerOffset() : null;
this.value('', _('driver default'));
return form.ListValue.prototype.load.apply(this, [section_id]);
}
return this.callTxPowerList(section_id).then(L.bind(function(pwrlist) {
this.powerval = this.wifiNetwork ? getDisplayTxPower(this.wifiNetwork) : null;
this.poweroff = this.wifiNetwork ? this.wifiNetwork.getTXPowerOffset() : null;
@ -2071,6 +2133,11 @@ var CBIWifiCountryValue = form.Value.extend({
}),
load: function(section_id) {
const device_section = this.getDeviceSection ? this.getDeviceSection(section_id) : section_id;
if (isConfigWifiDeviceDisabled(device_section))
return form.Value.prototype.load.apply(this, [section_id]);
return this.callCountryList(section_id).then(L.bind(function(countrylist) {
if (Array.isArray(countrylist) && countrylist.length > 0) {
this.value('', _('driver default'));

View File

@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=bandix
PKG_VERSION:=0.12.7
PKG_RELEASE:=2
PKG_VERSION:=0.12.8
PKG_RELEASE:=3
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=timsaya
@ -13,7 +13,7 @@ include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/rust/rust-values.mk
# 二进制文件的文件名和URL
RUST_BANDIX_VERSION:=0.12.7
RUST_BANDIX_VERSION:=0.12.8
RUST_BINARY_FILENAME:=bandix-$(RUST_BANDIX_VERSION)-$(RUSTC_TARGET_ARCH).tar.gz

View File

@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=teleproxy
PKG_VERSION:=4.11.0
PKG_RELEASE:=3
PKG_RELEASE:=4
PKG_MAINTAINER:=Kosntantine Shevlakov <shevlakov@132lan.ru>
PKG_LICENSE:=GPLv2
@ -30,6 +30,7 @@ endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/bin \
$(1)/usr/share \
$(1)/etc/config \
$(1)/etc/init.d \
$(1)/etc/uci-defaults
@ -37,6 +38,7 @@ define Package/$(PKG_NAME)/install
$(1)/usr/bin/
$(INSTALL_BIN) ./files/$(PKG_NAME).init $(1)/etc/init.d/$(PKG_NAME)
$(INSTALL_BIN) ./files/$(PKG_NAME).defaults $(1)/etc/uci-defaults/$(PKG_NAME)
$(INSTALL_BIN) ./files/$(PKG_NAME)-config-refresh.sh $(1)/usr/share/
$(INSTALL_CONF) ./files/$(PKG_NAME).config $(1)/etc/config/$(PKG_NAME)
endef

View File

@ -0,0 +1,48 @@
#!/bin/sh
# teleproxy config updater
# by koshev-msk 2026
URL=https://core.telegram.org/
which curl || echo "Error. cURL not found."
# Check proxy connectrion
SOCKS_PROXY=$(uci -q get teleproxy.default.socks)
[ -n $SOCKS_PROXY ] && {
# Check autentification proxy
SOCKS_AUTH=$(uci -q get teleproxy.default.socks_auth)
[ -n $SOCKS_AUTH ] && {
CURL="curl -x socks5://${SOCKS_AUTH}@${SOCKS_PROXY}"
} || {
CURL="curl -x socks://${SOCKS_PROXY}"
}
} || {
CURL="curl"
}
[ -d /etc/teleproxy ] || mkdir -p /etc/teleproxy
# Download latest configs and check new sha256
${CURL} -s --max-time 60 $URL/cidr.txt -o /tmp/cidr.txt && \
SHA256_CIDR_NEW=$(sha256sum /tmp/cidr.txt | awk '{print $1}') || SHA256_CIDR_NEW="failed"
${CURL} -s --max-time 60 $URL/getProxyConfig -o /tmp/proxy-multi.conf && \
SHA256_MULTI_NEW=$(sha256sum /tmp/proxy-multi.conf | awk '{print $1}') || SHA256_MULTI_NEW="failed"
${CURL} -s --max-time 60 $URL/getProxySecret -o /tmp/aes-secret && \
SHA256_AES_NEW=$(sha256sum /tmp/aes-secret | awk '{print $1}') || SHA256_AES_NEW="failed"
# Check old sha256 config
[ -f /etc/teleproxy/cidr.txt ] && \
SHA256_CIDR_OLD=$(sha256sum /etc/teleproxy/cidr.txt | awk '{print $1}') || SHA256_CIDR_OLD="failed"
[ -f /etc/teleproxy/proxy-multi.conf ] && \
SHA256_MULTI_OLD=$(sha256sum /etc/teleproxy/proxy-multi.conf | awk '{print $1}') || SHA256_MULTI_OLD="failed"
[ -f /etc/teleproxy/aes-secret ] && \
SHA256_AES_OLD=$(sha256sum /etc/teleproxy/aes-secret | awk '{print $1}') || SHA256_MULTI_OLD="failed"
# Comapre hashes
[ "$SHA256_CIDR_NEW" = "$SHA256_CIDR_OLD" ] || \
cp /tmp/cidr.txt /etc/teleproxy/cidr.txt && rm /tmp/cidr.txt
[ "$SHA256_MULTI_NEW" = "$SHA256_MULTI_OLD" ] || \
cp /tmp/proxy-multi.conf /etc/teleproxy/proxy-multi.conf && rm /tmp/proxy-multi.conf
[ "$SHA256_AES_NEW" = "$SHA256_AES_OLD" ] || \
cp /tmp/aes-secret /etc/teleproxy/aes-secret && rm /tmp/aes-secret

View File

@ -6,7 +6,7 @@ BIN=/usr/bin/${NAME}
PID=/var/run/${NAME}.pid
load_config(){
for v in ipv6 address port secret direct aes_pwd auth_socks socks extra; do
for v in ipv6 address port secret direct relay aes_pwd auth_socks socks extra; do
config_get $v $1 $v
done
}
@ -14,14 +14,14 @@ load_config(){
start() {
config_load teleproxy
local ipv6 address port secret direct aes_pwd auth_socks socks extra
local ipv6 address port secret direct relay aes_pwd auth_socks socks extra
config_foreach load_config
[ $ipv6 ] && args="-6"
[ $address ] && args="$args --address $address"
[ $port ] && args="$args -H $port"
[ $secret ] && args="$args -S $secret"
[ $aes_pwd ] && args="$args --aes-pwd $aes-pwd"
[ $socks ] && {
[ $aes_pwd ] && args="$args --aes-pwd $aes_pwd"
[ $socks -a "$direct" -eq "1" ] && {
[ $auth_socks ] && {
args="$args --socks socks5://${auth_socks}@${socks}"
} || {