Skip to content

Commit dfd1288

Browse files
committed
Fixed the name of AuthorizeAccountAync in IApiClient.cs. This is breaking, but I expect most callers are using the ConnectAsync front-end and won't see this. And, it's only breaking with respect to the upstream published package. There are no consumers yet of the DQD.Backblaze.Client package. :-)
Added property UnknownCapabilities to the Allowed.cs class. Updated DebuggerDisplay to represent unknown capabilities in the returned string. Made a copy of the Allowed class called AllowedRaw.cs in Bytewizer.Backblaze.Client.Internal that represents capabilities as a list of plain strings, with method ParseCapabilities to transform instances into the original Allowed class. Updated LangVersion in Backblaze.Client.csproj to 8.0 to allow the use of the coalescing assignment operator. Made a copy of AuthorizedAccountResponse.cs in Bytewizer.Backblaze.Client.Internal that uses AllowedRaw instead of Allowed. Updated AuthorizeAccountAsync to use AuthorizeAccountResponseRaw for the actual request and then convert the result to the regular AuthorizedAccountResponse structure, with ParseCapabilities splitting off unknown capabilities.
1 parent 277b00e commit dfd1288

File tree

7 files changed

+202
-9
lines changed

7 files changed

+202
-9
lines changed

src/Client/Backblaze.Client.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<Authors>Microcompiler</Authors>
1111
<Company>Bytewizer Inc.</Company>
1212
<Product>Backblaze B2 Cloud Storage</Product>
13-
<LangVersion>7.1</LangVersion>
13+
<LangVersion>8.0</LangVersion>
1414
<RootNamespace>Bytewizer.Backblaze</RootNamespace>
1515
<VersionPrefix>1.1.0</VersionPrefix>
1616
<Version Condition=" '$(Version)' == '' and '$(VersionSuffix)' != '' ">$(VersionPrefix)-$(VersionSuffix)</Version>

src/Client/Client/ApiRest.Endpoints.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
using Bytewizer.Backblaze.Models;
1414
using Bytewizer.Backblaze.Extensions;
1515

16+
using Bytewizer.Backblaze.Client.Internal;
17+
1618
namespace Bytewizer.Backblaze.Client
1719
{
1820
public abstract partial class ApiRest : DisposableObject
@@ -30,7 +32,7 @@ public abstract partial class ApiRest : DisposableObject
3032
/// <exception cref="AuthenticationException">Thrown when authentication fails.</exception>
3133
/// <exception cref="ApiException">Thrown when an error occurs during client operation.</exception>
3234
/// <returns>The <see cref="AuthorizeAccountResponse" /> of this <see cref="IApiResults{T}.Response"/> value, or <c>null</c>, if the response was was error data.</returns>
33-
public async Task<IApiResults<AuthorizeAccountResponse>> AuthorizeAccountAync
35+
public async Task<IApiResults<AuthorizeAccountResponse>> AuthorizeAccountAsync
3436
(string keyId, string applicationKey, CancellationToken cancellationToken)
3537
{
3638
if (string.IsNullOrEmpty(keyId))
@@ -47,7 +49,9 @@ public async Task<IApiResults<AuthorizeAccountResponse>> AuthorizeAccountAync
4749
using (var results = await _policy.InvokeClient.ExecuteAsync(async () =>
4850
{ return await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false); }))
4951
{
50-
return await HandleResponseAsync<AuthorizeAccountResponse>(results).ConfigureAwait(false);
52+
var rawResult = await HandleResponseAsync<AuthorizeAccountResponseRaw>(results).ConfigureAwait(false);
53+
54+
return new ApiResults<AuthorizeAccountResponse>(rawResult.HttpResponse, rawResult.Response.ToAuthorizedAccountResponse());
5155
}
5256

5357
}

src/Client/Client/ApiRest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ protected override void Dispose(bool disposing)
107107
public AccountInfo AccountInfo { get; } = new AccountInfo();
108108

109109
/// <summary>
110-
/// The authorization token to use with all calls other than <see cref="AuthorizeAccountAync"/>. This authorization token is valid for at most 24 hours.
110+
/// The authorization token to use with all calls other than <see cref="AuthorizeAccountAsync"/>. This authorization token is valid for at most 24 hours.
111111
/// </summary>
112112
public AuthToken AuthToken { get; private set; }
113113

