iobroker.backitup
Version:
ioBroker.backitup allows you to backup and restore your ioBroker installation and other systems, such as databases, Zigbee, scripts and many more.
171 lines (152 loc) • 6.11 kB
JavaScript
const fs = require('node:fs');
function uploadFiles(client, dir, fileNames, log, errors, callback) {
if (!fileNames || !fileNames.length) {
callback && callback();
} else {
let fileName = fileNames.shift();
fileName = fileName.replace(/\\/g, '/');
const onlyFileName = fileName.split('/').pop();
log.debug(`Send ${onlyFileName}`);
if (fs.existsSync(fileName)) {
client.put(fileName, `${dir}/${onlyFileName}`, err => {
if (err) {
errors.ftp = err;
log.error(err);
}
setImmediate(uploadFiles, client, dir, fileNames, log, errors, callback);
});
} else {
log.error(`File "${fileName}" not found`);
setImmediate(uploadFiles, client, dir, fileNames, log, errors, callback);
}
}
}
function deleteFiles(client, files, log, errors, callback) {
if (!files || !files.length) {
callback && callback();
} else {
log.debug(`delete ${files[0]}`);
const file = files.shift();
try {
client.delete(file, err => {
err && log.error(err);
setImmediate(deleteFiles, client, files, log, errors, callback);
});
} catch (e) {
log.error(e);
setImmediate(deleteFiles, client, files, log, errors, callback);
}
}
}
function cleanFiles(client, options, dir, names, num, log, errors, callback) {
if (!num) {
return callback && callback();
}
try {
if (dir[dir.length - 1] !== '/') {
dir += '/';
}
client.list(dir, (err, result) => {
if (err) {
errors.ftp = errors.ftp || err;
}
if (names && result && result.length) {
const files = [];
names.forEach(name => {
if (name) {
let subResult;
try {
subResult = result.filter(a => a.name.startsWith(name));
} catch (err) {
log.error(`FTP error: ${err}`);
}
let numDel = num;
if (name === 'influxDB' && options.influxDBMulti) numDel = num * options.influxDBEvents.length;
if (name === 'mysql' && options.mySqlMulti) numDel = num * options.mySqlEvents.length;
if (name === 'pgsql' && options.pgSqlMulti) numDel = num * options.pgSqlEvents.length;
if (name === 'homematic' && options.ccuMulti) numDel = num * options.ccuEvents.length;
if (subResult && subResult.length > numDel) {
// delete oldest files
subResult.sort((a, b) => {
const at = new Date(a.date).getTime();
const bt = new Date(b.date).getTime();
if (at > bt) return -1;
if (at < bt) return 1;
return 0;
});
for (let i = numDel; i < subResult.length; i++) {
files.push(dir + subResult[i].name);
}
}
}
});
deleteFiles(client, files, log, errors, callback);
} else {
callback && callback()
}
});
} catch (e) {
callback && callback(e);
}
}
function command(options, log, callback) {
if (options.host && options.context && options.context.fileNames && options.context.fileNames.length) {
const Client = require('ftp');
const client = new Client();
const fileNames = JSON.parse(JSON.stringify(options.context.fileNames));
if (!options.dir.startsWith('/')) {
options.dir = `/${options.dir}`;
}
let dir = (options.dir || '').replace(/\\/g, '/');
if (!dir || dir[0] !== '/') {
dir = `/${dir || ''}`;
}
client.on('ready', () => {
log.debug('FTP connected.');
uploadFiles(client, dir, fileNames, log, options.context.errors, err => {
if (options.deleteOldBackup === true) {
const ftpDeleteAfter = options.advancedDelete === false ? options.deleteBackupAfter : options.ftpDeleteAfter;
cleanFiles(client, options, dir, options.context.types, ftpDeleteAfter, log, options.context.errors, err => {
if (err) {
options.context.errors.ftp = options.context.errors.ftp || err;
} else {
options.context.done.push('ftp');
}
client.end();
if (callback) {
callback(err);
callback = null;
}
});
} else {
client.end();
!options.context.errors.ftp && options.context.done.push('ftp');
callback && callback();
}
});
});
client.on('error', err => {
options.context.errors.ftp = err;
if (callback) {
callback(err);
callback = null;
}
});
const srcFTP = {
host: options.host,
port: options.port || 21,
secure: options.secure || false,
secureOptions: { rejectUnauthorized: options.signedCertificates || true },
user: options.user,
password: options.pass
};
client.connect(srcFTP);
} else {
callback && callback();
}
}
module.exports = {
command,
ignoreErrors: true
};
;