From f4af7d5c7f3226e2bf7df2144acf39a1f99b5385 Mon Sep 17 00:00:00 2001 From: xion Date: Wed, 26 Mar 2025 01:17:46 +0800 Subject: [PATCH] feat: change env --- .env.example | 18 ++++++++++++++++++ .gitignore | 4 ++++ package.json | 5 +++-- src/module/config.ts | 27 ++++++++++++++++++++++++--- src/module/get-user-app.ts | 23 ++++++++++++++++++++++- src/module/index.ts | 9 ++++++--- src/module/minio.ts | 35 +++++++++++++++-------------------- src/module/redis/redis.ts | 12 +++++++----- src/module/sequelize.ts | 20 ++++++++------------ src/route/app/list.ts | 4 ++++ src/scripts/get-env.ts | 4 +++- src/scripts/query-config.ts | 22 ++++++++++++++++++++++ 12 files changed, 136 insertions(+), 47 deletions(-) create mode 100644 .env.example create mode 100644 src/scripts/query-config.ts diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b9e1c55 --- /dev/null +++ b/.env.example @@ -0,0 +1,18 @@ +# 代理配置 +PROXY_PORT=3005 +PROXY_DOMAIN=localhost +PROXY_RESOURCES=http://localhost:9000/resources +PROXY_ALLOWED_ORIGINS=localhost,xiongxiao.me,zxj.im +PROXY_HOME=/ai/chat + +# 后台代理 +API_HOST=http://localhost:4005 +API_PATH=/api/router + +# Minio 配置 +MINIO_ENDPOINT=localhost +MINIO_PORT=9000 +MINIO_BUCKET_NAME=resources +MINIO_USE_SSL=false +MINIO_ACCESS_KEY=username +MINIO_SECRET_KEY=**** diff --git a/.gitignore b/.gitignore index 04d84e9..4dee946 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,7 @@ proxy-upload/* proxy-upload/.gitkeep .env +.env* +!.env.example + +pack-dist \ No newline at end of file diff --git a/package.json b/package.json index 65208c9..b6b7716 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "", "main": "index.js", "type": "module", + "basename": "/root/page-proxy", "app": { "key": "page-proxy", "entry": "dist/app.mjs", @@ -22,7 +23,7 @@ "build": "rimraf dist && rollup -c", "start": "pm2 start dist/app.mjs --name page-proxy", "release": "node ./scripts/release/index.mjs", - "deploy": "envision switch root && envision pack -p -u", + "deploy": "envision pack -p -u", "pub": "npm run build && npm run deploy", "ssl": "ssh -L 6379:localhost:6379 light" }, @@ -40,7 +41,7 @@ "concurrently": "^9.1.2", "cross-env": "^7.0.3", "nodemon": "^3.1.9", - "rollup": "^4.36.0", + "rollup": "^4.37.0", "tslib": "^2.8.1", "typescript": "^5.8.2" }, diff --git a/src/module/config.ts b/src/module/config.ts index 7d6cb3c..c900c5f 100644 --- a/src/module/config.ts +++ b/src/module/config.ts @@ -1,4 +1,4 @@ -import { useConfig } from '@kevisual/use-config'; +import { useConfig } from '@kevisual/use-config/env'; import { useFileStore } from '@kevisual/use-config/file-store'; export const fileStore = useFileStore('proxy-upload'); @@ -37,7 +37,7 @@ type ConfigType = { * allow origin xiongxiao.me zxj.im silkyai.cn * 允许跨域访问的地址 */ - allowOrigin: string[]; + allowedOrigin: string[]; /** * home 不在代理范围内跳转到的地址 @@ -46,4 +46,25 @@ type ConfigType = { }; }; -export const config = useConfig(); +// export const config = useConfig(); +export const envConfig = useConfig() as any; +export const config: ConfigType = { + api: { + host: envConfig.API_HOST, + path: envConfig.API_PATH, + port: envConfig.PROXY_PORT, + }, + apiList: [ + { + path: '/api', + target: envConfig.API_HOST, + }, + ], + proxy: { + port: envConfig.PROXY_PORT, + domain: envConfig.PROXY_DOMAIN, + resources: envConfig.PROXY_RESOURCES, + allowedOrigin: (envConfig.PROXY_ALLOWED_ORIGINS as string)?.split(',') || [], + home: envConfig.PROXY_HOME, + }, +}; diff --git a/src/module/get-user-app.ts b/src/module/get-user-app.ts index 1fd23ed..19620a2 100644 --- a/src/module/get-user-app.ts +++ b/src/module/get-user-app.ts @@ -129,6 +129,17 @@ export class UserApp { app: fetchData.key, }; redis.set(key, data.user + ':' + data.app, 'EX', 60 * 60 * 24 * 7); // 7天 + + const userDomainApp = 'user:domain:app:' + data.user + ':' + data.app; + + const domainKeys = await redis.get(userDomainApp); + let domainKeysList = domainKeys ? JSON.parse(domainKeys) : []; + domainKeysList.push(domain); + const uniq = (arr: string[]) => { + return [...new Set(arr)]; + }; + domainKeysList = uniq(domainKeysList); + await redis.set(userDomainApp, JSON.stringify(domainKeysList), 'EX', 60 * 60 * 24 * 7); // 7天 return data; } /** @@ -167,7 +178,7 @@ export class UserApp { console.log('fetchRes is error', fetchRes, 'user', user, 'app', app); return { code: 500, message: 'fetchRes is error' }; } - + const loadStatus = await getAppLoadStatus(user, app); if (loadStatus.status === 'loading') { // 其他情况,error或者running都可以重新加载 @@ -282,6 +293,16 @@ export class UserApp { await redis.del('user:app:exist:' + app + ':' + user); await redis.del('user:app:set:' + app + ':' + user); await redis.del('user:app:status:' + app + ':' + user); + const userDomainApp = 'user:domain:app:' + user + ':' + app; + const domainKeys = await redis.get(userDomainApp); + if (domainKeys) { + const domainKeysList = JSON.parse(domainKeys); + domainKeysList.forEach(async (domain: string) => { + await redis.del('domain:' + domain); + }); + } + await redis.del(userDomainApp); + // 删除所有文件 deleteUserAppFiles(user, app); } diff --git a/src/module/index.ts b/src/module/index.ts index ec33ad3..581823f 100644 --- a/src/module/index.ts +++ b/src/module/index.ts @@ -1,6 +1,5 @@ import { getDNS, isLocalhost } from '@/utils/dns.ts'; import http from 'http'; -import https from 'https'; import { UserApp } from './get-user-app.ts'; import { config, fileStore } from '../module/config.ts'; import path from 'path'; @@ -8,12 +7,11 @@ import fs from 'fs'; import { getContentType } from './get-content-type.ts'; import { createRefreshHtml } from './html/create-refresh-html.ts'; import { fileProxy } from './proxy/file-proxy.ts'; -import net from 'net'; import { httpProxy } from './proxy/http-proxy.ts'; const api = config?.api || { host: 'kevisual.xiongxiao.me', path: '/api/router' }; const domain = config?.proxy?.domain || 'kevisual.xiongxiao.me'; -const allowedOrigins = config?.proxy?.allowOrigin || []; +const allowedOrigins = config?.proxy?.allowedOrigin || []; const home = config?.proxy?.home || '/ai/chat'; const noProxyUrl = ['/', '/favicon.ico']; @@ -43,6 +41,9 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR } // 提取req的headers中的非HOST的header const headers = Object.keys(req.headers).filter((item) => item && item.toLowerCase() !== 'host'); + const host = req.headers['host']; + console.log('host', host); + console.log('headers', headers); headers.forEach((item) => { header[item] = req.headers[item]; }); @@ -96,6 +97,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR let user, app; let domainApp = false; + console.log('dns.hostName', dns.hostName, domain); if (isLocalhost(dns.hostName)) { // 本地开发环境 测试 // user = 'root'; @@ -223,6 +225,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR // console.log('isExist', isExist); if (!appFile) { const [indexFilePath, etag] = indexFile.split('||'); + // console.log('indexFilePath', indexFile, path.join(fileStore, indexFilePath)); const contentType = getContentType(indexFilePath); const isHTML = contentType.includes('html'); const filePath = path.join(fileStore, indexFilePath); diff --git a/src/module/minio.ts b/src/module/minio.ts index 7fb1724..ffe11ae 100644 --- a/src/module/minio.ts +++ b/src/module/minio.ts @@ -1,26 +1,21 @@ -import { Client, ClientOptions } from 'minio'; -import { useConfig } from '@kevisual/use-config'; - -type MinioConfig = { - minio: ClientOptions & { bucketName: string }; +import { Client } from 'minio'; +import { useConfig } from '@kevisual/use-config/env'; +const config = useConfig(); +const minioConfig = { + bucketName: config.MINIO_BUCKET_NAME, + endPoint: config.MINIO_ENDPOINT, + port: config.MINIO_PORT, + useSSL: config.MINIO_USE_SSL === 'true', + accessKey: config.MINIO_ACCESS_KEY, + secretKey: config.MINIO_SECRET_KEY, }; -const config = useConfig(); -const { bucketName, ...minioRest } = config.minio; -const { port, endPoint, useSSL } = minioRest; +// const config = useConfig(); +const { port, endPoint, useSSL } = minioConfig; export const minioUrl = `http${useSSL ? 's' : ''}://${endPoint}:${port || 9000}`; export const minioResources = `${minioUrl}/resources`; -export const minioClient = new Client(minioRest); -export { bucketName }; +export const minioClient = new Client(minioConfig); +export const bucketName = minioConfig.bucketName; + if (!minioClient) { throw new Error('Minio client not initialized'); } -// 验证权限 -// (async () => { -// const bucketExists = await minioClient.bucketExists(bucketName); -// if (!bucketExists) { -// await minioClient.makeBucket(bucketName); -// } -// const res = await minioClient.putObject(bucketName, 'private/test/a.b', 'test'); -// console.log('minio putObject', res); - -// })(); diff --git a/src/module/redis/redis.ts b/src/module/redis/redis.ts index b46e24b..893e937 100644 --- a/src/module/redis/redis.ts +++ b/src/module/redis/redis.ts @@ -1,10 +1,12 @@ import { Redis } from 'ioredis'; -import { useConfig } from '@kevisual/use-config'; import { useContextKey } from '@kevisual/use-config/context'; +console.log(process.env.REDIS_HOST); -const config = useConfig<{ - redis: ConstructorParameters; -}>(); +const redisConfig = { + host: 'localhost', // Redis 服务器的主机名或 IP 地址 + port: 6379, // Redis 服务器的端口号 + // password: 'your_password', // Redis 的密码 (如果有) +}; const init = () => { return new Redis({ host: 'localhost', // Redis 服务器的主机名或 IP 地址 @@ -17,7 +19,7 @@ const init = () => { return Math.min(times * 50, 2000); // 每次重试时延迟增加 }, maxRetriesPerRequest: null, // 允许请求重试的次数 (如果需要无限次重试) - ...config.redis, + ...redisConfig, }); }; // 配置 Redis 连接 diff --git a/src/module/sequelize.ts b/src/module/sequelize.ts index 97c3a99..e136053 100644 --- a/src/module/sequelize.ts +++ b/src/module/sequelize.ts @@ -1,19 +1,15 @@ -import { useConfig } from '@kevisual/use-config'; import { Sequelize } from 'sequelize'; import { useContextKey, useContext } from '@kevisual/use-config/context'; +import { useConfig } from '@kevisual/use-config/env'; +const config = useConfig(); -type PostgresConfig = { - postgres: { - username: string; - password: string; - host: string; - port: number; - database: string; - }; +const postgresConfig = { + username: config.POSTGRES_USERNAME, + password: config.POSTGRES_PASSWORD, + host: config.POSTGRES_HOST, + port: config.POSTGRES_PORT, + database: config.POSTGRES_DATABASE, }; -const config = useConfig(); - -const postgresConfig = config.postgres; if (!postgresConfig) { console.error('postgres config is required'); diff --git a/src/route/app/list.ts b/src/route/app/list.ts index 16d5654..121b0ac 100644 --- a/src/route/app/list.ts +++ b/src/route/app/list.ts @@ -23,14 +23,18 @@ app path: 'app', key: 'list', middleware: ['auth-admin'], + description: '获取应用列表', + isDebug: true, }) .define(async (ctx) => { const keys = await redis.keys('user:app:*'); // const keys = await redis.keys('user:app:exist:*'); // const data = await redis.mget(...keys); + const domainList = await redis.keys('domain:*'); ctx.body = { // data: data, keys, + domainList, }; }) .addTo(app); diff --git a/src/scripts/get-env.ts b/src/scripts/get-env.ts index e588b0d..ef1faf0 100644 --- a/src/scripts/get-env.ts +++ b/src/scripts/get-env.ts @@ -1,3 +1,5 @@ import { useConfig } from '@kevisual/use-config/env'; -console.log(useConfig()); \ No newline at end of file +console.log(useConfig()); + +console.log(process.env); \ No newline at end of file diff --git a/src/scripts/query-config.ts b/src/scripts/query-config.ts new file mode 100644 index 0000000..374dc93 --- /dev/null +++ b/src/scripts/query-config.ts @@ -0,0 +1,22 @@ +const baseURL = 'https://kevisual.xiongxiao.me/api/router'; +export const fetchCnfig = async () => { + const res = await fetch(baseURL, { + method: 'POST', + body: JSON.stringify({ + path: 'app', + key: 'getApp', + data: { + user: 'root', + key: 'code-center', + }, + }), + }); + return res.json(); +}; + +const main = async () => { + const res = await fetchCnfig(); + // console.log(res); + console.log(JSON.stringify(res, null, 2)); +}; +main();