做适配

This commit is contained in:
xion 2025-02-20 23:28:43 +08:00
parent 79a9568a87
commit b3c2587903
8 changed files with 156 additions and 20 deletions

5
.gitignore vendored
View File

@ -5,4 +5,7 @@ coverage
.DS_Store .DS_Store
upload upload
app.config.json5 app.config.json5
release/*
!release/.gitkeep

1
README.md Normal file
View File

@ -0,0 +1 @@
# page proxy

10
app.config.json5.example Normal file
View File

@ -0,0 +1,10 @@
{
port: 3005,
api: {
host: 'localhost:3000', // 后台代理
path: '/api/router',
},
allowedOrigins: ['localhost', 'xiongxiao.me', 'zxj.im'],
domain: 'demo.kevisual.xiongxiao.me',
resources: 'localhost:9000/resources',
}

View File

@ -20,29 +20,32 @@
"build": "rimraf dist && rollup -c", "build": "rimraf dist && rollup -c",
"deploy": "rsync -avz dist/ light:~/apps/var-proxy/backend", "deploy": "rsync -avz dist/ light:~/apps/var-proxy/backend",
"reload": "ssh light pm2 restart proxy", "reload": "ssh light pm2 restart proxy",
"pub": "npm run build && npm run deploy && npm run reload" "pub": "npm run build && npm run deploy && npm run reload",
"demo": "rsync -avz dist/ on:~/docker/page-proxy/dist",
"start": "pm2 start dist/app.mjs --name page-proxy",
"release": "node ./scripts/release/index.mjs"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "^28.0.1", "@rollup/plugin-commonjs": "^28.0.2",
"@rollup/plugin-json": "^6.1.0", "@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-node-resolve": "^16.0.0",
"@rollup/plugin-typescript": "^12.1.1", "@rollup/plugin-typescript": "^12.1.2",
"@types/http-proxy": "^1.17.15", "@types/http-proxy": "^1.17.16",
"@types/node": "^22.10.1", "@types/node": "^22.13.4",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"nodemon": "^3.1.7", "nodemon": "^3.1.9",
"rollup": "^4.28.1", "rollup": "^4.34.8",
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.7.2" "typescript": "^5.7.3"
}, },
"dependencies": { "dependencies": {
"@kevisual/router": "0.0.6-alpha-2", "@kevisual/router": "0.0.6-alpha-5",
"@kevisual/use-config": "^1.0.7", "@kevisual/use-config": "^1.0.7",
"ioredis": "^5.4.1", "ioredis": "^5.5.0",
"nanoid": "^5.0.9" "nanoid": "^5.1.0"
}, },
"resolutions": { "resolutions": {
"picomatch": "^4.0.2" "picomatch": "^4.0.2"

0
release/.gitkeep Normal file
View File

114
scripts/release/index.mjs Normal file
View File

@ -0,0 +1,114 @@
import fs from 'fs';
import path from 'path';
import archiver from 'archiver';
import { exec } from 'child_process';
import { nanoid } from 'nanoid';
const cwd = process.cwd();
const pkgPath = path.join(cwd, 'package.json');
export const checkFileExistsSync = (filePath) => {
try {
// 使用 F_OK 检查文件或目录是否存在
fs.accessSync(filePath, fs.constants.F_OK);
return true;
} catch (err) {
return false;
}
};
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
const releasePath = path.join(cwd, 'release');
const distPath = path.join(cwd, 'dist');
const zip = archiver('zip', {
zlib: { level: 9 },
});
const zipName = `page-proxy-${pkg.version}.zip`;
const zipCache = path.join(releasePath, `page-proxy-${pkg.version}.zip`);
const getZip = async () => {
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(zipCache);
const startTime = (new Date().getTime() / 1000).toFixed(0);
// 监听事件
output.on('close', async () => {
const bytes = zip.pointer();
const size = bytes < 1024 ? `${bytes} bytes` : `${(bytes / 1024).toFixed(2)} KB`;
console.log(`Zip file has been created successfully. Total size: ${size} bytes.`);
let time = (new Date().getTime() / 1000).toFixed(0);
console.log('time', time - startTime);
resolve();
});
output.on('end', () => {
console.log('Data has been drained.'); // 数据已被耗尽
throw new CustomError('Data has been drained.');
});
zip.on('warning', (err) => {
if (err.code === 'ENOENT') {
console.warn('File not found:', err);
} else {
throw err;
}
});
zip.on('error', (err) => {
throw err;
});
// 通过管道将 zip 数据流输出到指定文件
zip.pipe(output);
// 添加 sh 字符串作为文件到 zip 中
const sh = `#!/bin/bash
npm i -g pnpm
pnpm install --prod
`;
zip.append(sh, { name: 'start.sh' });
// 把dist目录下的文件添加到zip中
zip.directory(distPath, 'dist');
// 把README.md添加到zip中
zip.file(path.join(cwd, 'README.md'), { name: 'README.md' });
// 把package.json添加到zip中
zip.file(pkgPath, { name: 'package.json' });
const ecosystemContent = `module.exports = {
apps: [
{
name: 'page-proxy', // 应用名称
script: './dist/app.mjs', // 入口文件
// cwd: '.', // 设置当前工作目录
output: './logs/page-proxy.log',
error: './logs/page-proxy.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss',
// watch: true, // 自动监控文件变化
watch: ['dist'], // 监控的文件夹
ignore_watch: ['node_modules', 'logs'], // 忽略的文件夹
}
]
}
`;
zip.append(ecosystemContent, { name: 'ecosystem.config.cjs' });
const json5Content = fs.readFileSync(path.join(cwd, 'app.config.json5.example'), 'utf8');
// tokenSecret 是一个随机字符串,用于生成 token
const tokenSecret = 'XX' + nanoid(39);
json5Content.replace('<TOKEN_SECRET>', tokenSecret);
// tokenSecret
// 把app.config.json5.example添加到zip中
// zip.file(path.join(cwd, 'app.config.json5.example'), { name: 'app.config.json5.example' });
zip.append(json5Content, { name: 'app.config.json5.example' });
// 结束归档(必须调用,否则 zip 文件无法完成)
zip.finalize();
});
};
getZip().then(() => {
console.log('zip success');
console.log(`envision switchOrg system && envision deploy ./release/${zipName} -v 1.0.0 -k page-proxy -y y -u`);
console.log(`download zip: https://kevisual.xiongxiao.me/system/page-proxy/${zipName}`);
});

View File

@ -255,7 +255,10 @@ export const downloadUserAppFiles = async (user: string, app: string, data: type
}; };
} }
if (data.type === 'oss') { if (data.type === 'oss') {
const serverPath = 'https://' + resources + '/'; let serverPath = 'https://' + resources + '/';
if(resources.includes('localhost')) {
serverPath = 'http://' + resources + '/';
}
// server download file // server download file
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
const file = files[i]; const file = files[i];

View File

@ -24,13 +24,18 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
res.write('proxy no favicon.ico\n'); res.write('proxy no favicon.ico\n');
return; return;
} }
if (req.url.startsWith('/api/router')) { if (req.url.startsWith('/api/proxy')) {
return;
}
if (req.url.startsWith('/api')) {
// 代理到 http://codeflow.xiongxiao.me/api // 代理到 http://codeflow.xiongxiao.me/api
const _u = new URL(req.url, `http://${api.host}`); const _u = new URL(req.url, `http://${api.host}`);
// 设置代理请求的目标 URL 和请求头 // 设置代理请求的目标 URL 和请求头
let header: any = {}; let header: any = {};
if (req.headers?.['Authroization']) { if (req.headers?.['Authorization']) {
header.Authorization = req.headers?.['Authroization']; header.authorization = req.headers['Authorization'];
} else if(req.headers?.['authorization']) {
header.authorization = req.headers['authorization'];
} }
if (req.headers?.['Content-Type']) { if (req.headers?.['Content-Type']) {
header['Content-Type'] = req.headers?.['Content-Type']; header['Content-Type'] = req.headers?.['Content-Type'];
@ -64,9 +69,6 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
req.pipe(proxyReq, { end: true }); req.pipe(proxyReq, { end: true });
return; return;
} }
if (req.url.startsWith('/api/proxy')) {
return;
}
if (req.url.startsWith('/api')) { if (req.url.startsWith('/api')) {
res.end('not catch api'); res.end('not catch api');
return; return;