Gioobc's picture
fast server for auditory of acts
5273cd2 verified
import { Client } from 'ssh2';
import fs from 'fs';
import path from 'path';
export default class RemoteFetcher {
constructor(config) {
this.config = {
host: config.host,
port: config.port || 22,
username: config.username,
password: config.password,
readyTimeout: 40000,
keepaliveInterval: 10000
};
this.conn = new Client();
}
connect() {
return new Promise((resolve, reject) => {
this.conn.on('ready', () => {
this.conn.sftp((err, sftp) => {
if (err) return reject(err);
this.sftp = sftp;
resolve();
});
})
.on('error', (err) => reject(err))
.connect(this.config);
});
}
// Volvemos a fastGet pero con configuración optimizada para velocidad/estabilidad
async fetchFile(remotePath, localPath, onProgress) {
return new Promise((resolve, reject) => {
this.sftp.fastGet(remotePath, localPath, {
concurrency: 6, // 6 descargas en paralelo para mayor velocidad
chunkSize: 32768, // Bloques de 32KB
step: (transferred, chunk, total) => {
if (onProgress) onProgress(transferred, total);
}
}, (err) => {
if (err) return reject(err);
resolve();
});
});
}
async listFiles(remoteDir, extension = '') {
return new Promise((resolve, reject) => {
this.sftp.readdir(remoteDir, (err, list) => {
if (err) return reject(err);
const files = list
.filter(f => f.attrs.isFile())
.map(f => f.filename);
if (extension) {
resolve(files.filter(f => f.toLowerCase().endsWith(extension.toLowerCase())));
} else {
resolve(files);
}
});
});
}
async listDirectories(remoteDir) {
return new Promise((resolve, reject) => {
this.sftp.readdir(remoteDir, (err, list) => {
if (err) return reject(err);
resolve(list.filter(f => f.attrs.isDirectory() && f.filename !== '.' && f.filename !== '..').map(f => f.filename));
});
});
}
async getFileStats(remotePath) {
return new Promise((resolve, reject) => {
this.sftp.stat(remotePath, (err, stats) => {
if (err) return reject(err);
resolve(stats);
});
});
}
disconnect() {
this.conn.end();
}
}