const EventEmitter = require('events');
const glob = require('glob');
const fs = require('fs');
const fs_extra = require('fs-extra');
const path = require('path');
const archiver = require('archiver');
const Zip = require("adm-zip");
const moment = require('moment');
/**
* Class offers functionality to manage backups
* @class
*/
class BackupManager extends EventEmitter {
/**
* @constructor
*/
constructor() {
super();
//defne backuplocation
this.backupfolder = path.join(global.appRoot, `backup`);
// check if backup directory exists. If not -> create it
if(!fs.existsSync(this.backupfolder)){
fs.mkdirSync(this.backupfolder);
}
//define backup-content
this.content_folders = [
path.join(global.appRoot, 'store'),
path.join(global.appRoot, 'public', 'assets', 'img')
];
}
/**
* creates a new Backup
* @param {function} callback
*/
Create(callback) {
var now = moment();
var zip_name = `alarmiatorserver_backup_` + now.format("YYYYMMDDHHmmss") + `.zip`;
var zip_file = path.join(this.backupfolder, zip_name);
var output = fs.createWriteStream(zip_file);
var archive = archiver('zip');
output.on('close', function () {
console.log('CORE | MODELS | BACKUP | ' + archive.pointer() + ' total bytes');
console.log('CORE | MODELS | BACKUP | archiver has been finalized and the output file descriptor has closed.');
return callback('reloadPage')
});
archive.on('error', function(err){
callback(err);
});
console.log('CORE | MODELS | BACKUP | start create backup: ' + zip_file);
archive.pipe(output);
this.content_folders.forEach((folder) => {
var foldername = path.basename(folder);
archive.directory(folder, foldername);
});
archive.finalize();
return callback(null);
}
/**
* Delete a Backup
* @param {function} callback
*/
Delete(filename, callback) {
var backupfile = path.join(this.backupfolder, filename)
if(fs.existsSync(backupfile)){
fs.unlink(backupfile, (err) => {
if(err){
console.log('CORE | MODELS | BACKUP | error during delete ' + filename + '!');
return callback(err);
}
else{
console.log('CORE | MODELS | BACKUP | ' + filename + ' deleted.');
return callback(null);
}
});
}
else
{
return callback(new Error(filename + ' not found!'));
}
}
/**
* restore a backupfile
* @param {string} filename
* @param {*} callback
*/
Restore(filename, callback) {
var backupfile = path.join(this.backupfolder, filename)
if(fs.existsSync(backupfile)){
// implement restore here
// 1. unzip
var zip = new Zip(backupfile);
var restorefolder = path.join(this.backupfolder, 'restore');
if(!fs.existsSync(restorefolder))
{
fs.mkdirSync(restorefolder);
}
zip.extractAllTo(restorefolder, true);
// 2 copy unzipped folders to location under global.appRoot
this.content_folders.forEach((dst_folder) => {
var foldername = path.basename(dst_folder)
var src_folder = path.join(restorefolder, foldername);
if(foldername === 'store')
{
dst_folder = path.join(dst_folder, 'restore');
}
fs_extra.copySync(src_folder, dst_folder);
});
fs.rmdirSync(restorefolder, { recursive: true });
return callback('finished');
}
else
{
return callback(new Error(filename + ' not found!'));
}
}
/**
* returns the complete path of a backupfile
* @param {string} filename
* @param {function} callback null or path to backupfile
*/
GetBackupfilePath(filename, callback) {
var backupfile = path.join(this.backupfolder, filename)
if (fs.existsSync(backupfile)) {
return callback(backupfile)
} else {
console.log('CORE | MODELS | BACKUP | ' + backupfile + ' not found!');
return callback(null);
}
}
/**
* returns list of backupfiles in a given folder
* @param {string} folder folder to look for backupfiles
* @param {function} callback list of files in folder as array
*/
getListOfBackupfilesInFolder(callback) {
var fullbackuppath = path.join(this.backupfolder, '*.zip');
glob(fullbackuppath, null, (er, files) => {
if (er) {
console.log('CORE | MODELS | BACKUP | Error getting list of backupfiles from filesystem: ' + er.message);
return callback(null);
} else {
return callback(files);
}
});
}
}
module.exports = BackupManager;