Skip to content

Commit 427b1bf

Browse files
committed
Add new CollapseCDN to CDN list
1 parent 82b8123 commit 427b1bf

File tree

4 files changed

+140
-52
lines changed

4 files changed

+140
-52
lines changed

CollapseLauncher/Classes/RepairManagement/Honkai/Fetch.cs

Lines changed: 123 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ private class XmfSenadinaFileIdentifierProperty(SenadinaFileIdentifier? blocksPl
6868
public CancellationToken CancelToken { get; } = token;
6969
}
7070

71-
private string? _mainMetaRepoUrl;
71+
private string? _primaryMainMetaRepoUrl;
72+
private string? _secondaryMainMetaRepoUrl;
7273
private readonly byte[] _collapseHeader = "Collapse"u8.ToArray();
7374

7475
private async Task Fetch(List<FilePropertiesRemote> assetIndex, CancellationToken token)
@@ -122,7 +123,8 @@ private async Task Fetch(List<FilePropertiesRemote> assetIndex, CancellationToke
122123
/* 2025-05-01: This is disabled for now as we now fully use MhyMurmurHash2_64B for the hash
123124
SenadinaFileIdentifier? asbReferenceSenadinaFileIdentifier = null;
124125
*/
125-
_mainMetaRepoUrl = null;
126+
_primaryMainMetaRepoUrl = null;
127+
_secondaryMainMetaRepoUrl = null;
126128

127129
// Get the status if the current game is Senadina version.
128130
GameTypeHonkaiVersion gameVersionKind = GameVersionManager.CastAs<GameTypeHonkaiVersion>();
@@ -132,20 +134,55 @@ private async Task Fetch(List<FilePropertiesRemote> assetIndex, CancellationToke
132134
// TODO: Use FallbackCDNUtil to fetch the stream.
133135
if (IsSenadinaVersion && !IsOnlyRecoverMain)
134136
{
135-
_mainMetaRepoUrl = $"https://r2.bagelnl.my.id/cl-meta/pustaka/{GameVersionManager!.GamePreset.ProfileName}/{string.Join('.', versionArray)}";
137+
_primaryMainMetaRepoUrl = $"https://r2.bagelnl.my.id/cl-meta/pustaka/{GameVersionManager!.GamePreset.ProfileName}/{string.Join('.', versionArray)}";
138+
_secondaryMainMetaRepoUrl = $"https://cdn.collapselauncher.com/cl-meta/pustaka/{GameVersionManager!.GamePreset.ProfileName}/{string.Join('.', versionArray)}";
136139

137140
// Get the Senadina File Identifier Dictionary and its file references
138-
senadinaFileIdentifier = await GetSenadinaIdentifierDictionary(client, _mainMetaRepoUrl, token);
139-
audioManifestSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client, senadinaFileIdentifier,
140-
SenadinaKind.chiptunesCurrent, versionArray, _mainMetaRepoUrl, false, token);
141-
blocksPlatformManifestSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client, senadinaFileIdentifier,
142-
SenadinaKind.platformBase, versionArray, _mainMetaRepoUrl, false, token);
143-
blocksBaseManifestSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client, senadinaFileIdentifier,
144-
SenadinaKind.bricksBase, versionArray, _mainMetaRepoUrl, false, token);
145-
blocksCurrentManifestSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client, senadinaFileIdentifier,
146-
SenadinaKind.bricksCurrent, versionArray, _mainMetaRepoUrl, false, token);
147-
patchConfigManifestSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client, senadinaFileIdentifier,
148-
SenadinaKind.wandCurrent, versionArray, _mainMetaRepoUrl, true, token);
141+
senadinaFileIdentifier = await GetSenadinaIdentifierDictionary(client,
142+
_primaryMainMetaRepoUrl,
143+
_secondaryMainMetaRepoUrl,
144+
false,
145+
token);
146+
audioManifestSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client,
147+
senadinaFileIdentifier,
148+
SenadinaKind.chiptunesCurrent,
149+
versionArray,
150+
_primaryMainMetaRepoUrl,
151+
_secondaryMainMetaRepoUrl,
152+
false,
153+
token);
154+
blocksPlatformManifestSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client,
155+
senadinaFileIdentifier,
156+
SenadinaKind.platformBase,
157+
versionArray,
158+
_primaryMainMetaRepoUrl,
159+
_secondaryMainMetaRepoUrl,
160+
false,
161+
token);
162+
blocksBaseManifestSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client,
163+
senadinaFileIdentifier,
164+
SenadinaKind.bricksBase,
165+
versionArray,
166+
_primaryMainMetaRepoUrl,
167+
_secondaryMainMetaRepoUrl,
168+
false,
169+
token);
170+
blocksCurrentManifestSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client,
171+
senadinaFileIdentifier,
172+
SenadinaKind.bricksCurrent,
173+
versionArray,
174+
_primaryMainMetaRepoUrl,
175+
_secondaryMainMetaRepoUrl,
176+
false,
177+
token);
178+
patchConfigManifestSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client,
179+
senadinaFileIdentifier,
180+
SenadinaKind.wandCurrent,
181+
versionArray,
182+
_primaryMainMetaRepoUrl,
183+
_secondaryMainMetaRepoUrl,
184+
true,
185+
token);
149186
/* 2025-05-01: This is disabled for now as we now fully use MhyMurmurHash2_64B for the hash
150187
asbReferenceSenadinaFileIdentifier = await GetSenadinaIdentifierKind(client, senadinaFileIdentifier,
151188
SenadinaKind.wonderland, versionArray, _mainMetaRepoUrl, true, token);
@@ -430,47 +467,88 @@ private static void ReorderAssetIndex(List<FilePropertiesRemote> assetIndex)
430467
assetIndex.AddRange(assetIndexFiltered);
431468
}
432469

433-
private async Task<Dictionary<string, SenadinaFileIdentifier>?> GetSenadinaIdentifierDictionary(HttpClient client, string mainUrl, CancellationToken token)
470+
private async Task<Dictionary<string, SenadinaFileIdentifier>?>
471+
GetSenadinaIdentifierDictionary(HttpClient client,
472+
string? mainUrl,
473+
string? secondaryUrl,
474+
bool throwIfFail = false,
475+
CancellationToken token = default)
434476
{
435-
string identifierUrl = CombineURLFromString(mainUrl, "daftar-pustaka");
436-
await using Stream fileIdentifierStream = (await HttpResponseInputStream.CreateStreamAsync(client, identifierUrl, null, null, null, null, null, token))!;
437-
await using Stream fileIdentifierStreamDecoder = new BrotliStream(fileIdentifierStream, CompressionMode.Decompress, true);
438-
439-
await ThrowIfFileIsNotSenadina(fileIdentifierStream, token);
440-
#if DEBUG
441-
using StreamReader rd = new StreamReader(fileIdentifierStreamDecoder);
442-
string response = await rd.ReadToEndAsync(token);
443-
LogWriteLine($"[HonkaiRepair::GetSenadinaIdentifierDictionary() Dictionary Response:\r\n{response}", LogType.Debug, true);
444-
return response.Deserialize(SenadinaJsonContext.Default.DictionaryStringSenadinaFileIdentifier);
445-
#else
446-
return await fileIdentifierStreamDecoder.DeserializeAsync(SenadinaJsonContext.Default.DictionaryStringSenadinaFileIdentifier, token: token);
447-
#endif
477+
mainUrl ??= secondaryUrl;
478+
try
479+
{
480+
string identifierUrl = CombineURLFromString(mainUrl, "daftar-pustaka");
481+
await using Stream fileIdentifierStream = (await HttpResponseInputStream.CreateStreamAsync(client, identifierUrl, null, null, null, null, null, token))!;
482+
await using Stream fileIdentifierStreamDecoder = new BrotliStream(fileIdentifierStream, CompressionMode.Decompress, true);
483+
484+
await ThrowIfFileIsNotSenadina(fileIdentifierStream, token);
485+
#if DEBUG
486+
using StreamReader rd = new StreamReader(fileIdentifierStreamDecoder);
487+
string response = await rd.ReadToEndAsync(token);
488+
LogWriteLine($"[HonkaiRepair::GetSenadinaIdentifierDictionary() Dictionary Response:\r\n{response}", LogType.Debug, true);
489+
return response.Deserialize(SenadinaJsonContext.Default.DictionaryStringSenadinaFileIdentifier);
490+
#else
491+
return await fileIdentifierStreamDecoder.DeserializeAsync(SenadinaJsonContext.Default.DictionaryStringSenadinaFileIdentifier, token: token);
492+
#endif
493+
}
494+
catch (Exception ex)
495+
{
496+
LogWriteLine($"[Senadina::DaftarPustaka] Failed while fetching Senadina's daftar-pustaka from URL: {mainUrl}\r\n{ex}", LogType.Error, true);
497+
if (throwIfFail)
498+
{
499+
throw;
500+
}
501+
LogWriteLine($"[Senadina::DaftarPustaka] Trying to get Senadina's daftar-pustaka from secondary URL: {secondaryUrl}", LogType.Warning, true);
502+
return await GetSenadinaIdentifierDictionary(client, null, secondaryUrl, true, token);
503+
}
448504
}
449505

450-
private async Task<SenadinaFileIdentifier?> GetSenadinaIdentifierKind(HttpClient client, Dictionary<string, SenadinaFileIdentifier>? dict, SenadinaKind kind, int[] gameVersion, string mainUrl, bool skipThrow, CancellationToken token)
506+
private async Task<SenadinaFileIdentifier?>
507+
GetSenadinaIdentifierKind(HttpClient client,
508+
Dictionary<string, SenadinaFileIdentifier>? dict,
509+
SenadinaKind kind,
510+
int[] gameVersion,
511+
string? mainUrl,
512+
string? secondaryUrl,
513+
bool skipThrow,
514+
CancellationToken token)
451515
{
516+
mainUrl ??= secondaryUrl;
452517
ArgumentNullException.ThrowIfNull(dict);
453-
454-
string origFileRelativePath = $"{gameVersion[0]}_{gameVersion[1]}_{kind.ToString().ToLower()}";
455-
string hashedRelativePath = SenadinaFileIdentifier.GetHashedString(origFileRelativePath);
456518

457-
string fileUrl = CombineURLFromString(mainUrl, hashedRelativePath);
458-
if (!dict.TryGetValue(origFileRelativePath, out var identifier))
519+
try
459520
{
460-
LogWriteLine($"Key reference to the pustaka file: {hashedRelativePath} is not found for game version: {string.Join('.', gameVersion)}. Please contact us on our Discord Server to report this issue.", LogType.Error, true);
461-
if (skipThrow) return null;
462-
throw new
463-
FileNotFoundException("Assets reference for repair is not found. " +
464-
"Please contact us in GitHub issues or Discord to let us know about this issue.");
465-
}
521+
string origFileRelativePath = $"{gameVersion[0]}_{gameVersion[1]}_{kind.ToString().ToLower()}";
522+
string hashedRelativePath = SenadinaFileIdentifier.GetHashedString(origFileRelativePath);
523+
524+
string fileUrl = CombineURLFromString(mainUrl, hashedRelativePath);
525+
if (!dict.TryGetValue(origFileRelativePath, out var identifier))
526+
{
527+
LogWriteLine($"Key reference to the pustaka file: {hashedRelativePath} is not found for game version: {string.Join('.', gameVersion)}. Please contact us on our Discord Server to report this issue.", LogType.Error, true);
528+
if (skipThrow) return null;
529+
throw new
530+
FileNotFoundException("Assets reference for repair is not found. " +
531+
"Please contact us in GitHub issues or Discord to let us know about this issue.");
532+
}
466533

467-
Stream networkStream = (await HttpResponseInputStream.CreateStreamAsync(client, fileUrl, null, null, null, null, null, token))!;
534+
Stream networkStream = (await HttpResponseInputStream.CreateStreamAsync(client, fileUrl, null, null, null, null, null, token))!;
468535

469-
await ThrowIfFileIsNotSenadina(networkStream, token);
470-
identifier.fileStream = SenadinaFileIdentifier.CreateKangBakso(networkStream, identifier.lastIdentifier!, origFileRelativePath, (int)identifier.fileTime);
471-
identifier.relativePath = origFileRelativePath;
536+
await ThrowIfFileIsNotSenadina(networkStream, token);
537+
identifier.fileStream = SenadinaFileIdentifier.CreateKangBakso(networkStream, identifier.lastIdentifier!, origFileRelativePath, (int)identifier.fileTime);
538+
identifier.relativePath = origFileRelativePath;
472539

473-
return identifier;
540+
return identifier;
541+
}
542+
catch (Exception ex)
543+
{
544+
LogWriteLine($"[Senadina::Identifier] Failed while fetching Senadina's identifier kind: {kind} from URL: {mainUrl}\r\n{ex}", LogType.Error, true);
545+
if (skipThrow)
546+
{
547+
throw;
548+
}
549+
LogWriteLine($"[Senadina::Identifier] Trying to get Senadina's identifier kind: {kind} from secondary URL: {secondaryUrl}", LogType.Warning, true);
550+
return await GetSenadinaIdentifierKind(client, dict, kind, gameVersion, null, secondaryUrl, true, token);
551+
}
474552
}
475553

476554
private async Task ThrowIfFileIsNotSenadina(Stream stream, CancellationToken token)

Hi3Helper.Core/Classes/Shared/Region/LauncherConfig.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,14 @@ private static void InitScreenResSettings()
163163

164164
public static List<CDNURLProperty> CDNList =>
165165
[
166+
new()
167+
{
168+
Name = "CollapseCDN",
169+
URLPrefix = "https://cdn.collapselauncher.com/cl-cdn",
170+
Description = Lang._Misc!.CDNDescription_CollapseCDN,
171+
PartialDownloadSupport = true
172+
},
173+
166174
new()
167175
{
168176
Name = "GitHub",

Hi3Helper.Core/Lang/Locale/LangMisc.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public sealed partial class LangMisc
9999
public string Default { get; set; } = LangFallback?._Misc.Default;
100100

101101
public string CDNDescription_Github { get; set; } = LangFallback?._Misc.CDNDescription_Github;
102+
public string CDNDescription_CollapseCDN { get; set; } = LangFallback?._Misc.CDNDescription_CollapseCDN;
102103
public string CDNDescription_Cloudflare { get; set; } = LangFallback?._Misc.CDNDescription_Cloudflare;
103104
public string CDNDescription_Bitbucket { get; set; } = LangFallback?._Misc.CDNDescription_Bitbucket;
104105
public string CDNDescription_Statically { get; set; } = LangFallback?._Misc.CDNDescription_Statically;

0 commit comments

Comments
 (0)