Skip to content

Commit

Permalink
v14.2.2 - upgrade to API from node v14.2.2
Browse files Browse the repository at this point in the history
  • Loading branch information
monoman committed Jun 19, 2024
1 parent 16a6b2a commit 27678c5
Show file tree
Hide file tree
Showing 52 changed files with 478 additions and 357 deletions.
39 changes: 23 additions & 16 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,16 @@ dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion

[*.xml]
indent_style = space
indent_size = 2

[*.cs]

file_header_template = ******************************************************************************************************************************\n \nCopyright (c) 2018-2022 InterlockLedger Network\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES, LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n******************************************************************************************************************************

csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
Expand Down Expand Up @@ -146,6 +150,22 @@ dotnet_style_qualification_for_property = false:silent
dotnet_style_readonly_field = true:warning
dotnet_style_require_accessibility_modifiers = always:silent

csharp_style_namespace_declarations = file_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_style_prefer_tuple_swap = true:suggestion
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
csharp_style_prefer_parameter_null_checking = true:suggestion
csharp_style_prefer_pattern_matching = true:silent
csharp_style_prefer_not_pattern = true:suggestion
csharp_style_prefer_extended_property_pattern = true:suggestion
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion

dotnet_diagnostic.CA1028.severity = none
dotnet_diagnostic.CA1031.severity = none
dotnet_diagnostic.CA1032.severity = none
Expand All @@ -159,24 +179,11 @@ dotnet_diagnostic.CA1707.severity = none
dotnet_diagnostic.CA1710.severity = none
dotnet_diagnostic.CA1815.severity = none
dotnet_diagnostic.CA1819.severity = none

file_header_template = ******************************************************************************************************************************\n \nCopyright (c) 2018-2022 InterlockLedger Network\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES, LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n******************************************************************************************************************************

dotnet_diagnostic.CA2007.severity = none
dotnet_diagnostic.CA2225.severity = none
dotnet_diagnostic.CA2227.severity = none
dotnet_diagnostic.RCS1194.severity = suggestion
csharp_style_namespace_declarations = file_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_style_prefer_tuple_swap = true:suggestion
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
csharp_style_prefer_parameter_null_checking = true:suggestion
csharp_style_prefer_pattern_matching = true:silent
csharp_style_prefer_not_pattern = true:suggestion
csharp_style_prefer_extended_property_pattern = true:suggestion
dotnet_diagnostic.MA0076.severity = none
dotnet_diagnostic.MA0042.severity = none
dotnet_diagnostic.MA0023.severity = none

Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public abstract class RestAbstractChain<T> : IRestChain where T : IRestChain

internal readonly RestAbstractNode<T> _node;

