UNPKG

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
'use strict'; 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 };