Files
newToy/deploy-ftp.js
2025-11-23 23:55:10 +08:00

144 lines
3.9 KiB
JavaScript

import SftpClient from 'ssh2-sftp-client';
import { readdir, stat } from 'fs/promises';
import { join } from 'path';
const sftp = new SftpClient();
const config = {
host: 'nas.rucky.cn',
port: 22,
username: 'rucky',
password: 'Scl@qq.com1'
};
const localRoot = './dist';
const remoteRoot = '/web/sports';
console.log('🚀 开始部署到 SFTP 服务器...');
console.log(`📦 服务器: ${config.host}:${config.port}`);
console.log(`📂 远程路径: ${remoteRoot}\n`);
let uploadedFiles = 0;
let uploadedSize = 0;
// 递归删除远程目录
async function removeDirectory(remotePath) {
try {
const exists = await sftp.exists(remotePath);
if (!exists) return;
const list = await sftp.list(remotePath);
for (const item of list) {
const itemPath = `${remotePath}/${item.name}`.replace(/\\/g, '/');
if (item.type === 'd') {
await removeDirectory(itemPath);
await sftp.rmdir(itemPath);
} else {
await sftp.delete(itemPath);
}
}
} catch (err) {
console.log(`⚠️ 清理失败: ${remotePath} - ${err.message}`);
}
}
// 递归上传目录
async function uploadDirectory(localDir, remoteDir) {
const files = await readdir(localDir);
for (const file of files) {
const localPath = join(localDir, file);
const remotePath = `${remoteDir}/${file}`.replace(/\\/g, '/');
try {
const stats = await stat(localPath);
if (stats.isDirectory()) {
// 创建目录
try {
const exists = await sftp.exists(remotePath);
if (!exists) {
await sftp.mkdir(remotePath);
}
} catch (err) {
// 忽略
}
await uploadDirectory(localPath, remotePath);
} else {
// 上传文件
await sftp.put(localPath, remotePath);
uploadedFiles++;
uploadedSize += stats.size;
const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
console.log(`✓ [${uploadedFiles}] ${file} (${sizeMB} MB)`);
}
} catch (err) {
console.log(`❌ 失败: ${file} - ${err.message}`);
}
}
}
async function deploy() {
const startTime = Date.now();
try {
// 1. 连接服务器
console.log('🔗 连接服务器...');
await sftp.connect(config);
console.log('✓ 连接成功!\n');
// 2. 检查并清理旧文件
console.log('🧹 清理旧文件...');
const exists = await sftp.exists(remoteRoot);
if (exists) {
await removeDirectory(remoteRoot);
console.log('✓ 旧文件已清理\n');
} else {
console.log('✓ 无需清理(首次部署)\n');
}
// 3. 创建根目录
console.log('📁 创建目标目录...');
await sftp.mkdir(remoteRoot, true);
console.log('✓ 目录创建完成\n');
// 4. 上传所有文件
console.log('📤 上传文件...\n');
await uploadDirectory(localRoot, remoteRoot);
// 5. 验证部署
console.log('\n🔍 验证部署...');
const fileList = await sftp.list(remoteRoot);
console.log(`✓ 部署成功!共 ${fileList.length} 个文件/目录`);
const totalSizeMB = (uploadedSize / 1024 / 1024).toFixed(2);
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
console.log(`\n📊 统计信息:`);
console.log(` - 上传文件数: ${uploadedFiles}`);
console.log(` - 总大小: ${totalSizeMB} MB`);
console.log(` - 耗时: ${duration}`);
console.log(` - 平均速度: ${(uploadedSize / 1024 / 1024 / duration * 1000).toFixed(2)} MB/s`);
console.log(`\n✅ 部署完成!`);
console.log(`🌐 访问地址: http://${config.host}/sports/\n`);
await sftp.end();
process.exit(0);
} catch (err) {
console.error('\n❌ 部署失败:', err.message);
console.error('详细信息:', err);
try {
await sftp.end();
} catch (e) {}
process.exit(1);
}
}
deploy();