Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 19, 2026

LinuxStrategy and WindowsStrategy in both GeneralUpdate.Core and GeneralUpdate.ClientCore contained ~80% duplicate code for pipeline execution, context setup, error handling, and version reporting.

Changes

AbstractStrategy Base Class

  • Implemented Template Method pattern for ExecuteAsync() with common execution flow
  • Added virtual CreatePipelineContext(version, patchPath) for context customization
  • Added abstract BuildPipeline(context) for platform-specific middleware chains
  • Added virtual OnExecuteComplete() hook for post-execution logic
  • Moved CheckPath() helper and HandleExecuteException() to base class

Strategy Subclasses

Each now only defines platform-specific behavior:

  • Core.WindowsStrategy: Driver middleware setup, Bowl app launching
  • Core.LinuxStrategy: Driver middleware setup, script execution
  • ClientCore.WindowsStrategy: Standard pipeline (no blacklists)
  • ClientCore.LinuxStrategy: Blacklist context parameters

Before (WindowsStrategy example):

public override async Task ExecuteAsync()
{
    var status = ReportType.None;
    var patchPath = StorageManager.GetTempDirectory(Patchs);
    foreach (var version in _configinfo.UpdateVersions)
    {
        try
        {
            var context = new PipelineContext();
            context.Add("ZipFilePath", Path.Combine(_configinfo.TempPath, $"{version.Name}{_configinfo.Format}"));
            context.Add("Hash", version.Hash);
            // ... 40+ more lines of duplicate setup

After:

protected override PipelineBuilder BuildPipeline(PipelineContext context)
{
    return new PipelineBuilder(context)
        .UseMiddlewareIf<PatchMiddleware>(_configinfo.PatchEnabled)
        .UseMiddleware<CompressMiddleware>()
        .UseMiddleware<HashMiddleware>()
        .UseMiddlewareIf<DriverMiddleware>(_configinfo.DriveEnabled);
}

Impact

  • Code reduction: 232 lines eliminated (563→331, 41% reduction)
  • Maintainability: Common logic centralized in AbstractStrategy
  • Extensibility: Clear extension points via virtual methods
  • All platform-specific functionality preserved
Original prompt

This section details on the original issue you should resolve

<issue_title>[REFACTOR] Refactor Strategy</issue_title>
<issue_description>### Target Module/File

GeneralUpdate.Core/Strategys/LinuxStrategy.cs and WindowsStrategy.cs

Current Code Problems

In GeneralUpdate.Core, LinuxStrategy and WindowsStrategy share a lot of similar code.

Refactoring Objectives

It is necessary to optimize the duplicate code without changing the original functionality.

Refactoring Scope and Boundaries

Only refactor in the GeneralUpdate.Core.

Risk Assessment

No response

Reference Materials

No response

Expected Completion Time

No response</issue_description>

<agent_instructions>The LinuxStrategy, WindowsStrategy and AbstractStrategy in GeneralUpdate.ClientCore and GeneralUpdate.Core need to be optimized as a whole to reduce duplicate code while maintaining the scalability of Strategy execution.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor LinuxStrategy and WindowsStrategy for code optimization Refactor Strategy classes to eliminate duplication using Template Method pattern Jan 19, 2026
Copilot AI requested a review from JusterZhu January 19, 2026 05:37
@JusterZhu JusterZhu marked this pull request as ready for review January 19, 2026 05:59
Copilot AI review requested due to automatic review settings January 19, 2026 05:59
@JusterZhu JusterZhu merged commit 07a8ea6 into master Jan 19, 2026
2 checks passed
@JusterZhu JusterZhu deleted the copilot/refactor-strategy-optimization branch January 19, 2026 05:59
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request successfully refactors the Strategy pattern implementation across GeneralUpdate.Core and GeneralUpdate.ClientCore by introducing a Template Method pattern that eliminates significant code duplication while maintaining all platform-specific functionality.

Changes:

  • Created a Template Method pattern in AbstractStrategy with ExecuteAsync() handling common execution flow
  • Added hook methods (CreatePipelineContext, BuildPipeline, OnExecuteComplete, HandleExecuteException) for customization
  • Reduced duplicate code by 232 lines (41% reduction from 563 to 331 lines)

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
AbstractStrategy.cs Implements Template Method pattern with common execution flow, context creation, error handling, and utility methods
Core/WindowsStrategy.cs Simplified to override only BuildPipeline, CreatePipelineContext (for driver config), and OnExecuteComplete (to start app)
Core/LinuxStrategy.cs Similar to WindowsStrategy, adds Execute() method that wraps ExecuteAsync, fixed error message to reference LinuxStrategy
ClientCore/WindowsStrategy.cs Overrides only BuildPipeline and CreatePipelineContext (minimal customization) - no OnExecuteComplete since StartApp is called externally
ClientCore/LinuxStrategy.cs Adds blacklist context parameters in CreatePipelineContext, otherwise similar to ClientCore/WindowsStrategy

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}
var context = base.CreatePipelineContext(version, patchPath);

// Add ClientCore-specific context items (blacklists are not needed for Windows in Core)
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment incorrectly states "blacklists are not needed for Windows in Core" when it should say "blacklists are not needed for Windows in ClientCore". The word "Core" at the end refers to GeneralUpdate.Core, but this class is in GeneralUpdate.ClientCore.

Suggested change
// Add ClientCore-specific context items (blacklists are not needed for Windows in Core)
// Add ClientCore-specific context items (blacklists are not needed for Windows in ClientCore)

Copilot uses AI. Check for mistakes.
EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message));
}
});
ExecuteAsync().Wait();
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using .Wait() on an async method can potentially cause deadlocks in certain synchronization contexts and swallows AggregateException details. Consider using .GetAwaiter().GetResult() instead, which preserves exception details and is less prone to deadlocks.

