2022-05-15 17:36:16 -04:00
using PatchClient.Models ;
using PatcherUtils.Model ;
using System ;
2024-05-03 14:57:08 -04:00
using System.Collections.Concurrent ;
2021-12-17 16:02:31 -05:00
using System.Collections.Generic ;
using System.Diagnostics ;
using System.IO ;
using System.Linq ;
2021-12-25 20:24:00 -05:00
using System.Security.Cryptography ;
2024-05-03 14:57:08 -04:00
using System.Threading ;
using System.Threading.Tasks ;
2023-11-15 19:44:29 -05:00
using PatcherUtils.Helpers ;
2021-12-17 16:02:31 -05:00
namespace PatcherUtils
{
public class PatchHelper
{
private string SourceFolder = "" ;
private string TargetFolder = "" ;
private string DeltaFolder = "" ;
private int fileCountTotal ;
private int filesProcessed ;
private int deltaCount ;
private int newCount ;
private int delCount ;
2021-12-25 20:24:00 -05:00
private int existCount ;
2021-12-17 16:02:31 -05:00
2023-11-09 20:49:40 -05:00
private bool debugOutput ;
2021-12-18 00:03:07 -05:00
private List < LineItem > AdditionalInfo = new List < LineItem > ( ) ;
2021-12-17 16:02:31 -05:00
2021-12-25 20:24:00 -05:00
/// <summary>
/// Reports patch creation or application progress
/// </summary>
/// <remarks>Includes an array of <see cref="LineItem"/> with details for each type of patch</remarks>
2021-12-17 16:02:31 -05:00
public event ProgressChangedHandler ProgressChanged ;
2024-05-03 14:57:08 -04:00
protected virtual void RaiseProgressChanged ( int progress , int total , string Message = "" ,
params LineItem [ ] AdditionalLineItems )
2021-12-17 16:02:31 -05:00
{
int percent = ( int ) Math . Floor ( ( double ) progress / total * 100 ) ;
ProgressChanged ? . Invoke ( this , progress , total , percent , Message , AdditionalLineItems ) ;
}
2021-12-25 20:24:00 -05:00
/// <summary>
/// A helper class to create and apply patches to folders
/// </summary>
/// <param name="SourceFolder">The directory that will have patches applied to it.</param>
/// <param name="TargetFolder">The directory to compare against during patch creation.</param>
/// <param name="DeltaFolder">The directory where the patches are/will be located.</param>
/// <remarks><paramref name="TargetFolder"/> can be null if you only plan to apply patches.</remarks>
2023-11-09 20:49:40 -05:00
public PatchHelper ( string SourceFolder , string TargetFolder , string DeltaFolder , bool debugOutput = false )
2021-12-17 16:02:31 -05:00
{
this . SourceFolder = SourceFolder ;
this . TargetFolder = TargetFolder ;
this . DeltaFolder = DeltaFolder ;
2023-11-09 20:49:40 -05:00
this . debugOutput = debugOutput ;
2021-12-17 16:02:31 -05:00
}
2021-12-25 20:24:00 -05:00
/// <summary>
/// Get the delta folder file path.
/// </summary>
/// <param name="SourceFilePath"></param>
/// <param name="SourceFolderPath"></param>
/// <param name="FileExtension">The extension to append to the file</param>
/// <returns>A file path inside the delta folder</returns>
private string GetDeltaPath ( string SourceFilePath , string SourceFolderPath , string FileExtension )
2021-12-17 16:02:31 -05:00
{
2021-12-25 20:24:00 -05:00
return Path . Join ( DeltaFolder , $"{SourceFilePath.Replace(SourceFolderPath, "")}.{FileExtension}" ) ;
2021-12-17 16:02:31 -05:00
}
2021-12-25 20:24:00 -05:00
/// <summary>
/// Check if two files have the same MD5 hash
/// </summary>
/// <param name="SourceFilePath"></param>
/// <param name="TargetFilePath"></param>
/// <returns>True if the hashes match</returns>
private bool CompareFileHashes ( string SourceFilePath , string TargetFilePath )
{
2022-06-14 21:26:23 -04:00
var sourceInfo = new FileInfo ( SourceFilePath ) ;
var targetInfo = new FileInfo ( TargetFilePath ) ;
2021-12-25 20:24:00 -05:00
using ( MD5 md5Service = MD5 . Create ( ) )
using ( var sourceStream = File . OpenRead ( SourceFilePath ) )
using ( var targetStream = File . OpenRead ( TargetFilePath ) )
{
byte [ ] sourceHash = md5Service . ComputeHash ( sourceStream ) ;
byte [ ] targetHash = md5Service . ComputeHash ( targetStream ) ;
2022-06-14 21:26:23 -04:00
bool matched = Enumerable . SequenceEqual ( sourceHash , targetHash ) ;
2024-05-03 14:57:08 -04:00
PatchLogger . LogInfo (
$"Hash Check: S({sourceInfo.Name}|{Convert.ToBase64String(sourceHash)}) - T({targetInfo.Name}|{Convert.ToBase64String(targetHash)}) - Match:{matched}" ) ;
2022-06-14 21:26:23 -04:00
return matched ;
2021-12-25 20:24:00 -05:00
}
}
/// <summary>
/// Apply a delta to a file using xdelta
/// </summary>
/// <param name="SourceFilePath"></param>
/// <param name="DeltaFilePath"></param>
2022-07-04 11:03:59 -04:00
private ( bool , string ) ApplyDelta ( string SourceFilePath , string DeltaFilePath )
2021-12-17 16:02:31 -05:00
{
string decodedPath = SourceFilePath + ".decoded" ;
2023-11-09 20:49:40 -05:00
var xdeltaArgs = $"-d {(debugOutput ? " - v - v " : " ")} -f -s" ;
2023-11-15 19:44:29 -05:00
var xdeltaHelper =
new XdeltaProcessHelper ( xdeltaArgs , SourceFilePath , DeltaFilePath , decodedPath , debugOutput ) ;
2023-11-09 20:49:40 -05:00
2023-11-15 19:44:29 -05:00
if ( ! xdeltaHelper . Run ( ) )
2023-11-09 20:49:40 -05:00
{
2023-11-15 19:44:29 -05:00
return ( false , "something went wrong during the xdelta3 process" ) ;
2023-11-09 20:49:40 -05:00
}
2021-12-17 16:02:31 -05:00
2021-12-25 20:24:00 -05:00
if ( File . Exists ( decodedPath ) )
2021-12-17 16:02:31 -05:00
{
2022-06-14 21:26:23 -04:00
PatchLogger . LogInfo ( $"File delta decoded: {SourceFilePath}" ) ;
try
{
File . Move ( decodedPath , SourceFilePath , true ) ;
PatchLogger . LogInfo ( $"Delta applied: {DeltaFilePath}" ) ;
2022-07-04 11:03:59 -04:00
return ( true , "" ) ;
2022-06-14 21:26:23 -04:00
}
catch ( Exception ex )
{
PatchLogger . LogException ( ex ) ;
2022-07-04 11:03:59 -04:00
return ( false , ex . Message ) ;
2022-06-14 21:26:23 -04:00
}
}
else
{
2022-07-04 11:03:59 -04:00
string error = $"Failed to decode file delta: {SourceFilePath}" ;
PatchLogger . LogError ( error ) ;
return ( false , error ) ;
2021-12-17 16:02:31 -05:00
}
}
2021-12-25 20:24:00 -05:00
/// <summary>
/// Create a .delta file using xdelta
/// </summary>
/// <param name="SourceFilePath"></param>
/// <param name="TargetFilePath"></param>
/// <remarks>Used to patch an existing file with xdelta</remarks>
2021-12-17 16:02:31 -05:00
private void CreateDelta ( string SourceFilePath , string TargetFilePath )
{
FileInfo sourceFileInfo = new FileInfo ( SourceFilePath ) ;
string deltaPath = GetDeltaPath ( SourceFilePath , SourceFolder , "delta" ) ;
2022-06-14 21:26:23 -04:00
try
{
Directory . CreateDirectory ( deltaPath . Replace ( sourceFileInfo . Name + ".delta" , "" ) ) ;
}
2024-05-03 14:57:08 -04:00
catch ( Exception ex )
2022-06-14 21:26:23 -04:00
{
PatchLogger . LogException ( ex ) ;
}
2021-12-17 16:02:31 -05:00
Process . Start ( new ProcessStartInfo
2024-05-03 14:57:08 -04:00
{
FileName = LazyOperations . XDelta3Path ,
Arguments = $"-0 -e -f -s \" { SourceFilePath } \ " \"{TargetFilePath}\" \"{deltaPath}\"" ,
CreateNoWindow = true
} )
. WaitForExit ( ) ;
2022-06-14 21:26:23 -04:00
if ( File . Exists ( deltaPath ) )
{
PatchLogger . LogInfo ( $"File created [DELTA]: {deltaPath}" ) ;
}
else
{
PatchLogger . LogError ( $"File Create failed [DELTA]: {deltaPath}" ) ;
}
2021-12-17 16:02:31 -05:00
}
2021-12-25 20:24:00 -05:00
/// <summary>
/// Create a .del file
/// </summary>
/// <param name="SourceFile"></param>
/// <remarks>Used to mark a file for deletion</remarks>
2021-12-17 16:02:31 -05:00
private void CreateDelFile ( string SourceFile )
{
FileInfo sourceFileInfo = new FileInfo ( SourceFile ) ;
string deltaPath = GetDeltaPath ( SourceFile , SourceFolder , "del" ) ;
2022-06-14 21:26:23 -04:00
try
{
Directory . CreateDirectory ( deltaPath . Replace ( sourceFileInfo . Name + ".del" , "" ) ) ;
}
2024-05-03 14:57:08 -04:00
catch ( Exception ex )
2022-06-14 21:26:23 -04:00
{
PatchLogger . LogException ( ex ) ;
}
2021-12-17 16:02:31 -05:00
2022-06-14 21:26:23 -04:00
try
{
File . Create ( deltaPath ) ;
PatchLogger . LogInfo ( $"File Created [DEL]: {deltaPath}" ) ;
}
2024-05-03 14:57:08 -04:00
catch ( Exception ex )
2022-06-14 21:26:23 -04:00
{
PatchLogger . LogException ( ex ) ;
}
2021-12-17 16:02:31 -05:00
}
2021-12-25 20:24:00 -05:00
/// <summary>
/// Create a .new file
/// </summary>
/// <param name="TargetFile"></param>
/// <remarks>Used to mark a file that needs to be added</remarks>
2021-12-17 16:02:31 -05:00
private void CreateNewFile ( string TargetFile )
{
FileInfo targetSourceInfo = new FileInfo ( TargetFile ) ;
string deltaPath = GetDeltaPath ( TargetFile , TargetFolder , "new" ) ;
2022-06-14 21:26:23 -04:00
try
{
Directory . CreateDirectory ( deltaPath . Replace ( targetSourceInfo . Name + ".new" , "" ) ) ;
}
2024-05-03 14:57:08 -04:00
catch ( Exception ex )
2022-06-14 21:26:23 -04:00
{
PatchLogger . LogException ( ex ) ;
}
2021-12-17 16:02:31 -05:00
2022-06-14 21:26:23 -04:00
try
{
targetSourceInfo . CopyTo ( deltaPath , true ) ;
PatchLogger . LogInfo ( $"File Created [NEW]: {deltaPath}" ) ;
}
2024-05-03 14:57:08 -04:00
catch ( Exception ex )
2022-06-14 21:26:23 -04:00
{
PatchLogger . LogException ( ex ) ;
}
2021-12-17 16:02:31 -05:00
}
2021-12-25 20:24:00 -05:00
/// <summary>
/// Generate a full set of patches using the source and target folders specified during contruction./>
/// </summary>
/// <returns></returns>
/// <remarks>Patches are created in the delta folder specified during contruction</remarks>
2022-05-16 17:33:37 -04:00
public PatchMessage GeneratePatches ( )
2021-12-17 16:02:31 -05:00
{
2022-06-14 21:26:23 -04:00
PatchLogger . LogInfo ( " ::: Starting patch generation :::" ) ;
2021-12-17 16:02:31 -05:00
//get all directory information needed
DirectoryInfo sourceDir = new DirectoryInfo ( SourceFolder ) ;
DirectoryInfo targetDir = new DirectoryInfo ( TargetFolder ) ;
DirectoryInfo deltaDir = Directory . CreateDirectory ( DeltaFolder ) ;
//make sure all directories exist
2022-06-14 21:26:23 -04:00
if ( ! sourceDir . Exists )
2021-12-17 16:02:31 -05:00
{
2022-06-14 21:26:23 -04:00
string message = $"Could not find source directory: {sourceDir.FullName}" ;
PatchLogger . LogError ( message ) ;
return new PatchMessage ( message , PatcherExitCode . MissingDir ) ;
}
if ( ! targetDir . Exists )
{
string message = $"Could not find target directory: {targetDir.FullName}" ;
PatchLogger . LogError ( message ) ;
return new PatchMessage ( message , PatcherExitCode . MissingDir ) ;
}
if ( ! deltaDir . Exists )
{
string message = $"Could not find delta directory: {deltaDir.FullName}" ;
PatchLogger . LogError ( message ) ;
return new PatchMessage ( message , PatcherExitCode . MissingDir ) ;
2021-12-17 16:02:31 -05:00
}
2021-12-29 11:04:02 -05:00
LazyOperations . ExtractResourcesToTempDir ( ) ;
2021-12-25 20:24:00 -05:00
2021-12-17 16:02:31 -05:00
List < FileInfo > SourceFiles = sourceDir . GetFiles ( "*" , SearchOption . AllDirectories ) . ToList ( ) ;
2024-05-03 14:57:08 -04:00
ConcurrentQueue < FileInfo > foundFilesQueue = new ConcurrentQueue < FileInfo > ( ) ;
2021-12-17 16:02:31 -05:00
fileCountTotal = SourceFiles . Count ;
2022-06-14 21:26:23 -04:00
PatchLogger . LogInfo ( $"Total source files: {fileCountTotal}" ) ;
2021-12-17 16:02:31 -05:00
AdditionalInfo . Clear ( ) ;
2021-12-25 20:24:00 -05:00
AdditionalInfo . Add ( new LineItem ( "Delta Patch" , 0 ) ) ;
AdditionalInfo . Add ( new LineItem ( "New Patch" , 0 ) ) ;
AdditionalInfo . Add ( new LineItem ( "Del Patch" , 0 ) ) ;
AdditionalInfo . Add ( new LineItem ( "File Exists" , 0 ) ) ;
2021-12-17 16:02:31 -05:00
filesProcessed = 0 ;
RaiseProgressChanged ( 0 , fileCountTotal , "Generating deltas..." ) ;
2024-05-03 14:57:08 -04:00
// use 5 threads to process source files / create deltas
Parallel . ForEach ( targetDir . GetFiles ( "*" , SearchOption . AllDirectories ) ,
new ParallelOptions ( ) { MaxDegreeOfParallelism = 5 } ,
targetFile = >
2021-12-17 16:02:31 -05:00
{
2024-05-03 14:57:08 -04:00
//find a matching source file based on the relative path of the file
FileInfo sourceFile = SourceFiles . Find ( f = >
f . FullName . Replace ( sourceDir . FullName , "" ) = =
targetFile . FullName . Replace ( targetDir . FullName , "" ) ) ;
//if the target file doesn't exist in the source files, the target file needs to be added.
if ( sourceFile = = null )
{
PatchLogger . LogInfo ( "::: Creating .new file :::" ) ;
CreateNewFile ( targetFile . FullName ) ;
newCount + + ;
filesProcessed + + ;
RaiseProgressChanged ( filesProcessed , fileCountTotal ,
$"{targetFile.FullName.Replace(TargetFolder, " . . . ")}.new" , AdditionalInfo . ToArray ( ) ) ;
return ;
}
string extension = "" ;
// if a matching source file was found, check the file hashes and get the delta.
// add it to the bag for removal later
if ( ! CompareFileHashes ( sourceFile . FullName , targetFile . FullName ) )
{
foundFilesQueue . Enqueue ( sourceFile ) ;
PatchLogger . LogInfo ( "::: Creating .delta file :::" ) ;
CreateDelta ( sourceFile . FullName , targetFile . FullName ) ;
extension = ".delta" ;
deltaCount + + ;
}
else
{
foundFilesQueue . Enqueue ( sourceFile ) ;
PatchLogger . LogInfo ( "::: File Exists :::" ) ;
existCount + + ;
}
2021-12-17 16:02:31 -05:00
2021-12-18 00:03:07 -05:00
filesProcessed + + ;
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
AdditionalInfo [ 0 ] . ItemValue = deltaCount ;
AdditionalInfo [ 1 ] . ItemValue = newCount ;
AdditionalInfo [ 3 ] . ItemValue = existCount ;
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
RaiseProgressChanged ( filesProcessed , fileCountTotal ,
$"{targetFile.FullName.Replace(TargetFolder, " . . . ")}{extension}" , AdditionalInfo . ToArray ( ) ) ;
} ) ;
2021-12-25 20:24:00 -05:00
2024-05-03 14:57:08 -04:00
// remove all queued files that were found in the source files list
PatchLogger . LogInfo ( ":: Updating Source List ::" ) ;
try
{
int processedQueueCount = 0 ;
int queueTotal = foundFilesQueue . Count ;
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
foreach ( var queuedFile in foundFilesQueue )
2022-06-14 21:26:23 -04:00
{
2024-05-03 14:57:08 -04:00
RaiseProgressChanged ( processedQueueCount , queueTotal , $"Queued file removed: {queuedFile.Name}" ,
AdditionalInfo . ToArray ( ) ) ;
SourceFiles . Remove ( queuedFile ) ;
2022-06-14 21:26:23 -04:00
}
2024-05-03 14:57:08 -04:00
}
catch ( Exception ex )
{
PatchLogger . LogException ( ex ) ;
2021-12-17 16:02:31 -05:00
}
//Any remaining source files do not exist in the target folder and can be removed.
//reset progress info
2021-12-28 19:44:25 -05:00
2022-06-14 21:26:23 -04:00
if ( SourceFiles . Count = = 0 )
{
PatchLogger . LogInfo ( "::: Patch Generation Complete :::" ) ;
return new PatchMessage ( "Generation Done" , PatcherExitCode . Success ) ;
}
2021-12-28 19:44:25 -05:00
2021-12-17 16:02:31 -05:00
RaiseProgressChanged ( 0 , SourceFiles . Count , "Processing .del files..." ) ;
filesProcessed = 0 ;
fileCountTotal = SourceFiles . Count ;
foreach ( FileInfo delFile in SourceFiles )
{
2022-06-14 21:26:23 -04:00
PatchLogger . LogInfo ( "::: Creating .del file :::" ) ;
2021-12-17 16:02:31 -05:00
CreateDelFile ( delFile . FullName ) ;
delCount + + ;
2021-12-25 20:24:00 -05:00
AdditionalInfo [ 2 ] . ItemValue = delCount ;
2021-12-17 16:02:31 -05:00
filesProcessed + + ;
2024-05-03 14:57:08 -04:00
RaiseProgressChanged ( filesProcessed , fileCountTotal ,
$"{delFile.FullName.Replace(SourceFolder, " . . . ")}.del" , AdditionalInfo . ToArray ( ) ) ;
2021-12-17 16:02:31 -05:00
}
2022-06-14 21:26:23 -04:00
PatchLogger . LogInfo ( "::: Patch Generation Complete :::" ) ;
2022-05-16 17:33:37 -04:00
return new PatchMessage ( "Generation Done" , PatcherExitCode . Success ) ;
2021-12-17 16:02:31 -05:00
}
2021-12-25 20:24:00 -05:00
/// <summary>
/// Apply a set of patches using the source and delta folders specified during construction.
/// </summary>
/// <returns></returns>
2022-05-15 17:36:16 -04:00
public PatchMessage ApplyPatches ( )
2021-12-17 16:02:31 -05:00
{
2022-06-14 21:26:23 -04:00
PatchLogger . LogInfo ( "::: Starting patch application :::" ) ;
2022-06-16 09:13:14 -04:00
PatchLogger . LogOSInfo ( ) ;
2021-12-17 16:02:31 -05:00
//get needed directory information
DirectoryInfo sourceDir = new DirectoryInfo ( SourceFolder ) ;
DirectoryInfo deltaDir = new DirectoryInfo ( DeltaFolder ) ;
//check directories exist
2022-06-14 21:26:23 -04:00
if ( ! sourceDir . Exists )
2021-12-17 16:02:31 -05:00
{
2022-06-14 21:26:23 -04:00
string message = $"Could not find source directory: {sourceDir.FullName}" ;
PatchLogger . LogError ( message ) ;
return new PatchMessage ( message , PatcherExitCode . MissingDir ) ;
}
2024-05-03 14:57:08 -04:00
if ( ! deltaDir . Exists )
2022-06-14 21:26:23 -04:00
{
string message = $"Could not find delta directory: {deltaDir.FullName}" ;
PatchLogger . LogError ( message ) ;
return new PatchMessage ( message , PatcherExitCode . MissingDir ) ;
2021-12-17 16:02:31 -05:00
}
2021-12-29 11:04:02 -05:00
LazyOperations . ExtractResourcesToTempDir ( ) ;
2021-12-25 20:24:00 -05:00
2021-12-17 16:02:31 -05:00
List < FileInfo > SourceFiles = sourceDir . GetFiles ( "*" , SearchOption . AllDirectories ) . ToList ( ) ;
List < FileInfo > deltaFiles = deltaDir . GetFiles ( "*" , SearchOption . AllDirectories ) . ToList ( ) ;
deltaCount = deltaFiles . Where ( x = > x . Extension = = ".delta" ) . Count ( ) ;
newCount = deltaFiles . Where ( x = > x . Extension = = ".new" ) . Count ( ) ;
delCount = deltaFiles . Where ( x = > x . Extension = = ".del" ) . Count ( ) ;
2022-06-14 21:26:23 -04:00
PatchLogger . LogInfo ( $"Patch File Counts: DELTA({deltaCount}) - NEW({newCount}) - DEL({delCount})" ) ;
2021-12-17 16:02:31 -05:00
AdditionalInfo = new List < LineItem > ( )
{
2021-12-25 20:24:00 -05:00
new LineItem ( "Patches Remaining" , deltaCount ) ,
new LineItem ( "New Files to Add" , newCount ) ,
new LineItem ( "Files to Delete" , delCount )
2021-12-17 16:02:31 -05:00
} ;
2024-05-03 14:57:08 -04:00
ConcurrentQueue < PatchMessage > errorsQueue = new ConcurrentQueue < PatchMessage > ( ) ;
2021-12-17 16:02:31 -05:00
filesProcessed = 0 ;
fileCountTotal = deltaFiles . Count ;
2024-05-03 14:57:08 -04:00
var patchingTokenSource = new CancellationTokenSource ( ) ;
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
// foreach (FileInfo deltaFile in deltaDir.GetFiles("*", SearchOption.AllDirectories))
Parallel . ForEach ( deltaDir . GetFiles ( "*" , SearchOption . AllDirectories ) . ToList ( ) ,
new ParallelOptions ( ) { MaxDegreeOfParallelism = 5 , CancellationToken = patchingTokenSource . Token } ,
deltaFile = >
2021-12-17 16:02:31 -05:00
{
2021-12-25 20:24:00 -05:00
switch ( deltaFile . Extension )
2021-12-17 16:02:31 -05:00
{
case ".delta" :
2024-05-03 14:57:08 -04:00
{
//apply delta
FileInfo sourceFile = SourceFiles . Find ( f = >
f . FullName . Replace ( sourceDir . FullName , "" ) = = deltaFile . FullName
. Replace ( deltaDir . FullName , "" ) . Replace ( ".delta" , "" ) ) ;
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
if ( sourceFile = = null )
{
patchingTokenSource . Cancel ( ) ;
errorsQueue . Enqueue ( new PatchMessage (
$"Failed to find matching source file for '{deltaFile.FullName}'" ,
PatcherExitCode . MissingFile ) ) ;
return ;
}
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
PatchLogger . LogInfo ( "::: Applying Delta :::" ) ;
var result = ApplyDelta ( sourceFile . FullName , deltaFile . FullName ) ;
2022-07-04 11:03:59 -04:00
2024-05-03 14:57:08 -04:00
if ( ! result . Item1 )
{
patchingTokenSource . Cancel ( ) ;
errorsQueue . Enqueue ( new PatchMessage ( result . Item2 , PatcherExitCode . PatchFailed ) ) ;
return ;
}
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
deltaCount - - ;
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
break ;
}
2021-12-17 16:02:31 -05:00
case ".new" :
2024-05-03 14:57:08 -04:00
{
//copy new file
string destination = Path . Join ( sourceDir . FullName ,
deltaFile . FullName . Replace ( deltaDir . FullName , "" ) . Replace ( ".new" , "" ) ) ;
PatchLogger . LogInfo ( "::: Adding New File :::" ) ;
try
2021-12-17 16:02:31 -05:00
{
2024-05-03 14:57:08 -04:00
Directory . CreateDirectory ( Path . GetDirectoryName ( destination ) ) ;
File . Copy ( deltaFile . FullName , destination , true ) ;
PatchLogger . LogInfo ( $"File added: {destination}" ) ;
2021-12-17 16:02:31 -05:00
}
2024-05-03 14:57:08 -04:00
catch ( Exception ex )
2021-12-17 16:02:31 -05:00
{
2024-05-03 14:57:08 -04:00
patchingTokenSource . Cancel ( ) ;
PatchLogger . LogException ( ex ) ;
errorsQueue . Enqueue ( new PatchMessage ( ex . Message , PatcherExitCode . PatchFailed ) ) ;
return ;
}
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
newCount - - ;
2022-06-14 21:26:23 -04:00
2024-05-03 14:57:08 -04:00
break ;
}
case ".del" :
{
//remove unneeded file
string delFilePath = Path . Join ( sourceDir . FullName ,
deltaFile . FullName . Replace ( deltaDir . FullName , "" ) . Replace ( ".del" , "" ) ) ;
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
PatchLogger . LogInfo ( "::: Removing Uneeded File :::" ) ;
2021-12-17 16:02:31 -05:00
2024-05-03 14:57:08 -04:00
try
{
File . Delete ( delFilePath ) ;
PatchLogger . LogInfo ( $"File removed: {delFilePath}" ) ;
2021-12-17 16:02:31 -05:00
}
2024-05-03 14:57:08 -04:00
catch ( Exception ex )
{
patchingTokenSource . Cancel ( ) ;
PatchLogger . LogException ( ex ) ;
errorsQueue . Enqueue ( new PatchMessage ( ex . Message , PatcherExitCode . PatchFailed ) ) ;
return ;
}
delCount - - ;
break ;
}
2021-12-17 16:02:31 -05:00
}
2021-12-25 20:24:00 -05:00
AdditionalInfo [ 0 ] . ItemValue = deltaCount ;
AdditionalInfo [ 1 ] . ItemValue = newCount ;
AdditionalInfo [ 2 ] . ItemValue = delCount ;
2021-12-17 16:02:31 -05:00
+ + filesProcessed ;
RaiseProgressChanged ( filesProcessed , fileCountTotal , deltaFile . Name , AdditionalInfo . ToArray ( ) ) ;
2024-05-03 14:57:08 -04:00
} ) ;
if ( errorsQueue . Count > 0 )
{
if ( ! errorsQueue . TryDequeue ( out PatchMessage error ) )
{
return new PatchMessage ( "Errors occurred during patching, but we couldn't dequeue them :(\n\nThere may be more information in the log" , PatcherExitCode . PatchFailed ) ;
}
return error ;
2021-12-17 16:02:31 -05:00
}
2022-06-14 21:26:23 -04:00
PatchLogger . LogInfo ( "::: Patching Complete :::" ) ;
2024-05-03 14:57:08 -04:00
return new PatchMessage ( $"Patching Complete. You can delete the patcher.exe file." ,
PatcherExitCode . Success ) ;
2021-12-17 16:02:31 -05:00
}
}
2024-05-03 14:57:08 -04:00
}