mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-06 03:14:12 +08:00
🍉 Sync 2026-10-20 11:10:09
This commit is contained in:
1 parent
cbd3ce4959
commit
0e175ff6b9
8 files changed
+2576
-234
No files matched your search
@@ -1,8 +1,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-trafficctl
|
||||
PKG_VERSION:=1.22.0
|
||||
PKG_RELEASE:=12
|
||||
PKG_VERSION:=1.23.0
|
||||
PKG_RELEASE:=13
|
||||
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_MAINTAINER:=Denis Iusupov <yusdyr@gmail.com>
|
||||
@@ -57,5 +57,6 @@ fi
|
||||
exit 0
|
||||
endef
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot will pick up the standard LuCI layout
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
# No explicit $(eval $(call BuildPackage,...)) here: luci.mk already calls it
|
||||
# for the main package, so the explicit call was a duplicate. Spotted by
|
||||
# @ntbowen in #73.
|
||||
@@ -45,9 +45,9 @@ function fmtRate(kbit) {
|
||||
kbit = kbit || 0;
|
||||
if (kbit >= 1000) {
|
||||
var m = kbit / 1000;
|
||||
return (m === Math.floor(m) ? m : m.toFixed(1)) + ' Mbit/s';
|
||||
return (m === Math.floor(m) ? m : m.toFixed(1)) + ' ' + _('Mbit/s');
|
||||
}
|
||||
return kbit + ' kbit/s';
|
||||
return kbit + ' ' + _('kbit/s');
|
||||
}
|
||||
|
||||
function scopeOf(row) {
|
||||
@@ -122,7 +122,7 @@ return view.extend({
|
||||
'class': 'cbi-button cbi-button-remove',
|
||||
'style': 'font-size:11px;padding:1px 6px;margin-left:6px',
|
||||
'title': _('Remove limit')
|
||||
}, '✕');
|
||||
}, _('✕'));
|
||||
rmBtn.addEventListener('click', function() {
|
||||
rmBtn.disabled = true;
|
||||
self.doCtl('limit', row, 0);
|
||||
@@ -136,7 +136,7 @@ return view.extend({
|
||||
var b = E('button', {
|
||||
'class': 'cbi-button',
|
||||
'style': 'font-size:10px;padding:0 5px;margin-right:2px',
|
||||
'title': _('Limit inbound to') + ' ' + fmtRate(p.kbit)
|
||||
'title': _('Limit inbound to %s').format(fmtRate(p.kbit))
|
||||
}, p.label);
|
||||
b.addEventListener('click', function() {
|
||||
b.disabled = true;
|
||||
|
||||
@@ -249,13 +249,13 @@ var callConfigGet = rpc.declare({
|
||||
|
||||
var RATE_PRESETS = [
|
||||
{v:'0', l: _('Off')},
|
||||
{v:'1000', l:'1 Mbit/s'},
|
||||
{v:'2000', l:'2 Mbit/s'},
|
||||
{v:'5000', l:'5 Mbit/s'},
|
||||
{v:'10000', l:'10 Mbit/s'},
|
||||
{v:'25000', l:'25 Mbit/s'},
|
||||
{v:'50000', l:'50 Mbit/s'},
|
||||
{v:'100000', l:'100 Mbit/s'},
|
||||
{v:'1000', l:_('1 Mbit/s')},
|
||||
{v:'2000', l:_('2 Mbit/s')},
|
||||
{v:'5000', l:_('5 Mbit/s')},
|
||||
{v:'10000', l:_('10 Mbit/s')},
|
||||
{v:'25000', l:_('25 Mbit/s')},
|
||||
{v:'50000', l:_('50 Mbit/s')},
|
||||
{v:'100000', l:_('100 Mbit/s')},
|
||||
{v:'custom', l: _('Custom…')}
|
||||
];
|
||||
|
||||
@@ -334,11 +334,11 @@ function renderTotalCell(cell, total, liveVal, since, pending, degraded) {
|
||||
}
|
||||
cell.appendChild(document.createTextNode(fmtBytes(total)));
|
||||
var tip = since
|
||||
? (_('Accumulated since') + ' ' + new Date(since * 1000).toLocaleString())
|
||||
? (_('Accumulated since %s').format(new Date(since * 1000).toLocaleString()))
|
||||
: _('Accumulated on the router');
|
||||
tip += '\n' + _('Resets when the router reboots.');
|
||||
if (liveVal != null && liveVal >= 0) {
|
||||
tip += '\n' + _('Currently tracked connections hold') + ' ' + fmtBytes(liveVal);
|
||||
tip += '\n' + _('Currently tracked connections hold %s').format(fmtBytes(liveVal));
|
||||
}
|
||||
cell.title = tip;
|
||||
}
|
||||
@@ -346,16 +346,16 @@ function renderTotalCell(cell, total, liveVal, since, pending, degraded) {
|
||||
function fmtSpeed(bps) {
|
||||
if (!bps || bps < 1) return '—';
|
||||
var bits = bps * 8;
|
||||
if (bits < 1000) return bits.toFixed(0) + ' bit/s';
|
||||
if (bits < 1000000) { var k = bits/1000; return (k % 1 === 0 ? k.toFixed(0) : k.toFixed(1)) + ' Kbit/s'; }
|
||||
if (bits < 1000000000) { var m = bits/1000000; return (m % 1 === 0 ? m.toFixed(0) : m.toFixed(1)) + ' Mbit/s'; }
|
||||
var g = bits/1000000000; return (g % 1 === 0 ? g.toFixed(0) : g.toFixed(2)) + ' Gbit/s';
|
||||
if (bits < 1000) return bits.toFixed(0) + ' ' + _('bit/s');
|
||||
if (bits < 1000000) { var k = bits/1000; return (k % 1 === 0 ? k.toFixed(0) : k.toFixed(1)) + ' ' + _('Kbit/s'); }
|
||||
if (bits < 1000000000) { var m = bits/1000000; return (m % 1 === 0 ? m.toFixed(0) : m.toFixed(1)) + ' ' + _('Mbit/s'); }
|
||||
var g = bits/1000000000; return (g % 1 === 0 ? g.toFixed(0) : g.toFixed(2)) + ' ' + _('Gbit/s');
|
||||
}
|
||||
function fmtRate(kbit) {
|
||||
if (!kbit || kbit <= 0) return '—';
|
||||
var mbit = kbit / 1000;
|
||||
if (mbit >= 1) return (mbit % 1 === 0 ? mbit.toFixed(0) : mbit.toFixed(1)) + ' Mbit/s';
|
||||
return kbit + ' kbit/s';
|
||||
if (mbit >= 1) return (mbit % 1 === 0 ? mbit.toFixed(0) : mbit.toFixed(1)) + ' ' + _('Mbit/s');
|
||||
return kbit + ' ' + _('kbit/s');
|
||||
}
|
||||
|
||||
// Render a "↓ down / ↑ up" speed cell. Both halves come from the same
|
||||
@@ -703,14 +703,14 @@ function renderFullGraph(history, limitKbit, width, height) {
|
||||
dlLeg.setAttribute('x', legendX); dlLeg.setAttribute('y', legendY);
|
||||
dlLeg.setAttribute('text-anchor', 'end'); dlLeg.setAttribute('font-size', '9');
|
||||
dlLeg.setAttribute('fill', 'var(--tc-speed)'); dlLeg.setAttribute('font-weight', '600');
|
||||
dlLeg.textContent = '↓ DL';
|
||||
dlLeg.textContent = _('↓ DL');
|
||||
svg.appendChild(dlLeg);
|
||||
if (hasUpload) {
|
||||
var ulLeg = document.createElementNS(ns, 'text');
|
||||
ulLeg.setAttribute('x', legendX); ulLeg.setAttribute('y', legendY + 12);
|
||||
ulLeg.setAttribute('text-anchor', 'end'); ulLeg.setAttribute('font-size', '9');
|
||||
ulLeg.setAttribute('fill', 'var(--tc-ok)'); ulLeg.setAttribute('font-weight', '600');
|
||||
ulLeg.textContent = '↑ UL';
|
||||
ulLeg.textContent = _('↑ UL');
|
||||
svg.appendChild(ulLeg);
|
||||
}
|
||||
|
||||
@@ -967,10 +967,10 @@ function buildOverviewPanel(ifaces, ifHistory, speedMap, nameByIp, showOther, on
|
||||
|
||||
// ── headline tiles ──────────────────────────────────────────────────
|
||||
var head = E('div', { 'class': 'tc-ov-tiles' }, [
|
||||
mkOvTile(_('Download') + ' · ' + (primary.label || primary.dev),
|
||||
fmtSpeed(primaryRate.down), fmtBytes(primary.rx_bytes) + ' ' + _('total'), 'tc-c-speed'),
|
||||
mkOvTile(_('Upload') + ' · ' + (primary.label || primary.dev),
|
||||
fmtSpeed(primaryRate.up), fmtBytes(primary.tx_bytes) + ' ' + _('total'), 'tc-c-ok'),
|
||||
mkOvTile(_('Download · %s').format(primary.label || primary.dev),
|
||||
fmtSpeed(primaryRate.down), _('%s total').format(fmtBytes(primary.rx_bytes)), 'tc-c-speed'),
|
||||
mkOvTile(_('Upload · %s').format(primary.label || primary.dev),
|
||||
fmtSpeed(primaryRate.up), _('%s total').format(fmtBytes(primary.tx_bytes)), 'tc-c-ok'),
|
||||
mkOvTile(_('Active devices'), String(activeDevices),
|
||||
_('sending or receiving now'), '')
|
||||
]);
|
||||
@@ -1337,7 +1337,7 @@ function buildSummaryTable(rows, sortCol, sortDir, onSort, onSelect, speedMap, d
|
||||
if (sd && (sd.current_up||0) > 1024) { cellMap._speed_up.className = 'td tc-right tc-mono tc-speed-active'; cellMap._speed_up.textContent = fmtSpeed(sd.current_up); }
|
||||
else { cellMap._speed_up.className = 'td tc-right tc-mono tc-speed-idle'; cellMap._speed_up.textContent = sd ? fmtSpeed(sd.current_up||0) : '—'; }
|
||||
|
||||
var sparkTip = r._throttle_kbit > 0 ? (_('Limit') + ': ' + fmtRate(r._throttle_kbit)) : '';
|
||||
var sparkTip = r._throttle_kbit > 0 ? (_('Limit: %s').format(fmtRate(r._throttle_kbit))) : '';
|
||||
cellMap._spark = E('div', { 'class': 'td tc-center', 'style': 'padding:2px 4px', 'data-spark-ip': r.ip, 'data-tip': sparkTip || undefined });
|
||||
var sparkSvg = renderSparkline(speedHistory[r.ip], globalSpeedMax, 60, 20, r._throttle_kbit);
|
||||
if (sparkSvg) cellMap._spark.appendChild(sparkSvg);
|
||||
@@ -1369,7 +1369,7 @@ function buildSummaryTable(rows, sortCol, sortDir, onSort, onSelect, speedMap, d
|
||||
if (lastTs) {
|
||||
var ago = Math.floor((Date.now()/1000) - lastTs);
|
||||
var agoStr = ago < 60 ? ago + 's' : ago < 3600 ? Math.floor(ago/60) + 'm' : Math.floor(ago/3600) + 'h';
|
||||
tip = _('Last seen') + ': ' + lastType + ', ' + agoStr + ' ' + _('ago');
|
||||
tip = _('Last seen: %s, %s ago').format(lastType, agoStr);
|
||||
}
|
||||
}
|
||||
linkBadge = E('span', { 'class': 'tc-c-faint', 'style': 'cursor:help', 'title': tip }, '?');
|
||||
@@ -1425,7 +1425,7 @@ function buildSummaryTable(rows, sortCol, sortDir, onSort, onSelect, speedMap, d
|
||||
cellMap._backlog = E('div', { 'class': 'td tc-center', 'data-backlog-ip': r.ip }, backlogBadge);
|
||||
|
||||
var cells = visibleCols.map(function(c) { return cellMap[c.key]; });
|
||||
var row = E('div', { 'class': 'tr', 'title': _('Click to inspect') + ' ' + r.name }, cells);
|
||||
var row = E('div', { 'class': 'tr', 'title': _('Click to inspect %s').format(r.name) }, cells);
|
||||
row.addEventListener('click', function() { addRecentDevice(r.ip, r.name); onSelect(r.ip, r.name); });
|
||||
return row;
|
||||
});
|
||||
@@ -1519,7 +1519,7 @@ function buildExtendedStatsPanel(ip, shapeMap, dropMap, speedMap) {
|
||||
}
|
||||
if (sm.memory_used != null) addRow(_('Queue memory'), fmtBytes(sm.memory_used), null);
|
||||
if (sm.lended != null || sm.borrowed != null) {
|
||||
addRow(_('Lended') + ' / ' + _('Borrowed'), (sm.lended || 0) + ' / ' + (sm.borrowed || 0), null);
|
||||
addRow(_('Lended / Borrowed'), (sm.lended || 0) + ' / ' + (sm.borrowed || 0), null);
|
||||
}
|
||||
if (spd && sm.rate_kbit > 0) {
|
||||
var currentBps = spd.current || 0;
|
||||
@@ -1612,7 +1612,7 @@ function buildExtendedStatsLegend(shapeMap, dropMap) {
|
||||
}
|
||||
|
||||
return E('div', { 'class': 'tc-ext-panel tc-ext-panel--sticky' }, [
|
||||
E('div', { 'class': 'tc-ext-panel__title' }, _('Extended Statistics') + ' (' + _('all devices') + ')'),
|
||||
E('div', { 'class': 'tc-ext-panel__title' }, _('Extended Statistics (all devices)')),
|
||||
E('div', { 'class': 'tc-ext-col-flex' }, rows)
|
||||
]);
|
||||
}
|
||||
@@ -2302,8 +2302,8 @@ return view.extend({
|
||||
'class': 'tc-custom-input' });
|
||||
var customUnitBtns = E('span', {'class':'tc-custom-unit-btns'});
|
||||
var _customUnit = 'mbit';
|
||||
var mbitBtn = E('span', {'style':'padding:4px 8px;font-size:11px;cursor:pointer;background:var(--tc-speed);color:#fff'}, 'Mbit/s');
|
||||
var kbitBtn = E('span', {'style':'padding:4px 8px;font-size:11px;cursor:pointer;background:var(--tc-bg);color:currentColor'}, 'kbit/s');
|
||||
var mbitBtn = E('span', {'style':'padding:4px 8px;font-size:11px;cursor:pointer;background:var(--tc-speed);color:#fff'}, _('Mbit/s'));
|
||||
var kbitBtn = E('span', {'style':'padding:4px 8px;font-size:11px;cursor:pointer;background:var(--tc-bg);color:currentColor'}, _('kbit/s'));
|
||||
function updateUnitBtns() {
|
||||
mbitBtn.style.background = _customUnit === 'mbit' ? 'var(--tc-speed)' : 'var(--tc-bg)';
|
||||
mbitBtn.style.color = _customUnit === 'mbit' ? '#fff' : 'currentColor';
|
||||
@@ -2552,7 +2552,7 @@ return view.extend({
|
||||
|
||||
function removeSubnetLimit(target, mode, btn) {
|
||||
btn.disabled = true;
|
||||
setStatus(statusDiv, 'loading', _('Removing limit on') + ' ' + target + '…');
|
||||
setStatus(statusDiv, 'loading', _('Removing limit on %s…').format(target));
|
||||
callRatelimit(target, 0, '', mode).then(function(res) {
|
||||
setStatus(statusDiv, (res && res.ok) ? 'ok' : 'error',
|
||||
(res && res.msg) || _('Throttle removed'));
|
||||
@@ -2591,7 +2591,7 @@ return view.extend({
|
||||
}, isShared ? _('shared between them') : _('each')),
|
||||
E('span', {'class':'tc-c-muted tc-subnet-limits__drops'},
|
||||
l.packets > 0
|
||||
? (String(l.packets) + ' ' + _('packets dropped') + ' (' + fmtBytes(l.bytes) + ')')
|
||||
? (_('%d packets dropped (%s)').format(l.packets, fmtBytes(l.bytes)))
|
||||
: _('nothing dropped yet')),
|
||||
removeBtn
|
||||
]));
|
||||
@@ -2604,8 +2604,8 @@ return view.extend({
|
||||
list.forEach(function(s) {
|
||||
if (!s || !s.cidr) { return; }
|
||||
addSubnetChip(s.cidr, s.cidr, s.kind === 'routed'
|
||||
? (_('Routed via') + ' ' + s.device)
|
||||
: (_('On') + ' ' + s.device));
|
||||
? (_('Routed via %s').format(s.device))
|
||||
: (_('On %s').format(s.device)));
|
||||
});
|
||||
updateSubnetChips();
|
||||
updateScopeExplain();
|
||||
@@ -3098,10 +3098,10 @@ return view.extend({
|
||||
var protoUdp = Number(data.protocols.udp) || 0;
|
||||
var protoOther = Number(data.protocols.other) || 0;
|
||||
var connCount = protoTcp + protoUdp + protoOther;
|
||||
var parts = [_('Connections') + ': <b>'+connCount+'</b>'];
|
||||
var parts = [_('Connections: <b>%d</b>').format(connCount)];
|
||||
if (connCount > 0) {
|
||||
parts.push('TCP: <b>'+protoTcp+'</b>');
|
||||
parts.push('UDP: <b>'+protoUdp+'</b>');
|
||||
parts.push(_('TCP: <b>%d</b>').format(protoTcp));
|
||||
parts.push(_('UDP: <b>%d</b>').format(protoUdp));
|
||||
if (data.tcp_states) {
|
||||
Object.keys(data.tcp_states).forEach(function(s) {
|
||||
parts.push(escHtml(s)+': <b>'+(Number(data.tcp_states[s]) || 0)+'</b>');
|
||||
@@ -3109,15 +3109,15 @@ return view.extend({
|
||||
}
|
||||
}
|
||||
if ((data.shape_kbit || 0) > 0) {
|
||||
parts.push(_('Shaped') + ': <b style="color:var(--tc-speed)">🌊 '+fmtRate(data.shape_kbit)+'</b>');
|
||||
parts.push(_('Shaped: <b style=\"color:var(--tc-speed)\">🌊 %s</b>').format(fmtRate(data.shape_kbit)));
|
||||
var sm = self._shapeMap[data.ip || searchSelect.getValue()] || {};
|
||||
if ((sm.backlog||0) > 0) parts.push(_('Queued') + ': <b style="color:var(--tc-speed)">'+fmtBytes(sm.backlog)+'</b>');
|
||||
if ((sm.bytes||0) > 0) parts.push(_('Passed') + ': <b>'+fmtBytes(sm.bytes)+'</b>');
|
||||
if ((sm.backlog||0) > 0) parts.push(_('Queued: <b style=\"color:var(--tc-speed)\">%s</b>').format(fmtBytes(sm.backlog)));
|
||||
if ((sm.bytes||0) > 0) parts.push(_('Passed: <b>%s</b>').format(fmtBytes(sm.bytes)));
|
||||
} else if ((data.rate_limit_kbit || 0) > 0) {
|
||||
parts.push(_('Speed limit') + ': <b style="color:var(--tc-warn)">⚡ '+fmtRate(data.rate_limit_kbit)+'</b>');
|
||||
parts.push(_('Speed limit: <b style=\"color:var(--tc-warn)\">⚡ %s</b>').format(fmtRate(data.rate_limit_kbit)));
|
||||
var dm = self._dropMap[data.ip || searchSelect.getValue()] || {};
|
||||
if ((dm.packets||0) > 0) {
|
||||
parts.push(_('Dropped') + ': <b style="color:var(--tc-err)">🚫 '+(Number(dm.packets) || 0)+' pkts / '+fmtBytes(dm.bytes||0)+'</b>');
|
||||
parts.push(_('Dropped: <b style="color:var(--tc-err)">🚫 %d pkts / %s</b>').format(Number(dm.packets) || 0, fmtBytes(dm.bytes||0)));
|
||||
}
|
||||
}
|
||||
// Listed but still associated is not a block, so it must not
|
||||
@@ -3130,11 +3130,11 @@ return view.extend({
|
||||
} else if (data.wifi_blocked) {
|
||||
wifiPart = ' | <b style="color:var(--tc-warn)">📵 ' + _('WiFi blocked') + '</b> ('+escHtml(data.mac||'') + ')';
|
||||
} else {
|
||||
wifiPart = data.mac ? ' | <span style="color:var(--tc-faint)">MAC: '+escHtml(data.mac)+'</span>' : '';
|
||||
wifiPart = data.mac ? ' | <span style="color:var(--tc-faint)">' + _('MAC:') + ' ' + escHtml(data.mac) + '</span>' : '';
|
||||
}
|
||||
statsDiv.className = 'alert-message ' + (data.blocked ? 'error' : 'info');
|
||||
statsDiv.innerHTML = (data.blocked
|
||||
? '<b>⛔ ' + _('BLOCKED') + '</b> — '+(Number(data.block_packets) || 0)+' pkts, '+fmtBytes(Number(data.block_bytes) || 0)+' ' + _('dropped') + ' | '
|
||||
? '<b>⛔ ' + _('BLOCKED') + '</b> — ' + _('%d pkts, %s dropped').format(Number(data.block_packets) || 0, fmtBytes(Number(data.block_bytes) || 0)) + ' | '
|
||||
: '') + parts.join(' | ') + wifiPart;
|
||||
}
|
||||
|
||||
@@ -3323,9 +3323,9 @@ return view.extend({
|
||||
}
|
||||
|
||||
var parts = [];
|
||||
parts.push(E('span', {}, [document.createTextNode(_('Active') + ': '), E('b', {}, String(rows.length))]));
|
||||
parts.push(E('span', {}, [document.createTextNode(_('Blocked') + ': '), mkFilterVal('blocked', 'var(--tc-err)', String(blocked))]));
|
||||
parts.push(E('span', {}, [document.createTextNode(_('WiFi') + ': '), mkFilterVal('wifi_blocked', 'var(--tc-warn)', String(wifiBlk))]));
|
||||
parts.push(E('span', {}, [document.createTextNode(_('Active:') + ' '), E('b', {}, String(rows.length))]));
|
||||
parts.push(E('span', {}, [document.createTextNode(_('Blocked:') + ' '), mkFilterVal('blocked', 'var(--tc-err)', String(blocked))]));
|
||||
parts.push(E('span', {}, [document.createTextNode(_('WiFi:') + ' '), mkFilterVal('wifi_blocked', 'var(--tc-warn)', String(wifiBlk))]));
|
||||
// Without this the header counts a device as blocked on the strength of
|
||||
// the uci maclist alone — which is how a router can report "WiFi: 2"
|
||||
// while both of those devices are browsing.
|
||||
@@ -3333,13 +3333,13 @@ return view.extend({
|
||||
parts.push(E('span', {
|
||||
'style': 'color:var(--tc-err);font-weight:700;cursor:help',
|
||||
'title': _('Devices on the WiFi deny list that are still connected — those blocks are not in effect on the running radio.')
|
||||
}, '⚠ ' + wifiPending + ' ' + _('not applied')));
|
||||
}, '⚠ ' + _('%d not applied').format(wifiPending)));
|
||||
}
|
||||
if (limited > 0) parts.push(E('span', {}, [document.createTextNode(_('Limited') + ': '), mkFilterVal('limited', 'var(--tc-warn)', '⚡' + limited)]));
|
||||
if (shaped > 0) parts.push(E('span', {}, [document.createTextNode(_('Shaped') + ': '), mkFilterVal('shaped', 'var(--tc-speed)', '🌊' + shaped)]));
|
||||
if (limited > 0) parts.push(E('span', {}, [document.createTextNode(_('Limited:') + ' '), mkFilterVal('limited', 'var(--tc-warn)', '⚡' + limited)]));
|
||||
if (shaped > 0) parts.push(E('span', {}, [document.createTextNode(_('Shaped:') + ' '), mkFilterVal('shaped', 'var(--tc-speed)', '🌊' + shaped)]));
|
||||
if (totalDropPkts > 0) {
|
||||
parts.push(E('span', {}, [
|
||||
document.createTextNode(_('Dropped') + ': '), E('b', {'style':'color:var(--tc-err)'}, '🚫' + totalDropPkts)
|
||||
document.createTextNode(_('Dropped:') + ' '), E('b', {'style':'color:var(--tc-err)'}, '🚫' + totalDropPkts)
|
||||
]));
|
||||
}
|
||||
|
||||
@@ -3912,7 +3912,7 @@ return view.extend({
|
||||
var limitBtns = [];
|
||||
RATE_PRESETS.forEach(function(p) {
|
||||
if (p.v === '0' || p.v === 'custom') return;
|
||||
limitBtns.push(E('span', {'class':'tg-kbd-btn'}, p.l.replace(' Mbit/s', 'M').replace(/\s/g, '')));
|
||||
limitBtns.push(E('span', {'class':'tg-kbd-btn'}, p.l.replace(' Mbit/s','M').replace(/\s/g,'')));
|
||||
});
|
||||
for (var li = 0; li < limitBtns.length; li += 3) {
|
||||
kbdBubble.appendChild(E('div', {'class':'tg-kbd-row'}, limitBtns.slice(li, li + 3)));
|
||||
@@ -3922,7 +3922,7 @@ return view.extend({
|
||||
var shapeBtns = [];
|
||||
RATE_PRESETS.forEach(function(p) {
|
||||
if (p.v === '0' || p.v === 'custom') return;
|
||||
shapeBtns.push(E('span', {'class':'tg-kbd-btn'}, '🔧 ' + p.l.replace(' Mbit/s', 'M').replace(/\s/g, '')));
|
||||
shapeBtns.push(E('span', {'class':'tg-kbd-btn'}, '🔧 ' + p.l.replace(' Mbit/s','M').replace(/\s/g,'')));
|
||||
});
|
||||
for (var si = 0; si < shapeBtns.length; si += 3) {
|
||||
kbdBubble.appendChild(E('div', {'class':'tg-kbd-row'}, shapeBtns.slice(si, si + 3)));
|
||||
@@ -4180,17 +4180,14 @@ return view.extend({
|
||||
var modeLabels = {
|
||||
'none': ['⊘', _('No offload'), 'var(--tc-muted)'],
|
||||
'software': ['◑', _('Software offload'), 'var(--tc-speed)'],
|
||||
// tctl_get_offload_mode splits software offload on the flowtable
|
||||
// counter flag, so this value reaches the badge too. Without an
|
||||
// entry the badge fell through to '?' and the raw mode string.
|
||||
'software-counter': ['◑', _('Software offload'), 'var(--tc-speed)'],
|
||||
'software-counter': ['◑', _('Software offload (counter)'), 'var(--tc-speed)'],
|
||||
'hardware-counter': ['●', _('Hardware offload'), 'var(--tc-warn)'],
|
||||
'hardware': ['●', _('Hardware offload'), 'var(--tc-warn)']
|
||||
};
|
||||
var ml = modeLabels[cfg.offload_mode] || ['?', cfg.offload_mode, 'var(--tc-muted)'];
|
||||
var modeBadge = E('div', {'style':'margin-bottom:10px;font-size:12px'}, [
|
||||
E('span', {'style':'color:'+ml[2]+';font-size:15px;margin-right:4px'}, ml[0]),
|
||||
E('span', {'style':'color:var(--tc-muted)'}, _('Current mode: ')),
|
||||
E('span', {'style':'color:var(--tc-muted)'}, _('Current mode:') + ' '),
|
||||
E('b', {}, ml[1])
|
||||
]);
|
||||
|
||||
@@ -4338,9 +4335,9 @@ return view.extend({
|
||||
|
||||
var sep = E('span', {'style': 'opacity:0.35;margin:0 6px'}, '|');
|
||||
var docLinks = para([
|
||||
link(openwrtUrl, 'OpenWrt: Flow offloading ↗'), sep.cloneNode(true),
|
||||
link(kernelUrl, 'Linux kernel: nf_flowtable ↗'), sep.cloneNode(true),
|
||||
link(nftUrl, 'nftables: Flowtables ↗')
|
||||
link(openwrtUrl, _('OpenWrt: Flow offloading ↗')), sep.cloneNode(true),
|
||||
link(kernelUrl, _('Linux kernel: nf_flowtable ↗')), sep.cloneNode(true),
|
||||
link(nftUrl, _('nftables: Flowtables ↗'))
|
||||
]);
|
||||
|
||||
if (mode === 'hardware-counter') {
|
||||
@@ -4349,15 +4346,15 @@ return view.extend({
|
||||
icon = '⚠️';
|
||||
body = E('div', {}, [
|
||||
para(bold(_('Hardware flow offloading active — real-time speed monitoring unavailable.'))),
|
||||
para([_('The flowtable '),
|
||||
para([_('The flowtable') + ' ',
|
||||
E('code', {}, 'counter'),
|
||||
_(' flag should sync hardware byte counts back to conntrack, but on many ' +
|
||||
' ' + _('flag should sync hardware byte counts back to conntrack, but on many ' +
|
||||
'platforms (e.g. Mediatek Filogic) the driver does not implement the stats ' +
|
||||
'callback, so conntrack counters remain frozen for active flows.')]),
|
||||
para(bold(_('To restore speed monitoring:'))),
|
||||
E('ul', {'class': 'tc-offload-ul'}, [
|
||||
E('li', {}, [
|
||||
_('Disable hardware offload (keeps software offload): '),
|
||||
_('Disable hardware offload (keeps software offload):') + ' ',
|
||||
E('code', {}, 'uci set firewall.@defaults[0].flow_offloading_hw=0 && uci commit firewall && fw4 reload'),
|
||||
]),
|
||||
E('li', {}, _('Or disable all flow offload in LuCI → Network → Firewall → General Settings.')),
|
||||
@@ -4379,12 +4376,12 @@ return view.extend({
|
||||
E('li', {}, _('Traffic shaping (tc/HTB) — bypassed for offloaded flows')),
|
||||
E('li', {}, _('Rate limiting — applies only to new connections')),
|
||||
]),
|
||||
para([_('WiFi blocking and internet blocking of new connections still work. '),
|
||||
para([_('WiFi blocking and internet blocking of new connections still work.') + ' ',
|
||||
_('Shaped devices are usually not offloaded (kernel detects the HTB qdisc).')]),
|
||||
para(bold(_('How to get full functionality without disabling offload:'))),
|
||||
para([_('The flowtable '),
|
||||
para([_('The flowtable') + ' ',
|
||||
E('code', {}, 'counter'),
|
||||
_(' flag (Linux 5.7+, set automatically by fw4/nftables) periodically syncs ' +
|
||||
' ' + _('flag (Linux 5.7+, set automatically by fw4/nftables) periodically syncs ' +
|
||||
'hardware byte counts back to conntrack — trafficctl detects this and all features work normally.')]),
|
||||
para(_('If your current firmware uses fw3 (iptables) or ships a kernel older than 5.7, ' +
|
||||
'a router with modern OpenWrt and fw4 support will have this working out of the box.')),
|
||||
@@ -4407,9 +4404,9 @@ return view.extend({
|
||||
para(bold(_('Software flow offloading is active, with counter sync.'))),
|
||||
para(_('The kernel fast-paths established connections through a flowtable for ' +
|
||||
'higher throughput.')),
|
||||
para([_('The flowtable carries the '),
|
||||
para([_('The flowtable carries the') + ' ',
|
||||
E('code', {}, 'counter'),
|
||||
_(' flag (Linux 5.7+, set automatically by fw4), so offloaded byte counts are ' +
|
||||
' ' + _('flag (Linux 5.7+, set automatically by fw4), so offloaded byte counts are ' +
|
||||
'synced back to conntrack. Speed and totals come from conntrack as usual and ' +
|
||||
'are accurate — the nftables counter fallback is not needed on this router.')]),
|
||||
para(_('Traffic shaping and blocking are not affected.')),
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Symlink
+1
@@ -0,0 +1 @@
|
||||
zh_Hans
|
||||
File diff suppressed because it is too large.
Load diff
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
|
||||
LUCI_TITLE:=LuCI Status Pages
|
||||
LUCI_DEPENDS:=+luci-base +luci-app-oui +luci-mod-dashboard +libiwinfo +rpcd-mod-iwinfo +rpcd-mod-rrdns +ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-socket
|
||||
|
||||
PKG_RELEASE:=34
|
||||
PKG_RELEASE:=35
|
||||
PKG_BUILD_DEPENDS:=iwinfo
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
|
||||
@@ -214,8 +214,9 @@ function addResolvedPort(knownPorts, seenPorts, role, device, mapping, board, sw
|
||||
});
|
||||
}
|
||||
else {
|
||||
const deviceInfo = L.isObject(board) && L.isObject(board['network-device'])
|
||||
? board['network-device'][value] : null;
|
||||
const devices = L.isObject(board)
|
||||
? (board['network-device'] || board.network_device) : null;
|
||||
const deviceInfo = L.isObject(devices) ? devices[value] : null;
|
||||
|
||||
addKnownPort(knownPorts, seenPorts, role, value,
|
||||
L.isObject(deviceInfo) && isString(deviceInfo.label) ? { label: deviceInfo.label } : null);
|
||||
|
||||
Reference in new issue
Block a user