using Microsoft.Extensions.DependencyInjection; using System; using System.Globalization; using System.Linq; using System.Net.Http.Json; using System.Threading; using System.Threading.Tasks; #if NETFRAMEWORK using System.Net.Http; #endif namespace ReC.Client { /// /// A client for interacting with the ReC API. /// public class ReCClient { private readonly HttpClient _http; /// /// A unique name for the HttpClient used by the ReCClient. /// public static readonly string ClientName = Guid.NewGuid().ToString(); /// /// Initializes a new instance of the class. /// /// The factory to create HttpClients. public ReCClient(IHttpClientFactory httpClientFactory) { _http = httpClientFactory.CreateClient(ClientName); } #if NETFRAMEWORK private static string BuildQuery(params (string Key, object Value)[] parameters) #else private static string BuildQuery(params (string Key, object? Value)[] parameters) #endif { var parts = parameters .Where(p => p.Value != null) .Select(p => $"{Uri.EscapeDataString(p.Key)}={Uri.EscapeDataString(Convert.ToString(p.Value, CultureInfo.InvariantCulture) ?? string.Empty)}"); var query = string.Join("&", parts); return string.IsNullOrWhiteSpace(query) ? string.Empty : $"?{query}"; } private static JsonContent ToJsonContent(T payload) => JsonContent.Create(payload); #region RecActionController /// /// Asynchronously invokes a ReC action for a specific profile. /// /// /// This method sends a POST request to the api/RecAction/invoke/{profileId} endpoint. /// /// The ID of the profile to invoke the action for. /// A token to cancel the asynchronous operation. /// A that represents the asynchronous operation. The task result is if the request was successful; otherwise, . public async Task InvokeRecActionAsync(int profileId, CancellationToken cancellationToken = default) { var resp = await _http.PostAsync($"api/RecAction/invoke/{profileId}", content: null, cancellationToken); return resp.IsSuccessStatusCode; } /// /// Asynchronously retrieves a list of ReC actions for the configured profile. /// /// /// This method sends a GET request to the api/RecAction endpoint with optional query parameters. /// /// The ID of the profile to retrieve actions for. If null, actions for all profiles are retrieved. /// Filter for invoked actions. If null, both invoked and not invoked actions are retrieved. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task GetRecActionsAsync(long? profileId = null, bool? invoked = null, CancellationToken cancel = default) { var query = BuildQuery(("ProfileId", profileId), ("Invoked", invoked)); return _http.GetAsync($"api/RecAction{query}", cancel); } /// /// Asynchronously creates a new ReC action. /// /// /// This method sends a POST request to the api/RecAction endpoint with the action data as JSON. /// /// The action data to create. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task CreateRecActionAsync(T procedure, CancellationToken cancel = default) => _http.PostAsync("api/RecAction", ToJsonContent(procedure), cancel); /// /// Asynchronously updates an existing ReC action. /// /// /// This method sends a PUT request to the api/RecAction/{id} endpoint with the updated action data as JSON. /// /// The ID of the action to update. /// The updated action data. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task UpdateRecActionAsync(long id, T procedure, CancellationToken cancel = default) => _http.PutAsync($"api/RecAction/{id}", ToJsonContent(procedure), cancel); /// /// Asynchronously deletes one or more ReC actions. /// /// /// This method sends a DELETE request to the api/RecAction endpoint with the IDs of the actions to delete as JSON. /// /// An object containing the IDs of the actions to delete. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task DeleteRecActionsAsync(T procedure, CancellationToken cancel = default) { var request = new HttpRequestMessage(HttpMethod.Delete, "api/RecAction") { Content = ToJsonContent(procedure) }; return _http.SendAsync(request, cancel); } #endregion #region OutResController /// /// Asynchronously retrieves results for the configured profile. /// /// /// This method sends a GET request to the api/OutRes endpoint with optional query parameters. /// /// Filter by result ID. /// Filter by action ID. /// Filter by profile ID. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task GetResultsAsync(long? id = null, long? actionId = null, long? profileId = null, CancellationToken cancel = default) { var query = BuildQuery(("Id", id), ("ActionId", actionId), ("ProfileId", profileId)); return _http.GetAsync($"api/OutRes{query}", cancel); } /// /// Asynchronously creates a new result. /// /// /// This method sends a POST request to the api/OutRes endpoint with the result data as JSON. /// /// The result data to create. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task CreateResultAsync(T procedure, CancellationToken cancel = default) => _http.PostAsync("api/OutRes", ToJsonContent(procedure), cancel); /// /// Asynchronously updates an existing result. /// /// /// This method sends a PUT request to the api/OutRes/{id} endpoint with the updated result data as JSON. /// /// The ID of the result to update. /// The updated result data. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task UpdateResultAsync(long id, T procedure, CancellationToken cancel = default) => _http.PutAsync($"api/OutRes/{id}", ToJsonContent(procedure), cancel); /// /// Asynchronously deletes one or more results. /// /// /// This method sends a DELETE request to the api/OutRes endpoint with the IDs of the results to delete as JSON. /// /// An object containing the IDs of the results to delete. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task DeleteResultsAsync(T procedure, CancellationToken cancel = default) { var request = new HttpRequestMessage(HttpMethod.Delete, "api/OutRes") { Content = ToJsonContent(procedure) }; return _http.SendAsync(request, cancel); } #endregion #region ProfileController /// /// Asynchronously retrieves a profile by ID. /// /// /// This method sends a GET request to the api/Profile endpoint with the profile ID as a query parameter. /// /// The ID of the profile to retrieve. /// Whether to include associated actions in the response. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task GetProfileAsync(long id, bool includeActions = false, CancellationToken cancel = default) { var query = BuildQuery(("Id", id), ("IncludeActions", includeActions)); return _http.GetAsync($"api/Profile{query}", cancel); } /// /// Asynchronously creates a new profile. /// /// /// This method sends a POST request to the api/Profile endpoint with the profile data as JSON. /// /// The profile data to create. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task CreateProfileAsync(T procedure, CancellationToken cancel = default) => _http.PostAsync("api/Profile", ToJsonContent(procedure), cancel); /// /// Asynchronously updates an existing profile. /// /// /// This method sends a PUT request to the api/Profile/{id} endpoint with the updated profile data as JSON. /// /// The ID of the profile to update. /// The updated profile data. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task UpdateProfileAsync(long id, T procedure, CancellationToken cancel = default) => _http.PutAsync($"api/Profile/{id}", ToJsonContent(procedure), cancel); /// /// Asynchronously deletes one or more profiles. /// /// /// This method sends a DELETE request to the api/Profile endpoint with the IDs of the profiles to delete as JSON. /// /// An object containing the IDs of the profiles to delete. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task DeleteProfilesAsync(T procedure, CancellationToken cancel = default) { var request = new HttpRequestMessage(HttpMethod.Delete, "api/Profile") { Content = ToJsonContent(procedure) }; return _http.SendAsync(request, cancel); } #endregion #region EndpointAuthController /// /// Asynchronously creates a new endpoint authentication. /// /// /// This method sends a POST request to the api/EndpointAuth endpoint with the authentication data as JSON. /// /// The authentication data to create. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task CreateEndpointAuthAsync(T procedure, CancellationToken cancel = default) => _http.PostAsync("api/EndpointAuth", ToJsonContent(procedure), cancel); /// /// Asynchronously updates an existing endpoint authentication. /// /// /// This method sends a PUT request to the api/EndpointAuth/{id} endpoint with the updated authentication data as JSON. /// /// The ID of the authentication to update. /// The updated authentication data. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task UpdateEndpointAuthAsync(long id, T procedure, CancellationToken cancel = default) => _http.PutAsync($"api/EndpointAuth/{id}", ToJsonContent(procedure), cancel); /// /// Asynchronously deletes one or more endpoint authentications. /// /// /// This method sends a DELETE request to the api/EndpointAuth endpoint with the IDs of the authentications to delete as JSON. /// /// An object containing the IDs of the authentications to delete. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task DeleteEndpointAuthAsync(T procedure, CancellationToken cancel = default) { var request = new HttpRequestMessage(HttpMethod.Delete, "api/EndpointAuth") { Content = ToJsonContent(procedure) }; return _http.SendAsync(request, cancel); } #endregion #region EndpointParamsController /// /// Asynchronously creates new endpoint parameters. /// /// /// This method sends a POST request to the api/EndpointParams endpoint with the parameters data as JSON. /// /// The parameters data to create. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task CreateEndpointParamsAsync(T procedure, CancellationToken cancel = default) => _http.PostAsync("api/EndpointParams", ToJsonContent(procedure), cancel); /// /// Asynchronously updates existing endpoint parameters. /// /// /// This method sends a PUT request to the api/EndpointParams/{id} endpoint with the updated parameters data as JSON. /// /// The ID of the parameters to update. /// The updated parameters data. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task UpdateEndpointParamsAsync(long id, T procedure, CancellationToken cancel = default) => _http.PutAsync($"api/EndpointParams/{id}", ToJsonContent(procedure), cancel); /// /// Asynchronously deletes one or more endpoint parameters. /// /// /// This method sends a DELETE request to the api/EndpointParams endpoint with the IDs of the parameters to delete as JSON. /// /// An object containing the IDs of the parameters to delete. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task DeleteEndpointParamsAsync(T procedure, CancellationToken cancel = default) { var request = new HttpRequestMessage(HttpMethod.Delete, "api/EndpointParams") { Content = ToJsonContent(procedure) }; return _http.SendAsync(request, cancel); } #endregion #region EndpointsController /// /// Asynchronously creates a new endpoint. /// /// /// This method sends a POST request to the api/Endpoints endpoint with the endpoint data as JSON. /// /// The endpoint data to create. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task CreateEndpointAsync(T procedure, CancellationToken cancel = default) => _http.PostAsync("api/Endpoints", ToJsonContent(procedure), cancel); /// /// Asynchronously updates an existing endpoint. /// /// /// This method sends a PUT request to the api/Endpoints/{id} endpoint with the updated endpoint data as JSON. /// /// The ID of the endpoint to update. /// The updated endpoint data. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task UpdateEndpointAsync(long id, T procedure, CancellationToken cancel = default) => _http.PutAsync($"api/Endpoints/{id}", ToJsonContent(procedure), cancel); /// /// Asynchronously deletes one or more endpoints. /// /// /// This method sends a DELETE request to the api/Endpoints endpoint with the IDs of the endpoints to delete as JSON. /// /// An object containing the IDs of the endpoints to delete. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task DeleteEndpointAsync(T procedure, CancellationToken cancel = default) { var request = new HttpRequestMessage(HttpMethod.Delete, "api/Endpoints") { Content = ToJsonContent(procedure) }; return _http.SendAsync(request, cancel); } #endregion #region CommonController /// /// Asynchronously creates a new object. /// /// /// This method sends a POST request to the api/Common endpoint with the object data as JSON. /// /// The object data to create. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task CreateObjectAsync(T procedure, CancellationToken cancel = default) => _http.PostAsync("api/Common", ToJsonContent(procedure), cancel); /// /// Asynchronously updates an existing object. /// /// /// This method sends a PUT request to the api/Common endpoint with the updated object data as JSON. /// /// The updated object data. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task UpdateObjectAsync(T procedure, CancellationToken cancel = default) => _http.PutAsync("api/Common", ToJsonContent(procedure), cancel); /// /// Asynchronously deletes one or more objects. /// /// /// This method sends a DELETE request to the api/Common endpoint with the IDs of the objects to delete as JSON. /// /// An object containing the IDs of the objects to delete. /// A token to cancel the asynchronous operation. /// A task representing the asynchronous operation, with a result containing the response data. public Task DeleteObjectAsync(T procedure, CancellationToken cancel = default) { var request = new HttpRequestMessage(HttpMethod.Delete, "api/Common") { Content = ToJsonContent(procedure) }; return _http.SendAsync(request, cancel); } #endregion #region Static private static readonly IServiceCollection Services = new ServiceCollection(); #if NET8_0_OR_GREATER private static IServiceProvider? Provider = null; #else private static IServiceProvider Provider = null; #endif /// /// Configures and builds the static for creating instances. /// /// /// This method should only be called once during application startup. /// /// The base URI of the ReC API. /// Thrown if the static provider has already been built. [Obsolete("Use a local service collection instead of the static provider.")] public static void BuildStaticClient(string apiUri) { if(Provider != null) throw new InvalidOperationException("Static Provider is already built."); Services.AddRecClient(apiUri); Provider = Services.BuildServiceProvider(); } /// /// Configures and builds the static for creating instances. /// /// /// This method should only be called once during application startup. /// /// An action to configure the . /// Thrown if the static provider has already been built. [Obsolete("Use a local service collection instead of the static provider.")] public static void BuildStaticClient(Action configureClient) { if (Provider != null) throw new InvalidOperationException("Static Provider is already built."); Services.AddRecClient(configureClient); Provider = Services.BuildServiceProvider(); } /// /// Creates a new instance using the statically configured provider. /// /// A new instance of the . /// Thrown if has not been called yet. [Obsolete("Use a local service collection instead of the static provider.")] public static ReCClient Create() { if (Provider == null) throw new InvalidOperationException("Static Provider is not built. Call BuildStaticClient first."); return Provider.GetRequiredService(); } #endregion } /// /// Specifies which part of the result to return for result view endpoints. /// public enum ResultType { Full, OnlyHeader, OnlyBody } }