Suggested change
ExecuteAsync().Wait();
ExecuteAsync().GetAwaiter().GetResult();

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +28
// Driver middleware (Windows-specific)
if (_configinfo.DriveEnabled == true)
{
var status = ReportType.None;
var patchPath = StorageManager.GetTempDirectory(Patchs);
foreach (var version in _configinfo.UpdateVersions)
{
try
{
var context = new PipelineContext();
//Common
context.Add("ZipFilePath",
Path.Combine(_configinfo.TempPath, $"{version.Name}{_configinfo.Format}"));
//Hash middleware
context.Add("Hash", version.Hash);
//Zip middleware
context.Add("Format", _configinfo.Format);
context.Add("Name", version.Name);
context.Add("Encoding", _configinfo.Encoding);
//Patch middleware
context.Add("SourcePath", _configinfo.InstallPath);
context.Add("PatchPath", patchPath);
context.Add("PatchEnabled", _configinfo.PatchEnabled);
//Driver middleware
if (_configinfo.DriveEnabled == true)
{
context.Add("DriverOutPut", StorageManager.GetTempDirectory("DriverOutPut"));
context.Add("FieldMappings", _configinfo.FieldMappings);
}

var pipelineBuilder = new PipelineBuilder(context)
.UseMiddlewareIf<PatchMiddleware>(_configinfo.PatchEnabled)
.UseMiddleware<CompressMiddleware>()
.UseMiddleware<HashMiddleware>()
.UseMiddlewareIf<DriverMiddleware>(_configinfo.DriveEnabled);
await pipelineBuilder.Build();
status = ReportType.Success;
}
catch (Exception e)
{
status = ReportType.Failure;
GeneralTracer.Error(
"The Execute method in the GeneralUpdate.Core.WindowsStrategy class throws an exception.",
e);
EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message));
}
finally
{
await VersionService.Report(_configinfo.ReportUrl
, version.RecordId
, status
, version.AppType
, _configinfo.Scheme
, _configinfo.Token);
}
}
context.Add("DriverOutPut", StorageManager.GetTempDirectory("DriverOutPut"));
context.Add("FieldMappings", _configinfo.FieldMappings);
}
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Driver middleware configuration logic is identical between WindowsStrategy and LinuxStrategy. Consider moving this logic to the base CreatePipelineContext method in AbstractStrategy to further reduce duplication. The base method could check DriveEnabled and add the driver context parameters, eliminating the need for both strategies to override this.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REFACTOR] Refactor Strategy

2 participants