💐 Sync 2026-09-01 02:40:52
Merge-upstream / merge (push) Canceled after 0s

This commit is contained in:
github-actions[bot] committed 2026-09-01 02:40:52 +08:00
1 parent 2a19f43c9e
commit 8cbf526882
13 files changed
+503 -220

No files matched your search

+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-mosdns PKG_NAME:=luci-app-mosdns
PKG_VERSION:=1.7.11 PKG_VERSION:=1.7.12
PKG_RELEASE:=19 PKG_RELEASE:=20
LUCI_TITLE:=LuCI Support for mosdns LUCI_TITLE:=LuCI Support for mosdns
LUCI_PKGARCH:=all LUCI_PKGARCH:=all
@@ -48,6 +48,10 @@ let nodeStats;
let nodeTop; let nodeTop;
let nodeLogs; let nodeLogs;
let autoStatusBadge; let autoStatusBadge;
let statsElements = null;
let currentBadgeState = null;
let lastTopJson = '';
let lastLogsJson = '';
const cleanIP = ip => { const cleanIP = ip => {
if (!ip) return '-'; if (!ip) return '-';
@@ -66,9 +70,10 @@ const injectStyles = () => {
'.mosdns-stat-card .title-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; font-size: 0.85rem; opacity: 0.75; font-weight: 500; }', '.mosdns-stat-card .title-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; font-size: 0.85rem; opacity: 0.75; font-weight: 500; }',
'.mosdns-stat-card .metric-val { font-size: 1.85rem; font-weight: 700; line-height: 1.1; letter-spacing: -0.02em; }', '.mosdns-stat-card .metric-val { font-size: 1.85rem; font-weight: 700; line-height: 1.1; letter-spacing: -0.02em; }',
'.mosdns-stat-card .subtext { font-size: 0.8rem; opacity: 0.6; margin-top: 0.4rem; }', '.mosdns-stat-card .subtext { font-size: 0.8rem; opacity: 0.6; margin-top: 0.4rem; }',
'.mosdns-sparkline-wrap { margin-top: 0.5rem; height: 44px; position: relative; overflow: visible; display: flex; align-items: flex-end; }', '.mosdns-sparkline-wrap { margin-top: 0.5rem; height: 44px; position: relative; overflow: visible; display: flex; align-items: flex-end; touch-action: none; -webkit-user-select: none; user-select: none; }',
'.mosdns-sparkline { width: 100%; height: 100%; display: block; overflow: visible; }', '.mosdns-sparkline { width: 100%; height: 100%; display: block; overflow: visible; }',
'.mosdns-sparkline-tooltip { position: absolute; pointer-events: none; z-index: 20; padding: 0.25rem 0.5rem; border-radius: 5px; background: var(--cbi-section-bg, #fff); border: 1px solid rgba(0,0,0,0.12); box-shadow: 0 3px 10px rgba(0,0,0,0.12); line-height: 1.25; text-align: center; white-space: nowrap; transition: opacity 0.15s ease; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }', '.mosdns-sparkline-tooltip { position: absolute; pointer-events: none; z-index: 20; padding: 0.25rem 0.5rem; border-radius: 5px; background: var(--cbi-section-bg, #fff); border: 1px solid rgba(0,0,0,0.12); box-shadow: 0 3px 10px rgba(0,0,0,0.12); line-height: 1.25; text-align: center; white-space: nowrap; transition: opacity 0.15s ease; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }',
'.spark-hover-hitbox { touch-action: none; -webkit-user-select: none; user-select: none; cursor: crosshair; }',
'.mosdns-rank-panel { background: var(--cbi-section-bg, #fff); border: 1px solid rgba(0,0,0,0.08); border-radius: 8px; padding: 1rem 1.1rem; box-shadow: 0 2px 6px rgba(0,0,0,0.03); }', '.mosdns-rank-panel { background: var(--cbi-section-bg, #fff); border: 1px solid rgba(0,0,0,0.08); border-radius: 8px; padding: 1rem 1.1rem; box-shadow: 0 2px 6px rgba(0,0,0,0.03); }',
'.mosdns-rank-panel h4 { margin: 0 0 0.85rem 0; font-size: 0.95rem; font-weight: 600; display: flex; align-items: center; justify-content: space-between; }', '.mosdns-rank-panel h4 { margin: 0 0 0.85rem 0; font-size: 0.95rem; font-weight: 600; display: flex; align-items: center; justify-content: space-between; }',
'.mosdns-rank-item { position: relative; overflow: hidden; border-radius: 6px; padding: 0.35rem 0.65rem; display: flex; justify-content: space-between; align-items: center; background: rgba(125,125,125,0.03); border: 1px solid rgba(125,125,125,0.08); margin-bottom: 0.35rem; }', '.mosdns-rank-item { position: relative; overflow: hidden; border-radius: 6px; padding: 0.35rem 0.65rem; display: flex; justify-content: space-between; align-items: center; background: rgba(125,125,125,0.03); border: 1px solid rgba(125,125,125,0.08); margin-bottom: 0.35rem; }',
@@ -143,7 +148,15 @@ const getLatencyClass = elapsedMs => {
const updateLiveStatusBadge = () => { const updateLiveStatusBadge = () => {
if (!autoStatusBadge) return; if (!autoStatusBadge) return;
if (pageIdx === 0 && !searchVal && !isUserPaused) { const isLive = (pageIdx === 0 && !searchVal && !isUserPaused);
const targetState = isLive ? 'live' : ('paused:' + pageIdx);
if (currentBadgeState === targetState)
return;
currentBadgeState = targetState;
if (isLive) {
dom.content(autoStatusBadge, [ dom.content(autoStatusBadge, [
E('span', { class: 'mosdns-badge badge-teal badge-pulse' }, _('● Live Auto-refresh')) E('span', { class: 'mosdns-badge badge-teal badge-pulse' }, _('● Live Auto-refresh'))
]); ]);
@@ -154,47 +167,17 @@ const updateLiveStatusBadge = () => {
} }
}; };
const createSparklineSVG = (dataItems, strokeColor, fillGradId, maxScale) => { const createSparklineSVG = (strokeColor, fillGradId) => {
const width = 300; const width = 300;
const height = 44; const height = 44;
const padTop = 4; const padTop = 4;
const padBottom = 2; const padBottom = 2;
const drawHeight = height - padTop - padBottom; const drawHeight = height - padTop - padBottom;
let items = (dataItems && dataItems.length > 0) ? dataItems : []; let coords = [];
if (!items.length) { let isHovered = false;
items = new Array(24).fill(0).map(() => ({ time: '', val: 0 })); let currentIdx = -1;
} let hideTimer = null;
if (items.length < 2) {
items = [items[0] || { time: '', val: 0 }, items[0] || { time: '', val: 0 }];
}
const vals = items.map(i => i.val || 0);
const maxVal = maxScale || Math.max(...vals, 1);
const len = items.length;
const coords = items.map((item, idx) => {
const x = (idx / (len - 1)) * width;
const y = height - padBottom - ((item.val || 0) / maxVal) * drawHeight;
return { x, y, time: item.time, val: item.val || 0 };
});
let pathD = 'M ' + coords[0].x.toFixed(1) + ',' + coords[0].y.toFixed(1);
for (let i = 0; i < coords.length - 1; i++) {
const p0 = coords[i === 0 ? 0 : i - 1];
const p1 = coords[i];
const p2 = coords[i + 1];
const p3 = coords[i + 2 < coords.length ? i + 2 : i + 1];
const cp1x = p1.x + (p2.x - p0.x) / 6;
const cp1y = p1.y + (p2.y - p0.y) / 6;
const cp2x = p2.x - (p3.x - p1.x) / 6;
const cp2y = p2.y - (p3.y - p1.y) / 6;
pathD += ' C ' + cp1x.toFixed(1) + ',' + cp1y.toFixed(1) + ' ' + cp2x.toFixed(1) + ',' + cp2y.toFixed(1) + ' ' + p2.x.toFixed(1) + ',' + p2.y.toFixed(1);
}
const areaD = pathD + ' L ' + width + ',' + height + ' L 0,' + height + ' Z';
const svgContainer = E('div', { class: 'mosdns-sparkline-wrap' }); const svgContainer = E('div', { class: 'mosdns-sparkline-wrap' });
svgContainer.innerHTML = svgContainer.innerHTML =
@@ -205,27 +188,26 @@ const createSparklineSVG = (dataItems, strokeColor, fillGradId, maxScale) => {
'<stop offset="100%" stop-color="' + strokeColor + '" stop-opacity="0.02" />' + '<stop offset="100%" stop-color="' + strokeColor + '" stop-opacity="0.02" />' +
'</linearGradient>' + '</linearGradient>' +
'</defs>' + '</defs>' +
'<path d="' + areaD + '" fill="url(#' + fillGradId + ')" />' + '<path class="spark-area-path" fill="url(#' + fillGradId + ')" />' +
'<path d="' + pathD + '" fill="none" stroke="' + strokeColor + '" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />' + '<path class="spark-line-path" fill="none" stroke="' + strokeColor + '" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />' +
'<g class="spark-hover-group" style="display: none;">' + '<g class="spark-hover-group" style="display: none;">' +
'<line class="spark-hover-line" x1="0" y1="' + padTop + '" x2="0" y2="' + (height - padBottom) + '" stroke="' + strokeColor + '" stroke-width="1.2" stroke-dasharray="2 2" opacity="0.6" />' + '<line class="spark-hover-line" x1="0" y1="' + padTop + '" x2="0" y2="' + (height - padBottom) + '" stroke="' + strokeColor + '" stroke-width="1.2" stroke-dasharray="2 2" opacity="0.6" />' +
'<circle class="spark-hover-dot" cx="0" cy="0" r="3.5" fill="' + strokeColor + '" stroke="#fff" stroke-width="1.5" />' + '<circle class="spark-hover-dot" cx="0" cy="0" r="3.5" fill="' + strokeColor + '" stroke="#fff" stroke-width="1.5" />' +
'</g>' + '</g>' +
'<rect width="' + width + '" height="' + height + '" fill="transparent" class="spark-hover-hitbox" style="cursor: crosshair;" />' + '<rect width="' + width + '" height="' + height + '" fill="transparent" class="spark-hover-hitbox" />' +
'</svg>' + '</svg>' +
'<div class="mosdns-sparkline-tooltip" style="display: none;"></div>'; '<div class="mosdns-sparkline-tooltip" style="display: none;"></div>';
const areaPath = svgContainer.querySelector('.spark-area-path');
const linePath = svgContainer.querySelector('.spark-line-path');
const hoverGroup = svgContainer.querySelector('.spark-hover-group'); const hoverGroup = svgContainer.querySelector('.spark-hover-group');
const hoverLine = svgContainer.querySelector('.spark-hover-line'); const hoverLine = svgContainer.querySelector('.spark-hover-line');
const hoverDot = svgContainer.querySelector('.spark-hover-dot'); const hoverDot = svgContainer.querySelector('.spark-hover-dot');
const hitbox = svgContainer.querySelector('.spark-hover-hitbox'); const hitbox = svgContainer.querySelector('.spark-hover-hitbox');
const tooltip = svgContainer.querySelector('.mosdns-sparkline-tooltip'); const tooltip = svgContainer.querySelector('.mosdns-sparkline-tooltip');
const onMove = e => { const renderTooltipAndHover = idx => {
const rect = svgContainer.getBoundingClientRect(); if (idx < 0 || idx >= coords.length) return;
const mouseX = e.clientX - rect.left;
const ratio = Math.max(0, Math.min(1, mouseX / rect.width));
const idx = Math.round(ratio * (len - 1));
const coord = coords[idx]; const coord = coords[idx];
if (!coord) return; if (!coord) return;
@@ -251,10 +233,14 @@ const createSparklineSVG = (dataItems, strokeColor, fillGradId, maxScale) => {
'<div style="font-size: 0.72rem; opacity: 0.75; margin-top: 0.15rem;">' + timeStr + '</div>'; '<div style="font-size: 0.72rem; opacity: 0.75; margin-top: 0.15rem;">' + timeStr + '</div>';
tooltip.style.display = 'block'; tooltip.style.display = 'block';
const tooltipX = (coord.x / width) * rect.width; const rect = svgContainer.getBoundingClientRect();
const containerWidth = rect.width || width;
const tooltipX = (coord.x / width) * containerWidth;
const ratio = coord.x / width;
if (ratio > 0.65) { if (ratio > 0.65) {
tooltip.style.left = 'auto'; tooltip.style.left = 'auto';
tooltip.style.right = (rect.width - tooltipX + 8) + 'px'; tooltip.style.right = (containerWidth - tooltipX + 8) + 'px';
} else { } else {
tooltip.style.left = (tooltipX + 8) + 'px'; tooltip.style.left = (tooltipX + 8) + 'px';
tooltip.style.right = 'auto'; tooltip.style.right = 'auto';
@@ -262,21 +248,203 @@ const createSparklineSVG = (dataItems, strokeColor, fillGradId, maxScale) => {
tooltip.style.top = '-6px'; tooltip.style.top = '-6px';
}; };
const onLeave = () => { const update = (dataItems, maxScale) => {
hoverGroup.style.display = 'none'; let items = (dataItems && dataItems.length > 0) ? dataItems : [];
tooltip.style.display = 'none'; if (!items.length) {
items = new Array(24).fill(0).map(() => ({ time: '', val: 0 }));
}
if (items.length < 2) {
items = [items[0] || { time: '', val: 0 }, items[0] || { time: '', val: 0 }];
}
const vals = items.map(i => i.val || 0);
const maxVal = maxScale || Math.max(...vals, 1);
const len = items.length;
coords = items.map((item, idx) => {
const x = (idx / (len - 1)) * width;
const y = height - padBottom - ((item.val || 0) / maxVal) * drawHeight;
return { x, y, time: item.time, val: item.val || 0 };
});
let pathD = 'M ' + coords[0].x.toFixed(1) + ',' + coords[0].y.toFixed(1);
for (let i = 0; i < coords.length - 1; i++) {
const p0 = coords[i === 0 ? 0 : i - 1];
const p1 = coords[i];
const p2 = coords[i + 1];
const p3 = coords[i + 2 < coords.length ? i + 2 : i + 1];
const cp1x = p1.x + (p2.x - p0.x) / 6;
const cp1y = p1.y + (p2.y - p0.y) / 6;
const cp2x = p2.x - (p3.x - p1.x) / 6;
const cp2y = p2.y - (p3.y - p1.y) / 6;
pathD += ' C ' + cp1x.toFixed(1) + ',' + cp1y.toFixed(1) + ' ' + cp2x.toFixed(1) + ',' + cp2y.toFixed(1) + ' ' + p2.x.toFixed(1) + ',' + p2.y.toFixed(1);
}
const areaD = pathD + ' L ' + width + ',' + height + ' L 0,' + height + ' Z';
areaPath.setAttribute('d', areaD);
linePath.setAttribute('d', pathD);
if (isHovered && currentIdx >= 0) {
renderTooltipAndHover(currentIdx);
}
}; };
hitbox.addEventListener('mousemove', onMove); const onPositionMove = clientX => {
hitbox.addEventListener('mouseleave', onLeave); if (hideTimer) {
clearTimeout(hideTimer);
hideTimer = null;
}
const rect = svgContainer.getBoundingClientRect();
if (!rect.width || !coords.length) return;
const mouseX = clientX - rect.left;
const ratio = Math.max(0, Math.min(1, mouseX / rect.width));
const idx = Math.round(ratio * (coords.length - 1));
currentIdx = idx;
isHovered = true;
renderTooltipAndHover(idx);
};
const onLeave = (delay = 0) => {
if (delay > 0) {
if (hideTimer) clearTimeout(hideTimer);
hideTimer = setTimeout(() => {
isHovered = false;
currentIdx = -1;
hoverGroup.style.display = 'none';
tooltip.style.display = 'none';
hideTimer = null;
}, delay);
} else {
if (hideTimer) {
clearTimeout(hideTimer);
hideTimer = null;
}
isHovered = false;
currentIdx = -1;
hoverGroup.style.display = 'none';
tooltip.style.display = 'none';
}
};
hitbox.addEventListener('mousemove', e => onPositionMove(e.clientX));
hitbox.addEventListener('mouseenter', e => onPositionMove(e.clientX));
hitbox.addEventListener('mouseleave', () => onLeave(0));
hitbox.addEventListener('touchstart', e => {
if (e.touches && e.touches.length > 0) {
onPositionMove(e.touches[0].clientX);
}
}, { passive: true });
hitbox.addEventListener('touchmove', e => {
if (e.touches && e.touches.length > 0) {
onPositionMove(e.touches[0].clientX);
}
}, { passive: true });
hitbox.addEventListener('touchend', () => onLeave(1500), { passive: true });
hitbox.addEventListener('touchcancel', () => onLeave(0), { passive: true });
svgContainer.update = update;
return svgContainer; return svgContainer;
}; };
const renderOverviewStats = (stats, historyData) => { const createOverviewStatsDOM = () => {
const metricTotal = E('div', { class: 'metric-val' }, '-');
const subtextTotal = E('div', { class: 'subtext' }, '-');
const sparklineTotal = createSparklineSVG('#3b82f6', 'spark-grad-total');
const badgeBlocked = E('span', { class: 'mosdns-badge badge-danger' }, '-');
const metricBlocked = E('div', { class: 'metric-val', style: 'color: #dc2626;' }, '-');
const sparklineBlocked = createSparklineSVG('#dc2626', 'spark-grad-blocked');
const badgeCached = E('span', { class: 'mosdns-badge badge-teal' }, '-');
const metricCached = E('div', { class: 'metric-val', style: 'color: #059669;' }, '-');
const sparklineCached = createSparklineSVG('#059669', 'spark-grad-cached');
const metricLatency = E('div', { class: 'metric-val', style: 'color: #2563eb;' }, '-');
const subtextLatency = E('div', { class: 'subtext' }, _('Per-query speed'));
const grid = E('div', { class: 'mosdns-grid' }, [
E('div', { class: 'mosdns-stat-card' }, [
E('div', {}, [
E('div', { class: 'title-row' }, [
E('span', {}, _('DNS Queries Total')),
E('span', { class: 'mosdns-badge badge-teal badge-pulse' }, _('● Live'))
]),
metricTotal,
subtextTotal
]),
sparklineTotal
]),
E('div', { class: 'mosdns-stat-card' }, [
E('div', {}, [
E('div', { class: 'title-row' }, [
E('span', {}, _('Blocked by Filters')),
badgeBlocked
]),
metricBlocked
]),
sparklineBlocked
]),
E('div', { class: 'mosdns-stat-card' }, [
E('div', {}, [
E('div', { class: 'title-row' }, [
E('span', {}, _('Cached Queries')),
badgeCached
]),
metricCached
]),
sparklineCached
]),
E('div', { class: 'mosdns-stat-card' }, [
E('div', {}, [
E('div', { class: 'title-row' }, [
E('span', {}, _('Average Processing Time')),
E('span', { class: 'mosdns-badge badge-primary' }, _('Latency'))
]),
metricLatency,
subtextLatency
])
])
]);
statsElements = {
grid,
metricTotal,
subtextTotal,
sparklineTotal,
badgeBlocked,
metricBlocked,
sparklineBlocked,
badgeCached,
metricCached,
sparklineCached,
metricLatency,
subtextLatency
};
return grid;
};
const updateOverviewStats = (stats, historyData) => {
if (!stats || stats.error) { if (!stats || stats.error) {
return E('div', { class: 'alert-message warning' }, if (nodeStats) {
_('MosDNS API is unreachable. Please ensure MosDNS is running and stats_api plugin is enabled.')); dom.content(nodeStats, E('div', { class: 'alert-message warning' },
_('MosDNS API is unreachable. Please ensure MosDNS is running and stats_api plugin is enabled.')));
statsElements = null;
}
return;
}
if (!statsElements || !nodeStats.contains(statsElements.grid)) {
dom.content(nodeStats, createOverviewStatsDOM());
} }
const { const {
@@ -295,52 +463,19 @@ const renderOverviewStats = (stats, historyData) => {
const baseMax = Math.max(...totalItems.map(i => i.val), 1); const baseMax = Math.max(...totalItems.map(i => i.val), 1);
return E('div', { class: 'mosdns-grid' }, [ statsElements.metricTotal.textContent = total.toLocaleString();
E('div', { class: 'mosdns-stat-card' }, [ statsElements.subtextTotal.textContent = _('Avg Processing') + ': ' + avg_ms + ' ms';
E('div', {}, [ statsElements.sparklineTotal.update(totalItems, baseMax);
E('div', { class: 'title-row' }, [
E('span', {}, _('DNS Queries Total')),
E('span', { class: 'mosdns-badge badge-teal badge-pulse' }, _('● Live'))
]),
E('div', { class: 'metric-val' }, total.toLocaleString()),
E('div', { class: 'subtext' }, _('Avg Processing') + ': ' + avg_ms + ' ms')
]),
createSparklineSVG(totalItems, '#3b82f6', 'spark-grad-total', baseMax)
]),
E('div', { class: 'mosdns-stat-card' }, [ statsElements.badgeBlocked.textContent = blocked_pct + '%';
E('div', {}, [ statsElements.metricBlocked.textContent = blocked.toLocaleString();
E('div', { class: 'title-row' }, [ statsElements.sparklineBlocked.update(blockedItems, baseMax);
E('span', {}, _('Blocked by Filters')),
E('span', { class: 'mosdns-badge badge-danger' }, blocked_pct + '%')
]),
E('div', { class: 'metric-val', style: 'color: #dc2626;' }, blocked.toLocaleString())
]),
createSparklineSVG(blockedItems, '#dc2626', 'spark-grad-blocked', baseMax)
]),
E('div', { class: 'mosdns-stat-card' }, [ statsElements.badgeCached.textContent = cached_pct + '%';
E('div', {}, [ statsElements.metricCached.textContent = cached.toLocaleString();
E('div', { class: 'title-row' }, [ statsElements.sparklineCached.update(cachedItems, baseMax);
E('span', {}, _('Cached Queries')),
E('span', { class: 'mosdns-badge badge-teal' }, cached_pct + '%')
]),
E('div', { class: 'metric-val', style: 'color: #059669;' }, cached.toLocaleString())
]),
createSparklineSVG(cachedItems, '#059669', 'spark-grad-cached', baseMax)
]),
E('div', { class: 'mosdns-stat-card' }, [ statsElements.metricLatency.textContent = avg_ms + ' ms';
E('div', {}, [
E('div', { class: 'title-row' }, [
E('span', {}, _('Average Processing Time')),
E('span', { class: 'mosdns-badge badge-primary' }, _('Latency'))
]),
E('div', { class: 'metric-val', style: 'color: #2563eb;' }, avg_ms + ' ms'),
E('div', { class: 'subtext' }, _('Per-query speed'))
])
])
]);
}; };
const renderTopRankings = topData => { const renderTopRankings = topData => {
@@ -398,6 +533,13 @@ const renderTopRankings = topData => {
]); ]);
}; };
const updateTopRankings = topData => {
const json = JSON.stringify(topData || {});
if (json === lastTopJson) return;
lastTopJson = json;
dom.content(nodeTop, renderTopRankings(topData));
};
const showLogDetailsModal = item => { const showLogDetailsModal = item => {
let statusBadge; let statusBadge;
if (item.is_blocked) { if (item.is_blocked) {
@@ -579,11 +721,15 @@ const pollScheduler = async () => {
const results = await Promise.all(promises); const results = await Promise.all(promises);
dom.content(nodeStats, renderOverviewStats(results[0], results[2])); updateOverviewStats(results[0], results[2]);
dom.content(nodeTop, renderTopRankings(results[1])); updateTopRankings(results[1]);
if (shouldRefreshLogs && results[3]) { if (shouldRefreshLogs && results[3]) {
dom.content(nodeLogs, renderLogsTable(results[3])); const json = JSON.stringify(results[3]);
if (json !== lastLogsJson) {
lastLogsJson = json;
dom.content(nodeLogs, renderLogsTable(results[3]));
}
} }
updateLiveStatusBadge(); updateLiveStatusBadge();
} catch (e) { } catch (e) {
@@ -593,6 +739,7 @@ const pollScheduler = async () => {
const refreshLogs = async () => { const refreshLogs = async () => {
try { try {
const logs = await callGetLogs(PAGE_SIZE, pageIdx * PAGE_SIZE, searchVal, filterVal); const logs = await callGetLogs(PAGE_SIZE, pageIdx * PAGE_SIZE, searchVal, filterVal);
lastLogsJson = JSON.stringify(logs || {});
dom.content(nodeLogs, renderLogsTable(logs)); dom.content(nodeLogs, renderLogsTable(logs));
updateLiveStatusBadge(); updateLiveStatusBadge();
} catch (e) { } catch (e) {
@@ -613,13 +760,19 @@ return view.extend({
render(data) { render(data) {
injectStyles(); injectStyles();
statsElements = null;
currentBadgeState = null;
lastTopJson = '';
lastLogsJson = '';
nodeStats = E('div', { id: 'overview-stats' }); nodeStats = E('div', { id: 'overview-stats' });
nodeTop = E('div', { id: 'top-rankings' }); nodeTop = E('div', { id: 'top-rankings' });
nodeLogs = E('div', { id: 'logs-table' }); nodeLogs = E('div', { id: 'logs-table' });
autoStatusBadge = E('div', { style: 'display: inline-block;' }); autoStatusBadge = E('div', { style: 'display: inline-block;' });
dom.content(nodeStats, renderOverviewStats(data[0], data[3])); updateOverviewStats(data[0], data[3]);
dom.content(nodeTop, renderTopRankings(data[1])); updateTopRankings(data[1]);
lastLogsJson = JSON.stringify(data[2] || {});
dom.content(nodeLogs, renderLogsTable(data[2])); dom.content(nodeLogs, renderLogsTable(data[2]));
updateLiveStatusBadge(); updateLiveStatusBadge();
+1 -1
View File
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.8.26 PKG_VERSION:=26.8.26
PKG_RELEASE:=254 PKG_RELEASE:=255
PKG_PO_VERSION:=$(PKG_VERSION) PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \
@@ -1810,18 +1810,7 @@ function gen_config(var)
end end
end end
table.insert(route.rules, {
action = "route",
ip_is_private = true,
outbound = "direct"
})
if COMMON.default_outbound_tag then if COMMON.default_outbound_tag then
table.insert(route.rules, {
action = "route",
port_range = { "0:65535" },
outbound = COMMON.default_outbound_tag
})
route.final = COMMON.default_outbound_tag route.final = COMMON.default_outbound_tag
end end
@@ -1540,11 +1540,6 @@ function gen_config(var)
}) })
end end
table.insert(rules, {
outboundTag = "direct",
ip = { "geoip:private" }
})
if default_outboundTag then if default_outboundTag then
local rule = { local rule = {
_flag = "default", _flag = "default",
+1 -1
View File
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2 PKG_NAME:=luci-app-passwall2
PKG_VERSION:=26.8.27 PKG_VERSION:=26.8.27
PKG_RELEASE:=106 PKG_RELEASE:=107
PKG_PO_VERSION:=$(PKG_VERSION) PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \
@@ -1797,11 +1797,6 @@ function gen_config(var)
end end
if COMMON.default_outbound_tag then if COMMON.default_outbound_tag then
table.insert(route.rules, {
action = "route",
port_range = { "0:65535" },
outbound = COMMON.default_outbound_tag
})
route.final = COMMON.default_outbound_tag route.final = COMMON.default_outbound_tag
end end
+1 -1
View File
@@ -17,7 +17,7 @@ LUCI_NAME:=luci-theme-footstrap
FOOTSTRAP_VERSION?= FOOTSTRAP_VERSION?=
ifneq ($(FOOTSTRAP_VERSION),) ifneq ($(FOOTSTRAP_VERSION),)
PKG_VERSION:=$(FOOTSTRAP_VERSION) PKG_VERSION:=$(FOOTSTRAP_VERSION)
PKG_RELEASE:=48 PKG_RELEASE:=49
endif endif
LUCI_TITLE:=Footstrap Theme LUCI_TITLE:=Footstrap Theme
@@ -130,6 +130,18 @@ function naturalHeight(el) {
const last = el.lastElementChild; const last = el.lastElementChild;
if (!last) return 0; if (!last) return 0;
const box = el.getBoundingClientRect(); const box = el.getBoundingClientRect();
/* A BOX WITH NO HEIGHT OF ITS OWN HOLDS NOTHING UP, and asking its content how tall it would be
* gets an answer about a page that is not on screen. `visibility: hidden` leaves children in the
* layout with rects of their own, so an inactive tab pane — collapsed to height 0 by
* theme/30-tables.css — measures its full content here and the floor then pins that collapse
* open: on Network -> Interfaces the hidden `device` pane held 893px, and the active pane's
* content sat that much further down the page (issue #41, reported against a third-party page
* and reproduced on the stock one). The clear-and-remeasure shape this replaced read the
* collapsed height and wrote nothing, which is the behaviour restored here.
*
* A container a tick has just emptied also measures 0, and that is the same answer for the same
* reason: the floor it already wears is what holds it up, and holdFloor() leaves it alone. */
if (!box.height) return 0;
const end = last.getBoundingClientRect(); const end = last.getBoundingClientRect();
if (!end.height && !end.width) return 0; /* a last child out of the flow says nothing */ if (!end.height && !end.width) return 0; /* a last child out of the flow says nothing */
const cs = window.getComputedStyle(el); const cs = window.getComputedStyle(el);
+2 -2
View File
@@ -14,8 +14,8 @@ MISE_HASH_x86_64:=3832f39c325e343f81fe3d92b2447c5d1a5eea1bc85092bb7b6c2580622264
MISE_HASH_aarch64:=06186cfbfe947049b21d58575fb0ea800cc26ed1375f20f4b678cb3a9d679437 MISE_HASH_aarch64:=06186cfbfe947049b21d58575fb0ea800cc26ed1375f20f4b678cb3a9d679437
PKG_NAME:=mise PKG_NAME:=mise
PKG_VERSION:=2026.8.15 PKG_VERSION:=2026.8.16
PKG_RELEASE:=2 PKG_RELEASE:=3
PKG_SOURCE:=$(PKG_NAME)-v$(PKG_VERSION)-linux-$(MISE_ARCH)-musl.tar.gz PKG_SOURCE:=$(PKG_NAME)-v$(PKG_VERSION)-linux-$(MISE_ARCH)-musl.tar.gz
PKG_SOURCE_URL:=https://github.com/jdx/mise/releases/download/v$(PKG_VERSION)/ PKG_SOURCE_URL:=https://github.com/jdx/mise/releases/download/v$(PKG_VERSION)/
PKG_HASH:=skip PKG_HASH:=skip
+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=mosdns PKG_NAME:=mosdns
PKG_VERSION:=5.3.4 PKG_VERSION:=5.3.4
PKG_RELEASE:=19 PKG_RELEASE:=20
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/IrineSistiana/mosdns/tar.gz/v$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/IrineSistiana/mosdns/tar.gz/v$(PKG_VERSION)?
@@ -1,16 +1,16 @@
From 201408484de552cb927f6a50b76a34d65c8ac8c6 Mon Sep 17 00:00:00 2001 From 4b76512586cd404855b717d6b8ac3b4d12ef7a54 Mon Sep 17 00:00:00 2001
From: sbwml <admin@cooluc.com> From: sbwml <admin@cooluc.com>
Date: Fri, 20 Mar 2026 10:39:22 +0800 Date: Fri, 20 Mar 2026 10:39:22 +0800
Subject: [PATCH] mosdns: update dependencies Subject: [PATCH] mosdns: update dependencies
Signed-off-by: sbwml <admin@cooluc.com> Signed-off-by: sbwml <admin@cooluc.com>
--- ---
.github/workflows/release.yml | 2 +- .github/workflows/release.yml | 2 +-
.github/workflows/test.yml | 2 +- .github/workflows/test.yml | 2 +-
go.mod | 36 +++++++++---------- go.mod | 60 ++++++++---------
go.sum | 68 +++++++++++++++++------------------ go.sum | 121 ++++++++++++++++------------------
pkg/query_context/context.go | 1 - pkg/query_context/context.go | 1 -
5 files changed, 54 insertions(+), 55 deletions(-) 5 files changed, 85 insertions(+), 101 deletions(-)
--- a/.github/workflows/release.yml --- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml +++ b/.github/workflows/release.yml
@@ -36,107 +36,132 @@ Signed-off-by: sbwml <admin@cooluc.com>
--- a/go.mod --- a/go.mod
+++ b/go.mod +++ b/go.mod
@@ -1,30 +1,30 @@ @@ -1,31 +1,31 @@
module github.com/IrineSistiana/mosdns/v5 module github.com/IrineSistiana/mosdns/v5
-go 1.24.9 -go 1.24.9
+go 1.25.0 +go 1.26.0
require ( require (
github.com/IrineSistiana/go-bytes-pool v0.0.0-20230918115058-c72bd9761c57 github.com/IrineSistiana/go-bytes-pool v0.0.0-20230918115058-c72bd9761c57
- github.com/go-chi/chi/v5 v5.2.3 - github.com/go-chi/chi/v5 v5.2.3
- github.com/go-viper/mapstructure/v2 v2.4.0 - github.com/go-viper/mapstructure/v2 v2.4.0
+ github.com/go-chi/chi/v5 v5.2.5 + github.com/go-chi/chi/v5 v5.3.2
+ github.com/go-viper/mapstructure/v2 v2.5.0 + github.com/go-viper/mapstructure/v2 v2.5.0
github.com/google/nftables v0.3.0 github.com/google/nftables v0.3.0
github.com/kardianos/service v1.2.4 - github.com/kardianos/service v1.2.4
- github.com/klauspost/compress v1.18.2 - github.com/klauspost/compress v1.18.2
- github.com/miekg/dns v1.1.70 - github.com/miekg/dns v1.1.70
+ github.com/klauspost/compress v1.18.4 + github.com/kardianos/service v1.3.0
+ github.com/miekg/dns v1.1.72 + github.com/klauspost/compress v1.19.2
+ github.com/miekg/dns v1.1.73
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/nadoo/ipset v0.5.0 github.com/nadoo/ipset v0.5.0
github.com/prometheus/client_golang v1.23.2 - github.com/prometheus/client_golang v1.23.2
- github.com/quic-go/quic-go v0.58.1 - github.com/quic-go/quic-go v0.58.1
+ github.com/quic-go/quic-go v0.59.0 + github.com/prometheus/client_golang v1.24.1
+ github.com/quic-go/quic-go v0.62.0
github.com/spf13/cobra v1.10.2 github.com/spf13/cobra v1.10.2
github.com/spf13/viper v1.21.0 github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1 - github.com/stretchr/testify v1.11.1
+ github.com/stretchr/testify v1.12.1
github.com/vishvananda/netlink v1.3.0 github.com/vishvananda/netlink v1.3.0
go.uber.org/zap v1.27.1 - go.uber.org/zap v1.27.1
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba - go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
- golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 - golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93
- golang.org/x/net v0.48.0 - golang.org/x/net v0.48.0
- golang.org/x/sync v0.19.0 - golang.org/x/sync v0.19.0
- golang.org/x/sys v0.40.0 - golang.org/x/sys v0.40.0
- golang.org/x/time v0.14.0 - golang.org/x/time v0.14.0
+ golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 - google.golang.org/protobuf v1.36.11
+ golang.org/x/net v0.52.0 + go.uber.org/zap v1.28.0
+ golang.org/x/sync v0.20.0 + go4.org/netipx v0.0.0-20260823151212-3075585bcbeb
+ golang.org/x/sys v0.42.0 + golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa
+ golang.org/x/net v0.58.0
+ golang.org/x/sync v0.22.0
+ golang.org/x/sys v0.47.0
+ golang.org/x/time v0.15.0 + golang.org/x/time v0.15.0
google.golang.org/protobuf v1.36.11 + google.golang.org/protobuf v1.36.12
) )
@@ -37,14 +37,14 @@ require ( replace github.com/nadoo/ipset v0.5.0 => github.com/IrineSistiana/ipset v0.5.1-0.20220703061533-6e0fc3b04c0a
github.com/fsnotify/fsnotify v1.9.0 // indirect @@ -33,18 +33,16 @@ replace github.com/nadoo/ipset v0.5.0 =>
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
- github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
- github.com/fsnotify/fsnotify v1.9.0 // indirect
+ github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
- github.com/mdlayher/netlink v1.8.0 // indirect - github.com/mdlayher/netlink v1.8.0 // indirect
+ github.com/mdlayher/netlink v1.9.0 // indirect - github.com/mdlayher/socket v0.5.1 // indirect
github.com/mdlayher/socket v0.5.1 // indirect + github.com/mdlayher/netlink v1.11.2 // indirect
+ github.com/mdlayher/socket v0.6.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect - github.com/prometheus/common v0.67.5 // indirect
- github.com/prometheus/procfs v0.19.2 // indirect - github.com/prometheus/procfs v0.19.2 // indirect
+ github.com/prometheus/procfs v0.20.1 // indirect + github.com/pelletier/go-toml/v2 v2.4.3 // indirect
+ github.com/prometheus/client_model v0.6.3 // indirect
+ github.com/prometheus/common v0.71.0 // indirect
+ github.com/prometheus/procfs v0.22.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/qpack v0.6.0 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect
@@ -55,11 +55,11 @@ require ( @@ -55,11 +53,7 @@ require (
github.com/vishvananda/netns v0.0.4 // indirect github.com/vishvananda/netns v0.0.4 // indirect
go.uber.org/mock v0.6.0 // indirect go.uber.org/mock v0.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
- go.yaml.in/yaml/v2 v2.4.3 // indirect - go.yaml.in/yaml/v2 v2.4.3 // indirect
+ go.yaml.in/yaml/v2 v2.4.4 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
- golang.org/x/crypto v0.46.0 // indirect - golang.org/x/crypto v0.46.0 // indirect
- golang.org/x/mod v0.32.0 // indirect - golang.org/x/mod v0.32.0 // indirect
- golang.org/x/text v0.33.0 // indirect - golang.org/x/text v0.33.0 // indirect
- golang.org/x/tools v0.40.0 // indirect - golang.org/x/tools v0.40.0 // indirect
+ golang.org/x/crypto v0.49.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect
+ golang.org/x/mod v0.34.0 // indirect + go.yaml.in/yaml/v3 v3.0.5 // indirect
+ golang.org/x/text v0.35.0 // indirect + golang.org/x/crypto v0.55.0 // indirect
+ golang.org/x/tools v0.43.0 // indirect + golang.org/x/text v0.41.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )
--- a/go.sum --- a/go.sum
+++ b/go.sum +++ b/go.sum
@@ -13,10 +13,10 @@ github.com/frankban/quicktest v1.14.6 h1 @@ -7,58 +7,56 @@ github.com/beorn7/perks v1.0.1/go.mod h1
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
-github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
-github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
-github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= -github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
-github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= -github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
-github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
-github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
+github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
+github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
+github.com/go-chi/chi/v5 v5.3.2 h1:5YQkICvTCSZ25hoRsyJazN0scjzKGiu4VAUc7H1o1nY=
+github.com/go-chi/chi/v5 v5.3.2/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
+github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
+github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/nftables v0.3.0 h1:bkyZ0cbpVeMHXOrtlFc8ISmfVqq5gPJukoYieyVmITg= github.com/google/nftables v0.3.0 h1:bkyZ0cbpVeMHXOrtlFc8ISmfVqq5gPJukoYieyVmITg=
@@ -25,20 +25,20 @@ github.com/inconshreveable/mousetrap v1. github.com/google/nftables v0.3.0/go.mod h1:BCp9FsrbF1Fn/Yu6CLUc9GGZFw/+hsxfluNXXmxBfRM=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kardianos/service v1.2.4 h1:XNlGtZOYNx2u91urOdg/Kfmc+gfmuIo1Dd3rEi2OgBk= -github.com/kardianos/service v1.2.4 h1:XNlGtZOYNx2u91urOdg/Kfmc+gfmuIo1Dd3rEi2OgBk=
github.com/kardianos/service v1.2.4/go.mod h1:E4V9ufUuY82F7Ztlu1eN9VXWIQxg8NoLQlmFe0MtrXc= -github.com/kardianos/service v1.2.4/go.mod h1:E4V9ufUuY82F7Ztlu1eN9VXWIQxg8NoLQlmFe0MtrXc=
-github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= -github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
-github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= -github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
+github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/kardianos/service v1.3.0 h1:/LGy+xPP2TM+GLTiCZ2di7cy0Jd/qrawlTUfqKYFdTI=
+github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/kardianos/service v1.3.0/go.mod h1:E4V9ufUuY82F7Ztlu1eN9VXWIQxg8NoLQlmFe0MtrXc=
+github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=
+github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -145,46 +170,80 @@ Signed-off-by: sbwml <admin@cooluc.com>
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/mdlayher/netlink v1.8.0 h1:e7XNIYJKD7hUct3Px04RuIGJbBxy1/c4nX7D5YyvvlM= -github.com/mdlayher/netlink v1.8.0 h1:e7XNIYJKD7hUct3Px04RuIGJbBxy1/c4nX7D5YyvvlM=
-github.com/mdlayher/netlink v1.8.0/go.mod h1:UhgKXUlDQhzb09DrCl2GuRNEglHmhYoWAHid9HK3594= -github.com/mdlayher/netlink v1.8.0/go.mod h1:UhgKXUlDQhzb09DrCl2GuRNEglHmhYoWAHid9HK3594=
+github.com/mdlayher/netlink v1.9.0 h1:G8+GLq2x3v4D4MVIqDdNUhTUC7TKiCy/6MDkmItfKco= -github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
+github.com/mdlayher/netlink v1.9.0/go.mod h1:YBnl5BXsCoRuwBjKKlZ+aYmEoq0r12FDA/3JC+94KDg= -github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
-github.com/miekg/dns v1.1.70 h1:DZ4u2AV35VJxdD9Fo9fIWm119BsQL5cZU1cQ9s0LkqA= -github.com/miekg/dns v1.1.70 h1:DZ4u2AV35VJxdD9Fo9fIWm119BsQL5cZU1cQ9s0LkqA=
-github.com/miekg/dns v1.1.70/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= -github.com/miekg/dns v1.1.70/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
+github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= +github.com/mdlayher/netlink v1.11.2 h1:HKh2jqe+omdSWcQ88nrT7INE61B0NXfiSPFdgL4YbNI=
+github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= +github.com/mdlayher/netlink v1.11.2/go.mod h1:uT2Yc/QLaZubzDpZIBi9d4GoeLwtp3x1AMeqSRrK2sA=
+github.com/mdlayher/socket v0.6.1 h1:M7uj2NtuujUY4mYr1C57NmfNiRHbkKpnBxO856lsc3A=
+github.com/mdlayher/socket v0.6.1/go.mod h1:+/SGtqc9V+5dAuRgQsU0fGBI+oRDiW7O2Obx10OIWfg=
+github.com/miekg/dns v1.1.73 h1:uhT8nJxmTrPJYClxVxTCX+CVn6qnzSiybRk72Z6DgrE=
+github.com/miekg/dns v1.1.73/go.mod h1:RW2Obtfd5NZHvOFe3zYG0W8koWOQtAzyHaLo8vASBuQ=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
@@ -53,12 +53,12 @@ github.com/prometheus/client_model v0.6. github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
-github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
-github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
-github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
-github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
-github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
-github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
-github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= -github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
-github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= -github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
+github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY=
+github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
+github.com/prometheus/client_golang v1.24.1 h1:JnJkREXzWxUdCuPFpIWZiPispT9xVV59uiuyR2bPlnU=
+github.com/prometheus/client_golang v1.24.1/go.mod h1:F+oSRECHg4sse5ucfYpYDeIv/hu68Zo0uoHKetWnzcE=
+github.com/prometheus/client_model v0.6.3 h1:O0jaTVAYNxTHYInEPFJt5I3+sN8zqBtVMPTB1qyxiEo=
+github.com/prometheus/client_model v0.6.3/go.mod h1:gpN5P9S7Rr6Yr92PiQ+Ixvhf6JZEkF1dnxsYL2aPBEM=
+github.com/prometheus/common v0.71.0 h1:9KDAKb7Mj3HEVKyFCK6Dc/HIwlBzZIN2l7/lrHl3KK8=
+github.com/prometheus/common v0.71.0/go.mod h1:CLJ5H8TEsGX8bl31BdMkfhIZ+QmZ9tBPPotUxUbfcmk=
+github.com/prometheus/procfs v0.22.0 h1:6q9+/JL9IKAPbCmBrv9n5O5Ty3NKnciV5X7YGw0oics=
+github.com/prometheus/procfs v0.22.0/go.mod h1:CvmFr/GVhIjIvWJZW3tgkODBQMRIf0EyWMQLHCHab58=
+github.com/quic-go/go-ossfuzz-seeds v0.1.0 h1:APacT+iIaNF6fd8AGEiN3bT/Jtkd2jz4v4TzM7MFjy0=
+github.com/quic-go/go-ossfuzz-seeds v0.1.0/go.mod h1:3IOHRbJIc+L6YKMwfDtJAM9Vj9k0YY4muhuyUYk5tbk=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
-github.com/quic-go/quic-go v0.58.1 h1:J0s55TVauDbnCEY5tU2B8e7nYb3gnKMSez5Fwi1dl2s= -github.com/quic-go/quic-go v0.58.1 h1:J0s55TVauDbnCEY5tU2B8e7nYb3gnKMSez5Fwi1dl2s=
-github.com/quic-go/quic-go v0.58.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= -github.com/quic-go/quic-go v0.58.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
+github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= +github.com/quic-go/quic-go v0.62.0 h1:ZHDjCk5OacATwGvs8PWE97CTvX7AqZiVoW7++ZOXTf8=
+github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= +github.com/quic-go/quic-go v0.62.0/go.mod h1:RAro2j2yN9a9EiPACLHT9IB2NXCvGQmmo/alT0yYI0w=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -91,32 +91,32 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSx @@ -75,8 +73,8 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2K
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
-github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
-github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
+github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
@@ -89,38 +87,31 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5E
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
-go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= -go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
-go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= -go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
-go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
+go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
+go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
+go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
+go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= -go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= -go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
-golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
-golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
-golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= -golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
@@ -195,16 +254,18 @@ Signed-off-by: sbwml <admin@cooluc.com>
-golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
+golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
+golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= +go4.org/netipx v0.0.0-20260823151212-3075585bcbeb h1:XBM4hvfwGAttkkiTIFfeigdfcL1xIfdKXqFdgiHGtDs=
+golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= +go4.org/netipx v0.0.0-20260823151212-3075585bcbeb/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
+golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
+golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
+golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa h1:QSyA8ishJCyT21kER9KwNt0b7BM3iRK4x9QXhjN5Fdk=
+golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa/go.mod h1:zeBbvyFKDaLwa7CH/zI8KXt7gTl14SF7sO08Pl5jBCM=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
+golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
+golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
@@ -215,17 +276,21 @@ Signed-off-by: sbwml <admin@cooluc.com>
-golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
-golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= -golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
-golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= -golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
+golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
+golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
+golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
+golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
+golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
+golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
+golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
+golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
--- a/pkg/query_context/context.go --- a/pkg/query_context/context.go
+++ b/pkg/query_context/context.go +++ b/pkg/query_context/context.go
@@ -108,7 +108,6 @@ func (ctx *Context) QQuestion() dns.Ques @@ -108,7 +108,6 @@ func (ctx *Context) QQuestion() dns.Ques
@@ -0,0 +1,74 @@
From 68799cf43340bf2e9e0b7145ea961d69ca45d6fe Mon Sep 17 00:00:00 2001
From: sbwml <admin@cooluc.com>
Date: Mon, 31 Aug 2026 22:49:01 +0800
Subject: [PATCH] feat(stats_api): exclude blocked queries from cache hit
percentage
Calculate cache hit rate based on unblocked queries (total - blocked)
instead of total queries to prevent ad blocking from skewing the stats.
Signed-off-by: sbwml <admin@cooluc.com>
---
plugin/executable/stats_api/stats_api.go | 7 +++-
plugin/executable/stats_api/stats_api_test.go | 35 +++++++++++++++++++
2 files changed, 41 insertions(+), 1 deletion(-)
--- a/plugin/executable/stats_api/stats_api.go
+++ b/plugin/executable/stats_api/stats_api.go
@@ -629,9 +629,14 @@ func (s *StatsAPI) handleStats(w http.Re
var blockedPct, cachedPct, avgLat float64
if total > 0 {
blockedPct = float64(blocked) / float64(total) * 100.0
- cachedPct = float64(cached) / float64(total) * 100.0
avgLat = (float64(latUs) / float64(total)) / 1000.0
}
+ if total > blocked {
+ cachedPct = float64(cached) / float64(total-blocked) * 100.0
+ if cachedPct > 100.0 {
+ cachedPct = 100.0
+ }
+ }
blockedPct = math.Round(blockedPct*100) / 100
cachedPct = math.Round(cachedPct*100) / 100
--- a/plugin/executable/stats_api/stats_api_test.go
+++ b/plugin/executable/stats_api/stats_api_test.go
@@ -511,3 +511,38 @@ func TestStatsAPINonExistentDumpFile(t *
t.Errorf("expected 0 total queries, got %d", s.totalQueries.Load())
}
}
+
+func TestStatsAPICachedPercentageExcludesBlocked(t *testing.T) {
+ s := NewStatsAPI(&Args{Capacity: 100}, zap.NewNop())
+ router := s.Router()
+
+ // 100 total queries: 50 blocked, 25 cached, 25 forwarded to upstream
+ s.totalQueries.Store(100)
+ s.blockedQueries.Store(50)
+ s.cachedQueries.Store(25)
+ s.totalLatencyUs.Store(50000)
+
+ req := httptest.NewRequest(http.MethodGet, "/api/v1/stats", nil)
+ w := httptest.NewRecorder()
+ router.ServeHTTP(w, req)
+
+ if w.Code != http.StatusOK {
+ t.Fatalf("expected HTTP 200, got %d", w.Code)
+ }
+
+ var statsResp map[string]any
+ if err := json.Unmarshal(w.Body.Bytes(), &statsResp); err != nil {
+ t.Fatalf("failed to unmarshal stats response: %v", err)
+ }
+
+ // blocked_percentage = 50 / 100 = 50%
+ if blockedPct := statsResp["blocked_percentage"].(float64); blockedPct != 50.0 {
+ t.Errorf("expected blocked_percentage 50.0, got %v", blockedPct)
+ }
+
+ // cached_percentage = 25 / (100 - 50) = 50% (previously 25%)
+ if cachedPct := statsResp["cached_percentage"].(float64); cachedPct != 50.0 {
+ t.Errorf("expected cached_percentage 50.0, got %v", cachedPct)
+ }
+}
+