Files
huishou/full-deploy-with-key.js
T
2026-07-27 14:07:26 +08:00

171 lines
4.8 KiB
JavaScript

const { Client } = require('ssh2');
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const privateKey = fs.readFileSync('D:\\Trae\\huishou用户密钥id_ed25519', 'utf8');
const keyConfig = {
host: 'hs.yifenbao.cn',
port: 22,
username: 'root',
privateKey: privateKey
};
const pwConfig = {
host: 'hs.yifenbao.cn',
port: 22,
username: 'root',
password: 'Torch1112'
};
function createConnection(config) {
return new Promise((resolve, reject) => {
const conn = new Client();
conn.on('ready', () => resolve(conn));
conn.on('error', (err) => {
conn.end();
reject(err);
});
conn.connect(config);
});
}
async function executeCommand(conn, cmd) {
return new Promise((resolve, reject) => {
conn.exec(cmd, (err, stream) => {
if (err) {
reject(err);
return;
}
stream.stdout.on('data', (data) => process.stdout.write(data));
stream.stderr.on('data', (data) => process.stdout.write(data));
stream.on('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`命令执行失败 (退出码: ${code})`));
}
});
});
});
}
async function uploadFileViaSFTP(conn, localPath, remotePath) {
return new Promise((resolve, reject) => {
conn.sftp((err, sftp) => {
if (err) {
reject(err);
return;
}
const dir = path.dirname(remotePath);
sftp.mkdir(dir, { recursive: true }, (err) => {
if (err && err.code !== 4) {
reject(err);
return;
}
const readStream = fs.createReadStream(localPath);
const writeStream = sftp.createWriteStream(remotePath);
writeStream.on('close', () => {
console.log(`${localPath}`);
resolve();
});
writeStream.on('error', (err) => {
reject(err);
});
readStream.pipe(writeStream);
});
});
});
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function run() {
let conn;
try {
console.log('尝试使用密钥登录...');
conn = await createConnection(keyConfig);
console.log('SSH连接成功(密钥登录)');
} catch (err) {
console.log('密钥登录失败:', err.message);
console.log('尝试密码登录...');
conn = await createConnection(pwConfig);
console.log('SSH连接成功(密码登录)');
}
try {
console.log('\n=== 上传核心文件 ===');
const coreFiles = [
{ local: './server/server.js', remote: '/www/huishou/server/server.js' },
{ local: './server/package.json', remote: '/www/huishou/server/package.json' },
{ local: './admin/index.html', remote: '/www/huishou/admin/index.html' },
{ local: './admin/nginx.conf', remote: '/www/huishou/admin/nginx.conf' },
{ local: './docker-compose.yml', remote: '/www/huishou/docker-compose.yml' },
];
for (const file of coreFiles) {
await uploadFileViaSFTP(conn, file.local, file.remote);
}
console.log('\n=== 打包H5文件 ===');
const tarPath = './h5-dist.tar.gz';
execSync(`cd dist/build/h5 && tar -czf ../../../${tarPath} .`, { stdio: 'ignore' });
console.log('✓ 使用系统tar命令打包完成');
console.log('\n=== 上传H5打包文件 ===');
await uploadFileViaSFTP(conn, tarPath, '/www/huishou/h5-dist.tar.gz');
console.log('✓ H5打包文件上传完成');
console.log('\n=== 解压H5文件 ===');
await executeCommand(conn, 'cd /www/huishou && mkdir -p dist/build/h5 && rm -rf dist/build/h5/* && tar -xzf h5-dist.tar.gz -C dist/build/h5');
console.log('✓ H5文件解压完成');
console.log('\n=== 清理临时文件 ===');
fs.unlinkSync(tarPath);
await executeCommand(conn, 'rm -f /www/huishou/h5-dist.tar.gz');
console.log('\n=== 开始部署 ===');
await executeCommand(conn, 'cd /www/huishou && docker-compose down');
console.log('\n=== 构建容器 ===');
await executeCommand(conn, 'cd /www/huishou && docker-compose build --no-cache 2>&1');
console.log('\n=== 启动服务 ===');
await executeCommand(conn, 'cd /www/huishou && docker-compose up -d');
console.log('\n=== 等待服务启动 ===');
await sleep(30000);
console.log('\n=== 检查容器状态 ===');
await executeCommand(conn, 'docker ps');
console.log('\n=== 检查API ===');
await executeCommand(conn, 'curl -s http://localhost:4000/api/statistics');
console.log('\n=== 部署完成 ===');
} catch (error) {
console.error('部署失败:', error.message);
process.exit(1);
} finally {
if (conn) conn.end();
}
}
run();