feat: change env

This commit is contained in:
熊潇 2025-03-26 01:17:46 +08:00
parent 29d0709083
commit f4af7d5c7f
12 changed files with 136 additions and 47 deletions

18
.env.example Normal file
View File

@ -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=****

4
.gitignore vendored
View File

@ -16,3 +16,7 @@ proxy-upload/*
proxy-upload/.gitkeep
.env
.env*
!.env.example
pack-dist

View File

@ -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"
},

View File

@ -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<ConfigType>();
// 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,
},
};

View File

@ -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);
}

View File

@ -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);

View File

@ -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<MinioConfig>();
const { bucketName, ...minioRest } = config.minio;
const { port, endPoint, useSSL } = minioRest;
// const config = useConfig<MinioConfig>();
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);
// })();

View File

@ -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<typeof Redis>;
}>();
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 连接

View File

@ -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<PostgresConfig>();
const postgresConfig = config.postgres;
if (!postgresConfig) {
console.error('postgres config is required');

View File

@ -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);

View File

@ -1,3 +1,5 @@
import { useConfig } from '@kevisual/use-config/env';
console.log(useConfig());
console.log(useConfig());
console.log(process.env);

View File

@ -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();