diff --git a/PrestoClient/Interfaces/IPrestoClient.cs b/PrestoClient/Interfaces/IPrestoClient.cs index cf0bb22..ef3bfd8 100644 --- a/PrestoClient/Interfaces/IPrestoClient.cs +++ b/PrestoClient/Interfaces/IPrestoClient.cs @@ -4,6 +4,7 @@ using BAMCIS.PrestoClient.Model.SPI; using BAMCIS.PrestoClient.Model.Statement; using BAMCIS.PrestoClient.Model.Thread; +using System.Threading; using System.Threading.Tasks; namespace BAMCIS.PrestoClient.Interfaces @@ -16,77 +17,167 @@ public interface IPrestoClient #region Threads /// - /// Lists thread details + /// Gets information about the in use threads in the cluster. /// - /// Details about each thread + /// + /// Information about all of the threads and their state. + /// Task ListThreads(); /// - /// Retrieves the web ui HTML page for thread stats + /// Gets information about the in use threads in the cluster. /// - /// + /// The cancellation token to cancel operation. + /// + /// Information about all of the threads and their state. + /// + Task ListThreads(CancellationToken cancellationToken); + + /// + /// Gets the web ui html that displays information about the threads + /// in the cluster and optionally opens that web page. + /// + /// The web page html/javascript/css. Task GetThreadUIHtml(); + /// + /// Gets the web ui html that displays information about the threads + /// in the cluster and optionally opens that web page. + /// + /// The cancellation token to cancel operation. + /// The web page html/javascript/css. + Task GetThreadUIHtml(CancellationToken cancellationToken); + #endregion #region Nodes /// - /// Gets a list of worker nodes + /// Gets the worker nodes in a presto cluster /// - /// The worker nodes + /// + /// Information about all of the worker nodes. If the request is unsuccessful, + /// a PrestoException is thrown. + /// Task ListNodes(); /// - /// Gets a list of failed worker nodes + /// Gets the worker nodes in a presto cluster /// - /// The list of failed worker nodes + /// The cancellation token to cancel operation. + /// + /// Information about all of the worker nodes. If the request is unsuccessful, + /// a PrestoException is thrown. + /// + Task ListNodes(CancellationToken cancellationToken); + + /// + /// Gets any failed nodes in a presto cluster. + /// + /// + /// Information about the failed nodes. If there are no failed nodes, + /// the FailedNodes property will be null. + /// Task ListFailedNodes(); + /// + /// Gets any failed nodes in a presto cluster. + /// + /// The cancellation token to cancel operation. + /// + /// Information about the failed nodes. If there are no failed nodes, + /// the FailedNodes property will be null. + /// + Task ListFailedNodes(CancellationToken cancellationToken); + #endregion #region Query /// - /// Kills a specified query + /// Kills an active query statement /// - /// The id of the query - /// + /// The id of the query to kill + /// No value is returned, but the method will throw an exception if it was not successful Task KillQuery(string queryId); /// - /// Gets basic query details about all queries that have not been purged + /// Kills an active query statement + /// + /// The Id of the query to kill + /// The cancellation token to cancel operation. + /// No value is returned, but the method will throw an exception if it was not successful + Task KillQuery(string queryId, CancellationToken cancellationToken); + + /// + /// This method returns information and statistics about queries that + /// are currently being executed on a Presto coordinator that have not been purged /// /// Details on the queries Task GetQueries(); + /// + /// This method returns information and statistics about queries that + /// are currently being executed on a Presto coordinator that have not been purged + /// + /// The cancellation token to cancel operation. + /// Details on the queries + Task GetQueries(CancellationToken cancellationToken); + /// /// Gets a detailed summary of the specified query /// - /// The id of the query + /// The id of the query to retrieve details about. /// Detailed summary of the query Task GetQuery(string queryId); /// /// Gets a detailed summary of the specified query /// - /// The id of the query + /// The id of the query to retrieve details about. + /// The cancellation token to cancel operation. + /// Detailed summary of the query + Task GetQuery(string queryId, CancellationToken CancellationToken); + + /// + /// Gets a detailed summary of the specified query + /// + /// The id of the query to retrieve details about. /// Detailed summary of the query Task GetQuery(QueryId queryId); + /// + /// Gets a detailed summary of the specified query + /// + /// The id of the query to retrieve details about. + /// The cancellation token to cancel operation. + /// Detailed summary of the query + Task GetQuery(QueryId queryId, CancellationToken cancellationToken); + #endregion #region Statements /// - /// Executes a Presto SQL statement + /// Submits a Presto SQL statement for execution. The Presto client + /// executes queries on behalf of a user against a catalog and a schema. /// - /// The request details - /// The response from the statement + /// The query execution request. + /// The resulting response object from the query. Task ExecuteQueryV1(ExecuteQueryV1Request request); + /// + /// Submits a Presto SQL statement for execution. The Presto client + /// executes queries on behalf of a user against a catalog and a schema. + /// + /// The query execution request. + /// The cancellation token to cancel operation. + /// The resulting response object from the query. + Task ExecuteQueryV1(ExecuteQueryV1Request request, CancellationToken cancellationToken); + // Not yet available as of Presto 0.198 // Task> ExecuteQueryV2(ExecuteQueryV2Request request); + // Task> ExecuteQueryV2(ExecuteQueryV2Request request, CancellationToken cancellationToken); #endregion @@ -99,6 +190,14 @@ public interface IPrestoClient /// Details about the specified Jmx Mbean Task GetJmxMbean(JmxMbeanV1Request request); + /// + /// Gets details about a specified Jmx Mbean + /// + /// The request details + /// The cancellation token to cancel operation. + /// Details about the specified Jmx Mbean + Task GetJmxMbean(JmxMbeanV1Request request, CancellationToken cancellationToken); + #endregion } } \ No newline at end of file diff --git a/PrestoClient/Model/Statement/ResponseHeaderCollection.cs b/PrestoClient/Model/Statement/ResponseHeaderCollection.cs index 6adc60f..dd25612 100644 --- a/PrestoClient/Model/Statement/ResponseHeaderCollection.cs +++ b/PrestoClient/Model/Statement/ResponseHeaderCollection.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net; using System.Net.Http.Headers; -using System.Web; namespace BAMCIS.PrestoClient.Model.Statement { @@ -86,14 +86,14 @@ public ResponseHeaderCollection(HttpResponseHeaders headers) continue; } - AddedPrepare.Add(HttpUtility.UrlDecode(Parts[0]), HttpUtility.UrlDecode(Parts[1])); + AddedPrepare.Add(WebUtility.UrlDecode(Parts[0]), WebUtility.UrlDecode(Parts[1])); } } // Get the deallocated prepared statements if (headers.TryGetValues(PrestoHeader.PRESTO_DEALLOCATED_PREPARE.Value, out Temp)) { - this.DeallocatedPreparedStatements = new HashSet(Temp.Select(x => HttpUtility.UrlDecode(x))); + this.DeallocatedPreparedStatements = new HashSet(Temp.Select(x => WebUtility.UrlDecode(x))); } else { diff --git a/PrestoClient/PrestoClient.csproj b/PrestoClient/PrestoClient.csproj index bb1a746..9d6f005 100644 --- a/PrestoClient/PrestoClient.csproj +++ b/PrestoClient/PrestoClient.csproj @@ -1,14 +1,14 @@ - + - netstandard2.0 + netstandard2.0;net461 PrestoClient BAMCIS.PrestoClient - 0.198.2 + 0.198.4-beta Michael Haken bamcis.io This is a presto db .NET client for Presto version 0.198. - 2018 BAMCIS + 2021 bamcis.io https://github.com/bamcis-io/PrestoClient true true @@ -16,13 +16,32 @@ https://github.com/bamcis-io/PrestoClient Git A .NET Core client for Presto. - https://github.com/bamcis-io/PrestoClient/blob/master/LICENSE - 0.198.2.0 + + 0.198.4.0 + true + prestoclient.snk + MIT - - + + + + + + + + + + + + <_Parameter1>DynamicProxyGenAssembly2,PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7 + + + <_Parameter1> + $(AssemblyName).Tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100055a653391531f8cac53f14cba9d262efc5f847873a45dcec35b3c5fc9b80295da9562eb92186acbae0aec962e19e87932fc2177c8eb808edcf8842fd23266a2f49e010cbf0b58beea5b113004642d6140bd6d3368338f222f4ebf100c0d902aea019d6dded20011bd38617493ea2ee5e49da8cae15a4be231bb9a6670e997be + + diff --git a/PrestoClient/PrestoClientSessionConfig.cs b/PrestoClient/PrestoClientSessionConfig.cs index 3e41553..50533f5 100644 --- a/PrestoClient/PrestoClientSessionConfig.cs +++ b/PrestoClient/PrestoClientSessionConfig.cs @@ -87,6 +87,11 @@ public string User } } + /// + /// The password to use in HTTP basic auth with the presto server + /// + public string Password { get; set; } + /// /// The catalog to use for interaction with presto. /// diff --git a/PrestoClient/PrestodbClient.cs b/PrestoClient/PrestodbClient.cs index dd5db03..3196c9a 100644 --- a/PrestoClient/PrestodbClient.cs +++ b/PrestoClient/PrestodbClient.cs @@ -19,7 +19,6 @@ using System.Threading; using System.Threading.Tasks; using System.Diagnostics; -using System.Web; using BAMCIS.PrestoClient.Model.NodeInfo; using BAMCIS.PrestoClient.Model.SPI; @@ -136,6 +135,18 @@ public PrestodbClient(PrestoClientSessionConfig config) /// Information about all of the threads and their state. /// public async Task ListThreads() + { + return await ListThreads(CancellationToken.None); + } + + /// + /// Gets information about the in use threads in the cluster. + /// + /// The cancellation token to cancel operation. + /// + /// Information about all of the threads and their state. + /// + public async Task ListThreads(CancellationToken cancellationToken) { HttpClient LocalClient = (this.Configuration.IgnoreSslErrors) ? this.IgnoreSslErrorClient : this.NormalClient; @@ -143,7 +154,7 @@ public async Task ListThreads() HttpRequestMessage Request = this.BuildRequest(Path, HttpMethod.Get); - HttpResponseMessage Response = await LocalClient.SendAsync(Request); + HttpResponseMessage Response = await LocalClient.SendAsync(Request,cancellationToken); string Json = await Response.Content.ReadAsStringAsync(); @@ -165,6 +176,17 @@ public async Task ListThreads() /// /// The web page html/javascript/css. public async Task GetThreadUIHtml() + { + return await GetThreadUIHtml(CancellationToken.None); + } + + /// + /// Gets the web ui html that displays information about the threads + /// in the cluster and optionally opens that web page. + /// + /// The cancellation token to cancel operation. + /// The web page html/javascript/css. + public async Task GetThreadUIHtml(CancellationToken cancellationToken) { HttpClient LocalClient = (this.Configuration.IgnoreSslErrors) ? this.IgnoreSslErrorClient : this.NormalClient; @@ -183,7 +205,7 @@ public async Task GetThreadUIHtml() Uri Path = new Uri(SB.ToString()); - HttpResponseMessage Response = await LocalClient.GetAsync(Path); + HttpResponseMessage Response = await LocalClient.GetAsync(Path, cancellationToken); string Html = await Response.Content.ReadAsStringAsync(); @@ -209,6 +231,19 @@ public async Task GetThreadUIHtml() /// a PrestoException is thrown. /// public async Task ListNodes() + { + return await ListNodes(CancellationToken.None); + } + + /// + /// Gets the worker nodes in a presto cluster + /// + /// The cancellation token to cancel operation. + /// + /// Information about all of the worker nodes. If the request is unsuccessful, + /// a PrestoException is thrown. + /// + public async Task ListNodes(CancellationToken cancellationToken) { HttpClient LocalClient = (this.Configuration.IgnoreSslErrors) ? this.IgnoreSslErrorClient : this.NormalClient; @@ -216,7 +251,7 @@ public async Task ListNodes() HttpRequestMessage Request = this.BuildRequest(Path, HttpMethod.Get); - HttpResponseMessage Response = await LocalClient.SendAsync(Request); + HttpResponseMessage Response = await LocalClient.SendAsync(Request, cancellationToken); string Json = await Response.Content.ReadAsStringAsync(); @@ -286,6 +321,19 @@ public async Task ListNodes() /// the FailedNodes property will be null. /// public async Task ListFailedNodes() + { + return await ListFailedNodes(CancellationToken.None); + } + + /// + /// Gets any failed nodes in a presto cluster. + /// + /// The cancellation token to cancel operation. + /// + /// Information about the failed nodes. If there are no failed nodes, + /// the FailedNodes property will be null. + /// + public async Task ListFailedNodes(CancellationToken cancellationToken) { HttpClient LocalClient = (this.Configuration.IgnoreSslErrors) ? this.IgnoreSslErrorClient : this.NormalClient; @@ -304,7 +352,7 @@ public async Task ListFailedNodes() Uri Path = new Uri(SB.ToString()); - HttpResponseMessage Response = await LocalClient.GetAsync(Path); + HttpResponseMessage Response = await LocalClient.GetAsync(Path, cancellationToken); string Json = await Response.Content.ReadAsStringAsync(); @@ -357,10 +405,20 @@ public async Task ListFailedNodes() /// /// Kills an active query statement /// - /// The Id of the query to kill - /// The header options to supply with the request to kill the query + /// The id of the query to kill /// No value is returned, but the method will throw an exception if it was not successful public async Task KillQuery(string queryId) + { + await KillQuery(queryId, CancellationToken.None); + } + + /// + /// Kills an active query statement + /// + /// The Id of the query to kill + /// The cancellation token to cancel operation. + /// No value is returned, but the method will throw an exception if it was not successful + public async Task KillQuery(string queryId, CancellationToken cancellationToken) { HttpClient localClient = (this.Configuration.IgnoreSslErrors) ? this.IgnoreSslErrorClient : this.NormalClient; @@ -368,7 +426,7 @@ public async Task KillQuery(string queryId) HttpRequestMessage Request = this.BuildRequest(Path, HttpMethod.Delete); - HttpResponseMessage Response = await localClient.SendAsync(Request); + HttpResponseMessage Response = await localClient.SendAsync(Request, cancellationToken); // Expect a 204 response if (Response.StatusCode != HttpStatusCode.NoContent) @@ -378,11 +436,22 @@ public async Task KillQuery(string queryId) } /// - /// This service returns information and statistics about queries that - /// are currently being executed on a Presto coordinator. + /// This method returns information and statistics about queries that + /// are currently being executed on a Presto coordinator that have not been purged /// - /// + /// Details on the queries public async Task GetQueries() + { + return await GetQueries(CancellationToken.None); + } + + /// + /// This method returns information and statistics about queries that + /// are currently being executed on a Presto coordinator that have not been purged + /// + /// The cancellation token to cancel operation. + /// Details on the queries + public async Task GetQueries(CancellationToken cancellationToken) { HttpClient LocalClient = (this.Configuration.IgnoreSslErrors) ? this.IgnoreSslErrorClient : this.NormalClient; @@ -390,7 +459,7 @@ public async Task GetQueries() HttpRequestMessage Request = this.BuildRequest(Path, HttpMethod.Get); - HttpResponseMessage Response = await LocalClient.SendAsync(Request); + HttpResponseMessage Response = await LocalClient.SendAsync(Request, cancellationToken); // Expect a 200 response if (Response.StatusCode != HttpStatusCode.OK) @@ -405,12 +474,22 @@ public async Task GetQueries() } /// - /// If you are looking to gather very detailed statistics about a - /// query, this is the service you would call. + /// Gets a detailed summary of the specified query /// /// The id of the query to retrieve details about. - /// Information about the specified query. + /// Detailed summary of the query public async Task GetQuery(string queryId) + { + return await GetQuery(queryId, CancellationToken.None); + } + + /// + /// Gets a detailed summary of the specified query + /// + /// The id of the query to retrieve details about. + /// The cancellation token to cancel operation. + /// Detailed summary of the query + public async Task GetQuery(string queryId, CancellationToken CancellationToken) { HttpClient LocalClient = (this.Configuration.IgnoreSslErrors) ? this.IgnoreSslErrorClient : this.NormalClient; @@ -418,7 +497,7 @@ public async Task GetQuery(string queryId) HttpRequestMessage Request = this.BuildRequest(Path, HttpMethod.Get); - HttpResponseMessage Response = await LocalClient.GetAsync(Path); + HttpResponseMessage Response = await LocalClient.GetAsync(Path, CancellationToken); // Expect a 200 response if (Response.StatusCode != HttpStatusCode.OK) @@ -433,14 +512,24 @@ public async Task GetQuery(string queryId) } /// - /// If you are looking to gather very detailed statistics about a - /// query, this is the service you would call. + /// Gets a detailed summary of the specified query /// /// The id of the query to retrieve details about. - /// Information about the specified query. + /// Detailed summary of the query public async Task GetQuery(QueryId queryId) { - return await this.GetQuery(queryId.ToString()); + return await GetQuery(queryId, CancellationToken.None); + } + + /// + /// Gets a detailed summary of the specified query + /// + /// The id of the query to retrieve details about. + /// The cancellation token to cancel operation. + /// Detailed summary of the query + public async Task GetQuery(QueryId queryId, CancellationToken cancellationToken) + { + return await this.GetQuery(queryId.ToString(), cancellationToken); } #endregion @@ -448,12 +537,24 @@ public async Task GetQuery(QueryId queryId) #region Statements /// - /// Submits a statement to Presto for execution. The Presto client + /// Submits a Presto SQL statement for execution. The Presto client + /// executes queries on behalf of a user against a catalog and a schema. + /// + /// The query execution request. + /// The resulting response object from the query. + public virtual async Task ExecuteQueryV1(ExecuteQueryV1Request request) + { + return await ExecuteQueryV1(request, CancellationToken.None); + } + + /// + /// Submits a Presto SQL statement for execution. The Presto client /// executes queries on behalf of a user against a catalog and a schema. /// /// The query execution request. + /// The cancellation token to cancel operation. /// The resulting response object from the query. - public async Task ExecuteQueryV1(ExecuteQueryV1Request request) + public async Task ExecuteQueryV1(ExecuteQueryV1Request request, CancellationToken cancellationToken) { // Check the required configuration items before running the query if (!CheckConfiguration(out Exception Ex)) @@ -486,7 +587,7 @@ public async Task ExecuteQueryV1(ExecuteQueryV1Request r // This is the original submission result, will contain the nextUri // property to follow in order to get the results - HttpResponseMessage ResponseMessage = await this.MakeHttpRequest(LocalClient, Request); + HttpResponseMessage ResponseMessage = await this.MakeHttpRequest(LocalClient, Request, cancellationToken: cancellationToken); // This doesn't really do anything but evaluate the headers right now this.ProcessResponseHeaders(ResponseMessage); @@ -539,7 +640,7 @@ public async Task ExecuteQueryV1(ExecuteQueryV1Request r // the MakeRequest method will throw an exception Request = BuildRequest(Path, HttpMethod.Get); - ResponseMessage = await this.MakeHttpRequest(LocalClient, Request); + ResponseMessage = await this.MakeHttpRequest(LocalClient, Request, cancellationToken: cancellationToken); this.ProcessResponseHeaders(ResponseMessage); @@ -568,7 +669,7 @@ public async Task ExecuteQueryV1(ExecuteQueryV1Request r bool Closed = false; // Explicitly closes the query - ResponseMessage = await LocalClient.SendAsync(new HttpRequestMessage(HttpMethod.Delete, LastUri)); + ResponseMessage = await LocalClient.SendAsync(new HttpRequestMessage(HttpMethod.Delete, LastUri), cancellationToken); // If a 204 is not returned, the query was not successfully closed if (ResponseMessage.StatusCode == HttpStatusCode.NoContent) @@ -591,7 +692,6 @@ public async Task ExecuteQueryV1(ExecuteQueryV1Request r } } - /// /// This API is not yet available in Presto as of version 0.197 /// Submits a statement to Presto for execution. The Presto client @@ -603,6 +703,22 @@ public async Task ExecuteQueryV1(ExecuteQueryV1Request r /// retrieved from the data uris. /// private async Task> ExecuteQueryV2(ExecuteQueryV2Request request) + { + return await ExecuteQueryV2(request, CancellationToken.None); + } + + /// + /// This API is not yet available in Presto as of version 0.197 + /// Submits a statement to Presto for execution. The Presto client + /// executes queries on behalf of a user against a catalog and a schema. + /// + /// The query execution request + /// The cancellation token to cancel operation. + /// + /// The final query response object where NextUri was null with all of the data + /// retrieved from the data uris. + /// + private async Task> ExecuteQueryV2(ExecuteQueryV2Request request, CancellationToken cancellationToken) { #region Standard Stuff @@ -661,7 +777,7 @@ private async Task> ExecuteQueryV2(ExecuteQ Request = new HttpRequestMessage(HttpMethod.Get, NextUri); } - HttpResponseMessage Response = await this.MakeHttpRequest(LocalClient, Request); + HttpResponseMessage Response = await this.MakeHttpRequest(LocalClient, Request, cancellationToken: cancellationToken); string raw = await Response.Content.ReadAsStringAsync(); @@ -688,7 +804,7 @@ private async Task> ExecuteQueryV2(ExecuteQ while (NextDataUri != null) { HttpRequestMessage DataRequest = new HttpRequestMessage(HttpMethod.Get, NextDataUri); - HttpResponseMessage DataResponse = await LocalClient.SendAsync(DataRequest); + HttpResponseMessage DataResponse = await LocalClient.SendAsync(DataRequest, cancellationToken); GetDataV2Response DataItem = JsonConvert.DeserializeObject(await DataResponse.Content.ReadAsStringAsync()); foreach (List Row in DataItem.Data) @@ -727,7 +843,7 @@ private async Task> ExecuteQueryV2(ExecuteQ QueryResponse.Response.Data = DataRows.ToList(); // Explicitly closes the query - HttpResponseMessage ClosureResponse = await LocalClient.SendAsync(new HttpRequestMessage(HttpMethod.Delete, LastUri)); + HttpResponseMessage ClosureResponse = await LocalClient.SendAsync(new HttpRequestMessage(HttpMethod.Delete, LastUri), cancellationToken); // If a 204 is not returned, the query was not successfully closed if (ClosureResponse.StatusCode == HttpStatusCode.NoContent) @@ -742,7 +858,23 @@ private async Task> ExecuteQueryV2(ExecuteQ #region JMX + /// + /// Gets details about a specified Jmx Mbean + /// + /// The request details + /// Details about the specified Jmx Mbean public async Task GetJmxMbean(JmxMbeanV1Request request) + { + return await GetJmxMbean(request, CancellationToken.None); + } + + /// + /// Gets details about a specified Jmx Mbean + /// + /// The request details + /// The cancellation token to cancel operation. + /// Details about the specified Jmx Mbean + public async Task GetJmxMbean(JmxMbeanV1Request request, CancellationToken cancellationToken) { // Check the required configuration items before running the query if (!CheckConfiguration(out Exception Ex)) @@ -757,7 +889,7 @@ public async Task GetJmxMbean(JmxMbeanV1Request request) HttpRequestMessage Request = this.BuildRequest(Path, HttpMethod.Get); // Submit the request for details on the requested object name - HttpResponseMessage Response = await this.MakeHttpRequest(Request); + HttpResponseMessage Response = await this.MakeHttpRequest(Request, cancellationToken); if (Response.StatusCode != HttpStatusCode.OK) { @@ -782,37 +914,40 @@ public async Task GetJmxMbean(JmxMbeanV1Request request) /// /// The http client to use to make the request. /// The request to send. + /// The cancellation token to cancel operation. /// The maximum number of times the method will try to contact the server /// if a service unavailable response code is returned. /// The http response message from the request. - private async Task MakeHttpRequest(HttpRequestMessage request, uint maxRetries = 5) + private async Task MakeHttpRequest(HttpRequestMessage request, CancellationToken cancellationToken, uint maxRetries = 5) { - return await this.MakeHttpRequest(this.Configuration.IgnoreSslErrors ? this.IgnoreSslErrorClient : this.NormalClient, request, maxRetries); + return await this.MakeHttpRequest(this.Configuration.IgnoreSslErrors ? this.IgnoreSslErrorClient : this.NormalClient, request, cancellationToken, maxRetries); } + /// /// Makes a request with the provided client and request message and /// returns the response message /// /// The http client to use to make the request. /// The request to send. + /// The cancellation token to cancel operation. /// The maximum number of times the method will try to contact the server /// if a service unavailable response code is returned. /// The http response message from the request. - private async Task MakeHttpRequest(HttpClient client, HttpRequestMessage request, uint maxRetries = 5) + private async Task MakeHttpRequest(HttpClient client, HttpRequestMessage request, CancellationToken cancellationToken, uint maxRetries = 5) { - HttpResponseMessage Response = null; + HttpResponseMessage response = null; uint Counter = 0; while (Counter < maxRetries) { - Response = await client.SendAsync(request); + response = await client.SendAsync(request, cancellationToken); - switch (Response.StatusCode) + switch (response.StatusCode) { case HttpStatusCode.OK: { - return Response; + return response; } case HttpStatusCode.ServiceUnavailable: { @@ -827,13 +962,13 @@ private async Task MakeHttpRequest(HttpClient client, HttpR } default: { - throw new PrestoWebException($"The request to {request.RequestUri} failed, message:{await Response.Content.ReadAsStringAsync()}", Response.StatusCode); + throw new PrestoWebException($"The request to {request.RequestUri} failed, message:{await response.Content.ReadAsStringAsync()}", response.StatusCode); } } } // This will only be reached if the while loop exits - throw new PrestoWebException($"The maximum number of retries, {maxRetries}, for path {request.RequestUri} was exceeded.", Response.StatusCode); + throw new PrestoWebException($"The maximum number of retries, {maxRetries}, for path {request.RequestUri} was exceeded.", response.StatusCode); } /// @@ -1024,7 +1159,7 @@ private void BuildQueryHeaders(ref HttpRequestMessage request, QueryOptions opti { foreach (KeyValuePair Statement in PreparedStatements) { - request.Headers.Add(PrestoHeader.PRESTO_PREPARED_STATEMENT.Value, $"{HttpUtility.UrlDecode(Statement.Key)}={HttpUtility.UrlDecode(Statement.Value)}"); + request.Headers.Add(PrestoHeader.PRESTO_PREPARED_STATEMENT.Value, $"{WebUtility.UrlDecode(Statement.Key)}={WebUtility.UrlDecode(Statement.Value)}"); } } @@ -1055,23 +1190,28 @@ private string GetVersionString(PrestoApiVersion version) /// private HttpRequestMessage BuildRequest(Uri url, HttpMethod method, HttpContent content = null) { - HttpRequestMessage Request = new HttpRequestMessage(method, url); + HttpRequestMessage request = new HttpRequestMessage(method, url); if (content != null) { - Request.Content = content; + request.Content = content; } - Request.Headers.Add("Accept", "application/json"); - Request.Headers.Add("User-Agent", $"bamcis_presto_dotnet_core_sdk/{AssemblyVersion}"); - Request.Headers.Add(PrestoHeader.PRESTO_SOURCE.Value, "bamcis_presto_dotnet_core_sdk"); + request.Headers.Add("Accept", "application/json"); + request.Headers.Add("User-Agent", $"bamcis_presto_dotnet_core_sdk/{AssemblyVersion}"); + request.Headers.Add(PrestoHeader.PRESTO_SOURCE.Value, "bamcis_presto_dotnet_core_sdk"); if (!String.IsNullOrEmpty(this.Configuration.User)) { - Request.Headers.Add(PrestoHeader.PRESTO_USER.Value, this.Configuration.User); + request.Headers.Add(PrestoHeader.PRESTO_USER.Value, this.Configuration.User.Replace(":", "")); + + if (!String.IsNullOrEmpty(this.Configuration.Password)) + { + request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{this.Configuration.User.Replace(":", "")}:{this.Configuration.Password}"))); + } } - return Request; + return request; } /// diff --git a/PrestoClient/prestoclient.snk b/PrestoClient/prestoclient.snk new file mode 100644 index 0000000..f5dfe1e Binary files /dev/null and b/PrestoClient/prestoclient.snk differ diff --git a/PrestoClientTests/PrestoClient.Tests.csproj b/PrestoClientTests/PrestoClient.Tests.csproj index 8060025..9145b5f 100644 --- a/PrestoClientTests/PrestoClient.Tests.csproj +++ b/PrestoClientTests/PrestoClient.Tests.csproj @@ -1,15 +1,23 @@ - netcoreapp2.0 + netcoreapp3.1 false + + true + + prestoclient.tests.snk - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/PrestoClientTests/PrestoClientDriver.cs b/PrestoClientTests/PrestoClientDriver.cs index f781f02..7737a24 100644 --- a/PrestoClientTests/PrestoClientDriver.cs +++ b/PrestoClientTests/PrestoClientDriver.cs @@ -19,6 +19,31 @@ public class PrestoClientDriver public PrestoClientDriver() { } + [Fact] + public async Task TestPassword() + { + // ARRANGE + PrestoClientSessionConfig config = new PrestoClientSessionConfig() + { + Host = "localhost", + Port = 8080, + Password = "password1!2@3#4$AA" + }; + + IPrestoClient client = new PrestodbClient(config); + + // ACT + ExecuteQueryV1Request req = new ExecuteQueryV1Request($"CREATE SCHEMA IF NOT EXISTS hive.{Schema}"); + + //mock.Verify(x => x.ExecuteQueryV1(captor.Capture())); + //req. + + ExecuteQueryV1Response res = await client.ExecuteQueryV1(req); + + // ASSERT + Assert.NotNull(res); + } + [Fact] public async Task CreateSchema() { diff --git a/PrestoClientTests/prestoclient.tests.snk b/PrestoClientTests/prestoclient.tests.snk new file mode 100644 index 0000000..f51e23f Binary files /dev/null and b/PrestoClientTests/prestoclient.tests.snk differ diff --git a/README.md b/README.md index 236ceee..55c84fd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# BAMCIS PrestoClient - A Prestodb .NET Client +# bamcis.io PrestoClient - A Prestodb .NET Client ## Usage @@ -8,24 +8,30 @@ This demonstrates creating a new client config, initializing an IPrestoClient, a returned data can be formatted in CSV or JSON. Additionally, all of the raw data is returned from the server in case the deserialization process fails in .NET, the user can still access and manipulate the returned data. - PrestoClientSessionConfig Config = new PrestoClientSessionConfig("hive", "cars") - { - Host = "localhost", - Port = 8080 - ) - ; - IPrestoClient Client = new PrestodbClient(Config); +```csharp +PrestoClientSessionConfig config = new PrestoClientSessionConfig("hive", "cars") +{ + Host = "localhost", + Port = 8080 +}; - ExecuteQueryV1Request Request = new ExecuteQueryV1Request("select * from tracklets limit 5;"); +IPrestoClient client = new PrestodbClient(config); +ExecuteQueryV1Request request = new ExecuteQueryV1Request("select * from tracklets limit 5;"); +ExecuteQueryV1Response queryResponse = await client.ExecuteQueryV1(request); - ExecuteQueryV1Response QueryResponse = await Client.ExecuteQueryV1(Request); - - Console.WriteLine(String.Join("\n", QueryResponse.Response.DataToCsv())); - Console.WriteLine("-------------------------------------------------------------------"); - Console.WriteLine(String.Join("\n", QueryResponse.Response.DataToJson())); +Console.WriteLine(String.Join("\n", queryResponse.Response.DataToCsv())); +Console.WriteLine("-------------------------------------------------------------------"); +Console.WriteLine(String.Join("\n", queryResponse.Response.DataToJson())); +``` ## Revision History +### 0.198.4-beta +Added `CancellationToken` support to all client methods. + +### 0.198.3-beta +Added username/password auth to client. + ### 0.198.2 Removed unused classes and allow null/empty values for `Catalog` and `Schema` in `PrestoClientSessionConfig`.