@ -787,9 +787,11 @@ namespace DepotDownloader
}
} ) ;
var semaphore = new SemaphoreSlim ( Config . MaxDownloads ) ;
var ioSemaphore = new SemaphoreSlim ( Config . MaxDownloads ) ;
var networkSemaphore = new SemaphoreSlim ( Config . MaxDownloads ) ;
var files = filesAfterExclusions . Where ( f = > ! f . Flags . HasFlag ( EDepotFileFlag . Directory ) ) . ToArray ( ) ;
var tasks = new Task [ files . Length ] ;
var ioT asks = new Task [ files . Length ] ;
for ( var i = 0 ; i < files . Length ; i + + )
{
var file = files [ i ] ;
@ -799,7 +801,7 @@ namespace DepotDownloader
try
{
await s emaphore. WaitAsync ( ) . ConfigureAwait ( false ) ;
await ioS emaphore. WaitAsync ( ) . ConfigureAwait ( false ) ;
cts . Token . ThrowIfCancellationRequested ( ) ;
string fileFinalPath = Path . Combine ( depot . installDir , file . FileName ) ;
@ -910,99 +912,136 @@ namespace DepotDownloader
}
}
foreach ( var chunk in neededChunks )
{
if ( cts . IsCancellationRequested ) break ;
var fileSemaphore = new SemaphoreSlim ( 1 ) ;
string chunkID = Util . EncodeHexString ( chunk . ChunkID ) ;
CDNClient . DepotChunk chunkData = null ;
var downloadTasks = new Task < DepotManifest . ChunkData > [ neededChunks . Count ] ;
for ( var x = 0 ; x < neededChunks . Count ; x + + )
{
var chunk = neededChunks [ x ] ;
while ( ! cts . IsCancellationRequested )
var downloadTask = Task . Run ( async ( ) = >
{
Tuple < CDNClient . Server , string > connection ;
cts . Token . ThrowIfCancellationRequested ( ) ;
try
{
connection = await cdnPool . GetConnectionForDepot ( appId , depot . id , cts . Token ) ;
}
catch ( OperationCanceledException )
{
break ;
}
await networkSemaphore . WaitAsync ( ) . ConfigureAwait ( false ) ;
cts . Token . ThrowIfCancellationRequested ( ) ;
DepotManifest . ChunkData data = new DepotManifest . ChunkData ( ) ;
data . ChunkID = chunk . ChunkID ;
data . Checksum = chunk . Checksum ;
data . Offset = chunk . Offset ;
data . CompressedLength = chunk . CompressedLength ;
data . UncompressedLength = chunk . UncompressedLength ;
string chunkID = Util . EncodeHexString ( chunk . ChunkID ) ;
CDNClient . DepotChunk chunkData = null ;
try
{
chunkData = await cdnPool . CDNClient . DownloadDepotChunkAsync ( depot . id , data ,
connection . Item1 , connection . Item2 , depot . depotKey ) . ConfigureAwait ( false ) ;
cdnPool . ReturnConnection ( connection ) ;
break ;
}
catch ( SteamKitWebRequestException e )
{
cdnPool . ReturnBrokenConnection ( connection ) ;
while ( ! cts . IsCancellationRequested )
{
Tuple < CDNClient . Server , string > connection ;
try
{
connection = await cdnPool . GetConnectionForDepot ( appId , depot . id , cts . Token ) ;
}
catch ( OperationCanceledException )
{
break ;
}
DepotManifest . ChunkData data = new DepotManifest . ChunkData ( ) ;
data . ChunkID = chunk . ChunkID ;
data . Checksum = chunk . Checksum ;
data . Offset = chunk . Offset ;
data . CompressedLength = chunk . CompressedLength ;
data . UncompressedLength = chunk . UncompressedLength ;
try
{
chunkData = await cdnPool . CDNClient . DownloadDepotChunkAsync ( depot . id , data ,
connection . Item1 , connection . Item2 , depot . depotKey ) . ConfigureAwait ( false ) ;
cdnPool . ReturnConnection ( connection ) ;
break ;
}
catch ( SteamKitWebRequestException e )
{
cdnPool . ReturnBrokenConnection ( connection ) ;
if ( e . StatusCode = = HttpStatusCode . Unauthorized | | e . StatusCode = = HttpStatusCode . Forbidden )
{
Console . WriteLine ( "Encountered 401 for chunk {0}. Aborting." , chunkID ) ;
cts . Cancel ( ) ;
break ;
}
else
{
Console . WriteLine ( "Encountered error downloading chunk {0}: {1}" , chunkID , e . StatusCode ) ;
}
}
catch ( TaskCanceledException )
{
Console . WriteLine ( "Connection timeout downloading chunk {0}" , chunkID ) ;
}
catch ( Exception e )
{
cdnPool . ReturnBrokenConnection ( connection ) ;
Console . WriteLine ( "Encountered unexpected error downloading chunk {0}: {1}" , chunkID , e . Message ) ;
}
}
if ( e . StatusCode = = HttpStatusCode . Unauthorized | | e . StatusCode = = HttpStatusCode . Forbidden )
if ( chunkData = = null )
{
Console . WriteLine ( "Encountered 401 for chunk {0}. Aborting." , chunkID ) ;
Console . WriteLine ( "Failed to find any server with chunk {0} for depot {1}. Aborting." , chunkID , depot . id ) ;
cts . Cancel ( ) ;
break ;
}
else
// Throw the cancellation exception if requested so that this task is marked failed
cts . Token . ThrowIfCancellationRequested ( ) ;
try
{
Console . WriteLine ( "Encountered error downloading chunk {0}: {1}" , chunkID , e . StatusCode ) ;
await fileSemaphore . WaitAsync ( ) . ConfigureAwait ( false ) ;
fs . Seek ( ( long ) chunkData . ChunkInfo . Offset , SeekOrigin . Begin ) ;
fs . Write ( chunkData . Data , 0 , chunkData . Data . Length ) ;
return chunkData . ChunkInfo ;
}
finally
{
fileSemaphore . Release ( ) ;
}
}
catch ( TaskCanceledException )
{
Console . WriteLine ( "Connection timeout downloading chunk {0}" , chunkID ) ;
}
catch ( Exception e )
finally
{
cdnPool . ReturnBrokenConnection ( connection ) ;
Console . WriteLine ( "Encountered unexpected error downloading chunk {0}: {1}" , chunkID , e . Message ) ;
networkSemaphore . Release ( ) ;
}
}
} ) ;
if ( chunkData = = null )
{
Console . WriteLine ( "Failed to find any server with chunk {0} for depot {1}. Aborting." , chunkID , depot . id ) ;
cts . Cancel ( ) ;
}
downloadTasks [ x ] = downloadTask ;
}
// Throw the cancellation exception if requested so that this task is marked failed
cts . Token . ThrowIfCancellationRequested ( ) ;
var completedDownloads = await Task . WhenAll ( downloadTasks ) . ConfigureAwait ( false ) ;
TotalBytesCompressed + = chunk . CompressedLength ;
DepotBytesCompressed + = chunk . CompressedLength ;
TotalBytesUncompressed + = chunk . UncompressedLength ;
DepotBytesUncompressed + = chunk . UncompressedLength ;
fs . Dispose ( ) ;
fs . Seek ( ( long ) chunk . Offset , SeekOrigin . Begin ) ;
fs . Write ( chunkData . Data , 0 , chunkData . Data . Length ) ;
foreach ( var chunkInfo in completedDownloads )
{
TotalBytesCompressed + = chunkInfo . CompressedLength ;
DepotBytesCompressed + = chunkInfo . CompressedLength ;
TotalBytesUncompressed + = chunkInfo . UncompressedLength ;
DepotBytesUncompressed + = chunkInfo . UncompressedLength ;
size_downloaded + = chunk . UncompressedLength ;
size_downloaded + = chunk Info . UncompressedLength ;
}
fs . Dispose ( ) ;
Console . WriteLine ( "{0,6:#00.00}% {1}" , ( ( float ) size_downloaded / ( float ) complete_download_size ) * 100.0f , fileFinalPath ) ;
Console . WriteLine ( "{0,6:#00.00}% {1}" , ( ( float ) size_downloaded / ( float ) complete_download_size ) * 100.0f , fileFinalPath ) ;
}
finally
{
s emaphore. Release ( ) ;
ioS emaphore. Release ( ) ;
}
} ) ;
t asks[ i ] = task ;
ioT asks[ i ] = task ;
}
await Task . WhenAll ( tasks ) . ConfigureAwait ( false ) ;
await Task . WhenAll ( ioTasks ) . ConfigureAwait ( false ) ;
DepotConfigStore . Instance . InstalledManifestIDs [ depot . id ] = depot . manifestId ;
DepotConfigStore . Save ( ) ;