perf: 优化缓存下载
This commit is contained in:
		| @@ -2,7 +2,7 @@ | ||||
|   port: 3005, | ||||
|   api: { | ||||
|     host: 'localhost:4000', // 后台代理 | ||||
|     testHost: 'localhost:4000', | ||||
|     path: '/api/router', | ||||
|   }, | ||||
|   allowedOrigins: ['localhost', 'xiongxiao.me', 'zxj.im'], | ||||
|   domain: 'kevisual.xiongxiao.me', | ||||
|   | ||||
| @@ -19,13 +19,13 @@ | ||||
|     "@rollup/plugin-json": "^6.1.0", | ||||
|     "@rollup/plugin-node-resolve": "^15.3.0", | ||||
|     "@rollup/plugin-typescript": "^12.1.0", | ||||
|     "@types/node": "^22.7.4", | ||||
|     "@types/node": "^22.7.5", | ||||
|     "cross-env": "^7.0.3", | ||||
|     "nodemon": "^3.1.7", | ||||
|     "rollup": "^4.24.0", | ||||
|     "ts-lib": "^0.0.5", | ||||
|     "tslib": "^2.7.0", | ||||
|     "typescript": "^5.6.2" | ||||
|     "typescript": "^5.6.3" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@abearxiong/use-config": "^0.0.2", | ||||
|   | ||||
							
								
								
									
										38
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										38
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @@ -16,7 +16,7 @@ importers: | ||||
|         version: 0.0.2 | ||||
|       '@abearxiong/use-file-store': | ||||
|         specifier: ^0.0.1 | ||||
|         version: 0.0.1(typescript@5.6.2) | ||||
|         version: 0.0.1(typescript@5.6.3) | ||||
|       ioredis: | ||||
|         specifier: ^5.4.1 | ||||
|         version: 5.4.1 | ||||
| @@ -35,10 +35,10 @@ importers: | ||||
|         version: 15.3.0(rollup@4.24.0) | ||||
|       '@rollup/plugin-typescript': | ||||
|         specifier: ^12.1.0 | ||||
|         version: 12.1.0(rollup@4.24.0)(tslib@2.7.0)(typescript@5.6.2) | ||||
|         version: 12.1.0(rollup@4.24.0)(tslib@2.7.0)(typescript@5.6.3) | ||||
|       '@types/node': | ||||
|         specifier: ^22.7.4 | ||||
|         version: 22.7.4 | ||||
|         specifier: ^22.7.5 | ||||
|         version: 22.7.5 | ||||
|       cross-env: | ||||
|         specifier: ^7.0.3 | ||||
|         version: 7.0.3 | ||||
| @@ -55,8 +55,8 @@ importers: | ||||
|         specifier: ^2.7.0 | ||||
|         version: 2.7.0 | ||||
|       typescript: | ||||
|         specifier: ^5.6.2 | ||||
|         version: 5.6.2 | ||||
|         specifier: ^5.6.3 | ||||
|         version: 5.6.3 | ||||
|  | ||||
| packages: | ||||
|  | ||||
| @@ -234,8 +234,8 @@ packages: | ||||
|   '@types/json-schema@7.0.15': | ||||
|     resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} | ||||
|  | ||||
|   '@types/node@22.7.4': | ||||
|     resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==} | ||||
|   '@types/node@22.7.5': | ||||
|     resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} | ||||
|  | ||||
|   '@types/resolve@1.20.2': | ||||
|     resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} | ||||
| @@ -738,8 +738,8 @@ packages: | ||||
|   tslib@2.7.0: | ||||
|     resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} | ||||
|  | ||||
|   typescript@5.6.2: | ||||
|     resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} | ||||
|   typescript@5.6.3: | ||||
|     resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} | ||||
|     engines: {node: '>=14.17'} | ||||
|     hasBin: true | ||||
|  | ||||
| @@ -785,10 +785,10 @@ snapshots: | ||||
|  | ||||
|   '@abearxiong/use-config@0.0.2': {} | ||||
|  | ||||
|   '@abearxiong/use-file-store@0.0.1(typescript@5.6.2)': | ||||
|   '@abearxiong/use-file-store@0.0.1(typescript@5.6.3)': | ||||
|     dependencies: | ||||
|       json5: 2.2.3 | ||||
|       ts-loader: 9.5.1(typescript@5.6.2)(webpack@5.95.0) | ||||
|       ts-loader: 9.5.1(typescript@5.6.3)(webpack@5.95.0) | ||||
|       webpack: 5.95.0 | ||||
|     transitivePeerDependencies: | ||||
|       - '@swc/core' | ||||
| @@ -849,11 +849,11 @@ snapshots: | ||||
|     optionalDependencies: | ||||
|       rollup: 4.24.0 | ||||
|  | ||||
|   '@rollup/plugin-typescript@12.1.0(rollup@4.24.0)(tslib@2.7.0)(typescript@5.6.2)': | ||||
|   '@rollup/plugin-typescript@12.1.0(rollup@4.24.0)(tslib@2.7.0)(typescript@5.6.3)': | ||||
|     dependencies: | ||||
|       '@rollup/pluginutils': 5.1.2(rollup@4.24.0) | ||||
|       resolve: 1.22.8 | ||||
|       typescript: 5.6.2 | ||||
|       typescript: 5.6.3 | ||||
|     optionalDependencies: | ||||
|       rollup: 4.24.0 | ||||
|       tslib: 2.7.0 | ||||
| @@ -918,7 +918,7 @@ snapshots: | ||||
|  | ||||
|   '@types/json-schema@7.0.15': {} | ||||
|  | ||||
|   '@types/node@22.7.4': | ||||
|   '@types/node@22.7.5': | ||||
|     dependencies: | ||||
|       undici-types: 6.19.8 | ||||
|  | ||||
| @@ -1210,7 +1210,7 @@ snapshots: | ||||
|  | ||||
|   jest-worker@27.5.1: | ||||
|     dependencies: | ||||
|       '@types/node': 22.7.4 | ||||
|       '@types/node': 22.7.5 | ||||
|       merge-stream: 2.0.0 | ||||
|       supports-color: 8.1.1 | ||||
|  | ||||
| @@ -1399,19 +1399,19 @@ snapshots: | ||||
|  | ||||
|   ts-lib@0.0.5: {} | ||||
|  | ||||
|   ts-loader@9.5.1(typescript@5.6.2)(webpack@5.95.0): | ||||
|   ts-loader@9.5.1(typescript@5.6.3)(webpack@5.95.0): | ||||
|     dependencies: | ||||
|       chalk: 4.1.2 | ||||
|       enhanced-resolve: 5.17.1 | ||||
|       micromatch: 4.0.8 | ||||
|       semver: 7.6.3 | ||||
|       source-map: 0.7.4 | ||||
|       typescript: 5.6.2 | ||||
|       typescript: 5.6.3 | ||||
|       webpack: 5.95.0 | ||||
|  | ||||
|   tslib@2.7.0: {} | ||||
|  | ||||
|   typescript@5.6.2: {} | ||||
|   typescript@5.6.3: {} | ||||
|  | ||||
|   undefsafe@2.0.5: {} | ||||
|  | ||||
|   | ||||
| @@ -9,9 +9,9 @@ import { pipeline } from 'stream'; | ||||
| import { promisify } from 'util'; | ||||
| const pipelineAsync = promisify(pipeline); | ||||
|  | ||||
| const { resources, api } = useConfig<{ resources: string; api: { host: string; testHost: string } }>(); | ||||
| const { resources, api } = useConfig<{ resources: string; api: { host: string; path: string } }>(); | ||||
| const fileStore = useFileStore('upload'); | ||||
|  | ||||
| const status: { [key: string]: boolean } = {}; | ||||
| const demoData = { | ||||
|   user: 'root', | ||||
|   key: 'codeflow', | ||||
| @@ -40,6 +40,7 @@ type UserAppOptions = { | ||||
|   user: string; | ||||
|   app: string; | ||||
| }; | ||||
|  | ||||
| export class UserApp { | ||||
|   user: string; | ||||
|   app: string; | ||||
| @@ -82,10 +83,8 @@ export class UserApp { | ||||
|     } | ||||
|  | ||||
|     // 获取域名对应的用户和应用 | ||||
|     const isDev = process.env.NODE_ENV === 'development'; | ||||
|     const fetchTestUrl = 'http://' + api.testHost + '/api/router'; | ||||
|     const fetchUrl = 'http://' + api.host + '/api/router'; | ||||
|     const fetchRes = await fetch(isDev ? fetchTestUrl : fetchUrl, { | ||||
|     const fetchUrl = 'http://' + api.host + api.path; | ||||
|     const fetchRes = await fetch(fetchUrl, { | ||||
|       method: 'POST', | ||||
|       headers: { | ||||
|         'Content-Type': 'application/json', | ||||
| @@ -114,14 +113,26 @@ export class UserApp { | ||||
|     redis.set(key, data.user + ':' + data.app, 'EX', 60 * 60 * 24 * 7); // 24小时 | ||||
|     return data; | ||||
|   } | ||||
|   async setLoaded() { | ||||
|     const app = this.app; | ||||
|     const user = this.user; | ||||
|     const key = 'user:app:' + app + ':' + user; | ||||
|     if (status[key]) { | ||||
|       status[key] = false; | ||||
|     } | ||||
|   } | ||||
|   async setCacheData() { | ||||
|     const app = this.app; | ||||
|     const user = this.user; | ||||
|     const key = 'user:app:' + app + ':' + user; | ||||
|     const isDev = process.env.NODE_ENV === 'development'; | ||||
|     const fetchTestUrl = 'http://' + api.testHost + '/api/router'; | ||||
|     const fetchUrl = 'http://' + api.host + '/api/router'; | ||||
|     const fetchRes = await fetch(isDev ? fetchTestUrl : fetchUrl, { | ||||
|     const fetchUrl = 'http://' + api.host + api.path; | ||||
|     if (status[key]) { | ||||
|       return { | ||||
|         loading: true, | ||||
|       }; | ||||
|     } | ||||
|     status[key] = true; | ||||
|     const fetchRes = await fetch(fetchUrl, { | ||||
|       method: 'POST', | ||||
|       headers: { | ||||
|         'Content-Type': 'application/json', | ||||
| @@ -137,7 +148,8 @@ export class UserApp { | ||||
|     }).then((res) => res.json()); | ||||
|     if (fetchRes?.code !== 200) { | ||||
|       console.log('fetchRes is error', fetchRes); | ||||
|       return false; | ||||
|       this.setLoaded(); | ||||
|       return { code: 500, message: 'fetchRes is error' }; | ||||
|     } | ||||
|     const fetchData = fetchRes.data; | ||||
|     if (!fetchData.type) { | ||||
| @@ -147,12 +159,17 @@ export class UserApp { | ||||
|     } | ||||
|     if (fetchData.status !== 'running') { | ||||
|       console.error('fetchData status is not running', fetchData.user, fetchData.key); | ||||
|       return null; | ||||
|       this.setLoaded(); | ||||
|       return { | ||||
|         code: 500, | ||||
|         message: 'fetchData status is not running', | ||||
|       }; | ||||
|     } | ||||
|     const value = await downloadUserAppFiles(user, app, fetchData); | ||||
|     if (value.data.files.length === 0) { | ||||
|       console.error('root files length is zero', user, app); | ||||
|       return false; | ||||
|       this.setLoaded(); | ||||
|       return { code: 404 }; | ||||
|     } | ||||
|     let valueIndexHtml = value.data.files.find((file) => file.name === 'index.html'); | ||||
|     if (!valueIndexHtml) { | ||||
| @@ -172,8 +189,9 @@ export class UserApp { | ||||
|       data[file.name] = file.path; | ||||
|     }); | ||||
|     await redis.hset('user:app:set:' + app + ':' + user, data); | ||||
|     this.setLoaded(); | ||||
|  | ||||
|     return true; | ||||
|     return { code: 200, data: valueIndexHtml.path }; | ||||
|   } | ||||
|   async getAllCacheData() { | ||||
|     const app = this.app; | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import fs from 'fs'; | ||||
| import { useConfig } from '@abearxiong/use-config'; | ||||
| import { redis } from './redis/redis.ts'; | ||||
| import { getContentType } from './get-content-type.ts'; | ||||
| import { sleep } from '@/utils/sleep.ts'; | ||||
| const { api, domain, allowedOrigins } = useConfig<{ | ||||
|   api: { | ||||
|     host: string; | ||||
| @@ -128,30 +129,38 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR | ||||
|   let isExist = await userApp.getExist(); | ||||
|   if (!isExist) { | ||||
|     try { | ||||
|       const hasApp = await userApp.setCacheData(); | ||||
|       if (!hasApp) { | ||||
|       const { code, loading, data } = await userApp.setCacheData(); | ||||
|       if (loading) { | ||||
|         res.writeHead(200, { 'Content-Type': 'text/html' }); | ||||
|         res.write('Loading App\n'); | ||||
|         res.end(); | ||||
|         return; | ||||
|       } | ||||
|       if (code !== 200) { | ||||
|         res.writeHead(404, { 'Content-Type': 'text/html' }); | ||||
|         res.write('Not Found App\n'); | ||||
|         res.end(); | ||||
|         return; | ||||
|       } | ||||
|       await sleep(1000); | ||||
|       isExist = data; // 设置缓存后再次获取 | ||||
|       if (!isExist) { | ||||
|         res.writeHead(404, { 'Content-Type': 'text/html' }); | ||||
|         res.write('Not Found App Index Page\n'); | ||||
|         res.end(); | ||||
|         return; | ||||
|       } | ||||
|     } catch (error) { | ||||
|       console.error('setCacheData error', error); | ||||
|       res.writeHead(500, { 'Content-Type': 'text/html' }); | ||||
|       res.write('Server Error\n'); | ||||
|       res.end(); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     isExist = await userApp.getExist(); | ||||
|     if (!isExist) { | ||||
|       res.writeHead(404, { 'Content-Type': 'text/html' }); | ||||
|       res.write('Not Found App Index Page\n'); | ||||
|       res.end(); | ||||
|       userApp.setLoaded(); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   const indexFile = isExist; | ||||
|   const indexFile = isExist; // 已经必定存在了 | ||||
|  | ||||
|   let appFileUrl: string; | ||||
|   if (domainApp) { | ||||
|     appFileUrl = (url + '').replace(`/`, ''); | ||||
|   | ||||
							
								
								
									
										1
									
								
								src/utils/sleep.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/utils/sleep.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); | ||||
		Reference in New Issue
	
	Block a user