private async Task <CDNFileDefinition> GetDefinition() { var client = new Wabbajack.Lib.Http.Client(); if (DomainRemaps.TryGetValue(Url.Host, out var remap)) { var builder = new UriBuilder(Url) { Host = remap }; using var data = await client.GetAsync(builder + "/definition.json.gz"); await using var gz = new GZipStream(await data.Content.ReadAsStreamAsync(), CompressionMode.Decompress); return(gz.FromJson <CDNFileDefinition>()); } else { client.Headers.Add(("Host", Url.Host)); using var data = await GetWithMirroredRetry(client, Url + "/definition.json.gz"); await using var gz = new GZipStream(await data.Content.ReadAsStreamAsync(), CompressionMode.Decompress); return(gz.FromJson <CDNFileDefinition>()); } }
public override async Task <bool> Download(Archive a, AbsolutePath destination) { destination.Parent.CreateDirectory(); var definition = await GetDefinition(); await using var fs = await destination.Create(); using var mmfile = MemoryMappedFile.CreateFromFile(fs, null, definition.Size, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, false); var client = new Wabbajack.Lib.Http.Client(); if (!DomainRemaps.ContainsKey(Url.Host)) { client.Headers.Add(("Host", Url.Host)); } using var queue = new WorkQueue(); await definition.Parts.PMap(queue, async part => { Utils.Status($"Downloading {a.Name}", Percent.FactoryPutInRange(definition.Parts.Length - part.Index, definition.Parts.Length)); await using var ostream = mmfile.CreateViewStream(part.Offset, part.Size); if (DomainRemaps.TryGetValue(Url.Host, out var remap)) { var builder = new UriBuilder(Url) { Host = remap }; using var response = await client.GetAsync($"{builder}/parts/{part.Index}"); if (!response.IsSuccessStatusCode) { throw new HttpException((int)response.StatusCode, response.ReasonPhrase); } await response.Content.CopyToAsync(ostream); } else { using var response = await GetWithMirroredRetry(client, $"{Url}/parts/{part.Index}"); if (!response.IsSuccessStatusCode) { throw new HttpException((int)response.StatusCode, response.ReasonPhrase); } await response.Content.CopyToAsync(ostream); } }); return(true); }
private async Task <HttpResponseMessage> GetWithCDNRetry(Http.Client client, string url, CancellationToken?token = null) { int retries = 0; TOP: try { return(await client.GetAsync(url, retry : false, token : token)); } catch (Exception ex) { if (retries > 2) { Utils.Log($"Trying CDN..."); var remap = url.Replace(new Uri(url).Host, DomainRemaps.FirstOrDefault(x => x.Value == new Uri(url).Host).Key); return(await client.GetAsync(remap, retry : false, token : token)); } retries += 1; Utils.Log($"Error reading {url} retrying [{retries}]"); Utils.Log(ex.ToString()); goto TOP; } }