diff --git a/FarmmapsApi/Services/FarmmapsUploader.cs b/FarmmapsApi/Services/FarmmapsUploader.cs index 0bd2945..02842dd 100644 --- a/FarmmapsApi/Services/FarmmapsUploader.cs +++ b/FarmmapsApi/Services/FarmmapsUploader.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.IO; using System.Net.Http; using System.Net.Mime; @@ -69,6 +68,8 @@ namespace FarmmapsApi.Services contentStream.ThrowIfNull(nameof(contentStream)); _streamLength = ContentStream.CanSeek ? ContentStream.Length : UnknownSize; + + body.ChunkSize = ChunkSize; Body = body; Path = "api/v1/file"; HttpClient = httpClient; @@ -93,16 +94,12 @@ namespace FarmmapsApi.Services /// Creates a request to initialize a request. private HttpRequestMessage CreateInitializeRequest() { - var baseAddres = HttpClient.BaseAddress; - var uri = new Uri($"{baseAddres.Scheme}://{baseAddres.Host}:{baseAddres.Port}"); var builder = new RequestBuilder() { - BaseUri = uri, + BaseUri = HttpClient.BaseAddress, Path = Path, Method = HttpMethod, }; - - SetAllPropertyValues(builder); HttpRequestMessage request = builder.CreateRequest(); if (ContentType != null) @@ -121,40 +118,5 @@ namespace FarmmapsApi.Services return request; } - - /// - /// Reflectively enumerate the properties of this object looking for all properties containing the - /// RequestParameterAttribute and copy their values into the request builder. - /// - private void SetAllPropertyValues(RequestBuilder requestBuilder) - { - Type myType = this.GetType(); - var properties = myType.GetProperties(); - - foreach (var property in properties) - { - var attribute = property.GetCustomAttribute(); - if (attribute != null) - { - string name = attribute.Name ?? property.Name.ToLower(); - object value = property.GetValue(this, null); - if (value != null) - { - if (!(value is string) && value is IEnumerable valueAsEnumerable) - { - foreach (var elem in valueAsEnumerable) - { - requestBuilder.AddParameter(attribute.Type, name, Utilities.ConvertToString(elem)); - } - } - else - { - // Otherwise just convert it to a string. - requestBuilder.AddParameter(attribute.Type, name, Utilities.ConvertToString(value)); - } - } - } - } - } } } \ No newline at end of file diff --git a/FarmmapsApiSamples/Constants.cs b/FarmmapsApiSamples/Constants.cs new file mode 100644 index 0000000..852f44b --- /dev/null +++ b/FarmmapsApiSamples/Constants.cs @@ -0,0 +1,10 @@ +namespace FarmmapsApiSamples +{ + public static class Constants + { + public const string USERINPUT_ITEMTYPE = "vnd.farmmaps.itemtype.user.input"; + public const string GEOTIFF_ITEMTYPE = "vnd.farmmaps.itemtype.geotiff"; + public const string CROPFIELD_ITEMTYPE = "vnd.farmmaps.itemtype.cropfield"; + public const string VRANBS_TASK = "vnd.farmmaps.task.vranbs"; + } +} \ No newline at end of file diff --git a/FarmmapsApiSamples/NbsApp.cs b/FarmmapsApiSamples/NbsApp.cs index 499e24b..6dd7ee9 100644 --- a/FarmmapsApiSamples/NbsApp.cs +++ b/FarmmapsApiSamples/NbsApp.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -8,24 +7,22 @@ using FarmmapsApi.Services; using Google.Apis.Upload; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; -using static FarmmapsApi.Extensions; +using static FarmmapsApiSamples.Constants; namespace FarmmapsApiSamples { public class NbsApp : IApp { - private const string USERINPUT_ITEMTYPE = "vnd.farmmaps.itemtype.user.input"; - private const string GEOTIFF_ITEMTYPE = "vnd.farmmaps.itemtype.geotiff"; - private const string CROPFIELD_ITEMTYPE = "vnd.farmmaps.itemtype.cropfield"; - private const string VRANBS_TASK = "vnd.farmmaps.task.vranbs"; - private readonly ILogger _logger; private readonly FarmmapsApiService _farmmapsApiService; + private readonly NitrogenService _nitrogenService; - public NbsApp(ILogger logger, FarmmapsApiService farmmapsApiService) + public NbsApp(ILogger logger, FarmmapsApiService farmmapsApiService, + NitrogenService nitrogenService) { _logger = logger; _farmmapsApiService = farmmapsApiService; + _nitrogenService = nitrogenService; farmmapsApiService.EventCallback += OnEvent; } @@ -40,13 +37,13 @@ namespace FarmmapsApiSamples try { _logger.LogInformation("NBS sample app started"); - + await _farmmapsApiService.AuthenticateAsync(); _logger.LogInformation("Authenticated client credentials"); var roots = await _farmmapsApiService.GetCurrentUserRootsAsync(); - + // upload data to Uploaded var uploadedRoot = roots.SingleOrDefault(r => r.Name == "Uploaded"); if (uploadedRoot != null) @@ -55,21 +52,21 @@ namespace FarmmapsApiSamples progress => { _logger.LogInformation($"Status: {progress.Status} - BytesSent: {progress.BytesSent}"); - if(progress.Status == UploadStatus.Failed) + if (progress.Status == UploadStatus.Failed) _logger.LogError($"Uploading failed {progress.Exception.Message}"); }); - + // need to transform shape data to geotiff var myDriveRoot = roots.SingleOrDefault(r => r.Name == "My drive"); if (myDriveRoot != null) { var cropfieldItem = await GetOrCreateCropfieldItem(myDriveRoot.Code); - + _logger.LogInformation($"Calculating targetN with targetYield: {60}"); - var targetN = await CalculateTargetN(cropfieldItem, 60); + var targetN = await _nitrogenService.CalculateTargetN(cropfieldItem, 60); _logger.LogInformation($"TargetN: {targetN}"); - + _logger.LogInformation("Calculating nitrogen map"); // var nitrogenMapItem = CalculateNitrogenMap(cropfieldItem,, targetN); } @@ -84,9 +81,9 @@ namespace FarmmapsApiSamples private async Task GetOrCreateCropfieldItem(string parentItemCode) { var cropfieldItems = await - _farmmapsApiService.GetItemChildrenAsync(parentItemCode,CROPFIELD_ITEMTYPE); + _farmmapsApiService.GetItemChildrenAsync(parentItemCode, CROPFIELD_ITEMTYPE); - if (cropfieldItems.Count > 0) + if (cropfieldItems.Count > 0) return cropfieldItems[0]; var currentYear = new DateTime(DateTime.UtcNow.Year, 1, 1); @@ -105,106 +102,5 @@ namespace FarmmapsApiSamples return await _farmmapsApiService.CreateItemAsync(cropfieldItemRequest); } - - /// - /// Calculates TargetN, makes the assumption the cropfield and user.input(targetn) item have the same parent - /// - /// The cropfield to base the calculations on - /// The target yield input for the TargetN calculation - /// The TargetN - private async Task 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]; - } - - var nbsTargetNRequest = new TaskRequest {TaskType = VRANBS_TASK}; - nbsTargetNRequest.attributes["operation"] = "targetn"; - nbsTargetNRequest.attributes["inputCode"] = targetNItem.Code; - nbsTargetNRequest.attributes["inputType"] = "irmi"; - nbsTargetNRequest.attributes["purposeType"] = "consumption"; - nbsTargetNRequest.attributes["targetYield"] = targetYield.ToString(); - string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, nbsTargetNRequest); - - await PollTask(TimeSpan.FromSeconds(3), async (tokenSource) => - { - var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); - if (itemTaskStatus.State != ItemTaskState.Processing && itemTaskStatus.State != ItemTaskState.Scheduled) - tokenSource.Cancel(); - }); - - var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); - if(itemTask.State == ItemTaskState.Error) - { - _logger.LogError($"Something went wrong with task execution: {itemTask.Message}"); - return 0; - } - - var item = await _farmmapsApiService.GetItemAsync(targetNItem.Code); - if (item.Data.ContainsKey("TargetN")) - return item.Data["TargetN"].Value(); - - return 0; - } - - private async Task CalculateNitrogenMap(Item cropfieldItem, Item inputItem, double targetN) - { - var nbsNitrogenRequest = new TaskRequest {TaskType = VRANBS_TASK}; - nbsNitrogenRequest.attributes["operation"] = "nitrogen"; - nbsNitrogenRequest.attributes["inputCode"] = inputItem.Code; - nbsNitrogenRequest.attributes["inputType"] = "irmi"; - nbsNitrogenRequest.attributes["targetN"] = targetN.ToString(CultureInfo.InvariantCulture); - - string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, nbsNitrogenRequest); - - await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => - { - var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); - if (itemTaskStatus.State != ItemTaskState.Processing && itemTaskStatus.State != ItemTaskState.Scheduled) - tokenSource.Cancel(); - }); - - var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); - if(itemTask.State == ItemTaskState.Error) - { - _logger.LogError($"Something went wrong with task execution: {itemTask.Message}"); - return null; - } - - var geotiffItems = await - _farmmapsApiService.GetItemChildrenAsync(cropfieldItem.Code, GEOTIFF_ITEMTYPE); - - // how to uniquely know which item is really created!? - var nitrogenItem = geotiffItems.SingleOrDefault(i => i.Name.Contains("nitrogen")); - if (nitrogenItem == null) - { - _logger.LogError("Could not find the nitrogen geotiff child item under cropfield"); - return null; - } - - return nitrogenItem; - } - - private ItemRequest CreateTargetNItemRequest(string parentItemCode) - { - return new ItemRequest() - { - ParentCode = parentItemCode, - ItemType = USERINPUT_ITEMTYPE, - Name = "TargetN", - DataDate = DateTime.UtcNow - }; - } } } \ No newline at end of file diff --git a/FarmmapsApiSamples/NitrogenService.cs b/FarmmapsApiSamples/NitrogenService.cs new file mode 100644 index 0000000..cc94516 --- /dev/null +++ b/FarmmapsApiSamples/NitrogenService.cs @@ -0,0 +1,125 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using FarmmapsApi.Models; +using FarmmapsApi.Services; +using Microsoft.Extensions.Logging; +using static FarmmapsApi.Extensions; +using static FarmmapsApiSamples.Constants; + +namespace FarmmapsApiSamples +{ + public class NitrogenService + { + private readonly ILogger _logger; + private readonly FarmmapsApiService _farmmapsApiService; + + public NitrogenService(ILogger logger, FarmmapsApiService farmmapsApiService) + { + _logger = logger; + _farmmapsApiService = farmmapsApiService; + } + + /// + /// Calculates TargetN, makes the assumption the cropfield and user.input(targetn) item have the same parent + /// + /// The cropfield to base the calculations on + /// The target yield input for the TargetN calculation + /// The TargetN + public async Task 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]; + } + + var nbsTargetNRequest = new TaskRequest {TaskType = VRANBS_TASK}; + nbsTargetNRequest.attributes["operation"] = "targetn"; + nbsTargetNRequest.attributes["inputCode"] = targetNItem.Code; + nbsTargetNRequest.attributes["inputType"] = "irmi"; + nbsTargetNRequest.attributes["purposeType"] = "consumption"; + nbsTargetNRequest.attributes["targetYield"] = targetYield.ToString(); + string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, nbsTargetNRequest); + + await PollTask(TimeSpan.FromSeconds(3), async (tokenSource) => + { + var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); + if (itemTaskStatus.State != ItemTaskState.Processing && itemTaskStatus.State != ItemTaskState.Scheduled) + tokenSource.Cancel(); + }); + + var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); + if(itemTask.State == ItemTaskState.Error) + { + _logger.LogError($"Something went wrong with task execution: {itemTask.Message}"); + return 0; + } + + var item = await _farmmapsApiService.GetItemAsync(targetNItem.Code); + if (item.Data.ContainsKey("TargetN")) + return item.Data.Value("TargetN"); + + return 0; + } + + public async Task CalculateNitrogenMap(Item cropfieldItem, Item inputItem, double targetN) + { + var nbsNitrogenRequest = new TaskRequest {TaskType = VRANBS_TASK}; + nbsNitrogenRequest.attributes["operation"] = "nitrogen"; + nbsNitrogenRequest.attributes["inputCode"] = inputItem.Code; + nbsNitrogenRequest.attributes["inputType"] = "irmi"; + nbsNitrogenRequest.attributes["targetN"] = targetN.ToString(CultureInfo.InvariantCulture); + + string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, nbsNitrogenRequest); + + await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => + { + var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); + if (itemTaskStatus.State != ItemTaskState.Processing && itemTaskStatus.State != ItemTaskState.Scheduled) + tokenSource.Cancel(); + }); + + var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); + if(itemTask.State == ItemTaskState.Error) + { + _logger.LogError($"Something went wrong with task execution: {itemTask.Message}"); + return null; + } + + var geotiffItems = await + _farmmapsApiService.GetItemChildrenAsync(cropfieldItem.Code, GEOTIFF_ITEMTYPE); + + // how to uniquely know which item is really created!? + var nitrogenItem = geotiffItems.SingleOrDefault(i => i.Name.Contains("nitrogen")); + if (nitrogenItem == null) + { + _logger.LogError("Could not find the nitrogen geotiff child item under cropfield"); + return null; + } + + return nitrogenItem; + } + + private ItemRequest CreateTargetNItemRequest(string parentItemCode) + { + return new ItemRequest() + { + ParentCode = parentItemCode, + ItemType = USERINPUT_ITEMTYPE, + Name = "TargetN", + DataDate = DateTime.UtcNow + }; + } + } +} \ No newline at end of file diff --git a/FarmmapsApiSamples/Program.cs b/FarmmapsApiSamples/Program.cs index 5428c48..51cb081 100644 --- a/FarmmapsApiSamples/Program.cs +++ b/FarmmapsApiSamples/Program.cs @@ -27,6 +27,7 @@ namespace FarmmapsApiSamples }) .AddFilter("System.Net.Http", LogLevel.Warning)) .AddFarmmapsServices(configuration) + .AddTransient() .AddSingleton() .BuildServiceProvider(); diff --git a/FarmmapsApiSamples/appsettings.json b/FarmmapsApiSamples/appsettings.json index c795f28..625a379 100644 --- a/FarmmapsApiSamples/appsettings.json +++ b/FarmmapsApiSamples/appsettings.json @@ -1,6 +1,6 @@ { "Authority": "https://accounts.farmmaps.awtest.nl/", - "Endpoint": "http://localhost:8083", + "Endpoint": "https://farmmaps.awtest.nl/", "BasePath": "api/v1", "DiscoveryEndpointUrl": "https://accounts.farmmaps.awtest.nl/.well-known/openid-configuration", "RedirectUri": "http://example.nl/api",