UNPKG

iobroker.backitup

Version:

Backitup enables the cyclic creation of backups of an IoBroker / Homematic installation

281 lines (241 loc) 12 kB
const path = require('path'); const fs = require('fs'); const tools = require('./tools'); function loadScripts() { const scripts = {}; const files = fs.readdirSync(__dirname + '/scripts'); files.forEach(file => { scripts[file.substring(3, file.length - 3)] = require(__dirname + '/scripts/' + file); }); return scripts; } function writeIntoFile(fileName, text) { if (text) { console.log(text); try { fs.appendFileSync(fileName, text + '\n'); } catch (e) { } } } function executeScripts(adapter, config, callback, scripts, code) { if (!scripts) { if (adapter && config.stopIoB && !config.afterBackup) { if (fs.existsSync(__dirname + '/total.json')) { const text = fs.readFileSync(__dirname + '/total.json'); if (text !== JSON.stringify(config, null, 2)) { fs.writeFileSync(__dirname + '/total.json', JSON.stringify(config, null, 2)); } } else { fs.writeFileSync(__dirname + '/total.json', JSON.stringify(config, null, 2)); } startDetachedBackup(); return callback && callback(); } scripts = loadScripts(); config.backupDir = path.join(tools.getIobDir(), 'backups').replace(/\\/g, '/'); config.context = {fileNames: [], errors: {}, done: [], types: []}; // common variables between scripts if (!fs.existsSync(config.backupDir)) { fs.mkdirSync(config.backupDir); } } for (const name in scripts) { if (scripts.hasOwnProperty(name) && scripts[name] && (!config.afterBackup || scripts[name].afterBackup)) { let func; let options; switch (name) { // Mount tasks case 'mount': if (config.cifs && config.cifs.enabled && config.cifs.mount) { func = scripts[name]; options = config.cifs; } break; case 'umount': if (config.cifs && config.cifs.enabled && config.cifs.mount) { func = scripts[name]; options = config.cifs; } break; // Copy/delete tasks case 'clean': func = scripts[name]; options = {name: config.name, deleteBackupAfter: config.deleteBackupAfter}; break; // startIOB tasks case 'start': if (config.stopIoB && config.name === 'total') { func = scripts[name]; options = config; } break; case 'cifs': case 'dropbox': case 'ftp': if (config[name] && config[name].enabled) { func = scripts[name]; options = Object.assign({}, config[name], {name: config.name, deleteBackupAfter: config.deleteBackupAfter}); } break; // Extra data sources case 'mysql': if ((config.name === 'total' || config.name === 'minimal' && config.mysqlEnabled === true) && config[name] && config[name].enabled) { func = scripts[name]; options = Object.assign({}, config[name]); } break; case 'redis': if ((config.name === 'total' || config.name === 'minimal' && config.redisEnabled === true) && config[name] && config[name].enabled) { func = scripts[name]; options = Object.assign({}, config[name]); } break; // Main tasks case 'ccu': case 'total': case 'minimal': if (config.name === name && config.enabled) { func = scripts[name]; options = config; } break; // Messaging tasks case 'history': if (config[name] && config[name].enabled) { func = scripts[name]; options = JSON.parse(JSON.stringify(config)); options[name].time = tools.getTimeString(options[name].systemLang); // provide date } break; case 'telegram': if (config[name] && config[name].enabled && config[name].notificationsType === 'Telegram') { func = scripts[name]; options = JSON.parse(JSON.stringify(config)); options[name].time = tools.getTimeString(options[name].systemLang); // provide date } break; case 'email': if (config[name] && config[name].enabled && config[name].notificationsType === 'E-Mail') { func = scripts[name]; options = JSON.parse(JSON.stringify(config)); options[name].time = tools.getTimeString(options[name].systemLang); // provide date } break; case 'pushover': if (config[name] && config[name].enabled && config[name].notificationsType === 'Pushover') { func = scripts[name]; options = JSON.parse(JSON.stringify(config)); options[name].time = tools.getTimeString(options[name].systemLang); // provide date } break; } scripts[name] = null; if (func) { const _options = JSON.parse(JSON.stringify(options)); if (_options.ftp && !_options.ftp.enabled) delete _options.ftp; if (_options.cifs && !_options.cifs.enabled) delete _options.cifs; if (_options.telegram && !_options.telegram.enabled) delete _options.telegram; if (_options.dropbox && !_options.dropbox.enabled) delete _options.dropbox; if (_options.mysql && !_options.mysql.enabled) delete _options.mysql; if (_options.ftp && _options.ftp.backupDir !== undefined) delete _options.ftp.backupDir; if (_options.cifs && _options.cifs.backupDir !== undefined) delete _options.cifs.backupDir; if (_options.mysql && _options.mysql.backupDir !== undefined) delete _options.mysql.backupDir; if (_options.redis && _options.redis.backupDir !== undefined) delete _options.redis.backupDir; if (!_options.nameSuffix && _options.nameSuffix !== undefined) delete _options.nameSuffix; if (_options.enabled !== undefined) delete _options.enabled; if (_options.context !== undefined) delete _options.context; if (_options.name !== undefined) delete _options.name; if (_options.ftp && _options.ftp.pass !== undefined) _options.ftp.pass = '****'; if (_options.cifs && _options.cifs.pass !== undefined) _options.cifs.pass = '****'; if (_options.mysql && _options.mysql.pass !== undefined) _options.mysql.pass = '****'; if (_options.dropbox && _options.dropbox.accessToken !== undefined) _options.dropbox.accessToken = '****'; if (_options.accessToken !== undefined) _options.accessToken = '****'; if (_options.pass !== undefined) _options.pass = '****'; if (_options.adapter !== undefined) delete _options.adapter; adapter && adapter.setState('output.line', `[DEBUG] [${name}] start with ${JSON.stringify(_options)}`); options.context = config.context; options.backupDir = config.backupDir; options.adapter = adapter; const fileName = path.join(config.backupDir, 'logs.txt'); const log = { debug: function (text) { const lines = text.toString().split('\n'); lines.forEach(line => { line = line.replace(/\r/g, ' ').trim(); line && adapter && adapter.log.debug(`[${config.name}/${name}] ${line}`); line && !adapter && writeIntoFile(fileName, `[DEBUG] [${config.name}/${name}] ${line}`); }); adapter && adapter.setState('output.line', '[DEBUG] [' + name + '] - ' + text); }, error: function (err) { const lines = (err || '').toString().split('\n'); lines.forEach(line => { line = line.replace(/\r/g, ' ').trim(); line && adapter && adapter.log.debug(`[${config.name}/${name}] ${line}`); line && !adapter && writeIntoFile(fileName, `[ERROR] [${config.name}/${name}] ${line}`); }); adapter && adapter.setState('output.line', '[ERROR] [' + name + '] - ' + err); } }; func.command(options, log, (err, output, _code) => { options.adapter = null; if (_code !== undefined) { code = _code } if (err) { if (func.ignoreErrors) { log.error('[IGNORED] ' + err); setImmediate(executeScripts, adapter, config, callback, scripts, code); } else { log.error(err); callback && callback(err); } } else { log.debug(output || 'done'); setImmediate(executeScripts, adapter, config, callback, scripts, code); } }); } else { setImmediate(executeScripts, adapter, config, callback, scripts, code); } return; } } adapter && adapter.setState('output.line', '[EXIT] ' + (code || 0)); callback && callback(); } function startDetachedBackup() { const {spawn} = require('child_process'); const isWin = process.platform.startsWith('win'); if (isWin == '') { fs.writeFileSync(__dirname + '/.backup.info', 'backup'); } const cmd = spawn(isWin ? 'stopIOB.bat' : 'bash', [isWin ? '' : 'stopIOB.sh'], {detached: true, cwd: __dirname, stdio: ['ignore', 'ignore', 'ignore']}); cmd.unref(); } function startIOB() { //const {spawn} = require('child_process'); const child_process = require('child_process'); const isWin = process.platform.startsWith('win'); /* child_process.exec(isWin ? 'startIOB.bat' : 'bash startIOB.sh', (error, stdout, stderr) => { setTimeout(() => adapter.terminate ? adapter.terminate() : process.exit(), 1500); }); */ /* const cmd = spawn(isWin ? 'start_b_IOB.bat' : 'bash', [isWin ? '' : 'startIOB.sh'], {detached: true, cwd: __dirname, stdio: ['ignore', 'ignore', 'ignore']}); cmd.unref(); setTimeout(() => adapter.terminate ? adapter.terminate() : process.exit(), 1000); */ setTimeout(() => adapter.terminate ? adapter.terminate() : process.exit(), 1500); } if (typeof module !== "undefined" && module.parent) { module.exports = executeScripts; } else { if (fs.existsSync(__dirname + '/total.json')) { const config = require(__dirname + '/total.json'); executeScripts(null, config, () => startIOB()); } else { console.log('No config found at "' + path.normalize(path.join(__dirname, 'total.json')) + '"'); } }