internal RestAbstractChain(RestAbstractNode<T> node, ChainIdModel chainId) {
protected RestAbstractChain(RestAbstractNode<T> node, ChainIdModel chainId) {
_node = node.Required();
Id = chainId.Required().Id.Required();
Name = chainId.Name;
Expand Down
68 changes: 34 additions & 34 deletions InterlockLedger.Rest.Client/Abstractions/RestAbstractNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@


using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.Mime;
using System.Net.Security;
Expand All @@ -43,19 +44,19 @@ namespace InterlockLedger.Rest.Client.Abstractions;
[DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")]
public abstract class RestAbstractNode<T> where T : IRestChain
{
public RestAbstractNode(X509Certificate2 x509Certificate, NetworkPredefinedPorts networkId = NetworkPredefinedPorts.MainNet, string address = "localhost")
protected RestAbstractNode(X509Certificate2 x509Certificate, NetworkPredefinedPorts networkId = NetworkPredefinedPorts.MainNet, string address = "localhost")
: this(x509Certificate, (ushort)networkId, address) { }

public RestAbstractNode(X509Certificate2 x509Certificate, ushort port, string address = "localhost") {
protected RestAbstractNode(X509Certificate2 x509Certificate, ushort port, string address = "localhost") {
_certificate = x509Certificate;
BaseUri = new Uri($"https://{address}:{port}/", UriKind.Absolute);
Network = new RestNetwork<T>(this);
}

public RestAbstractNode(string certFile, string certPassword, NetworkPredefinedPorts networkId = NetworkPredefinedPorts.MainNet, string address = "localhost")
protected RestAbstractNode(string certFile, string certPassword, NetworkPredefinedPorts networkId = NetworkPredefinedPorts.MainNet, string address = "localhost")
: this(certFile, certPassword, (ushort)networkId, address) { }

public RestAbstractNode(string certFile, string certPassword, ushort port, string address = "localhost")
protected RestAbstractNode(string certFile, string certPassword, ushort port, string address = "localhost")
: this(GetCertFromFile(certFile, certPassword), port, address) { }

public Uri BaseUri { get; }
Expand All @@ -69,16 +70,16 @@ public RestAbstractNode(string certFile, string certPassword, ushort port, strin
public Task<ChainCreatedModel?> CreateChainAsync(ChainCreationModel model)
=> PostAsync<ChainCreatedModel>($"/chain", model);

public async Task<IEnumerable<T>> GetChainsAsync() => (await GetAsync<IEnumerable<ChainIdModel>>("/chain")).Safe().Select(c => BuildChain(c));
public async Task<IEnumerable<T>> GetChainsAsync() => (await GetAsync<IEnumerable<ChainIdModel>>("/chain").ConfigureAwait(false)).Safe().Select(c => BuildChain(c));

public Task<NodeDetailsModel?> GetDetailsAsync() => GetAsync<NodeDetailsModel>("/");

public async Task<IEnumerable<T>> GetMirrorsAsync() => (await GetAsync<IEnumerable<ChainIdModel>>("/mirrors")).Safe().Select(c => BuildChain(c));
public async Task<IEnumerable<T>> GetMirrorsAsync() => (await GetAsync<IEnumerable<ChainIdModel>>("/mirrors").ConfigureAwait(false)).Safe().Select(c => BuildChain(c));

public Task<IEnumerable<PeerModel>?> GetPeersAsync() => GetAsync<IEnumerable<PeerModel>>("/peers");

public async Task<PageOf<InterlockingRecordModel>?> InterlocksOfAsync(string chain)
=> await GetAsync<PageOf<InterlockingRecordModel>>($"/interlockings/{chain}");
=> await GetAsync<PageOf<InterlockingRecordModel>>($"/interlockings/{chain}").ConfigureAwait(false);

public override string ToString() => $"Node [{BaseUri}] connected with certificate '{CertificateName}'";

Expand All @@ -93,27 +94,26 @@ protected internal static async Task<HttpWebResponse> GetResponseAsync(HttpWebRe
}

protected internal static async Task<string> GetStringResponseAsync(HttpWebRequest req)
=> (await IfOkOrCreatedReturnAsync(await GetResponseAsync(req), ReadAsStringAsync)).WithDefault(string.Empty);
=> (await IfOkOrCreatedReturnAsync(await GetResponseAsync(req).ConfigureAwait(false), ReadAsStringAsync).ConfigureAwait(false)).WithDefault(string.Empty);

private static async Task<TR?> IfOkOrCreatedReturnAsync<TR>(HttpWebResponse resp, Func<HttpWebResponse, Task<TR>> buildResult) {
return resp.StatusCode switch {
HttpStatusCode.OK or HttpStatusCode.Created => await buildResult(resp),
HttpStatusCode.OK or HttpStatusCode.Created => await buildResult(resp).ConfigureAwait(false),
HttpStatusCode.NotFound => default,
_ => await CheckMessageAsync(resp)
_ => await CheckMessageAsync(resp).ConfigureAwait(false),
};

static async Task<TR?> CheckMessageAsync(HttpWebResponse resp) {
string content = await ReadAsStringAsync(resp).ConfigureAwait(false);
if (content.Safe().Contains("outstanding", StringComparison.OrdinalIgnoreCase))
return default;
else {
string exceptionMessage = $"{resp.StatusCode}(#{(int)resp.StatusCode}){Environment.NewLine}{content}";
return resp.StatusCode switch {
HttpStatusCode.Unauthorized => throw new SecurityException(exceptionMessage),
HttpStatusCode.Forbidden => throw new SecurityException(exceptionMessage),
_ => throw new ApiException(exceptionMessage),
};
}

string exceptionMessage = $"{resp.StatusCode}(#{(int)resp.StatusCode}){Environment.NewLine}{content}";
return resp.StatusCode switch {
HttpStatusCode.Unauthorized => throw new SecurityException(exceptionMessage),
HttpStatusCode.Forbidden => throw new SecurityException(exceptionMessage),
_ => throw new ApiException(exceptionMessage),
};
}
}

Expand All @@ -122,19 +122,19 @@ protected internal static async Task<string> ReadAsStringAsync(HttpWebResponse r
if (resp == null)
return string.Empty;
using var readStream = new StreamReader(resp.GetResponseStream());
return await readStream.ReadToEndAsync();
return await readStream.ReadToEndAsync().ConfigureAwait(false);
}

protected internal abstract T BuildChain(ChainIdModel c);

protected internal async Task<string> CallApiAsync(string url, string method, string accept = "application/json")
=> await GetStringResponseAsync(PrepareRequest(url, method, accept));
=> await GetStringResponseAsync(PrepareRequest(url, method, accept)).ConfigureAwait(false);

protected internal async Task<string> CallApiPlainDocAsync(string url, string method, string accept = "plain/text")
=> await GetStringResponseAsync(PrepareRequest(url, method, accept));
=> await GetStringResponseAsync(PrepareRequest(url, method, accept)).ConfigureAwait(false);

protected internal async Task<RawDocumentModel?> CallApiRawDocAsync(string url, string method, string accept = "*")
=> await GetRawResponseAsync(PrepareRequest(url, method, accept));
=> await GetRawResponseAsync(PrepareRequest(url, method, accept)).ConfigureAwait(false);

protected internal async Task<TR?> GetAsync<TR>(string url)
=> Deserialize<TR>(await CallApiAsync(url, "GET").ConfigureAwait(false));
Expand All @@ -146,26 +146,26 @@ protected internal async Task<string> CallApiPlainDocAsync(string url, string me
throw new ArgumentException($"'{nameof(accept)}' cannot be null or empty", nameof(accept));
if (string.IsNullOrWhiteSpace(method))
throw new ArgumentException($"'{nameof(method)}' cannot be null or empty", nameof(method));
var resp = await GetResponseAsync(PrepareRequest(url, method, accept));
var resp = await GetResponseAsync(PrepareRequest(url, method, accept)).ConfigureAwait(false);
return resp.StatusCode == HttpStatusCode.OK ? (ParseFileName(resp), resp.ContentType, resp.GetResponseStream()) : null;
}
protected internal async Task<(ulong AppId, ulong PayloadTypeId, DateTimeOffset? CreatedAt, Stream Content)?> GetOpaqueStreamAsync(string url) {
var resp = await GetResponseAsync(PrepareRequest(url.Required(), "GET", "application/octet-stream"));
var resp = await GetResponseAsync(PrepareRequest(url.Required(), "GET", "application/octet-stream")).ConfigureAwait(false);
if (resp.StatusCode != HttpStatusCode.OK)
return null;
DateTimeOffset? createdAt = DateTimeOffset.TryParse(resp.Headers["x-created-at"], out var parsedCreatedAt) ? parsedCreatedAt : null;
DateTimeOffset? createdAt = DateTimeOffset.TryParse(resp.Headers["x-created-at"], CultureInfo.InvariantCulture, out var parsedCreatedAt) ? parsedCreatedAt : null;
return (ulong.Parse(resp.Headers["x-app-id"].WithDefault("0")), ulong.Parse(resp.Headers["x-payload-type-id"].WithDefault("0")), createdAt, resp.GetResponseStream());
}

protected internal async Task<TR?> PostAsync<TR>(string url, object? body)
=> Deserialize<TR>(await GetStringResponseAsync(PreparePostRequest(url, body, accept: "application/json")));
=> Deserialize<TR>(await GetStringResponseAsync(PreparePostRequest(url, body, accept: "application/json")).ConfigureAwait(false));

protected internal async Task<TR?> PostRawAsync<TR>(string url, byte[] body, string contentType)
=> Deserialize<TR>(await GetStringResponseAsync(PreparePostRawRequest(url, body, accept: "application/json", contentType)));
=> Deserialize<TR>(await GetStringResponseAsync(PreparePostRawRequest(url, body, accept: "application/json", contentType)).ConfigureAwait(false));

protected internal async Task<TR?> PostStreamAsync<TR>(string url, Stream body, string contentType) {
var resp = await GetResponseAsync(PreparePostStreamRequest(url, body, accept: "*/*", contentType));
return await IfOkOrCreatedReturnAsync(resp, async (rs) => Deserialize<TR>(await ReadAsStringAsync(rs)));
var resp = await GetResponseAsync(PreparePostStreamRequest(url, body, accept: "*/*", contentType)).ConfigureAwait(false);
return await IfOkOrCreatedReturnAsync(resp, async (rs) => Deserialize<TR>(await ReadAsStringAsync(rs).ConfigureAwait(false))).ConfigureAwait(false);
}

protected internal HttpWebRequest PrepareRequest(string url, string method, string accept) {
Expand All @@ -182,10 +182,10 @@ protected internal HttpWebRequest PrepareRequest(string url, string method, stri
return req;
}

protected internal bool ServerCertificateValidation(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors)
protected internal static bool ServerCertificateValidation(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors)
=> true;

private static readonly Encoding _utf8WithoutBOM = new UTF8Encoding(false);
private static readonly Encoding _utf8WithoutBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);

private static byte[] ArrayConcat(byte[] firstBuffer, Memory<byte> secondBuffer, int count) {
var concatBuffer = new byte[firstBuffer.Length + count];
Expand All @@ -209,15 +209,15 @@ private static X509Certificate2 GetCertFromFile(string certPath, string certPass
=> new(certPath, certPassword, X509KeyStorageFlags.PersistKeySet);

private static async Task<RawDocumentModel?> GetRawResponseAsync(HttpWebRequest req) {
var response = await GetResponseAsync(req);
var response = await GetResponseAsync(req).ConfigureAwait(false);
if (response is null)
return null;
using var resp = response;
using var readStream = resp.GetResponseStream();
var fullBuffer = Array.Empty<byte>();
var buffer = new byte[0x80000].AsMemory();
while (true) {
var readCount = await readStream.ReadAsync(buffer, cancellationToken: CancellationToken.None);
var readCount = await readStream.ReadAsync(buffer, cancellationToken: CancellationToken.None).ConfigureAwait(false);
if (readCount == 0)
break;
fullBuffer = ArrayConcat(fullBuffer, buffer, readCount);
Expand All @@ -233,7 +233,7 @@ private static string ParseFileName(HttpWebResponse resp) {
var filename = header.FileName;
if (header.Parameters.ContainsKey("filename*")) {
filename = header.Parameters["filename*"];
if (filename.Safe().StartsWith("UTF-8''"))
if (filename.Safe().StartsWith("UTF-8''", StringComparison.OrdinalIgnoreCase))
return WebUtility.UrlDecode(filename![7..]);
}
return filename.WithDefault("?");
Expand Down
Loading

0 comments on commit 27678c5

Please sign in to comment.