/// <summary> /// Сихронизация задания /// </summary> /// <param name="task">Задания</param> /// <param name="serv">Удаленный сервер</param> /// <param name="WorkNoteNotation">Текущее задание в WorkNote</param> /// <param name="NameAndValue">Колекция для ответа в журнал</param> /// <param name="IsOk">Выполнено задание или нет</param> private static void Sync(Task task, RemoteServer serv, Notation WorkNoteNotation, out List <More> NameAndValue, ref bool IsOk) { #region Ошибка подключения if (!serv.IsConnected) { NameAndValue = new List <More>() { new More("Состояние", $"Ошибка подключения к {task.TypeSunc.ToString()}") }; return; } #endregion try { #region Получаем список папок в которых были ошибки при синхронизации string PathSyncToErrorLocalFolder = $"{Folders.Sync}/tk-{task.Id}.ErrorLocalFolders.json"; var NewListErrorLocalFolders = new List <string>(); // Новый список папок с ошибкой синхронизации var oldListErrorLocalFolders = new List <string>(); // Текущий список папок с ошибкой синхронизации if (File.Exists(PathSyncToErrorLocalFolder)) { oldListErrorLocalFolders = JsonConvert.DeserializeObject <List <string> >(File.ReadAllText(PathSyncToErrorLocalFolder)); } #endregion #region Переменные // Список новых папок var ListNewLocalFolders = new List <string>(); // Время старта задания var TimeStartTask = DateTime.Now; // Количиство созданных папок и загруженых файлов int CountUploadToFilesOK = 0, CountUploadToFilesAll = 0, CountCreateToDirectoryOk = 0, CountCreateToDirectoryAll = 0; // Количиство провереных обьектов - (папок/файлов) int CountToCheckedObject = 0; // Общий размер переданых файлов в byte long CountUploadToBytes = 0; // Отчет созданных папок string ReportNameToCreateFolders = $"tk-{task.Id}_{DateTime.Now.ToString("dd-MM-yyy_HH-mm")}-{Generate.Passwd(6)}.folders.txt"; StreamWriter ReportToCreateFolders = new StreamWriter($"{Folders.ReportSync}/{ReportNameToCreateFolders}", false, Encoding.UTF8); // Отчет загруженных файлов string ReportNameToUploadFiles = $"tk-{task.Id}_{DateTime.Now.ToString("dd-MM-yyy_HH-mm")}-{Generate.Passwd(6)}.files.txt"; StreamWriter ReportToUploadFiles = new StreamWriter($"{Folders.ReportSync}/{ReportNameToUploadFiles}", false, Encoding.UTF8); #endregion // Получаем список всех папок foreach (var LocalFolder in SearchDirectory.Get(task.Whence)) { CountToCheckedObject++; // Если папка в списке игнорируемых папок if (task.IgnoreFileOrFolders.Exists(i => Regex.IsMatch(LocalFolder, i.Patch.Replace("\\", "/"), RegexOptions.IgnoreCase))) { continue; } // Проверяем папку, нужно ее синхронизировать или нет if (CacheLastWriteTimeToFiles(LocalFolder, task.CacheSync, ref CountToCheckedObject) || // Если дата изменения любого файла внутри папки LocalFolder выше чем CacheSync Directory.GetCreationTime(LocalFolder) > task.CacheSync || // Если дата создания папки выше CacheSync Directory.GetLastWriteTime(LocalFolder) > task.CacheSync || // Если дата изменения в папке выше CacheSync ListNewLocalFolders.Exists(i => LocalFolder.Contains(i)) || // Если эта папка является новой, нужно сихронизировать все включая все подпапки в ней oldListErrorLocalFolders.Exists(i => LocalFolder == i)) // Список папок в котрых в прошлый раз была ошибка при синхронизации { #region Переменные // Количиство потоков int ActiveConnections = 1; switch (task.TypeSunc) { case TypeSunc.OneDrive: ActiveConnections = 10; break; case TypeSunc.SFTP: ActiveConnections = task.FTP.ActiveConnections; break; } // Расширения файлов и папок string SyncRemoveFileAddExtension = ".remove"; string SyncRemoveFoldersExtension = $".SyncRemove.{DateTime.Now.ToBinary()}"; #endregion #region Локальный метод - "GetRemoteFolder" string GetRemoteFolder() { // Удаленный каталог string where = Tools.ConvertPatchToUnix(task.Where); // Локальный каталог string whence = Tools.ConvertPatchToUnix(task.Whence); // Результат return(LocalFolder.Replace(whence, where)); } #endregion // Папка на удаленном сервере Linux string RemoteFolder = GetRemoteFolder(); // Создаем папку на удаленом сервере serv.CreateDirectory(RemoteFolder, NotReport: true); // Список файлов и папок var ListRemoteServer = serv.ListDirectoryAndFiles(RemoteFolder); var ListLocalDirectoryToName = Directory.GetDirectories(LocalFolder, "*", SearchOption.TopDirectoryOnly).Select(i => Path.GetFileName(i)).ToList(); var ListLocalFilesToName = Directory.GetFiles(LocalFolder, "*", SearchOption.TopDirectoryOnly). Where(dir => !task.IgnoreFileOrFolders.Exists(i => Regex.IsMatch(dir, i.Patch, RegexOptions.IgnoreCase))). Select(dir => Path.GetFileName(dir)).ToList(); // Модель Tools ToolsModel md = new ToolsModel() { serv = serv, ActiveConnections = ActiveConnections, LocalFolder = LocalFolder, RemoteFolder = RemoteFolder, NewListErrorLocalFolders = NewListErrorLocalFolders }; // Переименовывем папки в 'SyncRemoveFoldersExtension' на удаленом сервере - (если их нету на локальном) Tools.RenameToRemoveDirectory(md, ListRemoteServer.Directory, SyncRemoveFoldersExtension); // Переименовывем файлы в 'SyncRemoveFileAddExtension' на удаленом сервере - (если их нету на локальном) Tools.RenameToRemoveFiles(md, ListRemoteServer.Files, SyncRemoveFileAddExtension); // Создаем папки на удаленом сервере - (папки есть на локальном но нету на удаленом сервере) foreach (string createFolder in Tools.CreateToDirectory(md, ListRemoteServer.Directory, ListLocalDirectoryToName, ref CountCreateToDirectoryOk, ref CountCreateToDirectoryAll, ListNewLocalFolders)) { // Сохраняем список созданных папок ReportToCreateFolders.WriteLine(createFolder); } // Удаляем файлы которые не до конца загружены Tools.DeleteFilesToErrorUpload(md, ref ListRemoteServer.Files, SyncRemoveFileAddExtension); // Загружаем файлы на удаленный сервер - (если файла нету на сервере) foreach (string uploadFile in Tools.UploadToFiles(md, ListRemoteServer.Files, ListLocalFilesToName, task.EncryptionAES, task.PasswdAES, ref CountUploadToFilesOK, ref CountUploadToFilesAll, ref CountUploadToBytes)) { // Сохраняем список загруженных файлов ReportToUploadFiles.WriteLine(uploadFile); } #region Очистка старых бекапов if (task.CountActiveBackup >= 1) { if (task.CountActiveBackup == 1) { // Удаляем все папки и файлы с пометкй "SyncRemoveFoldersExtension или SyncRemoveFoldersExtension" Tools.DeleteFilesOrDirectoryToRemove(md); } // Удаляем старые бекапы Tools.DeleteFilesToActiveBackup(md, task.CountActiveBackup); } // Удаляем старые по времени бекапы if (task.CountActiveDayBackup > 0) { Tools.DeleteFilesToActiveDayBackup(md, task.CountActiveDayBackup); } #endregion #region Обновляем WorkNote WorkNoteNotation.More = new List <More> { new More("Состояние", $"Выполняется {GetToWorkTime("")}"), new More("Проверено объектов", $"{CountToCheckedObject:N0}") }; if (CountUploadToFilesOK > 0) { WorkNoteNotation.More.Add(new More("Передано данных", ToSize(CountUploadToBytes))); WorkNoteNotation.More.Add(new More("Загружено файлов", $"{CountUploadToFilesOK:N0}")); } if (CountCreateToDirectoryOk > 0) { WorkNoteNotation.More.Add(new More("Создано папок", $"{CountCreateToDirectoryOk:N0}")); } #endregion } } // Закрываем потоки ReportToCreateFolders.Dispose(); ReportToUploadFiles.Dispose(); // Сохраняем новый список папок с ошибками, вместо старого File.WriteAllText(PathSyncToErrorLocalFolder, JsonConvert.SerializeObject(NewListErrorLocalFolders)); #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("за ")}"), new More("Проверено объектов", $"{CountToCheckedObject:N0}") }; if (CountCreateToDirectoryAll > 0) { NameAndValue.Add(new More("Создано папок", $"<a href='/reports/sync/{ReportNameToCreateFolders}' target='_blank'>{CountCreateToDirectoryOk:N0} из {CountCreateToDirectoryAll:N0}</a>")); } if (CountUploadToFilesAll > 0) { NameAndValue.Add(new More("Загружено файлов", $"<a href='/reports/sync/{ReportNameToUploadFiles}' target='_blank'>{CountUploadToFilesOK:N0} из {CountUploadToFilesAll:N0}</a>")); NameAndValue.Add(new More("Передано данных", ToSize(CountUploadToBytes))); } #endregion IsOk = true; } catch (Exception ex) { NameAndValue = new List <More>() { new More("Состояние", "Ошибка при выполнении задания"), new More("Код", ex.ToString()) }; } // Отключаемся от сервера serv.Disconnect(); }
/// <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 Open(string host, string IP, int AccessTimeToMinutes, AccessType accessType) { #region Демо режим if (Platform.IsDemo) { return(Json(new Modal("Операция недоступна в демо-режиме"))); } #endregion // Проверка IP if (string.IsNullOrWhiteSpace(IP) || (!IP.Contains(".") && !IP.Contains(":")) || (IP.Contains(".") && !Regex.IsMatch(IP, @"^[0-9]+\.[0-9]+\.[0-9]+\.([0-9]+|\*)$"))) { return(Json(new Modal("Поле 'IP-адрес' имеет недопустимое значение"))); } // ППроверка домена if (accessType != AccessType.allDomain && string.IsNullOrWhiteSpace(host)) { return(Json(new Modal("Поле 'Домен' не может быть пустым"))); } // Коректор времени if (AccessTimeToMinutes <= 0) { AccessTimeToMinutes = 2160; } // Достаем IMemoryCache var memoryCache = Service.Get <IMemoryCache>(); // Добавляем данные в список разрешенных IP, для вывода информации и отмены доступа AccessIP.Add(IP, accessType == AccessType.allDomain ? "все домены" : host, DateTime.Now.AddMinutes(AccessTimeToMinutes), accessType); // IP для кеша string ipCache = IP.Replace(".*", "").Replace(":*", ""); // Добовляем IP в белый список switch (accessType) { case AccessType.all: memoryCache.Set(KeyToMemoryCache.CheckLinkWhitelistToAll(host, ipCache), (byte)1, TimeSpan.FromMinutes(AccessTimeToMinutes)); break; case AccessType.Is2FA: memoryCache.Set(KeyToMemoryCache.CheckLinkWhitelistTo2FA(host, ipCache), (byte)1, TimeSpan.FromMinutes(AccessTimeToMinutes)); break; case AccessType.allDomain: memoryCache.Set(KeyToMemoryCache.CheckLinkWhitelistToAllDomain(ipCache), (byte)1, TimeSpan.FromMinutes(AccessTimeToMinutes)); break; } // Отдаем ответ return(Json(new Modal($"Разрешен доступ для '{IP}' на {AccessTimeToMinutes} {EndOfText.get("минуту", "минуты", "минут", AccessTimeToMinutes)}", true))); }