You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Readarr/src/NzbDrone.Core/Backup/BackupService.cs

174 lines
6.0 KiB

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Marr.Data;
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.Backup
{
public interface IBackupService
{
void Backup(BackupType backupType);
List<Backup> GetBackups();
}
public class BackupService : IBackupService, IExecute<BackupCommand>
{
private readonly IMainDatabase _maindDb;
private readonly IDiskTransferService _diskTransferService;
private readonly IDiskProvider _diskProvider;
private readonly IAppFolderInfo _appFolderInfo;
private readonly IArchiveService _archiveService;
private readonly Logger _logger;
private string _backupTempFolder;
private static readonly Regex BackupFileRegex = new Regex(@"nzbdrone_backup_[._0-9]+\.zip", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public BackupService(IMainDatabase maindDb,
IDiskTransferService diskTransferService,
IDiskProvider diskProvider,
IAppFolderInfo appFolderInfo,
IArchiveService archiveService,
Logger logger)
{
_maindDb = maindDb;
_diskTransferService = diskTransferService;
_diskProvider = diskProvider;
_appFolderInfo = appFolderInfo;
_archiveService = archiveService;
_logger = logger;
_backupTempFolder = Path.Combine(_appFolderInfo.TempFolder, "nzbdrone_backup");
}
public void Backup(BackupType backupType)
{
_logger.ProgressInfo("Starting Backup");
_diskProvider.EnsureFolder(_backupTempFolder);
_diskProvider.EnsureFolder(GetBackupFolder(backupType));
var backupFilename = string.Format("nzbdrone_backup_{0:yyyy.MM.dd_HH.mm.ss}.zip", DateTime.Now);
var backupPath = Path.Combine(GetBackupFolder(backupType), backupFilename);
Cleanup();
if (backupType != BackupType.Manual)
{
CleanupOldBackups(backupType);
}
BackupConfigFile();
BackupDatabase();
_logger.ProgressDebug("Creating backup zip");
_archiveService.CreateZip(backupPath, _diskProvider.GetFiles(_backupTempFolder, SearchOption.TopDirectoryOnly));
_logger.ProgressDebug("Backup zip created");
}
public List<Backup> GetBackups()
{
var backups = new List<Backup>();
foreach (var backupType in Enum.GetValues(typeof(BackupType)).Cast<BackupType>())
{
var folder = GetBackupFolder(backupType);
if (_diskProvider.FolderExists(folder))
{
backups.AddRange(GetBackupFiles(folder).Select(b => new Backup
{
Path = Path.GetFileName(b),
Type = backupType,
Time = _diskProvider.FileGetLastWrite(b)
}));
}
}
return backups;
}
private void Cleanup()
{
if (_diskProvider.FolderExists(_backupTempFolder))
{
_diskProvider.EmptyFolder(_backupTempFolder);
}
}
private void BackupDatabase()
{
_logger.ProgressDebug("Backing up database");
using (var unitOfWork = new UnitOfWork(() => _maindDb.GetDataMapper()))
{
unitOfWork.BeginTransaction(IsolationLevel.Serializable);
var databaseFile = _appFolderInfo.GetNzbDroneDatabase();
var tempDatabaseFile = Path.Combine(_backupTempFolder, Path.GetFileName(databaseFile));
_diskTransferService.TransferFile(databaseFile, tempDatabaseFile, TransferMode.Copy);
unitOfWork.Commit();
}
}
private void BackupConfigFile()
{
_logger.ProgressDebug("Backing up config.xml");
var configFile = _appFolderInfo.GetConfigPath();
var tempConfigFile = Path.Combine(_backupTempFolder, Path.GetFileName(configFile));
_diskTransferService.TransferFile(configFile, tempConfigFile, TransferMode.Copy);
}
private void CleanupOldBackups(BackupType backupType)
{
_logger.Debug("Cleaning up old backup files");
var files = GetBackupFiles(GetBackupFolder(backupType));
foreach (var file in files)
{
var lastWriteTime = _diskProvider.FileGetLastWrite(file);
if (lastWriteTime.AddDays(28) < DateTime.UtcNow)
{
_logger.Debug("Deleting old backup file: {0}", file);
_diskProvider.DeleteFile(file);
}
}
_logger.Debug("Finished cleaning up old backup files");
}
private string GetBackupFolder(BackupType backupType)
{
return Path.Combine(_appFolderInfo.GetBackupFolder(), backupType.ToString().ToLower());
}
private IEnumerable<string> GetBackupFiles(string path)
{
var files = _diskProvider.GetFiles(path, SearchOption.TopDirectoryOnly);
return files.Where(f => BackupFileRegex.IsMatch(f));
}
public void Execute(BackupCommand message)
{
Backup(message.Type);
}
}
}