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.
176 lines (154 loc) • 6.78 kB
JavaScript
const path = require('node:path');
const fs = require('node:fs');
const dropboxV2Api = require('dropbox-v2-api');
const Dropbox = require('../dropboxLib');
async function copyFiles(dbx, dropbox, 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();
if (fs.existsSync(fileName)) {
try {
log.debug(`Dropbox: Copy ${onlyFileName}...`);
const fileSize = fs.statSync(fileName).size;
if (fileSize && (Math.round(fileSize / (1024 * 1024) * 10) / 10) <= 100) {
const readStream = fs.createReadStream(fileName);
readStream.on('error', err => {
err && log.error(`readStream Dropbox: ${err}`);
});
dbx({
resource: 'files/upload',
parameters: {
path: path.join(dir, onlyFileName).replace(/\\/g, '/')
},
readStream: readStream
}, (err, result, response) => {
if (err) {
errors.dropbox = JSON.stringify(err);
}
err && log.error(`upload Dropbox: ${JSON.stringify(err)}`);
setImmediate(copyFiles, dbx, dropbox, dir, fileNames, log, errors, callback);
});
} else if (fileSize && (Math.round(fileSize / (1024 * 1024) * 10) / 10) > 100) {
await dropbox.sessionUpload(dbx, fileName, dir, log);
setImmediate(copyFiles, dbx, dropbox, dir, fileNames, log, errors, callback);
}
} catch (e) {
errors.dropbox = e;
log.error(`Dropbox: ${JSON.stringify(e)}`);
setImmediate(copyFiles, dbx, dropbox, dir, fileNames, log, errors, callback)
}
} else {
log.error(`Dropbox: File "${fileName}" not found`);
setImmediate(copyFiles, dbx, dropbox, dir, fileNames, log, errors, callback)
}
}
}
function deleteFiles(dbx, files, log, errors, callback) {
if (!files || !files.length) {
callback && callback();
} else {
log.debug(`Dropbox: delete ${files[0]}`);
try {
dbx({
resource: 'files/delete',
parameters: {
path: files.shift()
},
}, (err, result) => {
err && log.error(`Dropbox: ${JSON.stringify(err)}`);
setImmediate(deleteFiles, dbx, files, log, errors, callback);
});
} catch (e) {
log.error(`Dropbox: ${JSON.stringify(e)}`);
callback && callback();
setImmediate(deleteFiles, dbx, files, log, errors, callback);
}
}
}
function cleanFiles(dbx, options, dir, names, num, log, errors, callback) {
if (!num) {
return callback && callback();
}
try {
dbx({
resource: 'files/list_folder',
parameters: {
path: dir.replace(/^\/$/, '')
},
}, (err, result) => {
err && log.error(`Dropbox: ${JSON.stringify(err)}`);
if (result && result.entries) {
const files = [];
names.forEach(name => {
const subResult = result.entries.filter(a => a.name.startsWith(name));
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.length > numDel) {
// delete oldest files
subResult.sort((a, b) => {
const at = new Date(a.client_modified).getTime();
const bt = new Date(b.client_modified).getTime();
if (at > bt) return -1;
if (at < bt) return 1;
return 0;
});
for (let i = numDel; i < subResult.length; i++) {
files.push(subResult[i].path_display);
}
}
});
deleteFiles(dbx, files, log, errors, callback);
} else {
callback && callback();
}
});
} catch (e) {
callback && callback(e);
}
}
async function command(options, log, callback) {
const dropbox = new Dropbox();
// Token refresh
const db_accessToken = options.accessToken || '';
if (db_accessToken && options.context.fileNames.length) {
const fileNames = JSON.parse(JSON.stringify(options.context.fileNames));
const dbx = dropboxV2Api.authenticate({ token: db_accessToken });
let dir = (options.dir || '').replace(/\\/g, '/');
if (!dir || dir[0] !== '/') {
dir = `/${dir || ''}`;
}
copyFiles(dbx, dropbox, dir, fileNames, log, options.context.errors, err => {
if (err) {
options.context.errors.dropbox = err;
log.error(`Dropbox: ${JSON.stringify(err)}`);
}
if (options.deleteOldBackup === true) {
const dropboxDeleteAfter = options.advancedDelete === false ? options.deleteBackupAfter : options.dropboxDeleteAfter;
cleanFiles(dbx, options, dir, options.context.types, dropboxDeleteAfter, log, options.context.errors, err => {
if (err) {
options.context.errors.dropbox = options.context.errors.dropbox || err;
} else {
!options.context.errors.dropbox && options.context.done.push('dropbox');
}
callback && callback(err);
});
} else {
!options.context.errors.dropbox && options.context.done.push('dropbox');
callback && callback(err);
}
});
} else {
callback && callback();
}
}
module.exports = {
command,
ignoreErrors: true
};
;