using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using BLL.Base;
using Model.UnitsOfWork;
using Model.Entities.Files.FS_Entities;
using Model.Entities.Files;
namespace BLL.Services
{
/// <summary>
/// Сервис выполняет сканирование файловой системы
/// </summary>
public class ScanServices : BaseServices
{
public ScanServices(UOW uOW) : base(uOW) { }
///// <summary>
///// Для паралельной работы для каждого параллельного исполнения
///// нужен свой контекст и uow
///// С точки зрения зависимостей очень кривая реализация
///// </summary>
///// <param name="IsParalle"></param>
///// <returns></returns>
//private UOW GetUnit(bool IsParalle)
//{
// return !IsParalle ? UOW : new UOW();
//}
/// <summary>
/// Запускает полное сконирование базы от коренных папок
/// Для корекнных папок в случае отцутствия создается папка
/// </summary>
/// <param name="IsParalle"></param>
/// <returns></returns>
public async Task ScanAllDirs()//bool IsParalle = false)
{
await Task.Run(async () =>
{
await RecursScanDirectoryAsync(UOW.Repo_SRootDirectory.All.ToArray(), true);//, IsParalle);
});
}
public async Task RecursScanDirectoryAsync(IEnumerable<SDirectory> directorys, bool Recursive = true)//, bool IsParalle = false)
{
await Task.Run(async () =>
{
//Не параллельно
//if (!IsParalle)
//{
foreach (var elem in directorys)
await RecursScanDirectoryAsync(elem, true);//, IsParalle);
//}
////Параллельно
//else
//{
// var tasks = new List<Task>(directorys.Count());
// foreach (var elem in directorys)
// tasks.Add(RecursScanDirectoryAsync(elem, true, IsParalle));
// await Task.WhenAll(tasks);
//}
});
}
/// <summary>
/// Сравнивает содержимое файловой системы и базы
/// Приводя их в единый вид по правилу:
/// 1) Если есть в базе, но нет в ФС, то удалить из базы
/// 2) Если есть в ФС, но нет в базе, то добавить в базу
/// </summary>
/// <param name="directory"></param>
/// <param name="Recursive"></param>
/// <param name="IsParalle"></param>
/// <returns></returns>
public async Task RecursScanDirectoryAsync(SDirectory directory, bool Recursive = true)//, bool IsParalle = false)
{
await Task.Run(async () =>
{
//var uow = GetUnit(IsParalle);
//Если папка коренная то проверить наличие и если нет, то создать
if (directory.IsRoot)
{
if (Directory.Exists(directory.PhysicalPath))
Directory.CreateDirectory(directory.PhysicalPath);
}
//Данные о папке из базы
var db = new
{
files = directory.Files.ToList(),
dirs = directory.Directories.ToList(),
upload = directory.UploadFiles.ToList(),
};
//Данные о папке из файловой системы
var fs = new
{
files = new LinkedList<string>(
Directory.GetFiles(directory.PhysicalPath).
Select(e => Path.GetFileName(e))
),
dirs = new LinkedList<string>(
Directory.GetDirectories(directory.PhysicalPath).
Select(e => Path.GetFileName(e))
)
};
foreach (var elem in db.files)
{
var file = fs.files.FirstOrDefault(e => e == elem.Name);
//Если файл из базы не найден в фс
if (file != null)
UOW.Repo_SFile.DeleteInList(elem);
//Если файл найден, то удаляем из списка файловой системы
else
{
//Проверка что размеры файла совпадают
var size = new FileInfo(file).Length;
if (elem.Size != size)
{
elem._Size = size;
UOW.Repo_SFile.Update(elem);
}
fs.files.Remove(elem.Name);
}
}
//Если в файловой системе есть файлы, не зафиксированные в базе
if (fs.files.Count != 0)
{
var upload_name = db.upload.Select(e => e.Name);
foreach (var elem in fs.files)
{
//Файл находится в стадии загрузки
if (upload_name.Contains(elem))
continue;
//Файл вносится в базу
FileInfo file = new FileInfo(Path.Combine(directory.PhysicalPath, elem));
db.files.Add(UOW.Repo_SFile.Create(new SFile(directory, file.Name, file.Length, null)));
}
}
foreach (var elem in db.dirs)
{
//Если папка из базы не найден в фс
if (!fs.dirs.Contains(elem.Name))
{
UOW.Repo_SDirectory.DeleteInList(elem);
}
//Если папка найден, то удаляем из списка файловой системы
else
fs.dirs.Remove(elem.Name);
}
//Если в файловой системе есть папки, не зафиксированные в базе
if (fs.dirs.Count != 0)
{
foreach (var elem in fs.dirs)
{
db.dirs.Add(UOW.Repo_SDirectory.Create(new SDirectory(directory, elem, null)));
}
}
fs.files.Clear();
fs.dirs.Clear();
db.files.Clear();
db.upload.Clear();
//Рекурсивно вызвать сканирование для подпапок
if (Recursive)
await RecursScanDirectoryAsync(db.dirs, true);//, IsParalle);
db.dirs.Clear();
});
}
}
}