Private/Add-FoHistoryEntry.ps1
|
function Get-FoHistoryMutexName { param([string]$HistoryPath) $path = if ($HistoryPath) { $HistoryPath } else { Get-FoDefaultHistoryPath } $fullPath = [System.IO.Path]::GetFullPath($path).ToLowerInvariant() $hash = [System.BitConverter]::ToString( [System.Security.Cryptography.SHA256]::Create().ComputeHash( [System.Text.Encoding]::UTF8.GetBytes($fullPath) ) ).Replace('-', '') return "Local\FoHistory_$hash" } function Invoke-FoHistoryFileLock { param( [string]$HistoryPath, [Parameter(Mandatory)] [scriptblock]$Action ) $mutex = New-Object System.Threading.Mutex($false, (Get-FoHistoryMutexName -HistoryPath $HistoryPath)) try { if (-not $mutex.WaitOne(30000)) { throw 'Timed out waiting for history file lock.' } return & $Action } finally { try { $mutex.ReleaseMutex() } catch { Write-Debug $_.Exception.Message } $mutex.Dispose() } } function Get-FoHistoryData { param([string]$HistoryPath) $path = if ($HistoryPath) { $HistoryPath } else { Get-FoDefaultHistoryPath } if (-not (Test-Path -LiteralPath $path)) { return @{ Version = 1; Entries = @() } } return Import-FoJsonFile -Path $path } function Save-FoHistoryData { param( [hashtable]$Data, [string]$HistoryPath ) $path = if ($HistoryPath) { $HistoryPath } else { Get-FoDefaultHistoryPath } Save-FoJsonFile -Path $path -Data $Data -Depth 6 } function Add-FoHistoryEntry { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Parameters are used inside the history lock scriptblock.')] param( $Result, [hashtable]$Settings ) if (-not $Settings.HistoryEnabled) { return } Invoke-FoHistoryFileLock -HistoryPath $Settings.HistoryPath -Action { $data = Get-FoHistoryData -HistoryPath $Settings.HistoryPath $id = (Get-Date -Format 'yyyyMMdd-HHmmss') + '-' + ([guid]::NewGuid().ToString('N').Substring(0, 8)) # History entry fields: # - TargetPath / OriginalPath: user-visible path where the optimized file was written (undo restore destination) # - OptimizedPath: same as TargetPath for in-place modes; sibling path for OptimizedSuffix # - BackupPath: location of pre-optimization bytes for reversible modes (TempMove, BackupSuffix, BackupMove) # - OriginalSize / FinalSize: byte sizes before and after optimization $targetPath = $Result.Path $entry = @{ Id = $id Timestamp = (Get-Date -Format 'yyyy-MM-ddTHH:mm:ss') TargetPath = $targetPath OriginalPath = $targetPath OriginalSize = $Result.OriginalSize FinalSize = $Result.FinalSize OptimizedPath = $Result.OutputPath BackupPath = $Result.BackupPath OutputMode = $Result.OutputMode ReversalStatus = 'Pending' ErrorMessage = $null } $data.Entries = @($data.Entries) + @($entry) Save-FoHistoryData -Data $data -HistoryPath $Settings.HistoryPath $Result | Add-Member -NotePropertyName HistoryId -NotePropertyValue $id -Force } } function Update-FoHistoryEntry { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Parameters are used inside the history lock scriptblock.')] param( [string]$Id, [string]$ReversalStatus, [string]$ErrorMessage, [string]$HistoryPath ) Invoke-FoHistoryFileLock -HistoryPath $HistoryPath -Action { $data = Get-FoHistoryData -HistoryPath $HistoryPath $updated = @() foreach ($e in $data.Entries) { if ($e.Id -eq $Id) { $e.ReversalStatus = $ReversalStatus $e.ErrorMessage = $ErrorMessage } $updated += $e } $data.Entries = $updated Save-FoHistoryData -Data $data -HistoryPath $HistoryPath } } |