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.
185 lines (166 loc) • 7.39 kB
JavaScript
const fs = require('node:fs');
const path = require('node:path');
const fse = require('fs-extra');
const fs_async = require('node:fs').promises;
let waitRestore;
let timerDone;
async function restore(options, fileName, log, adapter, callback) {
log.debug('Start Javascript Restore ...');
// stop Javascript-Adapter before Restore
let startAfterRestore = false;
let enabledInstances = [];
adapter.getObjectView('system', 'instance', { startkey: 'system.adapter.javascript.', endkey: 'system.adapter.javascript.\u9999' }, async (err, instances) => {
let resultInstances = [];
if (!err && instances && instances.rows) {
instances.rows.forEach(row => {
resultInstances.push({ id: row.id.replace('system.adapter.', ''), config: row.value.native.type })
});
for (let i = 0; i < resultInstances.length; i++) {
let _id = resultInstances[i].id;
// Stop Javascript Instances
adapter.getForeignObject(`system.adapter.${_id}`, async (err, obj) => {
if (obj?.common?.enabled) {
adapter.setForeignState(`system.adapter.${_id}.alive`, false);
log.debug(`${_id} is stopped`);
enabledInstances.push(_id);
log.debug(`enabled Instances: ${enabledInstances}`)
startAfterRestore = true;
}
});
}
} else {
log.debug('Could not retrieve javascript instances!');
}
});
const tmpDir = path.join(options.backupDir, 'tmpScripts').replace(/\\/g, '/');
const desiredMode = '0o2775';
if (!fs.existsSync(tmpDir)) {
try {
fse.ensureDirSync(tmpDir, desiredMode);
log.debug(`Created javascript_tmp directory: "${tmpDir}"`);
} catch (err) {
log.debug(`Javascript tmp directory "${tmpDir}" cannot created ... ${err}`);
}
} else {
try {
log.debug(`Try deleting the old javascript_tmp directory: "${tmpDir}"`);
fse.removeSync(tmpDir);
} catch (err) {
log.debug(`Javascript tmp directory "${tmpDir}" cannot deleted ... ${err}`);
}
if (!fs.existsSync(tmpDir)) {
try {
log.debug(`old javascript_tmp directory "${tmpDir}" successfully deleted`);
fse.ensureDirSync(tmpDir, desiredMode);
log.debug('Created javascript_tmp directory');
} catch (err) {
log.debug(`Javascript tmp directory "${tmpDir}" cannot created ... ${err}`);
}
}
}
try {
log.debug('decompress started ...');
const decompress = require('../targz').decompress;
waitRestore = setTimeout(() =>
decompress({
src: fileName,
dest: tmpDir,
}, async (err, stdout, stderr) => {
if (err) {
log.error(err);
if (callback) {
log.error('Javascript Restore not completed');
callback(err, stderr);
callback = null;
clearTimeout(timerDone);
clearTimeout(waitRestore);
}
} else {
await restoreJavascriptObjects(tmpDir, adapter, log);
try {
log.debug(`Try deleting the Javascript tmp directory: "${tmpDir}"`);
fse.removeSync(tmpDir);
if (!fs.existsSync(tmpDir)) {
log.debug(`Javascript tmp directory "${tmpDir}" successfully deleted`);
}
} catch (err) {
log.debug(`Javascript tmp directory "${tmpDir}" cannot deleted ... ${err}`);
}
if (callback) {
// Start javascript Instances
if (startAfterRestore) {
enabledInstances.forEach(enabledInstance => {
adapter.getForeignObject(`system.adapter.${enabledInstance}`, async (err, obj) => {
if (obj && !obj.common?.enabled) {
adapter.setForeignState(`system.adapter.${enabledInstance}.alive`, true);
log.debug(`${enabledInstance} started`);
}
});
});
}
timerDone = setTimeout(async () => {
log.debug('Javascript Restore completed successfully');
callback(null, 'javascript restore done');
callback(null);
callback = null;
clearTimeout(timerDone);
clearTimeout(waitRestore);
}, 2000);
}
}
}), 2000);
} catch (e) {
if (callback) {
callback(e);
callback = null;
clearTimeout(timerDone);
clearTimeout(waitRestore);
}
}
}
async function restoreJavascriptObjects(tmpDir, adapter, log) {
return new Promise(async (resolve) => {
try {
const object = await fs_async.readFile(path.join(tmpDir, 'script.json'));
if (object) {
const jsObjects = JSON.parse(object);
for (const i in jsObjects) {
let _object;
try {
_object = await adapter.getForeignObjectAsync(jsObjects[i]._id);
} catch (err) {
log.debug(err);
}
if (_object) {
try {
await adapter.setForeignObjectAsync(jsObjects[i]._id, jsObjects[i]);
const scriptCheck = await adapter.getForeignObjectAsync(jsObjects[i]._id);
if (scriptCheck) {
log.debug(`Restore Script: ${jsObjects[i]._id.split('.').pop()}`);
}
} catch (err) {
log.debug(`Error on set Object: ${err}`);
}
} else {
try {
await adapter.setForeignObjectNotExistsAsync(jsObjects[i]._id, jsObjects[i]);
const scriptCheck = await adapter.getForeignObjectAsync(jsObjects[i]._id);
if (scriptCheck) {
log.debug(`Added Script: ${jsObjects[i]._id.split('.').pop()}`);
}
} catch (err) {
log.debug(`Error on create Object: ${err}`);
}
}
}
}
} catch (err) {
log.debug(`Error on Javascript-Restore: ${err}`);
}
resolve();
});
}
module.exports = {
restore,
isStop: false,
};