@@ -157,7 +157,7 @@ public async Task<AuthorizeAccountResponse> ConnectAsync(string keyId, string ap
157157
_policy.ConnectAsync = () => ConnectAsync(keyId, applicationKey);
158158
_cache.Clear();
159159

160-
var results = await AuthorizeAccountAync(keyId, applicationKey, CancellationToken.None).ConfigureAwait(false);
160+
var results = await AuthorizeAccountAsync(keyId, applicationKey, CancellationToken.None).ConfigureAwait(false);
161161
if (results.IsSuccessStatusCode)
162162
{
163163
AuthToken = new AuthToken(results.Response.AuthorizationToken)

src/Client/Client/IApiClient.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public interface IApiClient : IDisposable
2626
AccountInfo AccountInfo { get; }
2727

2828
/// <summary>
29-
/// The authorization token to use with all calls other than <see cref="AuthorizeAccountAync"/>.
29+
/// The authorization token to use with all calls other than <see cref="AuthorizeAccountAsync"/>.
3030
/// This authorization token is valid for at most 24 hours.
3131
/// </summary>
3232
AuthToken AuthToken { get; }
@@ -119,7 +119,7 @@ public interface IApiClient : IDisposable
119119
/// <exception cref="AuthenticationException">Thrown when authentication fails.</exception>
120120
/// <exception cref="ApiException">Thrown when an error occurs during client operation.</exception>
121121
/// The <see cref="AuthorizeAccountResponse" /> of this <see cref="IApiResults{T}.Response"/> value, or <c>null</c>, if the response was was error data.
122-
Task<IApiResults<AuthorizeAccountResponse>> AuthorizeAccountAync(string keyId, string applicationKey, CancellationToken cancellationToken);
122+
Task<IApiResults<AuthorizeAccountResponse>> AuthorizeAccountAsync(string keyId, string applicationKey, CancellationToken cancellationToken);
123123

124124
/// <summary>
125125
/// Cancels the upload of a large file and deletes all parts that have been uploaded.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
5+
using Newtonsoft.Json;
6+
7+
using Bytewizer.Backblaze.Models;
8+
9+
namespace Bytewizer.Backblaze.Client.Internal
10+
{
11+
/// <summary>
12+
/// Represents information related to an allowed authorization.
13+
/// </summary>
14+
[DebuggerDisplay("{DebuggerDisplay, nq}")]
15+
internal class AllowedRaw
16+
{
17+
/// <summary>
18+
/// Gets or sets a list of <see cref="Capability"/> allowed.
19+
/// </summary>
20+
[JsonProperty(Required = Required.Always)]
21+
public List<string> Capabilities { get; set; }
22+
23+
/// <summary>
24+
/// Gets or sets restricted access only to this bucket id.
25+
/// </summary>
26+
public string BucketId { get; set; }
27+
28+
/// <summary>
29+
/// When bucket id is set and it is a valid bucket that has not been deleted this field is set to the name of the
30+
/// bucket. It's possible that bucket id is set to a bucket that no longer exists in which case this field will be
31+
/// <c>null</c>. It's also null when bucket id is <c>null</c>.
32+
/// </summary>
33+
public string BucketName { get; set; }
34+
35+
/// <summary>
36+
/// Gets or sets restricted access to files whose names start with the prefix.
37+
/// </summary>
38+
public string NamePrefix { get; set; }
39+
40+
/// <summary>
41+
/// Debugger display for this object.
42+
/// </summary>
43+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
44+
private string DebuggerDisplay
45+
{
46+
get { return $"{{{nameof(Capabilities)}: {string.Join(", ", Capabilities)}, {nameof(NamePrefix)}: {NamePrefix}}}"; }
47+
}
48+
49+
/// <summary>
50+
/// Translates this <see cref="AllowedRaw"/> instance to an instance of <see cref="Allowed"/>,
51+
/// parsing capabilities into the <see cref="Allowed.Capabilities"/> and
52+
/// <see cref="Allowed.UnknownCapabilities"/> properties.
53+
/// </summary>
54+
/// <returns>An instance of <see cref="Allowed"/>.</returns>
55+
public Allowed ParseCapabilities()
56+
{
57+
Allowed parsed = new Allowed();
58+
59+
parsed.BucketId = this.BucketId;
60+
parsed.BucketName = this.BucketName;
61+
parsed.NamePrefix = this.NamePrefix;
62+
63+
foreach (string capabilityName in this.Capabilities)
64+
{
65+
if (Enum.TryParse<Capability>(capabilityName, out var parsedCapability))
66+
{
67+
parsed.Capabilities.Add(parsedCapability);
68+
}
69+
else
70+
{
71+
parsed.UnknownCapabilities ??= new List<string>();
72+
parsed.UnknownCapabilities.Add(capabilityName);
73+
}
74+
}
75+
76+
return parsed;
77+
}
78+
}
79+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using System.Diagnostics;
3+
4+
using Newtonsoft.Json;
5+
6+
using Bytewizer.Backblaze.Models;
7+
8+
namespace Bytewizer.Backblaze.Client.Internal
9+
{
10+
/// <summary>
11+
/// Contains the results of authorize account request operation.
12+
/// </summary>
13+
[DebuggerDisplay("{DebuggerDisplay, nq}")]
14+
internal class AuthorizeAccountResponseRaw : IResponse
15+
{
16+
/// <summary>
17+
/// The identifier for the account.
18+
/// </summary>
19+
[JsonProperty(Required = Required.Always)]
20+
public string AccountId { get; internal set; }
21+
22+
/// <summary>
23+
/// An authorization token to use with all calls other than authorize account that need an authorization header.
24+
/// This authorization token is valid for at most 24 hours.
25+
/// </summary>
26+
[JsonProperty(Required = Required.Always)]
27+
public string AuthorizationToken { get; internal set; }
28+
29+
/// <summary>
30+
/// The capabilities of this auth token and any restrictions on using it.
31+
/// </summary>
32+
[JsonProperty(Required = Required.Always)]
33+
public AllowedRaw Allowed { get; internal set; }
34+
35+
/// <summary>
36+
/// The base url to use for all API calls except for uploading and downloading files.
37+
/// </summary>
38+
[JsonProperty(Required = Required.Always)]
39+
public Uri ApiUrl { get; internal set; }
40+
41+
/// <summary>
42+
/// The base url to use for downloading files.
43+
/// </summary>
44+
[JsonProperty(Required = Required.Always)]
45+
public Uri DownloadUrl { get; internal set; }
46+
47+
/// <summary>
48+
/// The recommended size for each part of a large file. We recommend using this part size for optimal upload performance.
49+
/// </summary>
50+
[JsonProperty(Required = Required.Always)]
51+
public long RecommendedPartSize { get; internal set; }
52+
53+
/// <summary>
54+
/// The smallest possible size of a part of a large file (except the last one). This is smaller than the <see cref="RecommendedPartSize"/>.
55+
/// If you use it you may find that it takes longer overall to upload a large file.
56+
/// </summary>
57+
[JsonProperty(Required = Required.Always)]
58+
public long AbsoluteMinimumPartSize { get; internal set; }
59+
60+
/// <summary>
61+
/// OBSOLETE: This field will always have the same value as <see cref="RecommendedPartSize"/>.
62+
/// </summary>
63+
[Obsolete("This field will always have the same value as 'RecommendedPartSize'.")]
64+
public long MinimumPartSize { get; internal set; }
65+
66+
/// <summary>
67+
/// Debugger display for this object.
68+
/// </summary>
69+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
70+
private string DebuggerDisplay
71+
{
72+
get { return $"{{{nameof(AccountId)}: {AccountId}, {nameof(AuthorizationToken)}: {AuthorizationToken}}}"; }
73+
}
74+
75+
internal AuthorizeAccountResponse ToAuthorizedAccountResponse()
76+
{
77+
var response = new AuthorizeAccountResponse();
78+
79+
response.AccountId = this.AccountId;
80+
response.AuthorizationToken = this.AuthorizationToken;
81+
response.Allowed = this.Allowed.ParseCapabilities();
82+
response.ApiUrl = this.ApiUrl;
83+
response.DownloadUrl = this.DownloadUrl;
84+
response.RecommendedPartSize = this.RecommendedPartSize;
85+
response.AbsoluteMinimumPartSize = this.AbsoluteMinimumPartSize;
86+
87+
#pragma warning disable 618
88+
response.MinimumPartSize = this.MinimumPartSize;
89+
#pragma warning restore 618
90+
91+
return response;
92+
}
93+
}
94+
}

src/Client/Models/Allowed.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Diagnostics;
1+
using System.Collections.Generic;
2+
using System.Diagnostics;
23

34
using Newtonsoft.Json;
45

@@ -16,6 +17,11 @@ public class Allowed
1617
[JsonProperty(Required = Required.Always)]
1718
public Capabilities Capabilities { get; set; }
1819

20+
/// <summary>
21+
/// Gets or sets a list of capabilities that couldn't be parsed into <see cref="Capability"/> values.
22+
/// </summary>
23+
public List<string> UnknownCapabilities { get; set; }
24+
1925
/// <summary>
2026
/// Gets or sets restricted access only to this bucket id.
2127
/// </summary>
@@ -39,7 +45,17 @@ public class Allowed
3945
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
4046
private string DebuggerDisplay
4147
{
42-
get { return $"{{{nameof(Capabilities)}: {string.Join(", ", Capabilities)}, {nameof(NamePrefix)}: {NamePrefix}}}"; }
48+
get
49+
{
50+
string unknownCapabilitiesString = "";
51+
52+
if ((this.UnknownCapabilities != null) && (this.UnknownCapabilities.Count > 0))
53+
{
54+
unknownCapabilitiesString = " (+ " + string.Join(", ", UnknownCapabilities) + ")";
55+
}
56+
57+
return $"{{{nameof(Capabilities)}: {string.Join(", ", Capabilities)}{unknownCapabilitiesString}, {nameof(NamePrefix)}: {NamePrefix}}}";
58+
}
4359
}
4460
}
4561
}

0 commit comments

Comments
 (0)