diff --git a/Module/PSMinIO/bin/PSMinIO.dll b/Module/PSMinIO/bin/PSMinIO.dll index 5823803..e495b29 100644 Binary files a/Module/PSMinIO/bin/PSMinIO.dll and b/Module/PSMinIO/bin/PSMinIO.dll differ diff --git a/src/Cmdlets/GetMinIOObjectContentCmdlet.cs b/src/Cmdlets/GetMinIOObjectContentCmdlet.cs index 813db28..52abd05 100644 --- a/src/Cmdlets/GetMinIOObjectContentCmdlet.cs +++ b/src/Cmdlets/GetMinIOObjectContentCmdlet.cs @@ -120,7 +120,6 @@ namespace PSMinIO.Cmdlets } // Track progress - long lastReportedBytes = 0; var startTime = DateTime.UtcNow; // Download the object @@ -132,25 +131,8 @@ namespace PSMinIO.Cmdlets fileStream, bytesTransferred => { + // Only update the result object - no PowerShell calls from background thread downloadResult.BytesTransferred = bytesTransferred; - - // Report progress every 1MB or at completion - if (bytesTransferred - lastReportedBytes >= 1024 * 1024 || - (downloadResult.TotalSize > 0 && bytesTransferred >= downloadResult.TotalSize)) - { - var elapsed = DateTime.UtcNow - startTime; - var speed = elapsed.TotalSeconds > 0 ? bytesTransferred / elapsed.TotalSeconds : 0; - var percentage = downloadResult.TotalSize > 0 ? - (double)bytesTransferred / downloadResult.TotalSize * 100 : 0; - - WriteVerboseMessage("Download progress: {0:F1}% ({1}/{2}) at {3}", - percentage, - SizeFormatter.FormatBytes(bytesTransferred), - downloadResult.TotalSize > 0 ? SizeFormatter.FormatBytes(downloadResult.TotalSize) : "Unknown", - SizeFormatter.FormatSpeed(speed)); - - lastReportedBytes = bytesTransferred; - } }); downloadResult.TotalSize = bytesDownloaded; @@ -162,6 +144,15 @@ namespace PSMinIO.Cmdlets var duration = downloadResult.Duration ?? TimeSpan.Zero; var averageSpeed = downloadResult.AverageSpeed ?? 0; + // Report final progress from main thread + var percentage = downloadResult.TotalSize > 0 ? + (double)downloadResult.BytesTransferred / downloadResult.TotalSize * 100 : 100; + WriteVerboseMessage("Download progress: {0:F1}% ({1}/{2}) at {3}", + percentage, + SizeFormatter.FormatBytes(downloadResult.BytesTransferred), + downloadResult.TotalSize > 0 ? SizeFormatter.FormatBytes(downloadResult.TotalSize) : "Unknown", + SizeFormatter.FormatSpeed(averageSpeed)); + WriteVerboseMessage("Download completed: {0} in {1} at average speed of {2}", SizeFormatter.FormatBytes(downloadResult.BytesTransferred), SizeFormatter.FormatDuration(duration), diff --git a/src/Cmdlets/NewMinIOObjectCmdlet.cs b/src/Cmdlets/NewMinIOObjectCmdlet.cs index b7e33e3..b8406fc 100644 --- a/src/Cmdlets/NewMinIOObjectCmdlet.cs +++ b/src/Cmdlets/NewMinIOObjectCmdlet.cs @@ -147,7 +147,6 @@ namespace PSMinIO.Cmdlets // Track progress var fileSize = File.Length; var startTime = DateTime.UtcNow; - long lastReportedBytes = 0; WriteVerboseMessage("Starting upload of {0}", SizeFormatter.FormatBytes(fileSize)); @@ -163,23 +162,8 @@ namespace PSMinIO.Cmdlets metadata, bytesTransferred => { + // Only update the result object - no PowerShell calls from background thread uploadResult.BytesTransferred = bytesTransferred; - - // Report progress every 1MB or at completion - if (bytesTransferred - lastReportedBytes >= 1024 * 1024 || bytesTransferred == fileSize) - { - var elapsed = DateTime.UtcNow - startTime; - var speed = elapsed.TotalSeconds > 0 ? bytesTransferred / elapsed.TotalSeconds : 0; - var percentage = fileSize > 0 ? (double)bytesTransferred / fileSize * 100 : 100; - - WriteVerboseMessage("Upload progress: {0:F1}% ({1}/{2}) at {3}", - percentage, - SizeFormatter.FormatBytes(bytesTransferred), - SizeFormatter.FormatBytes(fileSize), - SizeFormatter.FormatSpeed(speed)); - - lastReportedBytes = bytesTransferred; - } }); } @@ -189,6 +173,14 @@ namespace PSMinIO.Cmdlets var duration = uploadResult.Duration ?? TimeSpan.Zero; var averageSpeed = uploadResult.AverageSpeed ?? 0; + // Report final progress from main thread + var percentage = fileSize > 0 ? (double)uploadResult.BytesTransferred / fileSize * 100 : 100; + WriteVerboseMessage("Upload progress: {0:F1}% ({1}/{2}) at {3}", + percentage, + SizeFormatter.FormatBytes(uploadResult.BytesTransferred), + SizeFormatter.FormatBytes(fileSize), + SizeFormatter.FormatSpeed(averageSpeed)); + WriteVerboseMessage("Upload completed in {0} at average speed of {1}", SizeFormatter.FormatDuration(duration), SizeFormatter.FormatSpeed(averageSpeed)); diff --git a/src/Core/Http/MinIOHttpClient.cs b/src/Core/Http/MinIOHttpClient.cs index 82bd663..1534b38 100644 --- a/src/Core/Http/MinIOHttpClient.cs +++ b/src/Core/Http/MinIOHttpClient.cs @@ -79,8 +79,8 @@ namespace PSMinIO.Core.Http try { - // Execute the request synchronously - var response = _httpClient.SendAsync(request).GetAwaiter().GetResult(); + // Execute the request synchronously using Task.Run to avoid threading issues + var response = Task.Run(async () => await _httpClient.SendAsync(request)).GetAwaiter().GetResult(); return response; } catch (Exception ex) diff --git a/src/Utils/MinIOErrorHandler.cs b/src/Utils/MinIOErrorHandler.cs index 9f523ff..d7817e1 100644 --- a/src/Utils/MinIOErrorHandler.cs +++ b/src/Utils/MinIOErrorHandler.cs @@ -74,13 +74,21 @@ namespace PSMinIO.Utils // Create detailed error information var errorDetails = CreateDetailedErrorInfo(exception, operationName, operationDetails); - + // Log detailed error information LogDetailedError(cmdlet, errorDetails); - + // Create and write PowerShell error record - var errorRecord = CreateErrorRecord(exception, operationName, errorCategory, targetObject); - cmdlet.WriteError(errorRecord); + try + { + var errorRecord = CreateErrorRecord(exception, operationName, errorCategory, targetObject); + cmdlet.WriteError(errorRecord); + } + catch (InvalidOperationException) + { + // Ignore threading errors - this means we're being called from a background thread + // The error details are still captured in the exception + } } /// @@ -128,27 +136,36 @@ namespace PSMinIO.Utils /// /// Logs detailed error information using PowerShell's Write-Warning + /// Only logs if called from the main PowerShell thread to avoid threading issues /// private static void LogDetailedError(PSCmdlet cmdlet, OrderedDictionary errorDetails) { - var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"); - - // Log header - cmdlet.WriteWarning($"{timestamp} - ERROR: PSMinIO Operation Failed"); - - // Log each error detail - foreach (DictionaryEntry detail in errorDetails) + try { - var key = detail.Key?.ToString() ?? "Unknown"; - var value = detail.Value?.ToString() ?? "N/A"; - - // Truncate very long values for readability - if (value.Length > 200) + var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"); + + // Log header + cmdlet.WriteWarning($"{timestamp} - ERROR: PSMinIO Operation Failed"); + + // Log each error detail + foreach (DictionaryEntry detail in errorDetails) { - value = value.Substring(0, 197) + "..."; + var key = detail.Key?.ToString() ?? "Unknown"; + var value = detail.Value?.ToString() ?? "N/A"; + + // Truncate very long values for readability + if (value.Length > 200) + { + value = value.Substring(0, 197) + "..."; + } + + cmdlet.WriteWarning($"{timestamp} - ERROR: {key}: {value}"); } - - cmdlet.WriteWarning($"{timestamp} - ERROR: {key}: {value}"); + } + catch (InvalidOperationException) + { + // Ignore threading errors - this means we're being called from a background thread + // The error details will still be included in the exception that gets thrown } }