feat: change env
This commit is contained in:
parent
29d0709083
commit
f4af7d5c7f
18
.env.example
Normal file
18
.env.example
Normal 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
4
.gitignore
vendored
@ -16,3 +16,7 @@ proxy-upload/*
|
|||||||
proxy-upload/.gitkeep
|
proxy-upload/.gitkeep
|
||||||
|
|
||||||
.env
|
.env
|
||||||
|
.env*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
pack-dist
|
@ -4,6 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"basename": "/root/page-proxy",
|
||||||
"app": {
|
"app": {
|
||||||
"key": "page-proxy",
|
"key": "page-proxy",
|
||||||
"entry": "dist/app.mjs",
|
"entry": "dist/app.mjs",
|
||||||
@ -22,7 +23,7 @@
|
|||||||
"build": "rimraf dist && rollup -c",
|
"build": "rimraf dist && rollup -c",
|
||||||
"start": "pm2 start dist/app.mjs --name page-proxy",
|
"start": "pm2 start dist/app.mjs --name page-proxy",
|
||||||
"release": "node ./scripts/release/index.mjs",
|
"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",
|
"pub": "npm run build && npm run deploy",
|
||||||
"ssl": "ssh -L 6379:localhost:6379 light"
|
"ssl": "ssh -L 6379:localhost:6379 light"
|
||||||
},
|
},
|
||||||
@ -40,7 +41,7 @@
|
|||||||
"concurrently": "^9.1.2",
|
"concurrently": "^9.1.2",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"nodemon": "^3.1.9",
|
"nodemon": "^3.1.9",
|
||||||
"rollup": "^4.36.0",
|
"rollup": "^4.37.0",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.8.2"
|
"typescript": "^5.8.2"
|
||||||
},
|
},
|
||||||
|
@ -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';
|
import { useFileStore } from '@kevisual/use-config/file-store';
|
||||||
export const fileStore = useFileStore('proxy-upload');
|
export const fileStore = useFileStore('proxy-upload');
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ type ConfigType = {
|
|||||||
* allow origin xiongxiao.me zxj.im silkyai.cn
|
* allow origin xiongxiao.me zxj.im silkyai.cn
|
||||||
* 允许跨域访问的地址
|
* 允许跨域访问的地址
|
||||||
*/
|
*/
|
||||||
allowOrigin: string[];
|
allowedOrigin: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* home 不在代理范围内跳转到的地址
|
* 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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -129,6 +129,17 @@ export class UserApp {
|
|||||||
app: fetchData.key,
|
app: fetchData.key,
|
||||||
};
|
};
|
||||||
redis.set(key, data.user + ':' + data.app, 'EX', 60 * 60 * 24 * 7); // 7天
|
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;
|
return data;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -282,6 +293,16 @@ export class UserApp {
|
|||||||
await redis.del('user:app:exist:' + app + ':' + user);
|
await redis.del('user:app:exist:' + app + ':' + user);
|
||||||
await redis.del('user:app:set:' + app + ':' + user);
|
await redis.del('user:app:set:' + app + ':' + user);
|
||||||
await redis.del('user:app:status:' + 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);
|
deleteUserAppFiles(user, app);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { getDNS, isLocalhost } from '@/utils/dns.ts';
|
import { getDNS, isLocalhost } from '@/utils/dns.ts';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import https from 'https';
|
|
||||||
import { UserApp } from './get-user-app.ts';
|
import { UserApp } from './get-user-app.ts';
|
||||||
import { config, fileStore } from '../module/config.ts';
|
import { config, fileStore } from '../module/config.ts';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
@ -8,12 +7,11 @@ import fs from 'fs';
|
|||||||
import { getContentType } from './get-content-type.ts';
|
import { getContentType } from './get-content-type.ts';
|
||||||
import { createRefreshHtml } from './html/create-refresh-html.ts';
|
import { createRefreshHtml } from './html/create-refresh-html.ts';
|
||||||
import { fileProxy } from './proxy/file-proxy.ts';
|
import { fileProxy } from './proxy/file-proxy.ts';
|
||||||
import net from 'net';
|
|
||||||
import { httpProxy } from './proxy/http-proxy.ts';
|
import { httpProxy } from './proxy/http-proxy.ts';
|
||||||
|
|
||||||
const api = config?.api || { host: 'kevisual.xiongxiao.me', path: '/api/router' };
|
const api = config?.api || { host: 'kevisual.xiongxiao.me', path: '/api/router' };
|
||||||
const domain = config?.proxy?.domain || 'kevisual.xiongxiao.me';
|
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 home = config?.proxy?.home || '/ai/chat';
|
||||||
|
|
||||||
const noProxyUrl = ['/', '/favicon.ico'];
|
const noProxyUrl = ['/', '/favicon.ico'];
|
||||||
@ -43,6 +41,9 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
|
|||||||
}
|
}
|
||||||
// 提取req的headers中的非HOST的header
|
// 提取req的headers中的非HOST的header
|
||||||
const headers = Object.keys(req.headers).filter((item) => item && item.toLowerCase() !== 'host');
|
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) => {
|
headers.forEach((item) => {
|
||||||
header[item] = req.headers[item];
|
header[item] = req.headers[item];
|
||||||
});
|
});
|
||||||
@ -96,6 +97,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
|
|||||||
|
|
||||||
let user, app;
|
let user, app;
|
||||||
let domainApp = false;
|
let domainApp = false;
|
||||||
|
console.log('dns.hostName', dns.hostName, domain);
|
||||||
if (isLocalhost(dns.hostName)) {
|
if (isLocalhost(dns.hostName)) {
|
||||||
// 本地开发环境 测试
|
// 本地开发环境 测试
|
||||||
// user = 'root';
|
// user = 'root';
|
||||||
@ -223,6 +225,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
|
|||||||
// console.log('isExist', isExist);
|
// console.log('isExist', isExist);
|
||||||
if (!appFile) {
|
if (!appFile) {
|
||||||
const [indexFilePath, etag] = indexFile.split('||');
|
const [indexFilePath, etag] = indexFile.split('||');
|
||||||
|
// console.log('indexFilePath', indexFile, path.join(fileStore, indexFilePath));
|
||||||
const contentType = getContentType(indexFilePath);
|
const contentType = getContentType(indexFilePath);
|
||||||
const isHTML = contentType.includes('html');
|
const isHTML = contentType.includes('html');
|
||||||
const filePath = path.join(fileStore, indexFilePath);
|
const filePath = path.join(fileStore, indexFilePath);
|
||||||
|
@ -1,26 +1,21 @@
|
|||||||
import { Client, ClientOptions } from 'minio';
|
import { Client } from 'minio';
|
||||||
import { useConfig } from '@kevisual/use-config';
|
import { useConfig } from '@kevisual/use-config/env';
|
||||||
|
const config = useConfig();
|
||||||
type MinioConfig = {
|
const minioConfig = {
|
||||||
minio: ClientOptions & { bucketName: string };
|
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 config = useConfig<MinioConfig>();
|
||||||
const { bucketName, ...minioRest } = config.minio;
|
const { port, endPoint, useSSL } = minioConfig;
|
||||||
const { port, endPoint, useSSL } = minioRest;
|
|
||||||
export const minioUrl = `http${useSSL ? 's' : ''}://${endPoint}:${port || 9000}`;
|
export const minioUrl = `http${useSSL ? 's' : ''}://${endPoint}:${port || 9000}`;
|
||||||
export const minioResources = `${minioUrl}/resources`;
|
export const minioResources = `${minioUrl}/resources`;
|
||||||
export const minioClient = new Client(minioRest);
|
export const minioClient = new Client(minioConfig);
|
||||||
export { bucketName };
|
export const bucketName = minioConfig.bucketName;
|
||||||
|
|
||||||
if (!minioClient) {
|
if (!minioClient) {
|
||||||
throw new Error('Minio client not initialized');
|
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);
|
|
||||||
|
|
||||||
// })();
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { Redis } from 'ioredis';
|
import { Redis } from 'ioredis';
|
||||||
import { useConfig } from '@kevisual/use-config';
|
|
||||||
import { useContextKey } from '@kevisual/use-config/context';
|
import { useContextKey } from '@kevisual/use-config/context';
|
||||||
|
console.log(process.env.REDIS_HOST);
|
||||||
|
|
||||||
const config = useConfig<{
|
const redisConfig = {
|
||||||
redis: ConstructorParameters<typeof Redis>;
|
host: 'localhost', // Redis 服务器的主机名或 IP 地址
|
||||||
}>();
|
port: 6379, // Redis 服务器的端口号
|
||||||
|
// password: 'your_password', // Redis 的密码 (如果有)
|
||||||
|
};
|
||||||
const init = () => {
|
const init = () => {
|
||||||
return new Redis({
|
return new Redis({
|
||||||
host: 'localhost', // Redis 服务器的主机名或 IP 地址
|
host: 'localhost', // Redis 服务器的主机名或 IP 地址
|
||||||
@ -17,7 +19,7 @@ const init = () => {
|
|||||||
return Math.min(times * 50, 2000); // 每次重试时延迟增加
|
return Math.min(times * 50, 2000); // 每次重试时延迟增加
|
||||||
},
|
},
|
||||||
maxRetriesPerRequest: null, // 允许请求重试的次数 (如果需要无限次重试)
|
maxRetriesPerRequest: null, // 允许请求重试的次数 (如果需要无限次重试)
|
||||||
...config.redis,
|
...redisConfig,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 配置 Redis 连接
|
// 配置 Redis 连接
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
import { useConfig } from '@kevisual/use-config';
|
|
||||||
import { Sequelize } from 'sequelize';
|
import { Sequelize } from 'sequelize';
|
||||||
import { useContextKey, useContext } from '@kevisual/use-config/context';
|
import { useContextKey, useContext } from '@kevisual/use-config/context';
|
||||||
|
import { useConfig } from '@kevisual/use-config/env';
|
||||||
|
const config = useConfig();
|
||||||
|
|
||||||
type PostgresConfig = {
|
const postgresConfig = {
|
||||||
postgres: {
|
username: config.POSTGRES_USERNAME,
|
||||||
username: string;
|
password: config.POSTGRES_PASSWORD,
|
||||||
password: string;
|
host: config.POSTGRES_HOST,
|
||||||
host: string;
|
port: config.POSTGRES_PORT,
|
||||||
port: number;
|
database: config.POSTGRES_DATABASE,
|
||||||
database: string;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
const config = useConfig<PostgresConfig>();
|
|
||||||
|
|
||||||
const postgresConfig = config.postgres;
|
|
||||||
|
|
||||||
if (!postgresConfig) {
|
if (!postgresConfig) {
|
||||||
console.error('postgres config is required');
|
console.error('postgres config is required');
|
||||||
|
@ -23,14 +23,18 @@ app
|
|||||||
path: 'app',
|
path: 'app',
|
||||||
key: 'list',
|
key: 'list',
|
||||||
middleware: ['auth-admin'],
|
middleware: ['auth-admin'],
|
||||||
|
description: '获取应用列表',
|
||||||
|
isDebug: true,
|
||||||
})
|
})
|
||||||
.define(async (ctx) => {
|
.define(async (ctx) => {
|
||||||
const keys = await redis.keys('user:app:*');
|
const keys = await redis.keys('user:app:*');
|
||||||
// const keys = await redis.keys('user:app:exist:*');
|
// const keys = await redis.keys('user:app:exist:*');
|
||||||
// const data = await redis.mget(...keys);
|
// const data = await redis.mget(...keys);
|
||||||
|
const domainList = await redis.keys('domain:*');
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
// data: data,
|
// data: data,
|
||||||
keys,
|
keys,
|
||||||
|
domainList,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.addTo(app);
|
.addTo(app);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
import { useConfig } from '@kevisual/use-config/env';
|
import { useConfig } from '@kevisual/use-config/env';
|
||||||
|
|
||||||
console.log(useConfig());
|
console.log(useConfig());
|
||||||
|
|
||||||
|
console.log(process.env);
|
22
src/scripts/query-config.ts
Normal file
22
src/scripts/query-config.ts
Normal 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();
|
Loading…
x
Reference in New Issue
Block a user