From c92f817d667e33e8fcdfad4d44f4a63df0534db5 Mon Sep 17 00:00:00 2001 From: xion Date: Fri, 11 Oct 2024 23:47:34 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/module/get-user-app.ts | 70 +++++++++++++++++++++++++++----------- src/module/index.ts | 21 ++++++++++-- src/utils/dns.ts | 2 +- 3 files changed, 70 insertions(+), 23 deletions(-) diff --git a/src/module/get-user-app.ts b/src/module/get-user-app.ts index a8d824f..e958ea9 100644 --- a/src/module/get-user-app.ts +++ b/src/module/get-user-app.ts @@ -96,7 +96,16 @@ export class UserApp { domain, }, }), - }).then((res) => res.json()); + }) + .then((res) => { + return res.json(); + }) + .catch((err) => { + return { + code: 500, + message: err, + }; + }); if (fetchRes?.code !== 200) { console.log('fetchRes is error', fetchRes); return null; @@ -121,6 +130,12 @@ export class UserApp { status[key] = false; } } + async getLoaded() { + const app = this.app; + const user = this.user; + const key = 'user:app:' + app + ':' + user; + return status[key]; + } async setCacheData() { const app = this.app; const user = this.user; @@ -214,6 +229,9 @@ export class UserApp { // 删除所有文件 deleteUserAppFiles(user, app); } + fileCheck(file: string) { + return checkFileExistsSync(file); + } async close() { // 关闭连接 await redis.quit(); @@ -229,25 +247,35 @@ export const downloadUserAppFiles = async (user: string, app: string, data: type fs.mkdirSync(uploadFiles, { recursive: true }); } const newFiles = []; - if (data.type === 'local') { - // local copy file - for (let i = 0; i < files.length; i++) { - const file = files[i]; - const copyFile = path.join(fileStore, file.path); - const destFile = path.join(uploadFiles, file.name); - const destDir = path.dirname(destFile); // 获取目标文件所在的目录路径 - // 检查目录是否存在,如果不存在则创建 - if (!checkFileExistsSync(destDir)) { - fs.mkdirSync(destDir, { recursive: true }); // 递归创建目录 + try { + if (data.type === 'local') { + // local copy file + for (let i = 0; i < files.length; i++) { + const file = files[i]; + const copyFile = path.join(fileStore, file.path); + const destFile = path.join(uploadFiles, file.name); + const destDir = path.dirname(destFile); // 获取目标文件所在的目录路径 + // 检查目录是否存在,如果不存在则创建 + if (!checkFileExistsSync(destDir)) { + fs.mkdirSync(destDir, { recursive: true }); // 递归创建目录 + } + fs.copyFileSync(copyFile, destFile); + // const etag = await setEtag(fs.readFileSync(destFile, 'utf-8')); + const etag = nanoid(); + newFiles.push({ + name: file.name, + path: destFile.replace(fileStore, '') + '||' + etag, + }); } - fs.copyFileSync(copyFile, destFile); - // const etag = await setEtag(fs.readFileSync(destFile, 'utf-8')); - const etag = nanoid(); - newFiles.push({ - name: file.name, - path: destFile.replace(fileStore, '') + '||' + etag, - }); } + } catch (err) { + const userApp = new UserApp({ user, app }); + userApp.clearCacheData(); + return { + data: { + files: [], + }, + }; } if (data.type === 'oss') { const serverPath = 'https://' + resources + '/'; @@ -292,7 +320,11 @@ export const deleteUserAppFiles = async (user: string, app: string) => { try { fs.rmSync(uploadFiles, { recursive: true }); } catch (err) { - console.error('deleteUserAppFiles', err); + if (err.code === 'ENOENT') { + // 文件不存在 + } else { + console.error('deleteUserAppFiles', err); + } } // console.log('deleteUserAppFiles', res); }; diff --git a/src/module/index.ts b/src/module/index.ts index d343aab..dcd6b00 100644 --- a/src/module/index.ts +++ b/src/module/index.ts @@ -17,7 +17,6 @@ const { api, domain, allowedOrigins } = useConfig<{ }>(); const fileStore = useFileStore('upload'); -console.log('filePath', fileStore); const noProxyUrl = ['/', '/favicon.ico']; export const handleRequest = async (req: http.IncomingMessage, res: http.ServerResponse) => { const dns = getDNS(req); @@ -42,7 +41,6 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR // app = 'codeflow'; // domainApp = true; } else { - // 生产环境 // 验证域名 if (dns.hostName !== domain) { // redis获取域名对应的用户和应用 @@ -172,6 +170,14 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR const [indexFilePath, etag] = indexFile.split('||'); const contentType = getContentType(indexFilePath); const isHTML = contentType.includes('html'); + const filePath = path.join(fileStore, indexFilePath); + if (!userApp.fileCheck(filePath)) { + res.writeHead(500, { 'Content-Type': 'text/html' }); + res.write('File expired, Not Found\n'); + res.end(); + await userApp.clearCacheData(); + return; + } // 如果 content是 'application/octet-stream' 会下载文件, 添加文件后缀 if (contentType === 'application/octet-stream') { // 提取文件名,只保留文件名而不是整个路径 @@ -181,9 +187,9 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR // 不存在的文件,返回indexFile的文件 res.writeHead(200, { 'Content-Type': contentType, 'Cache-Control': isHTML ? 'no-cache' : 'public, max-age=3600' }); - const filePath = path.join(fileStore, indexFilePath); const readStream = fs.createReadStream(filePath); readStream.pipe(res); + return; } else { const [appFilePath, eTag] = appFile.split('||'); @@ -207,8 +213,17 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR 'Cache-Control': isHTML ? 'no-cache' : 'public, max-age=3600', // 设置缓存时间为 1 小时 ETag: eTag, }); + if (!userApp.fileCheck(filePath)) { + console.error('File expired', filePath); + res.writeHead(500, { 'Content-Type': 'text/html' }); + res.write('File expired\n'); + res.end(); + await userApp.clearCacheData(); + return; + } const readStream = fs.createReadStream(filePath); readStream.pipe(res); + return; } }; diff --git a/src/utils/dns.ts b/src/utils/dns.ts index 39a6c63..19f9de6 100644 --- a/src/utils/dns.ts +++ b/src/utils/dns.ts @@ -7,5 +7,5 @@ export const getDNS = (req: http.IncomingMessage) => { }; export const isLocalhost = (hostName: string) => { - return hostName.includes('localhost'); + return hostName.includes('localhost') || hostName.includes('192.168'); };