public JsonResult Recovery(Task task, TypeRecovery typeRecovery, IDictionary <string, string> nameAndValue, bool IsAPI = false) { #region Демо режим if (Platform.IsDemo) { return(Json(new Text("Операция недоступна в демо-режиме"))); } #endregion DateTime DateRecovery = default(DateTime); #region Проверка данных if (string.IsNullOrWhiteSpace(task.Description)) { return(Json(new Text("Имя задания не может быть пустым"))); } if (string.IsNullOrWhiteSpace(task.Whence)) { return(Json(new Text("Локальный каталог не может быть пустым"))); } if (string.IsNullOrWhiteSpace(task.Where)) { return(Json(new Text("Удаленный каталог не может быть пустым"))); } switch (task.TypeSunc) { case TypeSunc.SFTP: case TypeSunc.FTP: { if (string.IsNullOrWhiteSpace(task.FTP.HostOrIP) || string.IsNullOrWhiteSpace(task.FTP.Login) || string.IsNullOrWhiteSpace(task.FTP.Passwd)) { return(Json(new Text("Настройки 'FTP/SFTP' имеют недопустимое значение"))); } break; } case TypeSunc.WebDav: { if (string.IsNullOrWhiteSpace(task.WebDav.url) || string.IsNullOrWhiteSpace(task.WebDav.Login) || string.IsNullOrWhiteSpace(task.WebDav.Passwd)) { return(Json(new Text("Настройки 'WebDav' имеют недопустимое значение"))); } break; } case TypeSunc.OneDrive: { if (string.IsNullOrWhiteSpace(task.OneDrive.ApplicationId) || string.IsNullOrWhiteSpace(task.OneDrive.RefreshToken)) { return(Json(new Text("Настройки 'OneDrive' имеют недопустимое значение"))); } break; } } if (task.EncryptionAES && string.IsNullOrWhiteSpace(task.PasswdAES)) { return(Json(new Text("Пароль для шифрования файлов не может быть пустым"))); } if (typeRecovery == TypeRecovery.Date && nameAndValue.TryGetValue("TypeRecoveryToDate", out string DateRecoveryTostring) && !DateTime.TryParse(DateRecoveryTostring, out DateRecovery)) { return(Json(new Text("Отметка бэкапа имеет неправильный формат"))); } #endregion // Искать файлы только в текущем каталоге bool SearchToCurrentDirectory = false; if (nameAndValue.TryGetValue("SearchOption", out string SearchOption) && SearchOption == "CurrentDirectory") { SearchToCurrentDirectory = true; } // Выполняем задание в потоке ThreadPool.QueueUserWorkItem(ob => { #region Добовляем задание в WorkNote CancellationToken cancellationToken = new CancellationToken(); var WorkNoteNotation = new Notation() { TaskId = task.Id, Category = "Восстановление", Msg = $"Задание: {task.Description}", Time = DateTime.Now, More = new List <More>() { new More("Состояние", "Выполняется поиск всех папок") } }; CoreDB.SyncBackupWorkNote.Add(WorkNoteNotation, cancellationToken); #endregion // Создание отчета по ошибкам Report report = new Report(task); // Выполняем задание Tools.Recovery(task, new RemoteServer(task.TypeSunc, task.FTP, task.WebDav, task.OneDrive, report, out _), WorkNoteNotation, out List <More> ResponseNameAndValue, typeRecovery, DateRecovery, SearchToCurrentDirectory); // Сохраняем отчет об ошибках (если есть ошибки) report.SaveAndDispose(ref ResponseNameAndValue); // Чистим WorkNote CoreDB.SyncBackupWorkNote.Take(cancellationToken); #region Сохраняем данные задание в базе SqlToMode.SetMode(SqlMode.Read); using (CoreDB coreDB = Service.Get <CoreDB>()) { // Добовляем задание в список завершеных операций coreDB.SyncBackup_Notations.Add(new Notation() { TaskId = task.Id, Category = "Восстановление", Msg = $"Задание: {task.Description}", Time = DateTime.Now, More = ResponseNameAndValue, }); // Сохраняем базу coreDB.SaveChanges(); } SqlToMode.SetMode(SqlMode.ReadOrWrite); #endregion }); // Отдаем ответ if (IsAPI) { return(Json(new TrueOrFalse(true))); } return(Json(new Text("Задание добавлено на обработку"))); }
/// <summary> /// Восстановить данные /// </summary> /// <param name="task">Задания</param> /// <param name="serv">Удаленный сервер</param> /// <param name="WorkNoteNotation">Текущее задание в WorkNote</param> /// <param name="NameAndValue">Колекция для ответа в журнал</param> /// <param name="typeRecovery">Режим востановления файлов</param> /// <param name="DateRecovery">Отметка бекапа для востановления по дате</param> public static void Recovery(Models.SyncBackup.Tasks.Task task, RemoteServer serv, Notation WorkNoteNotation, out List <More> NameAndValue, TypeRecovery typeRecovery, DateTime DateRecovery) { try { #region Переменные // Список папок которые нужно пропустить var ListSkipFolders = new List <string>(); // Время старта задания var TimeStartTask = DateTime.Now; // Количиство загруженых файлов и созданых папок int CountDownloadToFilesOK = 0, CountDownloadToFilesAll = 0, CountCreateToDirectoryOk = 0; // Общий размер загруженых файлов в byte long CountDownloadToBytes = 0; #endregion #region Получаем список всех папок var RemoteFolders = new List <DirectoryModel>(); RemoteFolders.Add(new DirectoryModel() { Folder = task.Where, RemoteCreated = default(DateTime), RemoteLastModified = DateTime.Now, }); serv.ListAllDirectory(task.Where, ref RemoteFolders); #endregion // Проходим список всех папок foreach (var RemoteFolder in RemoteFolders) { // Папки и их подпапки которые не нужно восстанавливать if (ListSkipFolders.Exists(i => RemoteFolder.Folder.Contains(i))) { continue; } // Пропускаем удаленые папки if (typeRecovery == TypeRecovery.Topical && RemoteFolder.Folder.Contains(".SyncRemove")) { continue; } #region Локальный метод - "GetLocalFolder" string GetLocalFolder() { // Удаленный каталог string where = ConvertPatchToUnix(task.Where); // Локальный каталог string whence = ConvertPatchToUnix(task.Whence); // Результат return(RemoteFolder.Folder.Replace(where, whence)); } #endregion // Локальная дириктория string LocalFolder = GetLocalFolder(); #region Востановление по дате if (typeRecovery == TypeRecovery.Date) { if (RemoteFolder.Folder.Contains(".SyncRemove")) { // Если дата модификации папки ниже отметки if (RemoteFolder.RemoteLastModified < DateRecovery) { ListSkipFolders.Add(RemoteFolder.Folder); continue; } } else { // Если дата создания папки выше отметки if (RemoteFolder.RemoteCreated > DateRecovery) { ListSkipFolders.Add(RemoteFolder.Folder); continue; } } // Удаляем 'SyncRemove' в 'LocalFolder' LocalFolder = Regex.Replace(LocalFolder, @"\.SyncRemove\.-[0-9]+", ""); } #endregion // Создаем локальную папку Directory.CreateDirectory(LocalFolder); CountCreateToDirectoryOk++; // Количиство потоков int ActiveConnections = task.TypeSunc == TypeSunc.SFTP ? task.FTP.ActiveConnections : 1; #region Загружаем файлы на локальный сервер Parallel.ForEach(SortedFiles(serv.ListDirectoryAndFiles(RemoteFolder.Folder).Files, SortedToLocalTime: false), new ParallelOptions { MaxDegreeOfParallelism = ActiveConnections }, RemoteData => { if (typeRecovery == TypeRecovery.Date) { // Ищем файл который ближе всего подходит к отметки бекапа if (RemoteData.Value.FirstOrDefault(i => i.RemoteCreated < DateRecovery) is SortedModel item) { // Загружаем файл который подходит по дате DownloadFile(item, RemoteData.Key); } } else { // Загружаем актуальный файл DownloadFile(RemoteData.Value[0], RemoteData.Key); // Загружаем бекапы if (typeRecovery == TypeRecovery.all) { // Пропускаем актуальный файл и загружаем остальные foreach (var RemoteFile in RemoteData.Value.Skip(1)) { // Загружаем файл DownloadFile(RemoteFile, RemoteFile.Name.Replace(".sync.aes.", ".sync.")); } } } }); #endregion #region Обновляем WorkNote if (CountDownloadToFilesOK > 0) { WorkNoteNotation.More = new List <More> { new More("Состояние", $"Выполняется {GetToWorkTime("")}"), new More("Загружено файлов", $"{CountDownloadToFilesOK:N0}"), new More("Получено данных", ToSize(CountDownloadToBytes)) }; } #endregion #region Локальный метод DownloadFile void DownloadFile(FileModel RemoteFile, string LocalFileName) { // Пропускаем удаленые файлы if (typeRecovery == TypeRecovery.Topical && RemoteFile.Name.Contains(".remove") || RemoteFile.FileSize < 1) { return; } // Пути к файлам string LocalFilePatch = LocalFolder + LocalFileName; string RemoteFilePatch = (RemoteFolder.Folder + "/" + RemoteFile.Name).Replace("//", "/"); // Проверяем на существование файла if (!task.EncryptionAES && File.Exists(LocalFilePatch) && (new FileInfo(LocalFilePatch)).Length == RemoteFile.FileSize) { return; } int CountReDownload = 0; // Загружаем удаленый файл в локальную папку ReDownloadFile : if (serv.DownloadFile(LocalFilePatch, RemoteFilePatch, task.EncryptionAES, task.PasswdAES, RemoteFile.FileSize)) { CountDownloadToFilesOK++; CountDownloadToBytes += RemoteFile.FileSize; } else { if (++CountReDownload < 3) // 3 попытки что-бы загрузить файл { goto ReDownloadFile; } } CountDownloadToFilesAll++; } #endregion } #region Локальный метод GetToWorkTime string GetToWorkTime(string arg) { var WorkTime = (DateTime.Now - TimeStartTask); if (WorkTime.TotalSeconds <= 60) { return(""); } if (WorkTime.TotalMinutes <= 60) { return($"{arg}{(int)WorkTime.TotalMinutes} {EndOfText.get("минуту", "минуты", "минут", (int)WorkTime.TotalMinutes)}"); } return($"{arg}{(int)WorkTime.TotalHours} {EndOfText.get("час", "часа", "часов", (int)WorkTime.TotalHours)}"); } #endregion #region Локальный метод ToSize string ToSize(double bytes) { string[] Suffix = { "Byte", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; int index = 0; while (bytes >= 1024) { bytes /= 1024; index++; } return($"{bytes:N3} {Suffix[index]}"); } #endregion #region Выполнено NameAndValue = new List <More>() { new More("Состояние", $"Выполнено {GetToWorkTime("за ")}") }; if (CountCreateToDirectoryOk > 0) { NameAndValue.Add(new More("Создано папок", $"{CountCreateToDirectoryOk:N0}")); } if (CountDownloadToFilesAll > 0) { NameAndValue.Add(new More("Загружено файлов", $"{CountDownloadToFilesOK:N0} из {CountDownloadToFilesAll:N0}")); NameAndValue.Add(new More("Получено данных", ToSize(CountDownloadToBytes))); } #endregion } catch (Exception ex) { NameAndValue = new List <More>() { new More("Состояние", "Ошибка при выполнении задания"), new More("Код", ex.ToString()) }; } // Отключаемся от сервера serv.Disconnect(); }
public JsonResult Recovery(Task tk, TypeRecovery type, IDictionary <string, string> value) => new SyncBackupFilesToTools().Recovery(tk, type, value);