forked from FarmMaps/FarmMapsApiClient
		
	polling for task status.
This commit is contained in:
		@@ -1,4 +1,7 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
using System.Net.Http;
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using FarmmapsApi.HttpMessageHandlers;
 | 
					using FarmmapsApi.HttpMessageHandlers;
 | 
				
			||||||
using FarmmapsApi.Models;
 | 
					using FarmmapsApi.Models;
 | 
				
			||||||
using FarmmapsApi.Services;
 | 
					using FarmmapsApi.Services;
 | 
				
			||||||
@@ -9,7 +12,8 @@ namespace FarmmapsApi
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public static class Extensions
 | 
					    public static class Extensions
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public static IServiceCollection AddFarmmapsServices(this IServiceCollection serviceCollection, Configuration configuration)
 | 
					        public static IServiceCollection AddFarmmapsServices(this IServiceCollection serviceCollection,
 | 
				
			||||||
 | 
					            Configuration configuration)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return serviceCollection
 | 
					            return serviceCollection
 | 
				
			||||||
                .AddSingleton(configuration)
 | 
					                .AddSingleton(configuration)
 | 
				
			||||||
@@ -23,7 +27,26 @@ namespace FarmmapsApi
 | 
				
			|||||||
                .AddTransient<FarmmapsAuthenticationHandler>()
 | 
					                .AddTransient<FarmmapsAuthenticationHandler>()
 | 
				
			||||||
                .AddHttpClient<FarmmapsApiService>()
 | 
					                .AddHttpClient<FarmmapsApiService>()
 | 
				
			||||||
                .AddHttpMessageHandler<FarmmapsAuthenticationHandler>()
 | 
					                .AddHttpMessageHandler<FarmmapsAuthenticationHandler>()
 | 
				
			||||||
                .Services;;
 | 
					                .Services;
 | 
				
			||||||
 | 
					            ;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static async Task PollTask(TimeSpan retryTime, Func<CancellationTokenSource, Task> callback)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var tokenSource = new CancellationTokenSource();
 | 
				
			||||||
 | 
					            var token = tokenSource.Token;
 | 
				
			||||||
 | 
					            do
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    await callback(tokenSource);
 | 
				
			||||||
 | 
					                    await Task.Delay(retryTime, token);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    // ignored
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } while (!token.IsCancellationRequested);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -11,8 +11,9 @@ using System.Threading.Tasks;
 | 
				
			|||||||
using System.Web;
 | 
					using System.Web;
 | 
				
			||||||
using FarmmapsApi.Models;
 | 
					using FarmmapsApi.Models;
 | 
				
			||||||
using IdentityModel;
 | 
					using IdentityModel;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Http.Connections;
 | 
				
			||||||
using Microsoft.AspNetCore.SignalR.Client;
 | 
					using Microsoft.AspNetCore.SignalR.Client;
 | 
				
			||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
using Newtonsoft.Json;
 | 
					using Newtonsoft.Json;
 | 
				
			||||||
using Newtonsoft.Json.Linq;
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,6 +21,7 @@ namespace FarmmapsApi.Services
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class FarmmapsApiService
 | 
					    public class FarmmapsApiService
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ILogger<FarmmapsApiService> _logger;
 | 
				
			||||||
        private readonly HttpClient _httpClient;
 | 
					        private readonly HttpClient _httpClient;
 | 
				
			||||||
        private readonly OpenIdConnectService _openIdConnectService;
 | 
					        private readonly OpenIdConnectService _openIdConnectService;
 | 
				
			||||||
        private readonly Configuration _configuration;
 | 
					        private readonly Configuration _configuration;
 | 
				
			||||||
