using AssetStoreTools.Api.Responses; using System; using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; namespace AssetStoreTools.Api { internal abstract class PackageUploaderBase : IPackageUploader { protected const int UploadChunkSizeBytes = 32768; protected const int UploadResponseTimeoutMs = 10000; protected abstract void ValidateSettings(); public abstract Task Upload(IAssetStoreClient client, IProgress progress = null, CancellationToken cancellationToken = default); protected void EnsureSuccessResponse(HttpResponseMessage response) { try { response.EnsureSuccessStatusCode(); } catch { throw new Exception(response.Content.ReadAsStringAsync().Result); } } protected void WaitForUploadCompletion(Task response, FileStream requestFileStream, IProgress progress, CancellationToken cancellationToken) { // Progress tracking int updateIntervalMs = 100; bool allBytesSent = false; DateTime timeOfCompletion = default; while (!response.IsCompleted) { float uploadProgress = (float)requestFileStream.Position / requestFileStream.Length * 100; progress?.Report(uploadProgress); Thread.Sleep(updateIntervalMs); // A timeout for rare cases, when package uploading reaches 100%, but Put task IsComplete value remains 'False' if (requestFileStream.Position == requestFileStream.Length) { if (!allBytesSent) { allBytesSent = true; timeOfCompletion = DateTime.UtcNow; } else if (DateTime.UtcNow.Subtract(timeOfCompletion).TotalMilliseconds > UploadResponseTimeoutMs) { throw new TimeoutException(); } } } } } }