whois
This commit is contained in:
+91
-37
@@ -10,27 +10,80 @@ let logsChart = null;
|
||||
let currentSortField = 'timestamp'; // 默认按时间排序,显示最新记录
|
||||
let currentSortDirection = 'desc'; // 默认降序
|
||||
|
||||
// IP地理位置缓存(检查是否已经存在,避免重复声明)
|
||||
// IP 地理位置缓存(检查是否已经存在,避免重复声明)
|
||||
if (typeof ipGeolocationCache === 'undefined') {
|
||||
var ipGeolocationCache = {};
|
||||
var GEOLOCATION_CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 缓存有效期24小时
|
||||
var ipGeolocationCacheOrder = []; // 维护缓存插入顺序,用于 LRU
|
||||
var GEOLOCATION_CACHE_MAX_SIZE = 1000; // 最大缓存 1000 条记录
|
||||
var GEOLOCATION_CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 缓存有效期 24 小时
|
||||
}
|
||||
|
||||
// 获取IP地理位置信息
|
||||
// LRU 缓存辅助函数:更新缓存顺序,将指定 IP 移到最后(最近使用)
|
||||
function updateCacheOrder(ip) {
|
||||
const index = ipGeolocationCacheOrder.indexOf(ip);
|
||||
if (index > -1) {
|
||||
// 已存在,移除旧位置
|
||||
ipGeolocationCacheOrder.splice(index, 1);
|
||||
}
|
||||
// 添加到末尾(最近使用)
|
||||
ipGeolocationCacheOrder.push(ip);
|
||||
}
|
||||
|
||||
// LRU 缓存辅助函数:淘汰最少使用的缓存项
|
||||
function evictLRUCache() {
|
||||
while (ipGeolocationCacheOrder.length >= GEOLOCATION_CACHE_MAX_SIZE) {
|
||||
// 淘汰最久未使用的(数组第一个)
|
||||
const oldestIP = ipGeolocationCacheOrder.shift();
|
||||
if (oldestIP) {
|
||||
delete ipGeolocationCache[oldestIP];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LRU 缓存辅助函数:清理过期缓存
|
||||
function cleanupExpiredCache() {
|
||||
const now = Date.now();
|
||||
const expiredIPs = [];
|
||||
|
||||
// 找出所有过期的 IP
|
||||
for (const ip of ipGeolocationCacheOrder) {
|
||||
if (ipGeolocationCache[ip] && (now - ipGeolocationCache[ip].timestamp) >= GEOLOCATION_CACHE_EXPIRY) {
|
||||
expiredIPs.push(ip);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除过期缓存
|
||||
for (const ip of expiredIPs) {
|
||||
delete ipGeolocationCache[ip];
|
||||
const orderIndex = ipGeolocationCacheOrder.indexOf(ip);
|
||||
if (orderIndex > -1) {
|
||||
ipGeolocationCacheOrder.splice(orderIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 IP 地理位置信息(优化版,带 LRU 缓存管理)
|
||||
async function getIpGeolocation(ip) {
|
||||
// 检查是否为内网IP
|
||||
// 检查是否为内网 IP
|
||||
if (isPrivateIP(ip)) {
|
||||
return "内网 内网";
|
||||
}
|
||||
|
||||
// 定期清理过期缓存(每 100 次请求清理一次)
|
||||
if (Math.random() < 0.01) {
|
||||
cleanupExpiredCache();
|
||||
}
|
||||
|
||||
// 检查缓存
|
||||
const now = Date.now();
|
||||
if (ipGeolocationCache[ip] && (now - ipGeolocationCache[ip].timestamp) < GEOLOCATION_CACHE_EXPIRY) {
|
||||
// 缓存命中,更新使用顺序
|
||||
updateCacheOrder(ip);
|
||||
return ipGeolocationCache[ip].location;
|
||||
}
|
||||
|
||||
try {
|
||||
// 使用whois.pconline.com.cn API获取IP地理位置
|
||||
// 使用 whois.pconline.com.cn API 获取 IP 地理位置
|
||||
const url = `https://whois.pconline.com.cn/ipJson.jsp?ip=${ip}&json=true`;
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
@@ -47,19 +100,25 @@ async function getIpGeolocation(ip) {
|
||||
let location = "未知 未知";
|
||||
|
||||
if (data && data.addr) {
|
||||
// 直接使用addr字段作为完整的地理位置信息
|
||||
// 直接使用 addr 字段作为完整的地理位置信息
|
||||
location = data.addr;
|
||||
}
|
||||
|
||||
// 如果缓存已满,先淘汰最少使用的项
|
||||
if (Object.keys(ipGeolocationCache).length >= GEOLOCATION_CACHE_MAX_SIZE) {
|
||||
evictLRUCache();
|
||||
}
|
||||
|
||||
// 保存到缓存
|
||||
ipGeolocationCache[ip] = {
|
||||
location: location,
|
||||
timestamp: now
|
||||
};
|
||||
updateCacheOrder(ip);
|
||||
|
||||
return location;
|
||||
} catch (error) {
|
||||
console.error('获取IP地理位置失败:', error);
|
||||
console.error('获取 IP 地理位置失败:', error);
|
||||
return "未知 未知";
|
||||
}
|
||||
}
|
||||
@@ -880,39 +939,27 @@ async function loadLogs() {
|
||||
}
|
||||
|
||||
// 构建缓存键,包含所有查询参数
|
||||
const cacheKey = `logs_${logsPerPage}_${currentPage}_${currentFilter}_${currentSearch}_${currentSortField}_${currentSortDirection}`;
|
||||
// 已禁用缓存,每次都从服务器获取最新数据
|
||||
// const cacheKey = `logs_${logsPerPage}_${currentPage}_${currentFilter}_${currentSearch}_${currentSortField}_${currentSortDirection}`;
|
||||
|
||||
// 检查是否有有效的缓存数据
|
||||
// 检查是否有有效的缓存数据(已禁用)
|
||||
/*
|
||||
const cachedLogs = window.pageDataCache && window.pageDataCache.getCache(cacheKey);
|
||||
if (cachedLogs) {
|
||||
console.log('使用缓存的日志数据');
|
||||
|
||||
// 确保cachedLogs是数组
|
||||
const logsArray = Array.isArray(cachedLogs.logs) ? cachedLogs.logs : [];
|
||||
// 确保totalLogs是有效的
|
||||
const totalLogs = cachedLogs.totalLogs || logsArray.length;
|
||||
|
||||
// 计算总页数
|
||||
totalPages = Math.ceil(totalLogs / logsPerPage);
|
||||
|
||||
// 更新日志表格
|
||||
await updateLogsTable(logsArray);
|
||||
|
||||
// 绑定操作按钮事件
|
||||
bindActionButtonsEvents();
|
||||
|
||||
// 更新分页信息
|
||||
updateLogsPagination();
|
||||
|
||||
// 重新初始化列宽调节功能,确保新添加的行也能继承列宽设置
|
||||
initResizableColumns();
|
||||
|
||||
// 隐藏加载状态
|
||||
if (loadingEl) {
|
||||
loadingEl.classList.add('hidden');
|
||||
}
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// 构建请求URL
|
||||
let endpoint = `/logs/query?limit=${logsPerPage}&offset=${(currentPage - 1) * logsPerPage}`;
|
||||
@@ -959,13 +1006,15 @@ async function loadLogs() {
|
||||
// 计算总页数
|
||||
totalPages = Math.ceil(totalLogs / logsPerPage);
|
||||
|
||||
// 存储数据到缓存
|
||||
// 禁用缓存存储,每次都从服务器获取最新数据
|
||||
/*
|
||||
if (window.pageDataCache) {
|
||||
window.pageDataCache.setCache(cacheKey, {
|
||||
logs: logsArray,
|
||||
totalLogs: totalLogs
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
// 更新日志表格
|
||||
await updateLogsTable(logsArray);
|
||||
@@ -1148,11 +1197,12 @@ async function updateLogsTable(logs) {
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm">
|
||||
<div class="font-medium flex items-center relative">
|
||||
${log.dnssec ? '<i class="fa fa-lock text-green-500 mr-1" title="DNSSEC已启用"></i>' : ''}
|
||||
${log.dnssec ? '<i class="fa fa-lock text-green-500 mr-1" title="DNSSEC 已启用"></i>' : ''}
|
||||
<div class="tracker-icon-container relative">
|
||||
${isTracker ? '<i class="fa fa-eye text-red-500 mr-1"></i>' : '<i class="fa fa-eye-slash text-gray-300 mr-1"></i>'}
|
||||
${trackerTooltip}
|
||||
</div>
|
||||
<img src="images/whois.svg" alt="WHOIS" class="w-4 h-4 mr-1 inline-block cursor-pointer hover:opacity-75" onclick="event.stopPropagation(); window.location.href = window.location.pathname + '#whois'; setTimeout(() => { const input = document.getElementById('whois-domain-input'); if(input && '${log.domain}') { input.value = '${log.domain}'; if(typeof searchDomainInfo === 'function') { searchDomainInfo(); } } }, 200);" title="查看域名信息" />
|
||||
${log.domain}
|
||||
</div>
|
||||
<div class="text-xs text-gray-500 mt-1">类型: ${log.queryType}, <span class="${statusClass}">${statusText}</span>, <span class="${cacheStatusClass}">${log.fromCache ? '缓存' : '非缓存'}</span>${log.dnssec ? ', <span class="text-green-500"><i class="fa fa-lock"></i> DNSSEC</span>' : ''}${log.edns ? ', <span class="text-blue-500"><i class="fa fa-exchange"></i> EDNS</span>' : ''}</div>
|
||||
@@ -1407,8 +1457,13 @@ function setupLogsReconnect() {
|
||||
}, reconnectDelay);
|
||||
}
|
||||
|
||||
// 从WebSocket更新日志统计数据
|
||||
// 从 WebSocket 更新日志统计数据 - 添加页面可见性检查
|
||||
function updateLogsStatsFromWebSocket(stats) {
|
||||
// 页面不可见时跳过处理,节省资源
|
||||
if (document.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 更新统计卡片
|
||||
if (stats.dns) {
|
||||
@@ -1430,7 +1485,7 @@ function updateLogsStatsFromWebSocket(stats) {
|
||||
document.getElementById('logs-block-rate').textContent = blockRate + '%';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('从WebSocket更新日志统计数据失败:', error);
|
||||
console.error('从 WebSocket 更新日志统计数据失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1786,7 +1841,13 @@ async function showLogDetailModal(log) {
|
||||
const domainInfoDiv = document.createElement('div');
|
||||
domainInfoDiv.className = 'col-span-1 md:col-span-2 space-y-1';
|
||||
domainInfoDiv.innerHTML = `
|
||||
<div class="text-xs text-gray-500 dark:text-gray-400">域名信息</div>
|
||||
<div class="text-xs text-gray-500 dark:text-gray-400 flex justify-between items-center">
|
||||
<span>域名信息</span>
|
||||
<button onclick="event.stopPropagation(); const modal = this.closest('.fixed'); if(modal && modal.parentElement === document.body) { modal.remove(); } window.location.href = window.location.pathname + '#whois'; setTimeout(() => { const input = document.getElementById('whois-domain-input'); if(input && '${domain}') { input.value = '${domain}'; if(typeof searchDomainInfo === 'function') { searchDomainInfo(); } } }, 200);" class="text-primary hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300 text-xs flex items-center transition-colors" title="查看详细 WHOIS 信息">
|
||||
<img src="images/whois.svg" alt="WHOIS" class="w-4 h-4 mr-1" />
|
||||
查看更多
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-sm font-medium text-gray-900 dark:text-gray-100 p-3 bg-gray-50 dark:bg-gray-700 rounded-md border border-gray-200 dark:border-gray-600 w-full">
|
||||
${domainInfo ? `
|
||||
<div class="flex items-center mb-2">
|
||||
@@ -2143,11 +2204,4 @@ function initLogDetailModal() {
|
||||
});
|
||||
}
|
||||
|
||||
// 定期更新日志统计数据(备用方案)
|
||||
setInterval(() => {
|
||||
// 只有在查询日志页面时才更新
|
||||
if (window.location.hash === '#logs') {
|
||||
loadLogsStats();
|
||||
// 不自动更新日志详情,只更新统计数据
|
||||
}
|
||||
}, 30000); // 每30秒更新一次
|
||||
|
||||
|
||||
Reference in New Issue
Block a user