using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Mime; using System.Security.Authentication; using System.Text; using System.Threading.Tasks; using System.Web; using FarmmapsApi.Models; using IdentityModel; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace FarmmapsApi.Services { public class FarmmapsApiService { private readonly HttpClient _httpClient; private readonly OpenIdConnectService _openIdConnectService; private readonly Configuration _configuration; private HubConnection _hubConnection; public event Action EventCallback; public FarmmapsApiService(HttpClient httpClient, OpenIdConnectService openIdConnectService, Configuration configuration) { _httpClient = httpClient; _openIdConnectService = openIdConnectService; _configuration = configuration; _httpClient.BaseAddress = new Uri(configuration.Endpoint); _httpClient.DefaultRequestHeaders.Add("Accept", MediaTypeNames.Application.Json); } public async Task AuthenticateAsync() { if (_httpClient.DefaultRequestHeaders.Authorization != null && _httpClient.DefaultRequestHeaders.Authorization.Scheme != OidcConstants.AuthenticationSchemes.AuthorizationHeaderBearer) throw new AuthenticationException("Already seems to be authenticated"); var disco = await _openIdConnectService.GetDiscoveryDocumentAsync(); var token = await _openIdConnectService.GetTokenClientCredentialsAsync(disco.TokenEndpoint, _configuration.ClientId, _configuration.ClientSecret); if (token.IsError) throw new AuthenticationException(token.Error); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(OidcConstants.AuthenticationSchemes.AuthorizationHeaderBearer, token.AccessToken); await StartEventHub(token.AccessToken); } private async Task StartEventHub(string accessToken) { var uri = new Uri(_configuration.Endpoint); var eventEndpoint = $"{uri.Scheme}://{uri.Host}:{uri.Port}/EventHub"; _hubConnection = new HubConnectionBuilder() .WithUrl(eventEndpoint) .WithAutomaticReconnect() .AddJsonProtocol() .Build(); _hubConnection.On("Event", (EventMessage @event) => EventCallback?.Invoke(@event)); await _hubConnection.StartAsync(); await _hubConnection.SendAsync("authenticate", accessToken); } public async Task GetCurrentUserCodeAsync() { var response = await _httpClient.GetAsync(ResourceEndpoints.CURRENTUSER_RESOURCE); if (!response.IsSuccessStatusCode) throw new Exception(response.ReasonPhrase); var jsonString = await response.Content.ReadAsStringAsync(); var json = JsonConvert.DeserializeObject(jsonString); return json["code"].Value(); } public async Task> GetCurrentUserRootsAsync() { var response = await _httpClient.GetAsync(ResourceEndpoints.MYROOTS_RESOURCE); if (!response.IsSuccessStatusCode) throw new Exception(response.ReasonPhrase); var jsonString = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject>(jsonString); } public async Task GetItemAsync(string itemCode, string itemType = null, JObject dataFilter = null) { if (dataFilter == null) return await GetItemSingleAsync(itemCode, itemType); var items = await GetItemsAsync(itemCode, itemType, dataFilter); return items[0]; } public async Task> GetItemsAsync(string itemCode, string itemType = null, JObject dataFilter = null) { var resourceUri = string.Format(ResourceEndpoints.ITEMS_RESOURCE, itemCode); var queryString = HttpUtility.ParseQueryString(string.Empty); if(itemType != null) queryString["it"] = itemType; if(dataFilter != null) queryString["df"] = dataFilter.ToString(Formatting.None); resourceUri = (queryString.Count > 0 ? $"{resourceUri}?" : resourceUri) + queryString; var response = await _httpClient.GetAsync(resourceUri); if (!response.IsSuccessStatusCode) { if (response.StatusCode == HttpStatusCode.NotFound) return null; throw new Exception(response.ReasonPhrase); } var jsonString = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject>(jsonString); } private async Task GetItemSingleAsync(string itemCode, string itemType = null) { var resourceUri = string.Format(ResourceEndpoints.ITEMS_RESOURCE, itemCode); if (!string.IsNullOrEmpty(itemType)) resourceUri = $"{resourceUri}/{itemType}"; var response = await _httpClient.GetAsync(resourceUri); if (!response.IsSuccessStatusCode) { if (response.StatusCode == HttpStatusCode.NotFound) return null; throw new Exception(response.ReasonPhrase); } var jsonString = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(jsonString); } public async Task> GetItemChildrenAsync(string itemCode, string itemType = null, JObject dataFilter = null) { var resourceUri = string.Format(ResourceEndpoints.ITEMS_CHILDREN_RESOURCE, itemCode); var queryString = HttpUtility.ParseQueryString(string.Empty); if(itemType != null) queryString["it"] = itemType; if(dataFilter != null) queryString["df"] = dataFilter.ToString(Formatting.None); resourceUri = (queryString.Count > 0 ? $"{resourceUri}?" : resourceUri) + queryString; var response = await _httpClient.GetAsync(resourceUri); if (!response.IsSuccessStatusCode) throw new Exception(response.ReasonPhrase); var jsonString = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject>(jsonString); } public async Task CreateItemAsync(ItemRequest itemRequest) { var jsonString = JsonConvert.SerializeObject(itemRequest); var content = new StringContent(jsonString, Encoding.UTF8,MediaTypeNames.Application.Json); var response = await _httpClient.PostAsync(ResourceEndpoints.ITEMS_CREATE_RESOURCE, content); if (!response.IsSuccessStatusCode) throw new Exception(response.ReasonPhrase); var jsonStringResponse = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(jsonStringResponse); } public async Task DeleteItemAsync(string itemCode) { var resourceUri = string.Format(ResourceEndpoints.ITEMS_RESOURCE, itemCode); var response = await _httpClient.DeleteAsync(resourceUri); if (!response.IsSuccessStatusCode) throw new Exception(response.ReasonPhrase); } public async Task DeleteItemsAsync(IList itemCodes) { var jsonString = JsonConvert.SerializeObject(itemCodes); var content = new StringContent(jsonString); var response = await _httpClient.PostAsync(ResourceEndpoints.ITEMS_DELETE_RESOURCE, content); if (!response.IsSuccessStatusCode) throw new Exception(response.ReasonPhrase); } public async Task DownloadItemAsync(string itemCode, string filePath) { var resourceUri = string.Format(ResourceEndpoints.ITEMS_DOWNLOAD_RESOURCE, itemCode); var response = await _httpClient.GetAsync(resourceUri, HttpCompletionOption.ResponseHeadersRead); if(response.IsSuccessStatusCode) { await using Stream streamToReadFrom = await response.Content.ReadAsStreamAsync(); await using Stream streamToWriteTo = File.Open(filePath, FileMode.Create); await streamToReadFrom.CopyToAsync(streamToWriteTo); } else { throw new FileNotFoundException(response.ReasonPhrase); } } public async Task QueueTaskAsync(string itemCode, TaskRequest taskRequest) { var resourceUri = string.Format(ResourceEndpoints.ITEMTASK_REQUEST_RESOURCE, itemCode); var jsonString = JsonConvert.SerializeObject(taskRequest); var content = new StringContent(jsonString, Encoding.UTF8,MediaTypeNames.Application.Json); var response = await _httpClient.PostAsync(resourceUri, content); if (!response.IsSuccessStatusCode) throw new Exception(response.ReasonPhrase); var jsonStringResponse = await response.Content.ReadAsStringAsync(); var json = JsonConvert.DeserializeObject(jsonStringResponse); return json["code"].Value(); } public async Task> GetTasksStatusAsync(string itemCode) { var resourceUri = string.Format(ResourceEndpoints.ITEMTASKS_RESOURCE, itemCode); var response = await _httpClient.GetAsync(resourceUri); if (!response.IsSuccessStatusCode) throw new Exception(response.ReasonPhrase); var jsonString = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject>(jsonString); } public async Task GetTaskStatusAsync(string itemCode, string itemTaskCode) { var resourceUri = string.Format(ResourceEndpoints.ITEMTASK_RESOURCE, itemCode, itemTaskCode); var response = await _httpClient.GetAsync(resourceUri); if (!response.IsSuccessStatusCode) throw new Exception(response.ReasonPhrase); var jsonString = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(jsonString); } } }