22using CollapseLauncher . Helper . LauncherApiLoader . HoYoPlay ;
33using CollapseLauncher . Helper . LauncherApiLoader . Legacy ;
44using CollapseLauncher . Helper . Loading ;
5+ using CollapseLauncher . Helper . StreamUtility ;
56using CollapseLauncher . Plugins ;
67using CollapseLauncher . Statics ;
78using Hi3Helper ;
@@ -500,10 +501,9 @@ async ValueTask LoadRegionMetadataConfig((int, (Stamp?, ConcurrentDictionary<str
500501 CurrentGameRegionMaxCount = LauncherMetadataConfig . Max ( x => x . Value ? . Count ?? 0 ) ;
501502 }
502503
503- internal static async Task < object ? > LoadAndGetConfig ( Stamp stamp ,
504- string currentChannel ,
505- bool throwAfterRetry = false ,
506- bool allowDeserializeKey = false )
504+ internal static async Task < FileStream > LoadOrGetConfigStream (
505+ Stamp stamp ,
506+ string currentChannel )
507507 {
508508 if ( string . IsNullOrEmpty ( stamp . MetadataPath ) )
509509 {
@@ -514,24 +514,47 @@ async ValueTask LoadRegionMetadataConfig((int, (Stamp?, ConcurrentDictionary<str
514514 string configRemoteFilePath =
515515 $ "/metadata/{ MetadataVersion } /{ currentChannel } /". CombineURLFromString ( stamp . MetadataPath ) ;
516516
517- FileStream ? configLocalStream = null ;
518- try
519- {
520- // Get the local stream
521- configLocalStream = new FileStream ( configLocalFilePath , FileMode . OpenOrCreate , FileAccess . ReadWrite ) ;
517+ FileInfo fileInfo = new FileInfo ( configLocalFilePath )
518+ . EnsureNoReadOnly ( ) ;
522519
523- // Check if the file doesn't exist, then download the file
524- if ( configLocalStream . Length == 0 )
520+ if ( ! fileInfo . Exists ||
521+ fileInfo . Length == 0 )
522+ {
523+ FileStream fileStream = fileInfo . Create ( ) ;
524+ try
525525 {
526526 // Get the stream and download the file
527527 await using Stream stampRemoteStream =
528528 await FallbackCDNUtil . TryGetCDNFallbackStream ( configRemoteFilePath ) ;
529- await stampRemoteStream . CopyToAsync ( configLocalStream ) ;
529+ await stampRemoteStream . CopyToAsync ( fileStream ) ;
530530
531531 // Reset the position to 0
532- configLocalStream . Position = 0 ;
532+ fileStream . Position = 0 ;
533+
534+ return fileStream ;
535+ }
536+ catch
537+ {
538+ fileStream . Dispose ( ) ;
539+ throw ;
533540 }
541+ }
542+
543+ return fileInfo . Open ( FileMode . Open , FileAccess . Read ) ;
544+ }
534545
546+ internal static async Task < object ? > LoadAndGetConfig ( Stamp stamp ,
547+ string currentChannel ,
548+ bool throwAfterRetry = false ,
549+ bool allowDeserializeKey = false )
550+ {
551+ // Get the local stream
552+ FileStream configLocalStream = await LoadOrGetConfigStream ( stamp , currentChannel ) ;
553+ string configLocalFilePath = configLocalStream . Name ;
554+ bool isSuccess = true ;
555+
556+ try
557+ {
535558 switch ( stamp . MetadataType )
536559 {
537560 case MetadataType . MasterKey when allowDeserializeKey :
@@ -554,12 +577,8 @@ async ValueTask LoadRegionMetadataConfig((int, (Stamp?, ConcurrentDictionary<str
554577 case MetadataType . PresetConfigV2 :
555578 {
556579 PresetConfig ? presetConfig =
557- await configLocalStream . DeserializeAsync ( PresetConfigJsonContext . Default . PresetConfig ) ;
558-
559- if ( presetConfig == null )
560- {
561- throw new InvalidDataException ( "Config seems to be empty!" ) ;
562- }
580+ await configLocalStream . DeserializeAsync ( PresetConfigJsonContext . Default . PresetConfig )
581+ ?? throw new InvalidDataException ( "Config seems to be empty!" ) ;
563582
564583 // Generate HashID and GameName
565584 string hashComposition = $ "{ stamp . LastUpdated } - { stamp . GameName } - { stamp . GameRegion } ";
@@ -588,6 +607,8 @@ async ValueTask LoadRegionMetadataConfig((int, (Stamp?, ConcurrentDictionary<str
588607 }
589608 catch ( Exception ex )
590609 {
610+ isSuccess = false ;
611+
591612 await SentryHelper . ExceptionHandlerAsync ( ex , SentryHelper . ExceptionType . UnhandledOther ) ;
592613 // Throw if it's allowed
593614 if ( throwAfterRetry )
@@ -602,8 +623,7 @@ async ValueTask LoadRegionMetadataConfig((int, (Stamp?, ConcurrentDictionary<str
602623 LogType . Warning , true ) ;
603624
604625 // Try to dispose and delete the old file first, then retry to initialize the config once again.
605- if ( configLocalStream != null )
606- await configLocalStream . DisposeAsync ( ) ;
626+ await configLocalStream . DisposeAsync ( ) ;
607627
608628 if ( File . Exists ( configLocalFilePath ) )
609629 File . Delete ( configLocalFilePath ) ;
@@ -612,12 +632,9 @@ async ValueTask LoadRegionMetadataConfig((int, (Stamp?, ConcurrentDictionary<str
612632 }
613633 finally
614634 {
615- // Dispose the local stream
616- if ( configLocalStream != null )
635+ await configLocalStream . DisposeAsync ( ) ;
636+ if ( isSuccess )
617637 {
618- await configLocalStream . DisposeAsync ( ) ;
619-
620- // Register last write timestamp into Stamp
621638 stamp . LastModifiedTimeUtc = GetFileLastModifiedStampUtc ( configLocalFilePath ) ;
622639 }
623640 }
0 commit comments