const { Client } = require('ssh2'); const fs = require('fs'); const path = require('path'); class SSHService { constructor(config) { this.config = config; this.client = null; } connect() { return new Promise((resolve, reject) => { this.client = new Client(); this.client.on('ready', () => { resolve(); }); this.client.on('error', (err) => { reject(err); }); this.client.connect({ host: this.config.host, port: this.config.port || 22, username: this.config.username, password: this.config.password }); }); } disconnect() { if (this.client) { this.client.end(); this.client = null; } } exec(command) { return new Promise((resolve, reject) => { if (!this.client) { reject(new Error('Not connected')); return; } this.client.exec(command, (err, stream) => { if (err) { reject(err); return; } let output = ''; let errorOutput = ''; stream.on('close', (code) => { if (code !== 0 && errorOutput) { reject(new Error(errorOutput)); } else { resolve(output); } }); stream.on('data', (data) => { output += data.toString(); }); stream.stderr.on('data', (data) => { errorOutput += data.toString(); }); }); }); } uploadFile(localPath, remotePath) { return new Promise((resolve, reject) => { if (!this.client) { reject(new Error('Not connected')); return; } this.client.sftp((err, sftp) => { if (err) { reject(err); return; } const readStream = fs.createReadStream(localPath); const writeStream = sftp.createWriteStream(remotePath); writeStream.on('close', () => { resolve(); }); writeStream.on('error', (err) => { reject(err); }); readStream.pipe(writeStream); }); }); } downloadFile(remotePath, localPath) { return new Promise((resolve, reject) => { if (!this.client) { reject(new Error('Not connected')); return; } this.client.sftp((err, sftp) => { if (err) { reject(err); return; } // Ensure local directory exists const localDir = path.dirname(localPath); if (!fs.existsSync(localDir)) { fs.mkdirSync(localDir, { recursive: true }); } const readStream = sftp.createReadStream(remotePath); const writeStream = fs.createWriteStream(localPath); writeStream.on('close', () => { resolve(); }); writeStream.on('error', (err) => { reject(err); }); readStream.on('error', (err) => { reject(err); }); readStream.pipe(writeStream); }); }); } readRemoteFile(remotePath) { return new Promise((resolve, reject) => { if (!this.client) { reject(new Error('Not connected')); return; } this.client.sftp((err, sftp) => { if (err) { reject(err); return; } sftp.readFile(remotePath, 'utf-8', (err, data) => { if (err) { reject(err); } else { resolve(data); } }); }); }); } listDirectory(remotePath) { return new Promise((resolve, reject) => { if (!this.client) { reject(new Error('Not connected')); return; } this.client.sftp((err, sftp) => { if (err) { reject(err); return; } sftp.readdir(remotePath, (err, list) => { if (err) { reject(err); } else { resolve(list.map(item => ({ name: item.filename, isDirectory: item.attrs.isDirectory(), size: item.attrs.size, mtime: item.attrs.mtime }))); } }); }); }); } } module.exports = { SSHService };