2020-05-14 04:08:27 +00:00
using System ;
using System.Reflection.Metadata.Ecma335 ;
using System.Threading.Tasks ;
using Microsoft.Extensions.Logging ;
using Wabbajack.BuildServer ;
using Wabbajack.Common ;
using Wabbajack.Lib.Downloaders ;
using Wabbajack.Lib.NexusApi ;
using Wabbajack.Server.DataLayer ;
using Wabbajack.Server.DTOs ;
namespace Wabbajack.Server.Services
{
public class ArchiveDownloader : AbstractService < ArchiveDownloader , int >
{
private SqlService _sql ;
private ArchiveMaintainer _archiveMaintainer ;
private NexusApiClient _nexusClient ;
2020-06-06 21:44:30 +00:00
private DiscordWebHook _discord ;
2021-03-11 02:28:28 +00:00
private NexusKeyMaintainance _nexus ;
2020-05-14 04:08:27 +00:00
2021-03-11 02:28:28 +00:00
public ArchiveDownloader ( ILogger < ArchiveDownloader > logger , AppSettings settings , SqlService sql , ArchiveMaintainer archiveMaintainer , DiscordWebHook discord , QuickSync quickSync , NexusKeyMaintainance nexus )
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-03-11 02:28:28 +00:00
_nexus = nexus ;
2020-05-14 04:08:27 +00:00
}
public override async Task < int > Execute ( )
{
2021-03-11 02:28:28 +00:00
_nexusClient ? ? = await _nexus . GetClient ( ) ;
2020-05-14 04:08:27 +00:00
int count = 0 ;
while ( true )
{
2020-05-15 05:25:02 +00:00
var ( daily , hourly ) = await _nexusClient . GetRemainingApiCalls ( ) ;
2020-05-16 15:08:40 +00:00
bool ignoreNexus = ( daily < 100 & & hourly < 10 ) ;
//var ignoreNexus = true;
2020-05-14 11:53:51 +00:00
if ( ignoreNexus )
2020-05-15 05:25:02 +00:00
_logger . LogWarning ( $"Ignoring Nexus Downloads due to low hourly api limit (Daily: {daily}, Hourly:{hourly})" ) ;
2020-05-14 11:53:51 +00:00
else
_logger . LogInformation ( $"Looking for any download (Daily: {_nexusClient.DailyRemaining}, Hourly:{_nexusClient.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
if ( nextDownload = = null )
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 ;
}
if ( nextDownload . Archive . State is ManualDownloader . State )
{
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 ) ;
if ( ! ( nextDownload . Archive . State is GameFileSourceDownloader . State ) )
await _discord . Send ( Channel . Spam ,
new DiscordMessage
{
Content = $"Downloading {nextDownload.Archive.State.PrimaryKeyString}"
} ) ;
2020-05-14 04:08:27 +00:00
await DownloadDispatcher . PrepareAll ( new [ ] { nextDownload . Archive . State } ) ;
2020-05-28 02:43:57 +00:00
await using var tempPath = new TempFile ( ) ;
2020-08-25 01:34:57 +00:00
if ( ! await nextDownload . Archive . State . Download ( nextDownload . Archive , tempPath . Path ) )
{
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
var hash = await tempPath . Path . FileHashAsync ( ) ;
2020-12-31 06:44:42 +00:00
2021-01-09 18:53:44 +00:00
if ( hash = = null | | ( 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 ,
$"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 & &
tempPath . Path . Size ! = nextDownload . Archive . Size )
{
await nextDownload . Fail ( _sql , "Invalid Size" ) ;
continue ;
}
2020-12-31 06:44:42 +00:00
2021-01-09 18:53:44 +00:00
nextDownload . Archive . Hash = hash . Value ;
2020-05-14 04:08:27 +00:00
nextDownload . Archive . Size = tempPath . Path . Size ;
_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 ) ;
2020-12-31 06:44:42 +00:00
if ( ! ( nextDownload . Archive . State is GameFileSourceDownloader . State ) )
await _discord . Send ( Channel . Spam ,
new DiscordMessage
{
Content = $"Finished downloading {nextDownload.Archive.State.PrimaryKeyString}"
} ) ;
2020-06-06 21:44:30 +00:00
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 ;
}
}
}