Skip to content

Commit

Permalink
Remote: Unzip while downloading
Browse files Browse the repository at this point in the history
  • Loading branch information
suchmememanyskill committed Jun 16, 2024
1 parent 1603beb commit 6ac424f
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 24 deletions.
62 changes: 38 additions & 24 deletions RemoteDownloaderPlugin/Game/GameDownload.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System.IO.Compression;
using ICSharpCode.SharpZipLib.Zip;
using LauncherGamePlugin;
using LauncherGamePlugin.Interfaces;
using RemoteDownloaderPlugin.Utils;
using ZipFile = System.IO.Compression.ZipFile;

namespace RemoteDownloaderPlugin.Game;

Expand Down Expand Up @@ -128,40 +129,53 @@ private async Task DownloadPc(IApp app, PcEntry entry)
Type = GameType.Pc;
BasePath = Path.Join(app.GameDir, "Remote", "Pc", entry.GameId);
Directory.CreateDirectory(BasePath);
var zipFilePath = Path.Join(BasePath, "__game__.zip");

using HttpClient client = new();
var fs = new FileStream(zipFilePath, FileMode.Create);

Progress<float> progress = new();
progress.ProgressChanged += OnProgressUpdate;

try
{
await client.DownloadAsync(entry.Url, fs, progress, _cts.Token);
}
catch (TaskCanceledException e)
{
await Task.Run(() => fs.Dispose());
using HttpResponseMessage response = await client.GetAsync(entry.Url, HttpCompletionOption.ResponseHeadersRead, _cts.Token);
response.EnsureSuccessStatusCode();
await using var responseStream = await response.Content.ReadAsStreamAsync();
var interceptor =
new StreamInterceptor(responseStream, progress, response.Content.Headers.ContentLength!.Value);
await using var zipInputStream = new ZipInputStream(interceptor);

while (zipInputStream.GetNextEntry() is { } zipEntry)
{
var destinationPath = Path.Combine(BasePath, zipEntry.Name);

Directory.Delete(BasePath);

throw;
}
// Ensure the parent directory exists
var directoryPath = Path.GetDirectoryName(destinationPath);
if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}


Percentage = 100;
Line1 = "Saving...";
InvokeOnUpdate();
await Task.Run(() => fs.Dispose());
Line1 = "Unzipping...";
InvokeOnUpdate();
await Task.Run(() => ZipFile.ExtractToDirectory(zipFilePath, BasePath));
File.Delete(zipFilePath);
// Skip directory entries
if (zipEntry.IsDirectory)
{
continue;
}

if (_cts.IsCancellationRequested)
var fileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write);
try
{
await zipInputStream.CopyToAsync(fileStream, _cts.Token);
}
finally
{
await Task.Run(() => fileStream.Dispose());
}
}
}
catch (Exception e)
{
Directory.Delete(BasePath);
app.Logger.Log($"Download failed: {e.Message}", LogType.Error, "Remote");
Directory.Delete(BasePath, true);
throw;
}

TotalSize = await Task.Run(() => LauncherGamePlugin.Utils.DirSize(new(BasePath)));
Expand Down
4 changes: 4 additions & 0 deletions RemoteDownloaderPlugin/RemoteDownloaderPlugin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,9 @@
<ExcludeAssets>runtime</ExcludeAssets>
</ProjectReference>
</ItemGroup>

<ItemGroup>
<PackageReference Include="SharpZipLib" Version="1.4.2" />
</ItemGroup>

</Project>
47 changes: 47 additions & 0 deletions RemoteDownloaderPlugin/Utils/StreamInterceptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace RemoteDownloaderPlugin.Utils;

public class StreamInterceptor : Stream
{
private Stream _stream;
private IProgress<float> _progress;
private long _contentLength;
private long _totalRead;

public StreamInterceptor(Stream stream, IProgress<float> progress, long contentLength)
{
_stream = stream;
_progress = progress;
_contentLength = contentLength;
}

public override void Flush()
=> _stream.Flush();

public override int Read(byte[] buffer, int offset, int count)
{
var bytesRead = _stream.Read(buffer, offset, count);
_totalRead += bytesRead;
_progress.Report((float)_totalRead / _contentLength);
return bytesRead;
}

public override long Seek(long offset, SeekOrigin origin)
=> _stream.Seek(offset, origin);

public override void SetLength(long value)
=> _stream.SetLength(value);

public override void Write(byte[] buffer, int offset, int count)
=> _stream.Write(buffer, offset, count);

public override bool CanRead => _stream.CanRead;
public override bool CanSeek => _stream.CanSeek;
public override bool CanWrite => _stream.CanWrite;
public override long Length => _stream.Length;

public override long Position
{
get => _stream.Position;
set => _stream.Position = value;
}
}

0 comments on commit 6ac424f

Please sign in to comment.