@@ -28,9 +30,10 @@ namespace FarmmapsApi.Services
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public event Action<EventMessage> EventCallback;
 | 
					        public event Action<EventMessage> EventCallback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public FarmmapsApiService(HttpClient httpClient,
 | 
					        public FarmmapsApiService(HttpClient httpClient, ILogger<FarmmapsApiService> logger,
 | 
				
			||||||
            OpenIdConnectService openIdConnectService, Configuration configuration)
 | 
					            OpenIdConnectService openIdConnectService, Configuration configuration)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            _logger = logger;
 | 
				
			||||||
            _httpClient = httpClient;
 | 
					            _httpClient = httpClient;
 | 
				
			||||||
            _openIdConnectService = openIdConnectService;
 | 
					            _openIdConnectService = openIdConnectService;
 | 
				
			||||||
            _configuration = configuration;
 | 
					            _configuration = configuration;
 | 
				
			||||||
@@ -65,13 +68,21 @@ namespace FarmmapsApi.Services
 | 
				
			|||||||
            var uri = new Uri(_configuration.Endpoint);
 | 
					            var uri = new Uri(_configuration.Endpoint);
 | 
				
			||||||
            var eventEndpoint = $"{uri.Scheme}://{uri.Host}:{uri.Port}/EventHub";
 | 
					            var eventEndpoint = $"{uri.Scheme}://{uri.Host}:{uri.Port}/EventHub";
 | 
				
			||||||
            _hubConnection = new HubConnectionBuilder()
 | 
					            _hubConnection = new HubConnectionBuilder()
 | 
				
			||||||
                .WithUrl(eventEndpoint)
 | 
					                .WithUrl(eventEndpoint, HttpTransportType.WebSockets, 
 | 
				
			||||||
 | 
					                    options => options.SkipNegotiation = true)
 | 
				
			||||||
 | 
					                .ConfigureLogging(log => log.AddConsole())
 | 
				
			||||||
                .WithAutomaticReconnect()
 | 
					                .WithAutomaticReconnect()
 | 
				
			||||||
                .AddJsonProtocol()
 | 
					 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
            _hubConnection.On("Event", (EventMessage @event) => EventCallback?.Invoke(@event));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await _hubConnection.StartAsync();
 | 
					            await _hubConnection.StartAsync();
 | 
				
			||||||
 | 
					            await AuthenticateEventHub(accessToken);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            _hubConnection.Reconnected += async s => await AuthenticateEventHub(accessToken);
 | 
				
			||||||
 | 
					            _hubConnection.On("event", (Object @event) => _logger.LogInformation(@event.ToString()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async Task AuthenticateEventHub(string accessToken)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            await _hubConnection.SendAsync("authenticate", accessToken);
 | 
					            await _hubConnection.SendAsync("authenticate", accessToken);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ using FarmmapsApi.Models;
 | 
				
			|||||||
using FarmmapsApi.Services;
 | 
					using FarmmapsApi.Services;
 | 
				
			||||||
using Microsoft.Extensions.Logging;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
using Newtonsoft.Json.Linq;
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using static FarmmapsApi.Extensions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FarmmapsApiSamples
 | 
					namespace FarmmapsApiSamples
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -44,30 +45,10 @@ namespace FarmmapsApiSamples
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (myDriveRoot != null)
 | 
					                if (myDriveRoot != null)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    // create or get a cropfield
 | 
					                    var cropfieldItem = await GetOrCreateCropfieldItem(myDriveRoot.Code);
 | 
				
			||||||
                    var cropfieldItem = await GetCreateCropfieldItem(myDriveRoot.Code);
 | 
					                    var targetN = await CalculateTargetN(cropfieldItem, 60);
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                    // create or get target n item
 | 
					                    _logger.LogInformation($"TargetN: {targetN}");
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    var targetNItems = await
 | 
					 | 
				
			||||||
                        _farmmapsApiService.GetItemChildrenAsync(myDriveRoot.Code, USERINPUT_ITEMTYPE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    Item targetNItem;
 | 
					 | 
				
			||||||
                    if (targetNItems.Count == 0)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        _logger.LogInformation("Creating targetN item");
 | 
					 | 
				
			||||||
                        var itemRequest = CreateTargetNItemRequest(myDriveRoot.Code);
 | 
					 | 
				
			||||||
                        targetNItem = await _farmmapsApiService.CreateItemAsync(itemRequest);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        targetNItem = targetNItems[0];
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    await CalculateTargetN(cropfieldItem, targetNItem, 60);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    await Task.Delay(2000);
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (Exception ex)
 | 
					            catch (Exception ex)
 | 
				
			||||||
@@ -76,7 +57,7 @@ namespace FarmmapsApiSamples
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private async Task<Item> GetCreateCropfieldItem(string parentItemCode)
 | 
					        private async Task<Item> GetOrCreateCropfieldItem(string parentItemCode)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var cropfieldItems = await
 | 
					            var cropfieldItems = await
 | 
				
			||||||
                _farmmapsApiService.GetItemChildrenAsync(parentItemCode, "vnd.farmmaps.itemtype.cropfield");
 | 
					                _farmmapsApiService.GetItemChildrenAsync(parentItemCode, "vnd.farmmaps.itemtype.cropfield");
 | 
				
			||||||
@@ -101,8 +82,25 @@ namespace FarmmapsApiSamples
 | 
				
			|||||||
            return await _farmmapsApiService.CreateItemAsync(cropfieldItemRequest);
 | 
					            return await _farmmapsApiService.CreateItemAsync(cropfieldItemRequest);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private async Task<Item> CalculateTargetN(Item cropfieldItem, Item targetNItem, int targetYield)
 | 
					        private async Task<double> CalculateTargetN(Item cropfieldItem, int targetYield)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var targetNItems = await
 | 
				
			||||||
 | 
					                _farmmapsApiService.GetItemChildrenAsync(cropfieldItem.ParentCode, USERINPUT_ITEMTYPE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Item targetNItem;
 | 
				
			||||||
 | 
					            if (targetNItems.Count == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _logger.LogInformation("Creating targetN item");
 | 
				
			||||||
 | 
					                var itemRequest = CreateTargetNItemRequest(cropfieldItem.ParentCode);
 | 
				
			||||||
 | 
					                targetNItem = await _farmmapsApiService.CreateItemAsync(itemRequest);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                targetNItem = targetNItems[0];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _logger.LogInformation($"Calculating targetN with targetYield: {targetYield}");
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            var nbsTargetNRequest = new TaskRequest {TaskType = VRANBS_TASK};
 | 
					            var nbsTargetNRequest = new TaskRequest {TaskType = VRANBS_TASK};
 | 
				
			||||||
            nbsTargetNRequest.attributes["operation"] = "targetn";
 | 
					            nbsTargetNRequest.attributes["operation"] = "targetn";
 | 
				
			||||||
            nbsTargetNRequest.attributes["inputCode"] = targetNItem.Code;
 | 
					            nbsTargetNRequest.attributes["inputCode"] = targetNItem.Code;
 | 
				
			||||||
@@ -111,11 +109,19 @@ namespace FarmmapsApiSamples
 | 
				
			|||||||
            nbsTargetNRequest.attributes["targetYield"] = targetYield.ToString();
 | 
					            nbsTargetNRequest.attributes["targetYield"] = targetYield.ToString();
 | 
				
			||||||
            string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, nbsTargetNRequest);
 | 
					            string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, nbsTargetNRequest);
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            // poll task
 | 
					            await PollTask(TimeSpan.FromSeconds(3), async (tokenSource) =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // get target N item again
 | 
					                if (itemTask.State != ItemTaskState.Processing && itemTask.State != ItemTaskState.Scheduled)
 | 
				
			||||||
 | 
					                    tokenSource.Cancel();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return targetNItem;
 | 
					            var item = await _farmmapsApiService.GetItemAsync(targetNItem.Code);
 | 
				
			||||||
 | 
					            if (item.Data.ContainsKey("TargetN"))
 | 
				
			||||||
 | 
					                return item.Data["TargetN"].Value<double>();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private ItemRequest CreateTargetNItemRequest(string parentItemCode)
 | 
					        private ItemRequest CreateTargetNItemRequest(string parentItemCode)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user