This commit is contained in:
蒋小陌 2024-10-13 15:09:25 +08:00
parent db2c953ae6
commit d0b5151228

View File

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