From e7b80008089eba3fb7b5e8fefeac4d8c03721f08 Mon Sep 17 00:00:00 2001 From: CN-JS-HuiBai Date: Sun, 5 Apr 2026 15:02:19 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Valkey=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/init.html | 29 +++++++++++++++++++++++--- public/js/init.js | 37 ++++++++++++++++++++++++++++++++- server/cache.js | 52 ++++++++++++++++++++++++++++------------------- server/index.js | 37 +++++++++++++++++++++++++++++++-- 4 files changed, 128 insertions(+), 27 deletions(-) diff --git a/public/init.html b/public/init.html index 55bafe9..3e1bc3a 100644 --- a/public/init.html +++ b/public/init.html @@ -116,12 +116,35 @@ + +
+

Valkey / Redis 缓存配置 (可选)

+
+ +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
-
- - +
+ + +
diff --git a/public/js/init.js b/public/js/init.js index 46707b9..0324e45 100644 --- a/public/js/init.js +++ b/public/js/init.js @@ -4,8 +4,12 @@ document.addEventListener('DOMContentLoaded', () => { const userInput = document.getElementById('user'); const passwordInput = document.getElementById('password'); const databaseInput = document.getElementById('database'); + const vHostInput = document.getElementById('vHost'); + const vPortInput = document.getElementById('vPort'); + const vPasswordInput = document.getElementById('vPassword'); const btnTest = document.getElementById('btnTest'); + const btnTestValkey = document.getElementById('btnTestValkey'); const btnInit = document.getElementById('btnInit'); const messageBox = document.getElementById('messageBox'); @@ -101,6 +105,34 @@ document.addEventListener('DOMContentLoaded', () => { btnTest.textContent = oldText; } }); + + btnTestValkey.addEventListener('click', async () => { + btnTestValkey.disabled = true; + const oldText = btnTestValkey.textContent; + btnTestValkey.textContent = '测试中...'; + try { + const res = await fetch('/api/setup/test-valkey', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + host: vHostInput.value, + port: vPortInput.value, + password: vPasswordInput.value + }) + }); + const data = await res.json(); + if (data.success) { + showMessage('Valkey 连接成功!'); + } else { + showMessage('Valkey 连接失败: ' + (data.error || '未知错误'), true); + } + } catch (err) { + showMessage('Valkey 请求失败: ' + err.message, true); + } finally { + btnTestValkey.disabled = false; + btnTestValkey.textContent = oldText; + } + }); btnInit.addEventListener('click', async () => { btnInit.disabled = true; @@ -115,7 +147,10 @@ document.addEventListener('DOMContentLoaded', () => { port: portInput.value, user: userInput.value, password: passwordInput.value, - database: databaseInput.value + database: databaseInput.value, + vHost: vHostInput.value, + vPort: vPortInput.value, + vPassword: vPasswordInput.value }) }); const data = await res.json(); diff --git a/server/cache.js b/server/cache.js index 0feac6d..422f124 100644 --- a/server/cache.js +++ b/server/cache.js @@ -1,32 +1,42 @@ const Redis = require('ioredis'); -const host = process.env.VALKEY_HOST || 'localhost'; -const port = parseInt(process.env.VALKEY_PORT) || 6379; -const password = process.env.VALKEY_PASSWORD || undefined; -const db = parseInt(process.env.VALKEY_DB) || 0; -const ttl = parseInt(process.env.VALKEY_TTL) || 30; - let redis = null; +let ttl = 30; -try { - redis = new Redis({ - host, - port, - password, - db, - lazyConnect: true, - maxRetriesPerRequest: 1 - }); +function init() { + if (redis) { + redis.disconnect(); + } - redis.on('error', (err) => { - // Fail silently after one retry, we just won't cache - console.warn('[Cache] Valkey connection failed, caching disabled:', err.message); - }); -} catch (err) { - console.warn('[Cache] Valkey init failed:', err.message); + const host = process.env.VALKEY_HOST || 'localhost'; + const port = parseInt(process.env.VALKEY_PORT) || 6379; + const password = process.env.VALKEY_PASSWORD || undefined; + const db = parseInt(process.env.VALKEY_DB) || 0; + ttl = parseInt(process.env.VALKEY_TTL) || 30; + + try { + redis = new Redis({ + host, + port, + password, + db, + lazyConnect: true, + maxRetriesPerRequest: 1 + }); + + redis.on('error', (err) => { + // Fail silently after one retry, we just won't cache + console.warn('[Cache] Valkey connection failed, caching disabled:', err.message); + }); + } catch (err) { + console.warn('[Cache] Valkey init failed:', err.message); + } } +init(); + const cache = { + init, async get(key) { if (!redis) return null; try { diff --git a/server/index.js b/server/index.js index 50b0064..8da6418 100644 --- a/server/index.js +++ b/server/index.js @@ -137,8 +137,29 @@ app.post('/api/setup/test', async (req, res) => { } }); +app.post('/api/setup/test-valkey', async (req, res) => { + const { host, port, password } = req.body; + try { + const Redis = require('ioredis'); + const redis = new Redis({ + host: host || 'localhost', + port: parseInt(port) || 6379, + password: password || undefined, + lazyConnect: true, + maxRetriesPerRequest: 1, + connectTimeout: 5000 + }); + await redis.connect(); + await redis.ping(); + await redis.disconnect(); + res.json({ success: true, message: 'Valkey connection successful' }); + } catch (err) { + res.status(400).json({ success: false, error: err.message }); + } +}); + app.post('/api/setup/init', async (req, res) => { - const { host, port, user, password, database } = req.body; + const { host, port, user, password, database, vHost, vPort, vPassword } = req.body; try { const mysql = require('mysql2/promise'); const connection = await mysql.createConnection({ @@ -211,6 +232,9 @@ MYSQL_PORT=${port || '3306'} MYSQL_USER=${user || 'root'} MYSQL_PASSWORD=${password || ''} MYSQL_DATABASE=${dbName} +VALKEY_HOST=${vHost || 'localhost'} +VALKEY_PORT=${vPort || '6379'} +VALKEY_PASSWORD=${vPassword || ''} PORT=${process.env.PORT || 3000} HOST=${process.env.HOST || '0.0.0.0'} REFRESH_INTERVAL=${process.env.REFRESH_INTERVAL || 5000} @@ -223,9 +247,13 @@ REFRESH_INTERVAL=${process.env.REFRESH_INTERVAL || 5000} process.env.MYSQL_USER = user; process.env.MYSQL_PASSWORD = password; process.env.MYSQL_DATABASE = dbName; + process.env.VALKEY_HOST = vHost; + process.env.VALKEY_PORT = vPort; + process.env.VALKEY_PASSWORD = vPassword; - // Re-initialize pool + // Re-initialize pools db.initPool(); + cache.init(); isDbInitialized = true; res.json({ success: true, message: 'Initialization complete' }); @@ -607,6 +635,10 @@ app.get('/api/metrics/overview', async (req, res) => { // Get network traffic history (past 24h) from Prometheus app.get('/api/metrics/network-history', async (req, res) => { try { + const cacheKey = 'network_history_all'; + const cached = await cache.get(cacheKey); + if (cached) return res.json(cached); + const [sources] = await db.query('SELECT * FROM prometheus_sources'); if (sources.length === 0) { return res.json({ timestamps: [], rx: [], tx: [] }); @@ -625,6 +657,7 @@ app.get('/api/metrics/network-history', async (req, res) => { } const merged = prometheusService.mergeNetworkHistories(validHistories); + await cache.set(cacheKey, merged, 300); // Cache for 5 minutes res.json(merged); } catch (err) { console.error('Error fetching network history history:', err);