2020-05-14 04:08:27 +00:00
using System ;
2021-09-27 12:42:46 +00:00
using System.Threading ;
2020-05-14 04:08:27 +00:00
using System.Threading.Tasks ;
using Microsoft.Extensions.Logging ;
using Wabbajack.BuildServer ;
using Wabbajack.Common ;
2021-09-27 12:42:46 +00:00
using Wabbajack.Downloaders ;
using Wabbajack.DTOs.DownloadStates ;
using Wabbajack.Networking.NexusApi ;
using Wabbajack.Paths.IO ;
2020-05-14 04:08:27 +00:00
using Wabbajack.Server.DataLayer ;
using Wabbajack.Server.DTOs ;
2021-10-23 16:51:17 +00:00
namespace Wabbajack.Server.Services ;
public class ArchiveDownloader : AbstractService < ArchiveDownloader , int >
2020-05-14 04:08:27 +00:00
{
2021-10-23 16:51:17 +00:00
private readonly DownloadDispatcher _dispatcher ;
private readonly TemporaryFileManager _manager ;
private readonly ArchiveMaintainer _archiveMaintainer ;
private readonly DiscordWebHook _discord ;
private NexusApi _nexusClient ;
private readonly SqlService _sql ;
public ArchiveDownloader ( ILogger < ArchiveDownloader > logger , AppSettings settings , SqlService sql ,
ArchiveMaintainer archiveMaintainer ,
DiscordWebHook discord , QuickSync quickSync , DownloadDispatcher dispatcher , TemporaryFileManager manager )
: base ( logger , settings , quickSync , TimeSpan . FromMinutes ( 10 ) )
2020-05-14 04:08:27 +00:00
{
2021-10-23 16:51:17 +00:00
_sql = sql ;
_archiveMaintainer = archiveMaintainer ;
_discord = discord ;
_dispatcher = dispatcher ;
_manager = manager ;
}
2020-05-14 04:08:27 +00:00
2021-10-23 16:51:17 +00:00
public override async Task < int > Execute ( )
{
var count = 0 ;
while ( true )
2020-05-14 04:08:27 +00:00
{
2021-10-23 16:51:17 +00:00
var ( _ , header ) = await _nexusClient . Validate ( ) ;
var ignoreNexus = header . DailyRemaining < 100 & & header . HourlyRemaining < 10 ;
//var ignoreNexus = true;
if ( ignoreNexus )
_logger . LogWarning (
$"Ignoring Nexus Downloads due to low hourly api limit (Daily: {header.DailyRemaining}, Hourly:{header.HourlyRemaining})" ) ;
else
_logger . LogInformation (
$"Looking for any download (Daily: {header.DailyRemaining}, Hourly:{header.HourlyRemaining})" ) ;
var nextDownload = await _sql . GetNextPendingDownload ( ignoreNexus ) ;
if ( nextDownload = = default )
break ;
_logger . LogInformation ( $"Checking for previously archived {nextDownload.Archive.Hash}" ) ;
2020-05-14 04:08:27 +00:00
2021-10-23 16:51:17 +00:00
if ( nextDownload . Archive . Hash ! = default & & _archiveMaintainer . HaveArchive ( nextDownload . Archive . Hash ) )
2020-05-14 04:08:27 +00:00
{
2021-10-23 16:51:17 +00:00
await nextDownload . Finish ( _sql ) ;
continue ;
}
if ( nextDownload . Archive . State is Manual or GameFileSource )
{
await nextDownload . Finish ( _sql ) ;
continue ;
}
try
{
_logger . Log ( LogLevel . Information , $"Downloading {nextDownload.Archive.State.PrimaryKeyString}" ) ;
ReportStarting ( nextDownload . Archive . State . PrimaryKeyString ) ;
await _discord . Send ( Channel . Spam ,
new DiscordMessage
{
Content = $"Downloading {nextDownload.Archive.State.PrimaryKeyString}"
} ) ;
await _dispatcher . PrepareAll ( new [ ] { nextDownload . Archive . State } ) ;
await using var tempPath = _manager . CreateFile ( ) ;
if ( await _dispatcher . Download ( nextDownload . Archive , tempPath . Path , CancellationToken . None ) = = default )
2020-05-14 04:08:27 +00:00
{
2021-10-23 16:51:17 +00:00
_logger . LogError (
$"Downloader returned false for {nextDownload.Archive.State.PrimaryKeyString}" ) ;
await nextDownload . Fail ( _sql , "Downloader returned false" ) ;
2020-05-14 04:08:27 +00:00
continue ;
}
2021-10-23 16:51:17 +00:00
var hash = await tempPath . Path . Hash ( ) ;
if ( hash = = default | | nextDownload . Archive . Hash ! = default & & hash ! = nextDownload . Archive . Hash )
2020-05-14 04:08:27 +00:00
{
2021-10-23 16:51:17 +00:00
_logger . Log ( LogLevel . Warning ,
$"Downloaded archive hashes don't match for {nextDownload.Archive.State.PrimaryKeyString} {nextDownload.Archive.Hash} {nextDownload.Archive.Size} vs {hash} {tempPath.Path.Size()}" ) ;
await nextDownload . Fail ( _sql , "Invalid Hash" ) ;
2020-05-14 04:08:27 +00:00
continue ;
}
2021-10-23 16:51:17 +00:00
if ( nextDownload . Archive . Size ! = default & &
tempPath . Path . Size ( ) ! = nextDownload . Archive . Size )
2020-05-14 04:08:27 +00:00
{
2021-10-23 16:51:17 +00:00
await nextDownload . Fail ( _sql , "Invalid Size" ) ;
continue ;
}
nextDownload . Archive . Hash = hash ;
nextDownload . Archive . Size = tempPath . Path . Size ( ) ;
2020-05-14 04:08:27 +00:00
2021-10-23 16:51:17 +00:00
_logger . Log ( LogLevel . Information , $"Archiving {nextDownload.Archive.State.PrimaryKeyString}" ) ;
await _archiveMaintainer . Ingest ( tempPath . Path ) ;
2020-12-31 06:44:42 +00:00
2021-10-23 16:51:17 +00:00
_logger . Log ( LogLevel . Information ,
$"Finished Archiving {nextDownload.Archive.State.PrimaryKeyString}" ) ;
await nextDownload . Finish ( _sql ) ;
await _discord . Send ( Channel . Spam ,
new DiscordMessage
2020-05-14 04:08:27 +00:00
{
2021-10-23 16:51:17 +00:00
Content = $"Finished downloading {nextDownload.Archive.State.PrimaryKeyString}"
} ) ;
}
catch ( Exception ex )
{
_logger . Log ( LogLevel . Warning , $"Error downloading {nextDownload.Archive.State.PrimaryKeyString}" ) ;
await nextDownload . Fail ( _sql , ex . ToString ( ) ) ;
await _discord . Send ( Channel . Spam ,
new DiscordMessage
2020-05-14 04:08:27 +00:00
{
2021-10-23 16:51:17 +00:00
Content = $"Error downloading {nextDownload.Archive.State.PrimaryKeyString}"
} ) ;
2020-05-14 04:08:27 +00:00
}
2021-10-23 16:51:17 +00:00
finally
2020-06-06 21:44:30 +00:00
{
2021-10-23 16:51:17 +00:00
ReportEnding ( nextDownload . Archive . State . PrimaryKeyString ) ;
2020-06-06 21:44:30 +00:00
}
2021-10-23 16:51:17 +00:00
count + + ;
2020-05-14 04:08:27 +00:00
}
2021-10-23 16:51:17 +00:00
if ( count > 0 )
// Wake the Patch builder up in case it needs to build a patch now
await _quickSync . Notify < PatchBuilder > ( ) ;
return count ;
2020-05-14 04:08:27 +00:00
}
2021-10-23 16:51:17 +00:00
}