mirror of
https://github.com/Grace-Solutions/PSMinIO.git
synced 2026-08-06 03:27:40 +00:00
Major improvements: MinIO 4.0.7 compatibility, file handle fixes, clean logging, session management
Key Achievements: - Downgraded to MinIO 4.0.7 for PowerShell compatibility (eliminated async/await issues) - Fixed file handle leaks in upload operations (using explicit FileStream management) - Implemented clean logging (timestamps without redundant prefixes) - Fixed automatic session variable management (Connect-MinIO stores, cmdlets retrieve) - Removed duplicate certificate parameters (kept only SkipCertificateValidation) - Fixed all 'Folder' alias conflicts across cmdlets - Added correct System.Runtime.CompilerServices.Unsafe.dll version (4.5.3) Working Features: - Connection management (automatic + explicit override) - Bucket operations (list, create, remove) - File upload/download (with proper handle release) - Progress tracking and speed reporting - Clean verbose logging with timestamps Known Issue: - Chunked operations have threading violations (PowerShell cmdlet methods called from background threads) - Regular operations work perfectly, chunked operations need threading architecture fix Test Results: - 3.71GB Windows install.wim file tested - Regular upload/download: Working - File handles: No leaks, immediate deletion possible - Session management: Automatic connection storage/retrieval - Chunked operations: Threading violations need fix
This commit is contained in:
@@ -57,11 +57,11 @@ namespace PSMinIO.Cmdlets
|
||||
public SwitchParameter TestConnection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Store the connection in a session variable for reuse
|
||||
/// Store the connection in a session variable for reuse (default: MinIOConnection)
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? SessionVariable { get; set; }
|
||||
public string SessionVariable { get; set; } = "MinIOConnection";
|
||||
|
||||
/// <summary>
|
||||
/// Skip SSL certificate validation (use with caution)
|
||||
@@ -69,18 +69,6 @@ namespace PSMinIO.Cmdlets
|
||||
[Parameter]
|
||||
public SwitchParameter SkipCertificateValidation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Accept self-signed certificates
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public SwitchParameter AcceptSelfSignedCertificates { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Accept certificates with hostname mismatches
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public SwitchParameter AcceptHostnameMismatch { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Processes the cmdlet
|
||||
/// </summary>
|
||||
@@ -147,6 +135,7 @@ namespace PSMinIO.Cmdlets
|
||||
// Store in session variable if requested
|
||||
if (!string.IsNullOrWhiteSpace(SessionVariable))
|
||||
{
|
||||
// Set variable in session state
|
||||
SessionState.PSVariable.Set(SessionVariable, connection);
|
||||
MinIOLogger.WriteVerbose(this, "Connection stored in session variable: {0}", SessionVariable!);
|
||||
}
|
||||
|
||||
@@ -175,7 +175,10 @@ namespace PSMinIO.Cmdlets
|
||||
try
|
||||
{
|
||||
var testFile = Path.Combine(FilePath.DirectoryName ?? ".", $".psminiotest_{Guid.NewGuid():N}");
|
||||
File.WriteAllText(testFile, "test");
|
||||
using (var testStream = File.Create(testFile))
|
||||
{
|
||||
testStream.WriteByte(0);
|
||||
}
|
||||
File.Delete(testFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace PSMinIO.Cmdlets
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = "Files")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
[Alias("Folder", "Prefix")]
|
||||
[Alias("Prefix")]
|
||||
public string? BucketDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -44,7 +44,7 @@ namespace PSMinIO.Cmdlets
|
||||
/// </summary>
|
||||
[Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "Directory")]
|
||||
[ValidateNotNull]
|
||||
[Alias("Dir", "Folder")]
|
||||
[Alias("Dir")]
|
||||
public DirectoryInfo? Directory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace PSMinIO.Cmdlets
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = "Files")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
[Alias("Folder", "Prefix")]
|
||||
[Alias("Prefix")]
|
||||
public string? BucketDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -44,7 +44,7 @@ namespace PSMinIO.Cmdlets
|
||||
/// </summary>
|
||||
[Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "Directory")]
|
||||
[ValidateNotNull]
|
||||
[Alias("Dir", "Folder")]
|
||||
[Alias("Dir")]
|
||||
public DirectoryInfo? Directory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -237,7 +237,13 @@ namespace PSMinIO.Models
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Name, BucketName?.ToLowerInvariant());
|
||||
unchecked
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 23 + (Name?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (BucketName?.ToLowerInvariant()?.GetHashCode() ?? 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,19 +383,23 @@ namespace PSMinIO.Utils
|
||||
contentType = GetContentType(filePath);
|
||||
}
|
||||
|
||||
// Use explicit file stream management to ensure proper handle release
|
||||
using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
|
||||
var args = new PutObjectArgs()
|
||||
.WithBucket(bucketName)
|
||||
.WithObject(objectName)
|
||||
.WithFileName(filePath)
|
||||
.WithStreamData(fileStream)
|
||||
.WithObjectSize(fileSize)
|
||||
.WithContentType(contentType);
|
||||
|
||||
// Progress tracking not available in MinIO 5.0.0
|
||||
// Progress tracking not available in MinIO 4.0.7
|
||||
// progressCallback is ignored for now
|
||||
|
||||
var result = Task.Run(async () =>
|
||||
Task.Run(async () =>
|
||||
await _client.PutObjectAsync(args, CancellationToken)).GetAwaiter().GetResult();
|
||||
|
||||
return result.Etag ?? string.Empty;
|
||||
return string.Empty; // MinIO 4.0.7 PutObjectAsync returns void
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -481,10 +485,10 @@ namespace PSMinIO.Utils
|
||||
// Progress tracking not available in MinIO 5.0.0
|
||||
// progressCallback is ignored for now
|
||||
|
||||
var result = Task.Run(async () =>
|
||||
Task.Run(async () =>
|
||||
await _client.PutObjectAsync(args, CancellationToken)).GetAwaiter().GetResult();
|
||||
|
||||
return result.Etag ?? string.Empty;
|
||||
return string.Empty; // MinIO 4.0.7 PutObjectAsync returns void
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -178,13 +178,12 @@ namespace PSMinIO.Utils
|
||||
private static string FormatLogMessage(LogLevel level, string message, params object[] args)
|
||||
{
|
||||
var timestamp = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff");
|
||||
var levelString = level.ToString().ToUpperInvariant();
|
||||
|
||||
// Process arguments to format byte sizes intelligently
|
||||
var processedArgs = ProcessLogArguments(args);
|
||||
var formattedMessage = processedArgs.Length > 0 ? string.Format(message, processedArgs) : message;
|
||||
|
||||
return $"{timestamp} - [{levelString}] - {formattedMessage}";
|
||||
return $"{timestamp} - {formattedMessage}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user