@@ -24,13 +24,13 @@ namespace GeneralUpdate.Core;
2424/// Unified update bootstrap — single entry point for Client, Upgrade, and OSS roles.
2525/// Use <see cref="AppType"/> to select the workflow:
2626/// <list type="bullet">
27- /// <item><see cref="AppType.ClientApp "/> — validate versions, download, start upgrade process</item>
28- /// <item><see cref="AppType.UpgradeApp "/> — receive ProcessInfo, apply updates, start main app</item>
29- /// <item><see cref="AppType.OSSApp "/> — OSS-based cloud storage update</item>
27+ /// <item><see cref="AppType.Client "/> — validate versions, download, start upgrade process</item>
28+ /// <item><see cref="AppType.Upgrade "/> — receive ProcessInfo, apply updates, start main app</item>
29+ /// <item><see cref="AppType.OSS "/> — OSS-based cloud storage update</item>
3030/// </list>
3131/// </summary>
3232/// <remarks>
33- /// For Client mode, use <c>Option(UpdateOptions.AppType, AppType.ClientApp )</c>.
33+ /// For Client mode, use <c>Option(UpdateOptions.AppType, AppType.Client )</c>.
3434/// </remarks>
3535public class GeneralUpdateBootstrap : AbstractBootstrap < GeneralUpdateBootstrap , IStrategy >
3636{
@@ -58,20 +58,20 @@ public void Cancel()
5858
5959 public override async Task < GeneralUpdateBootstrap > LaunchAsync ( )
6060 {
61- int appType = GetOption ( UpdateOptions . AppType ) ;
61+ var appType = GetOption ( UpdateOptions . AppType ) ;
6262
6363 // Silent mode: start background poll and return immediately
64- if ( appType == AppType . ClientApp && GetOption ( UpdateOptions . Silent ) )
64+ if ( appType == AppType . Client && GetOption ( UpdateOptions . Silent ) )
6565 {
6666 await LaunchSilentAsync ( ) . ConfigureAwait ( false ) ;
6767 return this ;
6868 }
6969
7070 return appType switch
7171 {
72- AppType . ClientApp => await LaunchWithStrategy ( new ClientUpdateStrategy ( ) ) ,
73- AppType . UpgradeApp => await LaunchWithStrategy ( new UpgradeUpdateStrategy ( ) ) ,
74- AppType . OSSApp => await LaunchOssAsync ( ) ,
72+ AppType . Client => await LaunchWithStrategy ( new ClientUpdateStrategy ( ) ) ,
73+ AppType . Upgrade => await LaunchWithStrategy ( new UpgradeUpdateStrategy ( ) ) ,
74+ AppType . OSS => await LaunchOssAsync ( ) ,
7575 _ => await LaunchWithStrategy ( new ClientUpdateStrategy ( ) )
7676 } ;
7777 }
@@ -94,6 +94,25 @@ private async Task<GeneralUpdateBootstrap> LaunchWithStrategy(IStrategy roleStra
9494 {
9595 clientStrat . Hooks = hooks ;
9696 clientStrat . Reporter = reporter ;
97+ // Resolve DownloadSource from extension registry (Hub, custom, etc.)
98+ var resolvedSource = ResolveExtension < Download . Abstractions . IDownloadSource > ( ) ;
99+
100+ // Inject SignalR Hub download source if configured (not available in AOT)
101+ #if ! AOT
102+ if ( resolvedSource == null )
103+ {
104+ var hubConfig = GetOption ( UpdateOptions . Hub ) ;
105+ if ( hubConfig != null && ! string . IsNullOrEmpty ( hubConfig . Url ) )
106+ {
107+ var hubSource = new Download . Sources . HubDownloadSource (
108+ hubConfig . Url , GetOption ( UpdateOptions . Token ) , GetOption ( UpdateOptions . AppSecretKey ) ) ;
109+ await hubSource . StartAsync ( ) . ConfigureAwait ( false ) ;
110+ resolvedSource = hubSource ;
111+ GeneralTracer . Info ( "GeneralUpdateBootstrap: HubDownloadSource started from HubConfig." ) ;
112+ }
113+ }
114+ #endif
115+ clientStrat . DownloadSource = resolvedSource ;
97116 if ( _updatePrecheck != null )
98117 clientStrat . UseUpdatePrecheck ( _updatePrecheck ) ;
99118 foreach ( var opt in _customOptions )
@@ -121,6 +140,9 @@ private async Task<GeneralUpdateBootstrap> LaunchWithStrategy(IStrategy roleStra
121140 }
122141 finally
123142 {
143+ // Dispose HubDownloadSource if it was started
144+ if ( roleStrategy is ClientUpdateStrategy cs && cs . DownloadSource is IDisposable d )
145+ d . Dispose ( ) ;
124146 _cts ? . Dispose ( ) ;
125147 _cts = null ;
126148 }
@@ -201,7 +223,7 @@ public GeneralUpdateBootstrap SetConfig(Configinfo configInfo)
201223 _configInfo = ConfigurationMapper . MapToGlobalConfigInfo ( configInfo ) ;
202224
203225 var appType = GetOption ( UpdateOptions . AppType ) ;
204- if ( appType != AppType . UpgradeApp )
226+ if ( appType != AppType . Upgrade )
205227 {
206228 _configInfo . TempPath = StorageManager . GetTempDirectory ( "upgrade_temp" ) ;
207229 InitBlackList ( ) ;
@@ -279,9 +301,11 @@ private void ApplyRuntimeOptions()
279301 /// Silent update mode — starts a background poll loop and returns immediately.
280302 /// The orchestrator checks for updates periodically and prepares them.
281303 /// When the host process exits, the prepared update is applied.
304+ /// Not available in AOT builds (SignalR dependency).
282305 /// </summary>
283306 private async Task LaunchSilentAsync ( )
284307 {
308+ #if ! AOT
285309 GeneralTracer . Info ( "GeneralUpdateBootstrap: starting silent update mode." ) ;
286310
287311 var pollMinutes = GetOption ( UpdateOptions . SilentPollIntervalMinutes ) ;
@@ -302,6 +326,10 @@ private async Task LaunchSilentAsync()
302326
303327 await orchestrator . StartAsync ( ) . ConfigureAwait ( false ) ;
304328 GeneralTracer . Info ( "GeneralUpdateBootstrap: silent update mode started, returning to caller." ) ;
329+ #else
330+ GeneralTracer . Warn ( "GeneralUpdateBootstrap: silent update not available in AOT builds." ) ;
331+ await Task . CompletedTask ;
332+ #endif
305333 }
306334
307335 private void InitBlackList ( )
0 commit comments