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