@@ -150,7 +150,12 @@ public async Task ExecuteAsync()
150150 if ( _configInfo == null )
151151 throw new InvalidOperationException ( "OssStrategy not configured. Call Create() first." ) ;
152152
153- // Dispatch by role �?no env-var detection needed.
153+ // Fill missing identity fields from generalupdate.manifest.json,
154+ // making the manifest the single source of configuration across
155+ // all update flows (standard ClientStrategy and OssStrategy).
156+ Configuration . AppMetadataDiscoverer . Discover ( _configInfo ) ;
157+
158+ // Dispatch by role — no env-var detection needed.
154159 if ( _role == AppType . OssUpgrade )
155160 {
156161 await ExecuteUpgradeAsync ( ) ;
@@ -189,35 +194,63 @@ private async Task ExecuteClientAsync()
189194 var versionFileName = $ "{ _configInfo . MainAppName ?? _configInfo . UpdateAppName } _versions.json";
190195 var versionsFilePath = Path . Combine ( installPath , versionFileName ) ;
191196
197+ GeneralTracer . Info ( $ "[OssClient] InstallPath={ installPath } ") ;
198+ GeneralTracer . Info ( $ "[OssClient] VersionFileName={ versionFileName } ") ;
199+ GeneralTracer . Info ( $ "[OssClient] ClientVersion={ _configInfo . ClientVersion } ") ;
200+ GeneralTracer . Info ( $ "[OssClient] MainAppName={ _configInfo . MainAppName } ") ;
201+ GeneralTracer . Info ( $ "[OssClient] UpdateAppName={ _configInfo . UpdateAppName } ") ;
202+
192203 if ( ! string . IsNullOrEmpty ( _configInfo . UpdateUrl ) )
193204 {
205+ GeneralTracer . Info ( $ "[OssClient] Downloading from { _configInfo . UpdateUrl } ...") ;
194206 await DownloadVersionConfig ( _configInfo . UpdateUrl , versionsFilePath ) . ConfigureAwait ( false ) ;
207+ GeneralTracer . Info ( $ "[OssClient] Downloaded -> { versionsFilePath } ") ;
195208 }
196209
197210 if ( ! File . Exists ( versionsFilePath ) )
198211 {
199- GeneralTracer . Info ( "OssStrategy : version config download failed, aborting. " ) ;
212+ GeneralTracer . Info ( "[OssClient] FAIL : version config file not found after download! " ) ;
200213 return ;
201214 }
202215
203- var versions = JsonSerializer . Deserialize (
204- File . ReadAllText ( versionsFilePath ) ,
205- JsonContext . OssVersionRecordJsonContext . Default . ListOssVersionRecord ) ;
216+ var jsonText = File . ReadAllText ( versionsFilePath ) ;
217+ GeneralTracer . Info ( $ "[OssClient] JSON downloaded ({ jsonText . Length } chars)") ;
218+
219+ List < OssVersionRecord > versions ;
220+ try
221+ {
222+ versions = JsonSerializer . Deserialize (
223+ jsonText ,
224+ JsonContext . OssVersionRecordJsonContext . Default . ListOssVersionRecord ) ;
225+ }
226+ catch ( Exception ex )
227+ {
228+ GeneralTracer . Error ( $ "[OssClient] JSON deserialize error: { ex . GetType ( ) . Name } : { ex . Message } ", ex ) ;
229+ throw ;
230+ }
231+
206232 if ( versions == null || versions . Count == 0 )
207233 {
208- GeneralTracer . Info ( "OssStrategy : no versions found, aborting. ") ;
234+ GeneralTracer . Info ( $ "[OssClient] FAIL : no versions found (count= { versions ? . Count . ToString ( ) ?? "null" } ) ") ;
209235 return ;
210236 }
211237
238+ GeneralTracer . Info ( $ "[OssClient] Deserialized { versions . Count } version(s)") ;
239+ foreach ( var v in versions )
240+ GeneralTracer . Info ( $ " - { v . PacketName } v{ v . Version } PubTime={ v . PubTime : O} ") ;
241+
212242 versions = versions . OrderByDescending ( x => x . PubTime ) . ToList ( ) ;
213243 var latest = versions . First ( ) ;
244+ GeneralTracer . Info ( $ "[OssClient] Latest: { latest . Version } (PubTime={ latest . PubTime : O} )") ;
214245
215246 if ( ! IsOssUpgrade ( _configInfo . ClientVersion , latest . Version ) )
216247 {
217- GeneralTracer . Info ( "OssStrategy: no upgrade needed. ") ;
248+ GeneralTracer . Info ( $ "[OssClient] No upgrade needed: { _configInfo . ClientVersion } >= { latest . Version } ") ;
218249 return ;
219250 }
220251
252+ GeneralTracer . Info ( $ "[OssClient] Upgrade needed: { _configInfo . ClientVersion } -> { latest . Version } ") ;
253+
221254 // Resolve upgrade exe: prefer UpdatePath, fall back to InstallPath
222255 var upgradeDir = ! string . IsNullOrWhiteSpace ( _configInfo . UpdatePath )
223256 ? ( Path . IsPathRooted ( _configInfo . UpdatePath )
@@ -228,10 +261,28 @@ private async Task ExecuteClientAsync()
228261 ? _configInfo . UpdateAppName
229262 : "GeneralUpdate.Upgrade.exe" ;
230263 var appPath = Path . Combine ( upgradeDir , upgradeAppName ) ;
264+ GeneralTracer . Info ( $ "[OssClient] Resolved upgrade path: { appPath } ") ;
265+
266+ // List exe files in the directory to help diagnose missing file issues
267+ try
268+ {
269+ var dirFiles = Directory . GetFiles ( upgradeDir , "*.exe" ) . Select ( f => Path . GetFileName ( f ) ) ;
270+ GeneralTracer . Info ( $ "[OssClient] *.exe files in { upgradeDir } : [{ string . Join ( ", " , dirFiles ) } ]") ;
271+ }
272+ catch ( Exception ex )
273+ {
274+ GeneralTracer . Warn ( $ "[OssClient] Could not list directory { upgradeDir } : { ex . Message } ") ;
275+ }
276+
231277 if ( ! File . Exists ( appPath ) )
278+ {
279+ GeneralTracer . Error ( $ "[OssClient] FAIL: Upgrade app NOT FOUND at { appPath } ") ;
232280 throw new FileNotFoundException ( $ "Upgrade application not found: { appPath } ") ;
281+ }
233282
283+ GeneralTracer . Info ( $ "[OssClient] Launching upgrade: { appPath } ") ;
234284 Process . Start ( appPath ) ;
285+ GeneralTracer . Info ( "[OssClient] Upgrade launched, exiting." ) ;
235286 await GracefulExit . CurrentProcessAsync ( ) . ConfigureAwait ( false ) ;
236287 }
237288
@@ -273,15 +324,6 @@ private async Task ExecuteUpgradeAsync()
273324 if ( ! File . Exists ( jsonPath ) && DownloadSource == null )
274325 throw new FileNotFoundException ( $ "Version config not found: { jsonPath } ") ;
275326
276- // Hooks: allow cancellation before download
277- if ( ! await SafeOnBeforeUpdateAsync ( ctx ) . ConfigureAwait ( false ) )
278- {
279- GeneralTracer . Info ( "OssStrategy (upgrade): cancelled by hook." ) ;
280- return ;
281- }
282-
283- await SafeReportUpdateStartedAsync ( ctx ) . ConfigureAwait ( false ) ;
284-
285327 // Build download assets from version config or injected source
286328 List < DownloadAsset > assets ;
287329 if ( DownloadSource != null )
@@ -314,13 +356,38 @@ private async Task ExecuteUpgradeAsync()
314356 if ( assets . Count == 0 )
315357 throw new InvalidOperationException ( "No assets to download." ) ;
316358
359+ // Compute LastVersion deterministically via Version comparison
360+ // so hooks see the correct TargetVersion regardless of source ordering.
361+ _configInfo . LastVersion = assets
362+ . Select ( a => new Version ( a . Version ) )
363+ . Max ( ) !
364+ . ToString ( ) ;
365+ ctx = BuildUpdateContext ( ) ;
366+
367+ // Hooks: allow cancellation before download. Called after assets are
368+ // built and LastVersion is set so OnBeforeUpdateAsync sees the real
369+ // TargetVersion for decision-making.
370+ if ( ! await SafeOnBeforeUpdateAsync ( ctx ) . ConfigureAwait ( false ) )
371+ {
372+ GeneralTracer . Info ( "OssStrategy (upgrade): cancelled by hook." ) ;
373+ return ;
374+ }
375+
376+ await SafeReportUpdateStartedAsync ( ctx ) . ConfigureAwait ( false ) ;
377+
317378 GeneralTracer . Debug ( $ "OssStrategy (upgrade): downloading { assets . Count } asset(s).") ;
318379 await DownloadAssetsAsync ( assets , installPath ) . ConfigureAwait ( false ) ;
319380
320381 GeneralTracer . Debug ( "OssStrategy (upgrade): decompressing." ) ;
321382 var encoding = Encoding . GetEncoding ( _configInfo ? . Encoding ? . CodePage ?? Encoding . UTF8 . CodePage ) ;
322383 DecompressAssets ( assets , installPath , encoding ) ;
323384
385+ // Update generalupdate.manifest.json ClientVersion so the client
386+ // reads the correct version on next startup, preventing infinite loops.
387+ Configuration . ManifestInfo . TryUpdateVersion (
388+ installPath ,
389+ clientVersion : _configInfo . LastVersion ) ;
390+
324391 await SafeOnDownloadCompletedAsync ( ctx ) . ConfigureAwait ( false ) ;
325392 await SafeOnAfterUpdateAsync ( ctx ) . ConfigureAwait ( false ) ;
326393 await SafeReportUpdateAppliedAsync ( ctx ) . ConfigureAwait ( false ) ;
0 commit comments