diff --git a/index.js b/index.js index a3c111c..7769b2d 100644 --- a/index.js +++ b/index.js @@ -29,20 +29,17 @@ if (!fs.existsSync(cacheDir)) { fs.mkdirSync(cacheDir); } - -// 定时清理过期缓存数据并更新请求 -setInterval(async () => { +// 定时清理过期缓存数据 +setInterval(() => { const currentTime = Date.now(); for (const key in pathIndex) { - const { timestamp } = pathIndex[key]; - // 24小时 - if (currentTime - timestamp > 24 * 60 * 60 * 1000) { + if (currentTime - pathIndex[key].timestamp > 24 * 60 * 60 * 1000) { delete pathIndex[key]; } } -}, 1 * 60 * 60 * 1000); // 每隔 1 小时执行一次 - +}, 60 * 60 * 1000); // 每隔 1 小时执行一次 +// 处理请求并返回数据 const server = http.createServer(async (req, res) => { if (req.url === '/favicon.ico') { res.writeHead(204); @@ -50,6 +47,21 @@ const server = http.createServer(async (req, res) => { return; } + // 返回 endpoint, 缓存目录, 缓存数量, 用于监听服务是否正常运行 + if (req.url === '/endpoint') { + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ + code: 200, + data: { + api: apiEndpoint, + port: port, + cacheDir: cacheDir, + pathIndexCount: Object.keys(pathIndex).length, + } + })); + return; + } + const parsedUrl = url.parse(req.url, true); const reqPath = parsedUrl.pathname; const sign = parsedUrl.query.sign || ''; @@ -83,7 +95,6 @@ const server = http.createServer(async (req, res) => { // 修改 pathIndex 记录时,添加时间戳 pathIndex[uniqidhex] = { uniqid: data.uniqid, timestamp: Date.now() }; - cacheMetaFile = pathModule.join(cacheDir, `${data.uniqid}.meta`); cacheContentFile = pathModule.join(cacheDir, `${data.uniqid}.content`); tempCacheContentFile = pathModule.join(cacheDir, `${data.uniqid}_${crypto.randomBytes(16).toString('hex')}.temp`); @@ -94,20 +105,21 @@ const server = http.createServer(async (req, res) => { // 如果内容缓存存在, 则直接调用 if (fs.existsSync(cacheContentFile)) { serveFromCache(cacheMetaFile, cacheContentFile, res); - return; + } else { + fetchAndServe(data, tempCacheContentFile, cacheContentFile, res); } - fetchAndServe(data, tempCacheContentFile, cacheContentFile, res); } else { res.writeHead(502, { 'Content-Type': 'text/plain' }); res.end(apiData.message || 'Bad Gateway'); } } catch (error) { res.writeHead(502, { 'Content-Type': 'text/plain' }); - res.end('Bad Gateway: Failed to decode JSON' + error); + res.end('Bad Gateway: Failed to decode JSON ' + error); } } }); +// 检查缓存是否有效 const isCacheValid = (cacheMetaFile, cacheContentFile) => { if (!fs.existsSync(cacheMetaFile) || !fs.existsSync(cacheContentFile)) return false; @@ -115,6 +127,7 @@ const isCacheValid = (cacheMetaFile, cacheContentFile) => { return cacheData.expiration > Date.now(); }; +// 从 API 获取数据 const fetchApiData = (reqPath, sign) => { return new Promise((resolve, reject) => { const postData = querystring.stringify({ path: reqPath, sign }); @@ -146,6 +159,7 @@ const fetchApiData = (reqPath, sign) => { }); }; +// 从真实 URL 获取数据并写入缓存 const fetchAndServe = (data, tempCacheContentFile, cacheContentFile, res) => { https.get(data.realUrl, { timeout: requestTimeout * 10 }, (realRes) => { const cacheStream = fs.createWriteStream(tempCacheContentFile, { flags: 'w' }); @@ -188,6 +202,7 @@ const fetchAndServe = (data, tempCacheContentFile, cacheContentFile, res) => { }); }; +// 从缓存中读取数据并返回 const serveFromCache = (cacheMetaFile, cacheContentFile, res) => { const cacheData = JSON.parse(fs.readFileSync(cacheMetaFile, 'utf8')); const readStream = fs.createReadStream(cacheContentFile); @@ -217,6 +232,7 @@ const serveFromCache = (cacheMetaFile, cacheContentFile, res) => { }); }; +// 处理响应错误 const handleResponseError = (res, tempCacheContentFile, realUrl) => { if (!res.headersSent) { res.writeHead(502, { 'Content-Type': 'text/plain' }); @@ -227,6 +243,7 @@ const handleResponseError = (res, tempCacheContentFile, realUrl) => { } }; +// 处理缓存读取错误 const handleCacheReadError = (res) => { if (!res.headersSent) { res.writeHead(500, { 'Content-Type': 'text/plain' }); @@ -234,11 +251,12 @@ const handleCacheReadError = (res) => { } }; +// 启动服务器 server.listen(port, () => { console.log(`Proxy server is running on http://localhost:${port}`); }); -// Graceful shutdown +// 处理 SIGINT 信号(Ctrl+C) process.on('SIGINT', () => { console.log('Received SIGINT. Shutting down gracefully...'); server.close(() => {