diff --git a/src/c#/GeneralUpdate.Core/Configuration/AbstractBootstrap.cs b/src/c#/GeneralUpdate.Core/Configuration/AbstractBootstrap.cs index 5c84c008..6ff36cbd 100644 --- a/src/c#/GeneralUpdate.Core/Configuration/AbstractBootstrap.cs +++ b/src/c#/GeneralUpdate.Core/Configuration/AbstractBootstrap.cs @@ -83,6 +83,9 @@ public TBootstrap Option(UpdateOption option, T value) public TBootstrap SslPolicy() where T : Security.ISslValidationPolicy, new() { _extensions[typeof(Security.ISslValidationPolicy)] = typeof(T); return (TBootstrap)this; } + public TBootstrap BinaryDiffer() where T : Differential.IBinaryDiffer, new() + { _extensions[typeof(Differential.IBinaryDiffer)] = typeof(T); return (TBootstrap)this; } + public TBootstrap DownloadPolicy() where T : Download.Abstractions.IDownloadPolicy, new() { _extensions[typeof(Download.Abstractions.IDownloadPolicy)] = typeof(T); return (TBootstrap)this; } diff --git a/src/c#/GeneralUpdate.Core/Differential/IBinaryDiffer.cs b/src/c#/GeneralUpdate.Core/Differential/IBinaryDiffer.cs new file mode 100644 index 00000000..c0f4aae6 --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Differential/IBinaryDiffer.cs @@ -0,0 +1,40 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace GeneralUpdate.Core.Differential +{ + /// + /// Defines a pluggable binary differential algorithm (diff generation and patch application). + /// Implementations may use different strategies: BSDIFF, HDiffPatch-style, VCDIFF, etc. + /// + /// + /// This interface lives in Core so that Pipeline middleware can depend on it + /// without creating a circular dependency on the GeneralUpdate.Differential assembly. + /// + /// Concrete implementations (StreamingHdiffDiffer, BSDIFF, etc.) live in + /// GeneralUpdate.Differential and are injected via Bootstrap.BinaryDiffer<T>(). + /// + public interface IBinaryDiffer + { + /// + /// Generates a binary patch from to , + /// writing the result to . + /// + Task CleanAsync( + string oldFilePath, + string newFilePath, + string patchFilePath, + CancellationToken cancellationToken = default); + + /// + /// Applies a binary patch to , producing + /// using the patch at . + /// + Task DirtyAsync( + string oldFilePath, + string newFilePath, + string patchFilePath, + CancellationToken cancellationToken = default); + } +} diff --git a/src/c#/GeneralUpdate.Core/Pipeline/PatchMiddleware.cs b/src/c#/GeneralUpdate.Core/Pipeline/PatchMiddleware.cs index 3f91ccec..75b7ceaa 100644 --- a/src/c#/GeneralUpdate.Core/Pipeline/PatchMiddleware.cs +++ b/src/c#/GeneralUpdate.Core/Pipeline/PatchMiddleware.cs @@ -1,21 +1,54 @@ using System; using System.Threading.Tasks; +using GeneralUpdate.Core.Differential; using GeneralUpdate.Core.Pipeline; using GeneralUpdate.Core; namespace GeneralUpdate.Core.Pipeline; /// -/// Differential patch middleware. -/// Full implementation requires GeneralUpdate.Differential (circular dependency — see T2). -/// Currently a no-op placeholder; patches are applied externally. +/// Differential patch middleware. Applies binary patches (BSDIFF, HDiffPatch, etc.) +/// to bring files from an old version to a new version. +/// +/// The implementation is injected via +/// Bootstrap.BinaryDiffer<T>(). Without injection, patches are skipped. /// public class PatchMiddleware : IMiddleware { + private readonly IBinaryDiffer? _differ; + + /// Parameterless constructor (required by PipelineBuilder). Uses no differ. + public PatchMiddleware() { } + + /// Creates a PatchMiddleware with an optional differ. + /// Binary differ implementation. If null, patches are skipped. + public PatchMiddleware(IBinaryDiffer? differ) + { + _differ = differ; + } + public async Task InvokeAsync(PipelineContext context) { - GeneralTracer.Info("PatchMiddleware.InvokeAsync: differential patching is not available in this build. " + - "IBinaryDiffer injection via Bootstrap.BinaryDiffer() will be re-enabled in a future PR."); - await Task.CompletedTask; + var sourcePath = context.Get("SourcePath"); + var targetPath = context.Get("PatchPath"); + + if (_differ == null) + { + GeneralTracer.Info("PatchMiddleware.InvokeAsync: no IBinaryDiffer injected — patch skipped. " + + "Use Bootstrap.BinaryDiffer() to enable differential patching."); + return; + } + + GeneralTracer.Info($"PatchMiddleware.InvokeAsync: applying differential patch. SourcePath={sourcePath}, PatchPath={targetPath}"); + try + { + await _differ.DirtyAsync(sourcePath, targetPath, targetPath); + GeneralTracer.Info("PatchMiddleware.InvokeAsync: differential patch applied successfully."); + } + catch (Exception ex) + { + GeneralTracer.Error("PatchMiddleware.InvokeAsync: failed to apply differential patch.", ex); + throw; + } } } diff --git a/src/c#/GeneralUpdate.Differential/Abstractions/IBinaryDiffer.cs b/src/c#/GeneralUpdate.Differential/Abstractions/IBinaryDiffer.cs index b732fc96..3d885f3a 100644 --- a/src/c#/GeneralUpdate.Differential/Abstractions/IBinaryDiffer.cs +++ b/src/c#/GeneralUpdate.Differential/Abstractions/IBinaryDiffer.cs @@ -1,46 +1,20 @@ -using System.IO; -using System.Threading; -using System.Threading.Tasks; +// IBinaryDiffer has been moved to GeneralUpdate.Core.Differential. +// This file provides a backward-compatible type alias. +// New code should reference GeneralUpdate.Core.Differential.IBinaryDiffer directly. + +using CoreBinaryDiffer = GeneralUpdate.Core.Differential.IBinaryDiffer; namespace GeneralUpdate.Differential.Abstractions { /// - /// Defines a pluggable binary differential algorithm (diff generation and patch application). - /// Implementations may use different strategies: BSDIFF, HDiffPatch-style, VCDIFF, etc. + /// Binary differential algorithm abstraction. /// /// - /// Implementations should document their thread-safety guarantees. - /// Callers should not assume a single instance is safe for concurrent use - /// unless the implementation explicitly states so. + /// Migration note: This interface is an alias for + /// . Use + /// using GeneralUpdate.Core.Differential; directly in new code. /// - public interface IBinaryDiffer + public interface IBinaryDiffer : CoreBinaryDiffer { - /// - /// Generates a binary patch from to , - /// writing the result to . - /// - /// Old version file path. - /// New version file path. - /// Output patch file path. - /// Optional cancellation token. - Task CleanAsync( - string oldFilePath, - string newFilePath, - string patchFilePath, - CancellationToken cancellationToken = default); - - /// - /// Applies a binary patch to , producing - /// using the patch at . - /// - /// Existing (old) file to patch. - /// Output (new) file path. - /// Input patch file path. - /// Optional cancellation token. - Task DirtyAsync( - string oldFilePath, - string newFilePath, - string patchFilePath, - CancellationToken cancellationToken = default); } }