Refactored ScanLibrary to accept and library id rather than DTO. Refactored ScanLibrary to use Task.Run() rather than having synchronous repo methods.

This commit is contained in:
Joseph Milazzo 2021-01-02 12:48:48 -06:00
parent 9168e12483
commit 7b1714349d
9 changed files with 44 additions and 75 deletions

View File

@ -70,8 +70,9 @@ namespace API.Controllers
if (await _userRepository.SaveAllAsync())
{
//TODO: Enqueue scan library task
{
var createdLibrary = await _libraryRepository.GetLibraryForNameAsync(library.Name);
BackgroundJob.Enqueue(() => _directoryService.ScanLibrary(createdLibrary.Id));
return Ok();
}
@ -128,27 +129,22 @@ namespace API.Controllers
[Authorize(Policy = "RequireAdminRole")]
[HttpPost("scan")]
public async Task<ActionResult> ScanLibrary(int libraryId)
public ActionResult ScanLibrary(int libraryId)
{
var library = await _libraryRepository.GetLibraryDtoForIdAsync(libraryId);
// We have to send a json encoded Library (aka a DTO) to the Background Job thread.
// Because we use EF, we have circular dependencies back to Library and it will crap out
// TODO: Refactor this to use libraryId and move Library call in method.
BackgroundJob.Enqueue(() => _directoryService.ScanLibrary(library));
BackgroundJob.Enqueue(() => _directoryService.ScanLibrary(libraryId));
return Ok();
}
[HttpGet("libraries-for")]
public async Task<ActionResult<IEnumerable<LibraryDto>>> GetLibrariesForUser(string username)
{
return Ok(await _libraryRepository.GetLibrariesForUsernameAysnc(username));
return Ok(await _libraryRepository.GetLibrariesDtoForUsernameAsync(username));
}
[HttpGet("series")]
public async Task<ActionResult<IEnumerable<Series>>> GetSeriesForLibrary(int libraryId)
{
return Ok(await _seriesRepository.GetSeriesForLibraryIdAsync(libraryId));
return Ok(await _seriesRepository.GetSeriesDtoForLibraryIdAsync(libraryId));
}
}
}

View File

@ -27,13 +27,13 @@ namespace API.Controllers
[HttpGet("{seriesId}")]
public async Task<ActionResult<SeriesDto>> GetSeries(int seriesId)
{
return Ok(await _seriesRepository.GetSeriesByIdAsync(seriesId));
return Ok(await _seriesRepository.GetSeriesDtoByIdAsync(seriesId));
}
[HttpGet("volumes")]
public async Task<ActionResult<IEnumerable<VolumeDto>>> GetVolumes(int seriesId)
{
return Ok(await _seriesRepository.GetVolumesAsync(seriesId));
return Ok(await _seriesRepository.GetVolumesDtoAsync(seriesId));
}
}
}

View File

@ -2,7 +2,6 @@
using System.Linq;
using System.Threading.Tasks;
using API.DTOs;
using API.Entities;
using API.Extensions;
using API.Interfaces;
using Microsoft.AspNetCore.Authorization;
@ -51,7 +50,7 @@ namespace API.Controllers
if (user == null) return BadRequest("Could not validate user");
var libs = await _libraryRepository.GetLibrariesForUsernameAysnc(user.UserName);
var libs = await _libraryRepository.GetLibrariesDtoForUsernameAsync(user.UserName);
return Ok(libs.Any(x => x.Id == libraryId));
}

View File

@ -36,16 +36,7 @@ namespace API.Data
return _context.SaveChanges() > 0;
}
public Library GetLibraryForName(string libraryName)
{
return _context.Library
.Where(x => x.Name == libraryName)
.Include(f => f.Folders)
.Include(s => s.Series)
.Single();
}
public async Task<IEnumerable<LibraryDto>> GetLibrariesForUsernameAysnc(string userName)
public async Task<IEnumerable<LibraryDto>> GetLibrariesDtoForUsernameAsync(string userName)
{
return await _context.Library
.Include(l => l.AppUsers)
@ -53,21 +44,22 @@ namespace API.Data
.ProjectTo<LibraryDto>(_mapper.ConfigurationProvider).ToListAsync();
}
public async Task<Library> GetLibraryForNameAsync(string libraryName)
{
return await _context.Library
.Where(x => x.Name == libraryName)
.Include(f => f.Folders)
.Include(s => s.Series)
.SingleAsync();
}
public async Task<IEnumerable<LibraryDto>> GetLibrariesAsync()
{
return await _context.Library
.Include(f => f.Folders)
.ProjectTo<LibraryDto>(_mapper.ConfigurationProvider).ToListAsync();
}
public async Task<LibraryDto> GetLibraryDtoForIdAsync(int libraryId)
{
return await _context.Library
.Where(x => x.Id == libraryId)
.Include(f => f.Folders)
.ProjectTo<LibraryDto>(_mapper.ConfigurationProvider).SingleAsync();
}
public async Task<Library> GetLibraryForIdAsync(int libraryId)
{
return await _context.Library

View File

@ -46,7 +46,7 @@ namespace API.Data
return _context.Series.SingleOrDefault(x => x.Name == name);
}
public async Task<IEnumerable<SeriesDto>> GetSeriesForLibraryIdAsync(int libraryId)
public async Task<IEnumerable<SeriesDto>> GetSeriesDtoForLibraryIdAsync(int libraryId)
{
return await _context.Series
.Where(series => series.LibraryId == libraryId)
@ -54,22 +54,14 @@ namespace API.Data
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider).ToListAsync();
}
public async Task<IEnumerable<VolumeDto>> GetVolumesAsync(int seriesId)
public async Task<IEnumerable<VolumeDto>> GetVolumesDtoAsync(int seriesId)
{
return await _context.Volume
.Where(vol => vol.SeriesId == seriesId)
.OrderBy(volume => volume.Number)
.ProjectTo<VolumeDto>(_mapper.ConfigurationProvider).ToListAsync();
}
public IEnumerable<VolumeDto> GetVolumesDto(int seriesId)
{
return _context.Volume
.Where(vol => vol.SeriesId == seriesId)
.OrderBy(vol => vol.Number)
.ProjectTo<VolumeDto>(_mapper.ConfigurationProvider).ToList();
}
public IEnumerable<Volume> GetVolumes(int seriesId)
{
return _context.Volume
@ -78,7 +70,7 @@ namespace API.Data
.ToList();
}
public async Task<SeriesDto> GetSeriesByIdAsync(int seriesId)
public async Task<SeriesDto> GetSeriesDtoByIdAsync(int seriesId)
{
return await _context.Series.Where(x => x.Id == seriesId)
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider).SingleAsync();

