mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Refactor downloader methods to use a dictionary for headers, has effect on Sources
This commit is contained in:
@@ -35,12 +35,14 @@ namespace Velopack.Sources
|
||||
protected virtual string? AccessToken { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Bearer token used in the request.
|
||||
/// The Bearer or other type of Authorization header used to authenticate against the Api.
|
||||
/// </summary>
|
||||
protected virtual string? Authorization => string.IsNullOrWhiteSpace(AccessToken) ? null : "Bearer " + AccessToken;
|
||||
protected abstract (string Name, string Value) Authorization { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public GitBase(string repoUrl, string? accessToken, bool prerelease, IFileDownloader? downloader = null)
|
||||
/// <summary>
|
||||
/// Base constructor.
|
||||
/// </summary>
|
||||
protected GitBase(string repoUrl, string? accessToken, bool prerelease, IFileDownloader? downloader = null)
|
||||
{
|
||||
RepoUri = new Uri(repoUrl.TrimEnd('/'));
|
||||
AccessToken = accessToken;
|
||||
@@ -55,7 +57,12 @@ namespace Velopack.Sources
|
||||
// this might be a browser url or an api url (depending on whether we have a AccessToken or not)
|
||||
// https://docs.github.com/en/rest/reference/releases#get-a-release-asset
|
||||
var assetUrl = GetAssetUrlFromName(githubEntry.Release, releaseEntry.FileName);
|
||||
return Downloader.DownloadFile(assetUrl, localFile, progress, Authorization, "application/octet-stream", cancelToken: cancelToken);
|
||||
return Downloader.DownloadFile(assetUrl, localFile, progress,
|
||||
new Dictionary<string, string> {
|
||||
[Authorization.Name] = Authorization.Value,
|
||||
["Accept"] = "application/octet-stream"
|
||||
},
|
||||
cancelToken: cancelToken);
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Expected releaseEntry to be {nameof(GitBaseAsset)} but got {releaseEntry.GetType().Name}.");
|
||||
@@ -84,7 +91,12 @@ namespace Velopack.Sources
|
||||
logger.Trace(ex.ToString());
|
||||
continue;
|
||||
}
|
||||
var releaseBytes = await Downloader.DownloadBytes(assetUrl, Authorization, "application/octet-stream").ConfigureAwait(false);
|
||||
var releaseBytes = await Downloader.DownloadBytes(assetUrl,
|
||||
new Dictionary<string, string> {
|
||||
[Authorization.Name] = Authorization.Value,
|
||||
["Accept"] = "application/octet-stream"
|
||||
}
|
||||
).ConfigureAwait(false);
|
||||
var txt = CoreUtil.RemoveByteOrderMarkerIfPresent(releaseBytes);
|
||||
var feed = VelopackAssetFeed.FromJson(txt);
|
||||
foreach (var f in feed.Assets) {
|
||||
|
||||
@@ -81,11 +81,10 @@ namespace Velopack.Sources
|
||||
: base(repoUrl, accessToken, prerelease, downloader)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// The authorization token used in the request.
|
||||
/// Overwrite it to token
|
||||
/// </summary>
|
||||
protected override string? Authorization => string.IsNullOrWhiteSpace(AccessToken) ? null : "token " + AccessToken;
|
||||
|
||||
/// <inheritdoc cref="Authorization"/>
|
||||
protected override (string Name, string Value) Authorization => ("Authorization", $"token {AccessToken}");
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<GiteaRelease[]> GetReleases(bool includePrereleases)
|
||||
{
|
||||
@@ -97,7 +96,12 @@ namespace Velopack.Sources
|
||||
var releasesPath = $"repos{RepoUri.AbsolutePath}/releases?limit={perPage}&page={page}&draft=false";
|
||||
var baseUri = GetApiBaseUrl(RepoUri);
|
||||
var getReleasesUri = new Uri(baseUri, releasesPath);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(), Authorization, "application/json").ConfigureAwait(false);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(),
|
||||
new Dictionary<string, string> {
|
||||
[Authorization.Name] = Authorization.Value,
|
||||
["Accept"] = "application/json"
|
||||
}
|
||||
).ConfigureAwait(false);
|
||||
var releases = CompiledJson.DeserializeGiteaReleaseList(response);
|
||||
if (releases == null) return new GiteaRelease[0];
|
||||
return releases.OrderByDescending(d => d.PublishedAt).Where(x => includePrereleases || !x.Prerelease).ToArray();
|
||||
|
||||
@@ -87,6 +87,9 @@ namespace Velopack.Sources
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Authorization"/>
|
||||
protected override (string Name, string Value) Authorization => ("Authorization", $"Bearer {AccessToken}");
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<GithubRelease[]> GetReleases(bool includePrereleases)
|
||||
{
|
||||
@@ -96,7 +99,12 @@ namespace Velopack.Sources
|
||||
var releasesPath = $"repos{RepoUri.AbsolutePath}/releases?per_page={perPage}&page={page}";
|
||||
var baseUri = GetApiBaseUrl(RepoUri);
|
||||
var getReleasesUri = new Uri(baseUri, releasesPath);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(), Authorization, "application/vnd.github.v3+json").ConfigureAwait(false);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(),
|
||||
new Dictionary<string, string> {
|
||||
[Authorization.Name] = Authorization.Value,
|
||||
["Accept"] = "application/vnd.github.v3+json"
|
||||
}
|
||||
).ConfigureAwait(false);
|
||||
var releases = CompiledJson.DeserializeGithubReleaseList(response);
|
||||
if (releases == null) return Array.Empty<GithubRelease>();
|
||||
return releases.OrderByDescending(d => d.PublishedAt).Where(x => includePrereleases || !x.Prerelease).ToArray();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Velopack.Util;
|
||||
@@ -98,6 +99,9 @@ namespace Velopack.Sources
|
||||
/// </summary>
|
||||
public class GitlabSource : GitBase<GitlabRelease>
|
||||
{
|
||||
/// <inheritdoc cref="Authorization"/>
|
||||
protected override (string Name, string Value) Authorization => ("PRIVATE-TOKEN", AccessToken ?? string.Empty);
|
||||
|
||||
/// <inheritdoc cref="GitlabSource" />
|
||||
/// <param name="repoUrl">
|
||||
/// The URL of the GitLab repository to download releases from
|
||||
@@ -156,7 +160,11 @@ namespace Velopack.Sources
|
||||
var releasesPath = $"{RepoUri.AbsolutePath}/releases?per_page={perPage}&page={page}";
|
||||
var baseUri = new Uri("https://gitlab.com");
|
||||
var getReleasesUri = new Uri(baseUri, releasesPath);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(), Authorization).ConfigureAwait(false);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(),
|
||||
new Dictionary<string, string> {
|
||||
[Authorization.Name] = Authorization.Value,
|
||||
["Accept"] = "application/json"
|
||||
}).ConfigureAwait(false);
|
||||
var releases = CompiledJson.DeserializeGitlabReleaseList(response);
|
||||
if (releases == null) return new GitlabRelease[0];
|
||||
return releases.OrderByDescending(d => d.ReleasedAt).Where(x => includePrereleases || !x.UpcomingRelease).ToArray();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
@@ -18,9 +19,9 @@ namespace Velopack.Sources
|
||||
public static ProductInfoHeaderValue UserAgent => new("Velopack", VelopackRuntimeInfo.VelopackNugetVersion.ToFullString());
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual async Task DownloadFile(string url, string targetFile, Action<int> progress, string? authorization, string? accept, double timeout, CancellationToken cancelToken = default)
|
||||
public virtual async Task DownloadFile(string url, string targetFile, Action<int> progress, IDictionary<string, string>? headers, double timeout, CancellationToken cancelToken = default)
|
||||
{
|
||||
using var client = CreateHttpClient(authorization, accept, timeout);
|
||||
using var client = CreateHttpClient(headers, timeout);
|
||||
|
||||
try {
|
||||
using (var fs = File.Open(targetFile, FileMode.Create)) {
|
||||
@@ -36,9 +37,9 @@ namespace Velopack.Sources
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual async Task<byte[]> DownloadBytes(string url, string? authorization, string? accept, double timeout)
|
||||
public virtual async Task<byte[]> DownloadBytes(string url, IDictionary<string, string>? headers, double timeout)
|
||||
{
|
||||
using var client = CreateHttpClient(authorization, accept, timeout);
|
||||
using var client = CreateHttpClient(headers, timeout);
|
||||
|
||||
try {
|
||||
return await client.GetByteArrayAsync(url).ConfigureAwait(false);
|
||||
@@ -50,9 +51,9 @@ namespace Velopack.Sources
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual async Task<string> DownloadString(string url, string? authorization, string? accept, double timeout)
|
||||
public virtual async Task<string> DownloadString(string url, IDictionary<string, string>? headers, double timeout)
|
||||
{
|
||||
using var client = CreateHttpClient(authorization, accept, timeout);
|
||||
using var client = CreateHttpClient(headers, timeout);
|
||||
|
||||
try {
|
||||
return await client.GetStringAsync(url).ConfigureAwait(false);
|
||||
@@ -123,16 +124,15 @@ namespace Velopack.Sources
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="HttpClient"/> for every request.
|
||||
/// </summary>
|
||||
protected virtual HttpClient CreateHttpClient(string? authorization, string? accept, double timeout = 30)
|
||||
protected virtual HttpClient CreateHttpClient(IDictionary<string, string>? headers, double timeout)
|
||||
{
|
||||
var client = new HttpClient(CreateHttpClientHandler());
|
||||
client.DefaultRequestHeaders.UserAgent.Add(UserAgent);
|
||||
|
||||
if (authorization != null)
|
||||
client.DefaultRequestHeaders.Add("Authorization", authorization);
|
||||
|
||||
if (accept != null)
|
||||
client.DefaultRequestHeaders.Add("Accept", accept);
|
||||
foreach (var header in headers ?? new Dictionary<string, string>())
|
||||
{
|
||||
client.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||
}
|
||||
|
||||
client.Timeout = TimeSpan.FromMinutes(timeout);
|
||||
return client;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -14,31 +15,26 @@ namespace Velopack.Sources
|
||||
/// </summary>
|
||||
/// <param name="url">The url which will be downloaded.</param>
|
||||
/// <param name="targetFile">
|
||||
/// The local path where the file will be stored
|
||||
/// If a file exists at this path, it will be overwritten.</param>
|
||||
/// The local path where the file will be stored
|
||||
/// If a file exists at this path, it will be overwritten.</param>
|
||||
/// <param name="progress">
|
||||
/// A delegate for reporting download progress, with expected values from 0-100.
|
||||
/// </param>
|
||||
/// <param name="authorization">
|
||||
/// Text to be sent in the 'Authorization' header of the request.
|
||||
/// </param>
|
||||
/// <param name="accept">
|
||||
/// Text to be sent in the 'Accept' header of the request.
|
||||
/// A delegate for reporting download progress, with expected values from 0-100.
|
||||
/// </param>
|
||||
/// <param name="headers">Headers that can be passed to Http Downloader, e.g. Accept or Authorization.</param>
|
||||
/// <param name="timeout">
|
||||
/// The maximum time in minutes to wait for the download to complete.
|
||||
/// The maximum time in minutes to wait for the download to complete.
|
||||
/// </param>
|
||||
/// <param name="cancelToken">Optional token to cancel the request.</param>
|
||||
Task DownloadFile(string url, string targetFile, Action<int> progress, string? authorization = null, string? accept = null, double timeout = 30, CancellationToken cancelToken = default);
|
||||
Task DownloadFile(string url, string targetFile, Action<int> progress, IDictionary<string, string>? headers = null, double timeout = 30, CancellationToken cancelToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a byte array containing the contents of the file at the specified url
|
||||
/// </summary>
|
||||
Task<byte[]> DownloadBytes(string url, string? authorization = null, string? accept = null, double timeout = 30);
|
||||
Task<byte[]> DownloadBytes(string url, IDictionary<string, string>? headers = null, double timeout = 30);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string containing the contents of the specified url
|
||||
/// </summary>
|
||||
Task<string> DownloadString(string url, string? authorization = null, string? accept = null, double timeout = 30);
|
||||
Task<string> DownloadString(string url, IDictionary<string, string>? headers = null, double timeout = 30);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,23 +7,21 @@ public class FakeDownloader : IFileDownloader
|
||||
{
|
||||
public string LastUrl { get; private set; }
|
||||
public string LastLocalFile { get; private set; }
|
||||
public string LastAuthHeader { get; private set; }
|
||||
public string LastAcceptHeader { get; private set; }
|
||||
public IDictionary<string, string>? LastHeaders { get; private set; }
|
||||
public byte[] MockedResponseBytes { get; set; } = [];
|
||||
public bool WriteMockLocalFile { get; set; } = false;
|
||||
|
||||
public Task<byte[]> DownloadBytes(string url, string auth, string acc, double timeout = 30)
|
||||
public Task<byte[]> DownloadBytes(string url, IDictionary<string, string> headers, double timeout = 30)
|
||||
{
|
||||
LastUrl = url;
|
||||
LastAuthHeader = auth;
|
||||
LastAcceptHeader = acc;
|
||||
LastHeaders = headers;
|
||||
return Task.FromResult(MockedResponseBytes);
|
||||
}
|
||||
|
||||
public async Task DownloadFile(string url, string targetFile, Action<int> progress, string auth, string acc, double timeout, CancellationToken token)
|
||||
public async Task DownloadFile(string url, string targetFile, Action<int> progress, IDictionary<string, string> headers, double timeout = 30, CancellationToken token = default)
|
||||
{
|
||||
LastLocalFile = targetFile;
|
||||
var resp = await DownloadBytes(url, auth, acc);
|
||||
var resp = await DownloadBytes(url, headers);
|
||||
progress?.Invoke(25);
|
||||
progress?.Invoke(50);
|
||||
progress?.Invoke(75);
|
||||
@@ -32,8 +30,8 @@ public class FakeDownloader : IFileDownloader
|
||||
File.WriteAllBytes(targetFile, resp);
|
||||
}
|
||||
|
||||
public async Task<string> DownloadString(string url, string auth, string acc, double timeout = 30)
|
||||
public async Task<string> DownloadString(string url, IDictionary<string, string> headers, double timeout = 30)
|
||||
{
|
||||
return Encoding.UTF8.GetString(await DownloadBytes(url, auth, acc));
|
||||
return Encoding.UTF8.GetString(await DownloadBytes(url, headers));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ internal class FakeFixtureRepository : IFileDownloader
|
||||
_releases = releases;
|
||||
}
|
||||
|
||||
public Task<byte[]> DownloadBytes(string url, string authorization = null, string accept = null, double timeout = 30)
|
||||
public Task<byte[]> DownloadBytes(string url, IDictionary<string, string> headers = null, double timeout = 30)
|
||||
{
|
||||
if (url.Contains($"/{_releasesName}?")) {
|
||||
MemoryStream ms = new MemoryStream();
|
||||
@@ -82,7 +82,7 @@ internal class FakeFixtureRepository : IFileDownloader
|
||||
return Task.FromResult(File.ReadAllBytes(filePath));
|
||||
}
|
||||
|
||||
public Task DownloadFile(string url, string targetFile, Action<int> progress, string authorization = null, string accept = null, double timeout = 30,
|
||||
public Task DownloadFile(string url, string targetFile, Action<int> progress, IDictionary<string, string> headers = null, double timeout = 30,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var rel = _releases.FirstOrDefault(r => url.EndsWith(r.OriginalFilename));
|
||||
@@ -99,7 +99,7 @@ internal class FakeFixtureRepository : IFileDownloader
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<string> DownloadString(string url, string authorization = null, string accept = null, double timeout = 30)
|
||||
public Task<string> DownloadString(string url, IDictionary<string, string> headers = null, double timeout = 30)
|
||||
{
|
||||
if (url.Contains($"/{_releasesName}?")) {
|
||||
MemoryStream ms = new MemoryStream();
|
||||
|
||||
Reference in New Issue
Block a user