mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-29 04:05:13 +08:00
🍕 Sync 2026-09-17 11:06:12
This commit is contained in:
1 parent
6bd796a758
commit
50871a0a18
10 files changed
+510
-48
No files matched your search
@@ -12,7 +12,7 @@ LUCI_DEPENDS:=+luci-base +logd +jsonfilter
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
PKG_VERSION:=0.1.41
|
||||
PKG_RELEASE:=19
|
||||
PKG_RELEASE:=20
|
||||
|
||||
# Reproducible build: honor SOURCE_DATE_EPOCH from the build environment (set by docker-sdk.sh / CI).
|
||||
ifdef SOURCE_DATE_EPOCH
|
||||
|
||||
@@ -12,6 +12,10 @@ return baseclass.extend({
|
||||
APP_VERSION: '0.1.41',
|
||||
ROW_LIMIT_OPTIONS: [25, 50, 100, 250, 500, 1000, 2000],
|
||||
DEFAULT_ROW_LIMIT: 100,
|
||||
FETCH_MODE_OPTIONS: ['auto', 'manual'],
|
||||
MANUAL_FETCH_LINES_OPTIONS: [25, 50, 100, 250, 500, 1000, 2000],
|
||||
DEFAULT_FETCH_MODE: 'auto',
|
||||
DEFAULT_MANUAL_FETCH_LINES: 100,
|
||||
/* Row pass/deny tint: classic green/red default; accessible teal/orange */
|
||||
ROW_TINT_OPTIONS: ['off', 'classic', 'accessible'],
|
||||
DEFAULT_ROW_TINT: 'classic',
|
||||
|
||||
@@ -94,6 +94,10 @@ function optionNodes(pairs) {
|
||||
|
||||
return view.extend({
|
||||
rowLimit: constants.DEFAULT_ROW_LIMIT,
|
||||
fetchMode: constants.DEFAULT_FETCH_MODE,
|
||||
manualFetchLines: constants.DEFAULT_MANUAL_FETCH_LINES,
|
||||
manualFetchLinesExplicit: false,
|
||||
rpcPreferencesResolved: false,
|
||||
entries: [],
|
||||
sessionSeen: null,
|
||||
pauseBufferLoading: false,
|
||||
@@ -108,14 +112,19 @@ return view.extend({
|
||||
pollRequestQueued: false,
|
||||
pollRequestWaiters: [],
|
||||
pollRequestQueuedWaiters: [],
|
||||
coordinatorDisposed: false,
|
||||
/* Layer 2 — visibility / RTT cadence / shed surfacing. */
|
||||
pollEpoch: 0,
|
||||
pollCadenceSec: 1,
|
||||
rttStreakKind: null,
|
||||
rttStreakCount: 0,
|
||||
serverAdaptive: 1,
|
||||
serverAdaptive: undefined,
|
||||
serverTruncated: 0,
|
||||
serverShed: null,
|
||||
lastPollRequestedLines: null,
|
||||
lastPollEffectiveLimit: null,
|
||||
lastPollReturnedMessages: null,
|
||||
fillingBuffer: false,
|
||||
weakDevice: false,
|
||||
degradedSampling: false,
|
||||
/* Layer 2 summary fallback — rows remain available behind an explicit toggle. */
|
||||
@@ -194,27 +203,163 @@ return view.extend({
|
||||
.map((k) => '%s=%s'.format(encodeURIComponent(k), encodeURIComponent(filters[k])));
|
||||
if (this.rowLimit !== constants.DEFAULT_ROW_LIMIT)
|
||||
parts.push('limit=%s'.format(encodeURIComponent(this.rowLimit)));
|
||||
if (this.fetchMode === 'manual') {
|
||||
parts.push('poll=manual');
|
||||
parts.push('maxraw=%s'.format(encodeURIComponent(this.manualFetchLines)));
|
||||
}
|
||||
if (this.viewMode === 'detailed') parts.push('view=detailed');
|
||||
location.hash = parts.join('&');
|
||||
},
|
||||
|
||||
applyHash() {
|
||||
if (!location.hash || location.hash.length < 2) return;
|
||||
hashEntries() {
|
||||
if (!location.hash || location.hash.length < 2) return [];
|
||||
|
||||
const entries = location.hash.substring(1).split('&');
|
||||
const result = [];
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const kv = entries[i].split('=');
|
||||
if (kv.length !== 2) continue;
|
||||
const key = decodeURIComponent(kv[0]);
|
||||
const val = decodeURIComponent(kv[1]);
|
||||
if (key === 'limit') {
|
||||
const n = parseInt(val, 10);
|
||||
if (isFinite(n) && constants.ROW_LIMIT_OPTIONS.indexOf(n) >= 0) {
|
||||
this.applyRowLimit(n);
|
||||
this.saveRowLimit();
|
||||
}
|
||||
let key;
|
||||
let val;
|
||||
try {
|
||||
key = decodeURIComponent(kv[0]);
|
||||
val = decodeURIComponent(kv[1]);
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
result.push({ key: key, val: val });
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
readFetchMode() {
|
||||
const v = storedValue('fwlive-poll-mode', constants.DEFAULT_FETCH_MODE);
|
||||
return constants.FETCH_MODE_OPTIONS.indexOf(v) >= 0 ? v : constants.DEFAULT_FETCH_MODE;
|
||||
},
|
||||
|
||||
saveFetchMode() {
|
||||
storeValue('fwlive-poll-mode', this.fetchMode);
|
||||
},
|
||||
|
||||
readManualFetchLines() {
|
||||
const raw = storedValue('fwlive-manual-lines', '');
|
||||
const n = Number(raw);
|
||||
return String(n) === raw && constants.MANUAL_FETCH_LINES_OPTIONS.indexOf(n) >= 0 ? n : null;
|
||||
},
|
||||
|
||||
saveManualFetchLines() {
|
||||
storeValue('fwlive-manual-lines', String(this.manualFetchLines));
|
||||
},
|
||||
|
||||
autoFetchLines() {
|
||||
return Math.min(Math.max(this.rowLimit * 4, 100), constants.FETCH_LINES_MAX);
|
||||
},
|
||||
|
||||
snapManualFetchLines(lines) {
|
||||
const options = constants.MANUAL_FETCH_LINES_OPTIONS;
|
||||
let snapped = options[0];
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
if (options[i] > lines) break;
|
||||
snapped = options[i];
|
||||
}
|
||||
return snapped;
|
||||
},
|
||||
|
||||
resolveRpcPreferences() {
|
||||
if (this.rpcPreferencesResolved) return;
|
||||
|
||||
this.applyRowLimit(this.readRowLimit());
|
||||
this.fetchMode = this.readFetchMode();
|
||||
const storedManual = this.readManualFetchLines();
|
||||
this.manualFetchLinesExplicit = storedManual !== null;
|
||||
this.manualFetchLines =
|
||||
storedManual === null ? this.snapManualFetchLines(this.autoFetchLines()) : storedManual;
|
||||
|
||||
let hashLimit = null;
|
||||
let hashMode = null;
|
||||
let hashManual = null;
|
||||
const entries = this.hashEntries();
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const key = entries[i].key;
|
||||
const val = entries[i].val;
|
||||
if (key === 'limit') {
|
||||
const n = Number(val);
|
||||
if (String(n) === val && constants.ROW_LIMIT_OPTIONS.indexOf(n) >= 0) hashLimit = n;
|
||||
continue;
|
||||
}
|
||||
if (key === 'poll') {
|
||||
if (constants.FETCH_MODE_OPTIONS.indexOf(val) >= 0) hashMode = val;
|
||||
continue;
|
||||
}
|
||||
if (key === 'maxraw') {
|
||||
const n = Number(val);
|
||||
if (String(n) === val && constants.MANUAL_FETCH_LINES_OPTIONS.indexOf(n) >= 0)
|
||||
hashManual = n;
|
||||
}
|
||||
}
|
||||
|
||||
if (hashLimit !== null) {
|
||||
this.applyRowLimit(hashLimit);
|
||||
this.saveRowLimit();
|
||||
}
|
||||
if (hashMode !== null) {
|
||||
this.fetchMode = hashMode;
|
||||
this.saveFetchMode();
|
||||
}
|
||||
if (hashManual !== null && this.fetchMode === 'manual') {
|
||||
this.manualFetchLines = hashManual;
|
||||
this.manualFetchLinesExplicit = true;
|
||||
this.saveManualFetchLines();
|
||||
}
|
||||
if (storedManual === null && !(hashManual !== null && this.fetchMode === 'manual')) {
|
||||
this.manualFetchLines = this.snapManualFetchLines(this.autoFetchLines());
|
||||
}
|
||||
|
||||
this.rpcPreferencesResolved = true;
|
||||
},
|
||||
|
||||
requestedFetchLines() {
|
||||
this.resolveRpcPreferences();
|
||||
if (this.paused)
|
||||
return this.fetchMode === 'manual' ? this.manualFetchLines : constants.FETCH_LINES_MAX;
|
||||
return this.fetchMode === 'manual' ? this.manualFetchLines : this.autoFetchLines();
|
||||
},
|
||||
|
||||
updateFillingState(beforeLength, reply, requestedLines) {
|
||||
if (!this.paused || this.resumeMerge) {
|
||||
this.fillingBuffer = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const cap = this.ingestCap();
|
||||
const grew = this.entries.length > beforeLength;
|
||||
if (this.entries.length >= cap || !grew) {
|
||||
this.fillingBuffer = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const rawCount =
|
||||
reply &&
|
||||
typeof reply.messages_received === 'number' &&
|
||||
isFinite(reply.messages_received) &&
|
||||
Math.floor(reply.messages_received) === reply.messages_received &&
|
||||
reply.messages_received >= 0
|
||||
? reply.messages_received
|
||||
: null;
|
||||
const effective =
|
||||
this.lastPollEffectiveLimit !== null ? this.lastPollEffectiveLimit : requestedLines;
|
||||
const shortRead = rawCount !== null && rawCount < effective;
|
||||
this.fillingBuffer = !shortRead && (rawCount === null || rawCount >= effective || grew);
|
||||
},
|
||||
|
||||
applyHash() {
|
||||
this.resolveRpcPreferences();
|
||||
|
||||
const entries = this.hashEntries();
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const key = entries[i].key;
|
||||
const val = entries[i].val;
|
||||
if (key === 'limit' || key === 'poll' || key === 'maxraw') continue;
|
||||
if (key === 'view') {
|
||||
if (val === 'advanced' || val === 'detailed') this.viewMode = 'detailed';
|
||||
else if (val === 'simple') this.viewMode = 'simple';
|
||||
@@ -732,6 +877,11 @@ return view.extend({
|
||||
|
||||
const epoch = this.pollEpoch;
|
||||
const resumeMerge = !!this.resumeMerge;
|
||||
const fetchLines = this.requestedFetchLines();
|
||||
const beforeLength = this.entries.length;
|
||||
this.lastPollRequestedLines = fetchLines;
|
||||
this.lastPollReturnedMessages = null;
|
||||
this.lastPollEffectiveLimit = null;
|
||||
const t0 = this.nowMs();
|
||||
let reply;
|
||||
let errored = false;
|
||||
@@ -739,9 +889,6 @@ return view.extend({
|
||||
/* Raw logd lines, not post-filter rows. Fetch a multiple of the
|
||||
* display limit so mixed syslog still fills the table; pause
|
||||
* reads the ring cap so the buffer can catch up. */
|
||||
const fetchLines = this.paused
|
||||
? constants.FETCH_LINES_MAX
|
||||
: Math.min(Math.max(this.rowLimit * 4, 100), constants.FETCH_LINES_MAX);
|
||||
reply = await callFwlivePoll({
|
||||
addresses: [String(fetchLines)]
|
||||
});
|
||||
@@ -756,12 +903,14 @@ return view.extend({
|
||||
|
||||
if (!reply || typeof reply !== 'object' || Array.isArray(reply)) {
|
||||
this.lastPollError = true;
|
||||
this.fillingBuffer = false;
|
||||
this.notePollRtt(rtt, true);
|
||||
this.updateAdaptiveBanner();
|
||||
return;
|
||||
}
|
||||
if (reply.error) {
|
||||
this.lastPollError = true;
|
||||
this.fillingBuffer = false;
|
||||
this.notePollRtt(rtt, true);
|
||||
this.updateAdaptiveBanner();
|
||||
return;
|
||||
@@ -769,18 +918,32 @@ return view.extend({
|
||||
const raw = reply.log;
|
||||
if (!Array.isArray(raw)) {
|
||||
this.lastPollError = true;
|
||||
this.fillingBuffer = false;
|
||||
this.notePollRtt(rtt, true);
|
||||
this.updateAdaptiveBanner();
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastPollError = false;
|
||||
this.serverAdaptive = reply.adaptive === 0 || reply.adaptive === false ? 0 : 1;
|
||||
if (reply.adaptive === 0 || reply.adaptive === false) this.serverAdaptive = 0;
|
||||
else if (reply.adaptive === 1 || reply.adaptive === true) this.serverAdaptive = 1;
|
||||
else this.serverAdaptive = undefined;
|
||||
this.serverTruncated = reply.truncated ? 1 : 0;
|
||||
this.serverShed =
|
||||
reply.shed && typeof reply.shed === 'object' && !Array.isArray(reply.shed)
|
||||
? reply.shed
|
||||
: null;
|
||||
this.lastPollReturnedMessages = raw.length;
|
||||
if (
|
||||
this.serverAdaptive === 1 &&
|
||||
typeof reply.effective_limit === 'number' &&
|
||||
isFinite(reply.effective_limit) &&
|
||||
Math.floor(reply.effective_limit) === reply.effective_limit &&
|
||||
reply.effective_limit >= 1 &&
|
||||
reply.effective_limit <= constants.FETCH_LINES_MAX
|
||||
) {
|
||||
this.lastPollEffectiveLimit = reply.effective_limit;
|
||||
}
|
||||
|
||||
this.notePollRtt(rtt, errored);
|
||||
this.updateAdaptiveBanner();
|
||||
@@ -803,6 +966,7 @@ return view.extend({
|
||||
rowLimit: this.rowLimit,
|
||||
fetchLinesMax: constants.FETCH_LINES_MAX
|
||||
});
|
||||
this.updateFillingState(beforeLength, reply, fetchLines);
|
||||
/* A stale request returns above. Keep this obligation until a current
|
||||
* request has actually applied the merged batch. */
|
||||
if (resumeMerge) this.resumeMerge = false;
|
||||
@@ -835,6 +999,7 @@ return view.extend({
|
||||
const bits = [];
|
||||
if (this.paused) {
|
||||
if (this.pauseBufferLoading) bits.push(_('loading buffer'));
|
||||
if (this.fillingBuffer) bits.push(_('buffer filling'));
|
||||
}
|
||||
|
||||
const cap = this.ingestCap();
|
||||
@@ -954,6 +1119,7 @@ return view.extend({
|
||||
},
|
||||
|
||||
resumePollingAfterVisible() {
|
||||
if (this.coordinatorDisposed) return;
|
||||
this.bumpPollEpoch();
|
||||
this.resetRttHistory();
|
||||
if (!this.pollFn) this.pollFn = this.pollData.bind(this);
|
||||
@@ -999,18 +1165,55 @@ return view.extend({
|
||||
this.visibilityBound = false;
|
||||
},
|
||||
|
||||
disposeCoordinator() {
|
||||
if (this.coordinatorDisposed) return;
|
||||
this.coordinatorDisposed = true;
|
||||
this.bumpPollEpoch();
|
||||
this.stopPollingForHidden();
|
||||
this.unbindVisibility();
|
||||
this.pollFn = null;
|
||||
this.pollRequestQueued = false;
|
||||
const queued = this.pollRequestQueuedWaiters;
|
||||
this.pollRequestQueuedWaiters = [];
|
||||
for (let i = 0; i < queued.length; i++) queued[i].resolve();
|
||||
},
|
||||
|
||||
updateAdaptiveBanner() {
|
||||
const el = document.getElementById('fwlive-adaptive');
|
||||
if (!el) return;
|
||||
if (!el.style) el.style = { display: '' };
|
||||
|
||||
if (!this.clientBackoffEnabled()) {
|
||||
el.style.display = 'none';
|
||||
el.textContent = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const parts = [];
|
||||
const mode = this.fetchMode === 'manual' ? _('Manual') : _('Auto');
|
||||
if (this.lastPollRequestedLines !== null && this.lastPollReturnedMessages !== null) {
|
||||
if (
|
||||
this.serverAdaptive === 1 &&
|
||||
this.lastPollEffectiveLimit !== null &&
|
||||
this.lastPollEffectiveLimit < this.lastPollRequestedLines
|
||||
) {
|
||||
parts.push(
|
||||
_(
|
||||
'%s · requested up to %d raw lines · server limited fetch to %d · %d firewall messages returned'
|
||||
).format(
|
||||
mode,
|
||||
this.lastPollRequestedLines,
|
||||
this.lastPollEffectiveLimit,
|
||||
this.lastPollReturnedMessages
|
||||
)
|
||||
);
|
||||
} else {
|
||||
parts.push(
|
||||
_('%s · requested up to %d raw lines · %d firewall messages returned').format(
|
||||
mode,
|
||||
this.lastPollRequestedLines,
|
||||
this.lastPollReturnedMessages
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (this.serverAdaptive === undefined) parts.push(_('Server protection state is unknown.'));
|
||||
else if (this.serverAdaptive === 0)
|
||||
parts.push(_('Server adaptive protection is disabled.'));
|
||||
if (this.degradedSampling)
|
||||
parts.push(_('Degraded — sampling (slow poll RTT; cadence reduced).'));
|
||||
if (this.serverShed && this.serverShed.limit)
|
||||
@@ -1030,6 +1233,22 @@ return view.extend({
|
||||
}
|
||||
},
|
||||
|
||||
fetchModeOptions() {
|
||||
return optionNodes([
|
||||
['auto', _('Auto')],
|
||||
['manual', _('Manual')]
|
||||
]);
|
||||
},
|
||||
|
||||
manualFetchLinesOptions() {
|
||||
const pairs = [];
|
||||
for (let i = 0; i < constants.MANUAL_FETCH_LINES_OPTIONS.length; i++) {
|
||||
const n = constants.MANUAL_FETCH_LINES_OPTIONS[i];
|
||||
pairs.push([String(n), String(n)]);
|
||||
}
|
||||
return optionNodes(pairs);
|
||||
},
|
||||
|
||||
summaryListText(label, values) {
|
||||
const lines = [label + ':'];
|
||||
if (!Array.isArray(values) || !values.length) {
|
||||
@@ -1284,6 +1503,8 @@ return view.extend({
|
||||
const label = document.getElementById('fwlive-watch-label');
|
||||
const pauseBtn = document.getElementById('fwlive-pause');
|
||||
const sel = document.getElementById('fwlive-limit');
|
||||
const modeSel = document.getElementById('fwlive-fetch-mode');
|
||||
const manualSel = document.getElementById('fwlive-manual-lines');
|
||||
const hostCb = document.getElementById('fwlive-show-hostnames');
|
||||
|
||||
if (map) {
|
||||
@@ -1297,6 +1518,11 @@ return view.extend({
|
||||
if (label) label.textContent = this.paused ? _('Paused') : _('Watching');
|
||||
if (pauseBtn) pauseBtn.textContent = this.paused ? _('Resume') : _('Pause');
|
||||
if (sel) sel.value = String(this.rowLimit);
|
||||
if (modeSel) modeSel.value = this.fetchMode;
|
||||
if (manualSel) {
|
||||
manualSel.value = String(this.manualFetchLines);
|
||||
manualSel.disabled = this.fetchMode !== 'manual';
|
||||
}
|
||||
if (hostCb) hostCb.checked = !!this.showHostnames;
|
||||
this.updateRowTintUi();
|
||||
},
|
||||
@@ -1312,6 +1538,29 @@ return view.extend({
|
||||
else this.renderRows(true);
|
||||
},
|
||||
|
||||
onFetchModeChange(ev) {
|
||||
const mode = ev && ev.target ? ev.target.value : '';
|
||||
if (constants.FETCH_MODE_OPTIONS.indexOf(mode) < 0) return;
|
||||
this.fetchMode = mode;
|
||||
if (mode === 'manual' && !this.manualFetchLinesExplicit) {
|
||||
this.manualFetchLines = this.snapManualFetchLines(this.autoFetchLines());
|
||||
this.manualFetchLinesExplicit = true;
|
||||
}
|
||||
this.saveFetchMode();
|
||||
if (mode === 'manual') this.saveManualFetchLines();
|
||||
this.updateStreamControlsUi();
|
||||
this.updateHash(this.readFilters());
|
||||
},
|
||||
|
||||
onManualFetchLinesChange(ev) {
|
||||
const n = parseInt(ev && ev.target ? ev.target.value : '', 10);
|
||||
if (constants.MANUAL_FETCH_LINES_OPTIONS.indexOf(n) < 0) return;
|
||||
this.manualFetchLines = n;
|
||||
this.manualFetchLinesExplicit = true;
|
||||
this.saveManualFetchLines();
|
||||
this.updateHash(this.readFilters());
|
||||
},
|
||||
|
||||
onPauseClick() {
|
||||
const wasPaused = this.paused;
|
||||
this.paused = !this.paused;
|
||||
@@ -1332,6 +1581,7 @@ return view.extend({
|
||||
}
|
||||
|
||||
if (wasPaused && !this.paused) {
|
||||
this.fillingBuffer = false;
|
||||
this.followLive = true;
|
||||
/* Merge pause buffer with the first live poll — do not replace. */
|
||||
this.resumeMerge = true;
|
||||
@@ -1761,6 +2011,13 @@ return view.extend({
|
||||
const limitSel = document.getElementById('fwlive-limit');
|
||||
if (limitSel) limitSel.addEventListener('change', this.onRowLimitChange.bind(this));
|
||||
|
||||
const modeSel = document.getElementById('fwlive-fetch-mode');
|
||||
if (modeSel) modeSel.addEventListener('change', this.onFetchModeChange.bind(this));
|
||||
|
||||
const manualSel = document.getElementById('fwlive-manual-lines');
|
||||
if (manualSel)
|
||||
manualSel.addEventListener('change', this.onManualFetchLinesChange.bind(this));
|
||||
|
||||
const hostCb = document.getElementById('fwlive-show-hostnames');
|
||||
if (hostCb) hostCb.addEventListener('change', this.onShowHostnamesChange.bind(this));
|
||||
|
||||
@@ -1779,7 +2036,7 @@ return view.extend({
|
||||
},
|
||||
|
||||
requestPoll() {
|
||||
if (this.isTabHidden()) return Promise.resolve();
|
||||
if (this.coordinatorDisposed || this.isTabHidden()) return Promise.resolve();
|
||||
|
||||
const waiter = {};
|
||||
const promise = new Promise(function (resolve) {
|
||||
@@ -1836,7 +2093,7 @@ return view.extend({
|
||||
|
||||
/* If visibility changed while the request was active, retain the
|
||||
* queued intent until the visible catch-up can start it. */
|
||||
if (this.pollRequestQueued && !this.isTabHidden()) {
|
||||
if (this.pollRequestQueued && !this.coordinatorDisposed && !this.isTabHidden()) {
|
||||
const queued = this.pollRequestQueuedWaiters;
|
||||
this.pollRequestQueuedWaiters = [];
|
||||
this.pollRequestQueued = false;
|
||||
@@ -1877,6 +2134,9 @@ return view.extend({
|
||||
},
|
||||
|
||||
load() {
|
||||
/* RPC-affecting preferences must precede poll registration and the first
|
||||
* request; filter widgets still restore in addFooter after render. */
|
||||
this.resolveRpcPreferences();
|
||||
this.bindVisibility();
|
||||
if (!this.pollFn) {
|
||||
this.pollFn = this.pollData.bind(this);
|
||||
@@ -1887,15 +2147,7 @@ return view.extend({
|
||||
window.addEventListener(
|
||||
'pagehide',
|
||||
function () {
|
||||
this.unbindVisibility();
|
||||
if (this.pollFn) {
|
||||
try {
|
||||
poll.remove(this.pollFn);
|
||||
} catch (e) {
|
||||
/* poll gone */
|
||||
}
|
||||
this.pollFn = null;
|
||||
}
|
||||
this.disposeCoordinator();
|
||||
if (this.filterInputTimer) {
|
||||
clearTimeout(this.filterInputTimer);
|
||||
this.filterInputTimer = null;
|
||||
@@ -2077,6 +2329,36 @@ return view.extend({
|
||||
this.limitSelectOptions()
|
||||
)
|
||||
]),
|
||||
E('label', { 'class': 'fwlive-display-ctl', 'for': 'fwlive-fetch-mode' }, [
|
||||
_('Fetch budget'),
|
||||
E(
|
||||
'select',
|
||||
{
|
||||
'id': 'fwlive-fetch-mode',
|
||||
'class': 'cbi-input-select',
|
||||
'aria-controls': 'fwlive-manual-lines'
|
||||
},
|
||||
this.fetchModeOptions()
|
||||
)
|
||||
]),
|
||||
E(
|
||||
'label',
|
||||
{ 'class': 'fwlive-display-ctl', 'for': 'fwlive-manual-lines' },
|
||||
[
|
||||
_('Maximum raw lines'),
|
||||
E(
|
||||
'select',
|
||||
{
|
||||
'id': 'fwlive-manual-lines',
|
||||
'class': 'cbi-input-select',
|
||||
'title': _(
|
||||
'Manual still uses server protection and poll cadence'
|
||||
)
|
||||
},
|
||||
this.manualFetchLinesOptions()
|
||||
)
|
||||
]
|
||||
),
|
||||
E('label', { 'class': 'fwlive-display-ctl' }, [
|
||||
E('input', {
|
||||
'id': 'fwlive-row-tint-toggle',
|
||||
@@ -2236,6 +2518,16 @@ return view.extend({
|
||||
'Display options on the bar set Limit, row tint, palette, and hostnames.'
|
||||
)
|
||||
]),
|
||||
E('li', {}, [
|
||||
_(
|
||||
'Fetch budget controls raw log lines per poll. Auto derives from Limit; Manual selects a bounded maximum.'
|
||||
)
|
||||
]),
|
||||
E('li', {}, [
|
||||
_(
|
||||
'Manual still uses server protection and poll cadence; it changes the fetch budget, not the polling interval.'
|
||||
)
|
||||
]),
|
||||
E('li', {}, [
|
||||
_(
|
||||
'For a responsive table on a weak device, keep Limit at 250 rows or below. The weak-device cap affects rendered rows; the buffer can still retain more.'
|
||||
@@ -2306,7 +2598,6 @@ return view.extend({
|
||||
this.hostnameFailed = new Map();
|
||||
this.resolveGeneration = 0;
|
||||
this.lastPollError = false;
|
||||
this.applyRowLimit(this.readRowLimit());
|
||||
this.applyHash();
|
||||
this.attachHandlers();
|
||||
this.applyRowTintMode();
|
||||
|
||||
@@ -790,3 +790,41 @@ msgstr "Häufigste Regeln"
|
||||
|
||||
msgid "Top talkers"
|
||||
msgstr "Häufigste Absender"
|
||||
|
||||
msgid "Auto"
|
||||
msgstr "Auto"
|
||||
|
||||
msgid "Fetch budget"
|
||||
msgstr "Fetch budget"
|
||||
|
||||
msgid "Maximum raw lines"
|
||||
msgstr "Maximum raw lines"
|
||||
|
||||
msgid "Manual"
|
||||
msgstr "Manual"
|
||||
|
||||
msgid "Manual still uses server protection and poll cadence"
|
||||
msgstr "Manual still uses server protection and poll cadence"
|
||||
|
||||
msgid "%s · requested up to %d raw lines · %d firewall messages returned"
|
||||
msgstr "%s · requested up to %d raw lines · %d firewall messages returned"
|
||||
|
||||
msgid "%s · requested up to %d raw lines · server limited fetch to %d · %d firewall messages returned"
|
||||
msgstr "%s · requested up to %d raw lines · server limited fetch to %d · %d firewall messages returned"
|
||||
|
||||
msgid "Server adaptive protection is disabled."
|
||||
msgstr "Server adaptive protection is disabled."
|
||||
|
||||
msgid "Server protection state is unknown."
|
||||
msgstr "Server protection state is unknown."
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2250
|
||||
msgid "Fetch budget controls raw log lines per poll. Auto derives from Limit; Manual selects a bounded maximum."
|
||||
msgstr "Fetch budget controls raw log lines per poll. Auto derives from Limit; Manual selects a bounded maximum."
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2255
|
||||
msgid "Manual still uses server protection and poll cadence; it changes the fetch budget, not the polling interval."
|
||||
msgstr "Manual still uses server protection and poll cadence; it changes the fetch budget, not the polling interval."
|
||||
|
||||
msgid "buffer filling"
|
||||
msgstr "buffer filling"
|
||||
@@ -795,3 +795,41 @@ msgstr "Частые правила"
|
||||
|
||||
msgid "Top talkers"
|
||||
msgstr "Частые источники"
|
||||
|
||||
msgid "Auto"
|
||||
msgstr "Auto"
|
||||
|
||||
msgid "Fetch budget"
|
||||
msgstr "Fetch budget"
|
||||
|
||||
msgid "Maximum raw lines"
|
||||
msgstr "Maximum raw lines"
|
||||
|
||||
msgid "Manual"
|
||||
msgstr "Manual"
|
||||
|
||||
msgid "Manual still uses server protection and poll cadence"
|
||||
msgstr "Manual still uses server protection and poll cadence"
|
||||
|
||||
msgid "%s · requested up to %d raw lines · %d firewall messages returned"
|
||||
msgstr "%s · requested up to %d raw lines · %d firewall messages returned"
|
||||
|
||||
msgid "%s · requested up to %d raw lines · server limited fetch to %d · %d firewall messages returned"
|
||||
msgstr "%s · requested up to %d raw lines · server limited fetch to %d · %d firewall messages returned"
|
||||
|
||||
msgid "Server adaptive protection is disabled."
|
||||
msgstr "Server adaptive protection is disabled."
|
||||
|
||||
msgid "Server protection state is unknown."
|
||||
msgstr "Server protection state is unknown."
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2250
|
||||
msgid "Fetch budget controls raw log lines per poll. Auto derives from Limit; Manual selects a bounded maximum."
|
||||
msgstr "Fetch budget controls raw log lines per poll. Auto derives from Limit; Manual selects a bounded maximum."
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2255
|
||||
msgid "Manual still uses server protection and poll cadence; it changes the fetch budget, not the polling interval."
|
||||
msgstr "Manual still uses server protection and poll cadence; it changes the fetch budget, not the polling interval."
|
||||
|
||||
msgid "buffer filling"
|
||||
msgstr "buffer filling"
|
||||
@@ -735,3 +735,53 @@ msgstr ""
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1959
|
||||
msgid "Show rows"
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1134
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1182
|
||||
msgid "Auto"
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2283
|
||||
msgid "Fetch budget"
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2295
|
||||
msgid "Maximum raw lines"
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1134
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1183
|
||||
msgid "Manual"
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2301
|
||||
msgid "Manual still uses server protection and poll cadence"
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1151
|
||||
msgid "%s · requested up to %d raw lines · %d firewall messages returned"
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1142
|
||||
msgid "%s · requested up to %d raw lines · server limited fetch to %d · %d firewall messages returned"
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1160
|
||||
msgid "Server adaptive protection is disabled."
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:1159
|
||||
msgid "Server protection state is unknown."
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2250
|
||||
msgid "Fetch budget controls raw log lines per poll. Auto derives from Limit; Manual selects a bounded maximum."
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2255
|
||||
msgid "Manual still uses server protection and poll cadence; it changes the fetch budget, not the polling interval."
|
||||
msgstr ""
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:997
|
||||
msgid "buffer filling"
|
||||
msgstr ""
|
||||
@@ -759,3 +759,41 @@ msgstr "主要规则"
|
||||
|
||||
msgid "Top talkers"
|
||||
msgstr "主要通信方"
|
||||
|
||||
msgid "Auto"
|
||||
msgstr "Auto"
|
||||
|
||||
msgid "Fetch budget"
|
||||
msgstr "Fetch budget"
|
||||
|
||||
msgid "Maximum raw lines"
|
||||
msgstr "Maximum raw lines"
|
||||
|
||||
msgid "Manual"
|
||||
msgstr "Manual"
|
||||
|
||||
msgid "Manual still uses server protection and poll cadence"
|
||||
msgstr "Manual still uses server protection and poll cadence"
|
||||
|
||||
msgid "%s · requested up to %d raw lines · %d firewall messages returned"
|
||||
msgstr "%s · requested up to %d raw lines · %d firewall messages returned"
|
||||
|
||||
msgid "%s · requested up to %d raw lines · server limited fetch to %d · %d firewall messages returned"
|
||||
msgstr "%s · requested up to %d raw lines · server limited fetch to %d · %d firewall messages returned"
|
||||
|
||||
msgid "Server adaptive protection is disabled."
|
||||
msgstr "Server adaptive protection is disabled."
|
||||
|
||||
msgid "Server protection state is unknown."
|
||||
msgstr "Server protection state is unknown."
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2250
|
||||
msgid "Fetch budget controls raw log lines per poll. Auto derives from Limit; Manual selects a bounded maximum."
|
||||
msgstr "Fetch budget controls raw log lines per poll. Auto derives from Limit; Manual selects a bounded maximum."
|
||||
|
||||
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js:2255
|
||||
msgid "Manual still uses server protection and poll cadence; it changes the fetch budget, not the polling interval."
|
||||
msgstr "Manual still uses server protection and poll cadence; it changes the fetch budget, not the polling interval."
|
||||
|
||||
msgid "buffer filling"
|
||||
msgstr "buffer filling"
|
||||
@@ -443,13 +443,14 @@ fwlive_adaptive_is_hot() {
|
||||
# Merge adaptive siblings into a JSON object ending with }. A successful
|
||||
# filter already carries the exact messages_received count; do not append a
|
||||
# duplicate key in that case.
|
||||
# Args: json_body shed_flag limit truncated messages_received
|
||||
# Args: json_body shed_flag limit truncated messages_received success_flag
|
||||
fwlive_adaptive_merge_reply() {
|
||||
_body=$1
|
||||
_shed=$2
|
||||
_limit=$3
|
||||
_trunc=$4
|
||||
_msgs=$5
|
||||
_success=${6:-0}
|
||||
_adapt=1
|
||||
fwlive_adaptive_enabled || _adapt=0
|
||||
case "$_body" in
|
||||
@@ -457,6 +458,8 @@ fwlive_adaptive_merge_reply() {
|
||||
*) printf '%s' "$_body"; return 0 ;;
|
||||
esac
|
||||
_base=${_body%\}}
|
||||
_effective=
|
||||
[ "$_success" = 1 ] && _effective=",\"effective_limit\":$_limit"
|
||||
_has_msgs=0
|
||||
case "$_body" in
|
||||
*',"messages_received":'*) _has_msgs=1 ;;
|
||||
@@ -471,18 +474,18 @@ fwlive_adaptive_merge_reply() {
|
||||
fi
|
||||
if [ "$_shed" = 1 ]; then
|
||||
if [ "$_has_msgs" = 1 ]; then
|
||||
printf '%s,"adaptive":1,"truncated":%s,"shed":{"level":"hot","limit":%s}}' \
|
||||
"$_base" "$_trunc" "$_limit"
|
||||
printf '%s,"adaptive":1%s,"truncated":%s,"shed":{"level":"hot","limit":%s}}' \
|
||||
"$_base" "$_effective" "$_trunc" "$_limit"
|
||||
else
|
||||
printf '%s,"adaptive":1,"messages_received":%s,"truncated":%s,"shed":{"level":"hot","limit":%s}}' \
|
||||
"$_base" "$_msgs" "$_trunc" "$_limit"
|
||||
printf '%s,"adaptive":1,"messages_received":%s%s,"truncated":%s,"shed":{"level":"hot","limit":%s}}' \
|
||||
"$_base" "$_msgs" "$_effective" "$_trunc" "$_limit"
|
||||
fi
|
||||
else
|
||||
if [ "$_has_msgs" = 1 ]; then
|
||||
printf '%s,"adaptive":1,"truncated":%s}' "$_base" "$_trunc"
|
||||
printf '%s,"adaptive":1%s,"truncated":%s}' "$_base" "$_effective" "$_trunc"
|
||||
else
|
||||
printf '%s,"adaptive":1,"messages_received":%s,"truncated":%s}' \
|
||||
"$_base" "$_msgs" "$_trunc"
|
||||
printf '%s,"adaptive":1,"messages_received":%s%s,"truncated":%s}' \
|
||||
"$_base" "$_msgs" "$_effective" "$_trunc"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -440,7 +440,7 @@ fetch_firewall_logs() {
|
||||
# Do not record ~0 ms as cold: failure is not healthy fast processing
|
||||
# and must not clear an existing hot/shed cap (#329 Hermes Q1).
|
||||
out='{"log":[],"error":"log_read_failed"}'
|
||||
fwlive_adaptive_merge_reply "$out" "$shed_flag" "$lines" 0 0
|
||||
fwlive_adaptive_merge_reply "$out" "$shed_flag" "$lines" 0 0 0
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -486,7 +486,7 @@ fetch_firewall_logs() {
|
||||
_trunc=0
|
||||
[ "$shed_flag" = 1 ] && _trunc=1
|
||||
[ "$lines" -lt "$requested" ] && _trunc=1
|
||||
fwlive_adaptive_merge_reply "$out" "$shed_flag" "$lines" "$_trunc" 0
|
||||
fwlive_adaptive_merge_reply "$out" "$shed_flag" "$lines" "$_trunc" 0 "$_filter_ok"
|
||||
}
|
||||
|
||||
poll_logs() {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=mihomo-meta
|
||||
PKG_VERSION:=1.19.30
|
||||
PKG_RELEASE:=14
|
||||
PKG_VERSION:=1.19.31
|
||||
PKG_RELEASE:=15
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git
|
||||
PKG_SOURCE_VERSION:=v1.19.30
|
||||
PKG_SOURCE_VERSION:=v1.19.31
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
||||
PKG_LICENSE:=GPL3.0+
|
||||
@@ -18,7 +18,7 @@ PKG_BUILD_DEPENDS:=golang/host
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_BUILD_FLAGS:=no-mips16
|
||||
|
||||
PKG_BUILD_VERSION:=v1.19.30
|
||||
PKG_BUILD_VERSION:=v1.19.31
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_TIME:=$(shell date -u -Iseconds)
|
||||
|
||||
|
||||
Reference in new issue
Block a user