View File

@ -1,5 +1,4 @@
using System.Collections.Generic;
using API.DTOs;
namespace API.Interfaces
{
@ -7,6 +6,6 @@ namespace API.Interfaces
{
IEnumerable<string> ListDirectory(string rootPath);
void ScanLibrary(LibraryDto library);
void ScanLibrary(int libraryId);
}
}

View File

@ -10,16 +10,10 @@ namespace API.Interfaces
void Update(Library library);
Task<bool> SaveAllAsync();
Task<IEnumerable<LibraryDto>> GetLibrariesAsync();
/// <summary>
/// Checks to see if a library of the same name exists. We only allow unique library names, no duplicates per LibraryType.
/// </summary>
/// <param name="libraryName"></param>
/// <returns></returns>
Task<bool> LibraryExists(string libraryName);
Task<LibraryDto> GetLibraryDtoForIdAsync(int libraryId);
Task<Library> GetLibraryForIdAsync(int libraryId);
bool SaveAll();
Library GetLibraryForName(string libraryName);
Task<IEnumerable<LibraryDto>> GetLibrariesForUsernameAysnc(string userName);
Task<IEnumerable<LibraryDto>> GetLibrariesDtoForUsernameAsync(string userName);
Task<Library> GetLibraryForNameAsync(string libraryName);
}
}

View File

@ -12,11 +12,10 @@ namespace API.Interfaces
Task<Series> GetSeriesByNameAsync(string name);
Series GetSeriesByName(string name);
bool SaveAll();
Task<IEnumerable<SeriesDto>> GetSeriesForLibraryIdAsync(int libraryId);
Task<IEnumerable<VolumeDto>> GetVolumesAsync(int seriesId);
IEnumerable<VolumeDto> GetVolumesDto(int seriesId);
Task<IEnumerable<SeriesDto>> GetSeriesDtoForLibraryIdAsync(int libraryId);
Task<IEnumerable<VolumeDto>> GetVolumesDtoAsync(int seriesId);
IEnumerable<Volume> GetVolumes(int seriesId);
Task<SeriesDto> GetSeriesByIdAsync(int seriesId);
Task<SeriesDto> GetSeriesDtoByIdAsync(int seriesId);
}
}

View File

@ -5,11 +5,9 @@ using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using API.DTOs;
using API.Entities;
using API.Interfaces;
using API.Parser;
@ -149,6 +147,7 @@ namespace API.Services
// BUG: This is creating new volume entries and not resetting each run.
IList<Volume> existingVolumes = _seriesRepository.GetVolumes(series.Id).ToList();
//IList<Volume> existingVolumes = Task.Run(() => _seriesRepository.GetVolumesAsync(series.Id)).Result.ToList();
foreach (var info in infos)
{
var existingVolume = existingVolumes.SingleOrDefault(v => v.Name == info.Volumes);
@ -189,46 +188,45 @@ namespace API.Services
return series;
}
public void ScanLibrary(LibraryDto library)
public void ScanLibrary(int libraryId)
{
var library = Task.Run(() => _libraryRepository.GetLibraryForIdAsync(libraryId)).Result;
_scannedSeries = new ConcurrentDictionary<string, ConcurrentBag<ParserInfo>>();
_logger.LogInformation($"Beginning scan on {library.Name}");
foreach (var folderPath in library.Folders)
{
try {
TraverseTreeParallelForEach(folderPath, (f) =>
TraverseTreeParallelForEach(folderPath.Path, (f) =>
{
// Exceptions are no-ops.
try
{
Process(f);
}
catch (FileNotFoundException) {}
catch (IOException) {}
catch (UnauthorizedAccessException) {}
catch (SecurityException) {}
catch (FileNotFoundException exception)
{
_logger.LogError(exception, "The file could not be found");
}
});
}
catch (ArgumentException ex) {
_logger.LogError(ex, "The directory '{folderPath}' does not exist");
_logger.LogError(ex, $"The directory '{folderPath}' does not exist");
}
}
var filtered = _scannedSeries.Where(kvp => !kvp.Value.IsEmpty);
var series = filtered.ToImmutableDictionary(v => v.Key, v => v.Value);
// Perform DB activities on ImmutableDictionary
var libraryEntity = _libraryRepository.GetLibraryForName(library.Name);
libraryEntity.Series = new List<Series>(); // Temp delete everything for testing
// Perform DB activities
library.Series = new List<Series>(); // Temp delete everything until we can mark items Unavailable
foreach (var seriesKey in series.Keys)
{
var s = UpdateSeries(seriesKey, series[seriesKey].ToArray());
_logger.LogInformation($"Created/Updated series {s.Name}");
libraryEntity.Series.Add(s);
library.Series.Add(s);
}
_libraryRepository.Update(libraryEntity);
_libraryRepository.Update(library);
if (_libraryRepository.SaveAll())
{