Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 35 additions & 15 deletions src/c#/GeneralUpdate.Core/Configuration/AbstractBootstrap.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using GeneralUpdate.Core.Strategy;
Expand All @@ -13,38 +15,42 @@ public abstract class AbstractBootstrap<TBootstrap, TStrategy>
{
private readonly ConcurrentDictionary<UpdateOption, UpdateOptionValue> _options;

protected internal AbstractBootstrap() =>
/// <summary>User-registered extension types for lazy instantiation.</summary>
private readonly Dictionary<Type, Type> _extensions = new();

protected internal AbstractBootstrap()
{
_options = new ConcurrentDictionary<UpdateOption, UpdateOptionValue>();
PopulateDefaults();
}

/// <summary>
/// Launch async udpate.
/// Populate all UpdateOptions with their best-practice defaults.
/// Subclasses can override to customize.
/// </summary>
/// <returns></returns>
public abstract Task<TBootstrap> LaunchAsync();
protected virtual void PopulateDefaults()
{
Option(UpdateOptions.MaxConcurrency, 3);
Option(UpdateOptions.RetryCount, 3);
Option(UpdateOptions.EnableResume, true);
Option(UpdateOptions.VerifyChecksum, true);
Option(UpdateOptions.SilentAutoInstall, false);
}

public abstract Task<TBootstrap> LaunchAsync();
protected abstract void ExecuteStrategy();

protected abstract Task ExecuteStrategyAsync();

protected abstract TBootstrap StrategyFactory();

/// <summary>
/// Setting update configuration.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="option">Configuration Action Enumeration.</param>
/// <param name="value">Value</param>
/// <returns></returns>
public TBootstrap Option<T>(UpdateOption<T> option, T value)
{
if (value == null)
{
_options.TryRemove(option, out _);
}
else
{
_options[option] = new UpdateOptionValue<T>(option, value);
}
return (TBootstrap)this;
}

Expand All @@ -62,5 +68,19 @@ public TBootstrap Option<T>(UpdateOption<T> option, T value)
return default;
}
}

// ═══════════ Extension point registration ═══════════

/// <summary>Register a custom update strategy.</summary>
public TBootstrap Strategy<T>() where T : IStrategy, new()
{ _extensions[typeof(IStrategy)] = typeof(T); return (TBootstrap)this; }

/// <summary>Resolve a registered extension type, or null if not registered.</summary>
protected TExtension? ResolveExtension<TExtension>() where TExtension : class
{
if (_extensions.TryGetValue(typeof(TExtension), out var t))
return Activator.CreateInstance(t) as TExtension;
return null;
}
}
}
}
49 changes: 49 additions & 0 deletions src/c#/GeneralUpdate.Core/Configuration/UpdateOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

namespace GeneralUpdate.Core.Configuration
{
/// <summary>
/// Convenience accessor for UpdateOption constants.
/// Maps to the underlying UpdateOption singleton constants.
/// New code should use UpdateOptions.X instead of UpdateOption.X.
/// </summary>
public static class UpdateOptions
{
// ═══ Core ═══
public static UpdateOption<int> AppType => UpdateOption.ValueOf<int>("APPTYPE");

// ═══ Existing options (backward-compatible) ═══
public static UpdateOption<Encoding> Encoding => UpdateOption.Encoding;
public static UpdateOption<string> Format => UpdateOption.Format;
public static UpdateOption<int?> DownloadTimeout => UpdateOption.DownloadTimeOut;
public static UpdateOption<bool?> DriveEnabled => UpdateOption.Drive;
public static UpdateOption<bool?> PatchEnabled => UpdateOption.Patch;
public static UpdateOption<bool?> BackupEnabled => UpdateOption.BackUp;
public static UpdateOption<UpdateMode?> Mode => UpdateOption.Mode;
public static UpdateOption<bool> Silent => UpdateOption.EnableSilentUpdate;

// ═══ New options ═══
public static readonly UpdateOption<string?> UpdateUrl = UpdateOption.ValueOf<string?>("UPDATEURL");
public static readonly UpdateOption<string> AppSecretKey = UpdateOption.ValueOf<string>("APPSECRETKEY");
public static readonly UpdateOption<string> AppName = UpdateOption.ValueOf<string>("APPNAME");
public static readonly UpdateOption<string> MainAppName = UpdateOption.ValueOf<string>("MAINAPPNAME");
public static readonly UpdateOption<string> InstallPath = UpdateOption.ValueOf<string>("INSTALLPATH");
public static readonly UpdateOption<string> ClientVersion = UpdateOption.ValueOf<string>("CLIENTVERSION");
public static readonly UpdateOption<string?> UpgradeClientVersion = UpdateOption.ValueOf<string?>("UPGRADECLIENTVERSION");
public static readonly UpdateOption<int?> Platform = UpdateOption.ValueOf<int?>("PLATFORM");
public static readonly UpdateOption<bool> SilentAutoInstall = UpdateOption.ValueOf<bool>("SILENTAUTOINSTALL");
public static readonly UpdateOption<int> MaxConcurrency = UpdateOption.ValueOf<int>("MAXCONCURRENCY");
public static readonly UpdateOption<bool> EnableResume = UpdateOption.ValueOf<bool>("ENABLERESUME");
public static readonly UpdateOption<int> RetryCount = UpdateOption.ValueOf<int>("RETRYCOUNT");
public static readonly UpdateOption<bool> VerifyChecksum = UpdateOption.ValueOf<bool>("VERIFYCHECKSUM");
public static readonly UpdateOption<string?> ReportUrl = UpdateOption.ValueOf<string?>("REPORTURL");
public static readonly UpdateOption<string?> ProductId = UpdateOption.ValueOf<string?>("PRODUCTID");
public static readonly UpdateOption<string?> PermissionScript = UpdateOption.ValueOf<string?>("PERMISSIONSCRIPT");
public static readonly UpdateOption<string?> Scheme = UpdateOption.ValueOf<string?>("SCHEME");
public static readonly UpdateOption<string?> Token = UpdateOption.ValueOf<string?>("TOKEN");
}
}
Loading