From 0f9699477370185c8a03d2969a2cedc5a19b9443 Mon Sep 17 00:00:00 2001 From: luke-else <52086083+luke-else@users.noreply.github.com> Date: Mon, 22 Nov 2021 13:07:56 +0000 Subject: [PATCH 1/8] Route request being made (Needs polling) --- Controllers/API/APIInterface.cs | 23 +++++++-- Controllers/Form/FormAuthenticator.cs | 2 +- Controllers/RouteController.cs | 73 +++++++++++++++++++++++++-- Controllers/UserController.cs | 2 +- Models/JSON/RouteRequest.cs | 18 +++++++ Models/RouteModel.cs | 4 +- Models/TokenModel.cs | 2 +- 7 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 Models/JSON/RouteRequest.cs diff --git a/Controllers/API/APIInterface.cs b/Controllers/API/APIInterface.cs index f15712b..9cd8528 100644 --- a/Controllers/API/APIInterface.cs +++ b/Controllers/API/APIInterface.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Text; +using System; using System.Threading.Tasks; using Newtonsoft.Json; using System.Net.Http; @@ -35,9 +36,18 @@ namespace EFB.Controllers.API string resultString = result.Content.ReadAsStringAsync().Result; + object response; + + //Assess return value (object or raw string) + try{ + response = JsonConvert.DeserializeObject(resultString); + }catch { + response = resultString; + } + return new ResponseModel{ //Sender should be aware of type T becuase of Generic function - Result = JsonConvert.DeserializeObject(resultString) + Result = response }; } catch (System.Exception e) @@ -70,10 +80,17 @@ namespace EFB.Controllers.API var pendingResult = this.HttpClient.PostAsync(Endpoint, Body); var result = await pendingResult; string resultString = result.Content.ReadAsStringAsync().Result; + + object response = resultString; - return new ResponseModel{ + if (typeof(T) != typeof(string)) + {//If the user requests string for return type + response = JsonConvert.DeserializeObject(resultString); + } + + return new ResponseModel(){ //Sender should be aware of type T becuase of Generic function - Result = JsonConvert.DeserializeObject(resultString) + Result = response }; }catch(System.Exception e){ return new ResponseModel{Error = e.Message}; diff --git a/Controllers/Form/FormAuthenticator.cs b/Controllers/Form/FormAuthenticator.cs index 28dded6..df42554 100644 --- a/Controllers/Form/FormAuthenticator.cs +++ b/Controllers/Form/FormAuthenticator.cs @@ -37,7 +37,7 @@ namespace EFB.Controllers.Form return false; } - public static bool ValidateCruiseAlt(int CruiseAlt){ + public static bool ValidateCruiseAlt(uint CruiseAlt){ if (CruiseAlt > 0 && CruiseAlt < 50000) { return true; diff --git a/Controllers/RouteController.cs b/Controllers/RouteController.cs index 15f2b84..ba0281a 100644 --- a/Controllers/RouteController.cs +++ b/Controllers/RouteController.cs @@ -1,13 +1,17 @@ using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; using System.Threading.Tasks; +using System.Collections.Generic; +using System.Text; +using System.Net.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Http; +using Newtonsoft.Json; using EFB.Models; +using EFB.Models.JSON; using EFB.Sessions; +using EFB.Controllers.Form; +using EFB.Controllers.API; namespace EFB.Controllers { @@ -23,8 +27,8 @@ namespace EFB.Controllers public IActionResult Index() { //Check the user has a valid login - UserModel User = HttpContext.Session.GetObject("User"); - if (User == null || User.Route != null || User.Token.IsExpired()) + UserModel user = HttpContext.Session.GetObject("User"); + if (user == null || user.Route != null || user.Token.IsExpired()) { return RedirectToAction("Index", "Home"); } @@ -37,5 +41,64 @@ namespace EFB.Controllers { return View("Error!"); } + + public async Task New(string departure, string arrival, string cruise){ + UserModel user = HttpContext.Session.GetObject("User"); + if (!(user == null || user.Token.IsExpired())) + {//If the user is still authenticated + if (FormAuthenticator.ValidateICAOCode(departure) && FormAuthenticator.ValidateICAOCode(arrival)) + {//If the user has entered valid ICAOs + + uint cruiseAlt; + + if (uint.TryParse(cruise, out cruiseAlt) && FormAuthenticator.ValidateCruiseAlt(cruiseAlt)) + {//If the cruise altitude if within limits. + + //Submit route request... + APIInterface API = new APIInterface(); + + //Prepare data to be send off with request (route) + Dictionary headerData = new Dictionary(); + headerData.Add("Authorization", $"Bearer {user.Token.TokenValue}"); + + RouteRequest routeRequest = new RouteRequest(){ + departure = departure, + destination = arrival, + preferredminlevel = cruiseAlt / 1000, + preferredmaxlevel = cruiseAlt / 1000, + }; + StringContent content = new StringContent(JsonConvert.SerializeObject(routeRequest), Encoding.UTF8, "application/json"); + + //Make initial Route Request + var requestRoute = API.Post("https://api.autorouter.aero/v1.0/router", headerData, content); + + ResponseModel responseRoute = await requestRoute; + + if (responseRoute.Error == null) + {//Update User session and add route ID + RouteModel route = new RouteModel(){ + RouteID = responseRoute.Result.ToString() + }; + + user.Route = route; + HttpContext.Session.SetObject("User", user); + + } + + TempData["Error"] = responseRoute.Error; + return RedirectToAction("Index", "Route"); + + } + TempData["Error"] = "Invalid Cruise Altitude"; + TempData["Departure"] = departure; + TempData["Arrival"] = arrival; + return RedirectToAction("Index", "Route"); + + } + TempData["Error"] = "Invalid Departure or Arrival ICAO"; + return RedirectToAction("Index", "Route"); + } + return RedirectToAction("Index", "Home"); + } } } \ No newline at end of file diff --git a/Controllers/UserController.cs b/Controllers/UserController.cs index 00a3971..d961576 100644 --- a/Controllers/UserController.cs +++ b/Controllers/UserController.cs @@ -65,7 +65,7 @@ namespace EFB.Controllers UserModel user = new UserModel{ EMail = email, Token = new TokenModel{ - Token = login.access_token, + TokenValue = login.access_token, Expiration = DateTime.UtcNow.AddSeconds(login.expires_in) } }; diff --git a/Models/JSON/RouteRequest.cs b/Models/JSON/RouteRequest.cs new file mode 100644 index 0000000..27cdbc5 --- /dev/null +++ b/Models/JSON/RouteRequest.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace EFB.Models.JSON +{ + public class RouteRequest + { + [JsonProperty] + public string departure { get; set; } + [JsonProperty] + public string destination { get; set; } + [JsonProperty] + public uint preferredminlevel { get; set; } + [JsonProperty] + public uint preferredmaxlevel { get; set; } + [JsonProperty] + public string optimise { get; } = "preferred"; + } +} \ No newline at end of file diff --git a/Models/RouteModel.cs b/Models/RouteModel.cs index a0468b1..2e874af 100644 --- a/Models/RouteModel.cs +++ b/Models/RouteModel.cs @@ -13,7 +13,9 @@ namespace EFB.Models Route only becomes populated after route is recieved from autorouter API */ - public WaypointModel Departure { get; init; } = null; + public string RouteID { get; init; } + + public WaypointModel Departure { get; set; } = null; public WaypointModel Arrival { get; set; } = null; public IWaypoint Current { get; set; } = null; public uint Cruise { get; set; } = 0; diff --git a/Models/TokenModel.cs b/Models/TokenModel.cs index 64ddf38..08faff2 100644 --- a/Models/TokenModel.cs +++ b/Models/TokenModel.cs @@ -10,7 +10,7 @@ namespace EFB.Models /* Auto Router API Token Model */ - public string Token { get; init; } + public string TokenValue { get; init; } public DateTime Expiration { get; init; } public bool IsExpired(){ From e1347517456663345d7de9494a65c0971a057e16 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Mon, 27 Dec 2021 21:15:55 +0000 Subject: [PATCH 2/8] Updated UserModel and started on making the polling http calls to the server. Started with the Polling command: What I'm thinking is that I should have the command consecutively make calls every 5 seconds, not sure how it will work without hanging the thread, will figure out tomorrow :) --- Controllers/RouteController.cs | 21 +++++++++++++++++++++ Models/UserModel.cs | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Controllers/RouteController.cs b/Controllers/RouteController.cs index ba0281a..78da5c6 100644 --- a/Controllers/RouteController.cs +++ b/Controllers/RouteController.cs @@ -100,5 +100,26 @@ namespace EFB.Controllers } return RedirectToAction("Index", "Home"); } + + + public async Task Poll(){ + if (HttpContext.Session.GetString("User") != null) + {//If the user is currently logged in + UserModel User = HttpContext.Session.GetObject("User"); + + if (User.Route != null) + {//If the user has a route object (e.g, they have been to the route page) + + //Make calls to the server to fetch route + return RedirectToAction("Index", "Route"); + + }else{ + return RedirectToAction("Index", "Route"); + } + + }else{ + return RedirectToAction("Index", "Route"); + } + } } } \ No newline at end of file diff --git a/Models/UserModel.cs b/Models/UserModel.cs index e4e2dce..500b82e 100644 --- a/Models/UserModel.cs +++ b/Models/UserModel.cs @@ -21,7 +21,7 @@ namespace EFB.Models public TokenModel Token { get; set; } = null; //Contains the most recent route generated by the user through the App - public object Route { get; set; } = null; + public RouteModel Route { get; set; } = null; //Contains the most recently stored position of the user in the simulator public object SimPosition { get; set; } = null; From 5a2f109e65be5e1a69452b8ed08f241bdf21b379 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Tue, 28 Dec 2021 21:53:31 +0000 Subject: [PATCH 3/8] Added Poll response function JSON is not properly serialised... still in progress --- Controllers/API/APIInterface.cs | 75 +++++++++++++++++++++++++-------- Controllers/RouteController.cs | 29 +++++++++++-- Controllers/UserController.cs | 4 +- Models/JSON/PollResponse.cs | 19 +++++++++ Models/ResponseModel.cs | 5 +-- 5 files changed, 107 insertions(+), 25 deletions(-) create mode 100644 Models/JSON/PollResponse.cs diff --git a/Controllers/API/APIInterface.cs b/Controllers/API/APIInterface.cs index 9cd8528..5e2db81 100644 --- a/Controllers/API/APIInterface.cs +++ b/Controllers/API/APIInterface.cs @@ -12,7 +12,7 @@ namespace EFB.Controllers.API { private HttpClient HttpClient { get; set; } - public async Task Get(string Endpoint, Dictionary Headers){ + public async Task> Get(string Endpoint, Dictionary Headers){ this.HttpClient = new HttpClient(); @@ -36,32 +36,31 @@ namespace EFB.Controllers.API string resultString = result.Content.ReadAsStringAsync().Result; - object response; - //Assess return value (object or raw string) - try{ + object response = resultString; + + if (typeof(T) != typeof(string)) + {//If the user requests string for return type response = JsonConvert.DeserializeObject(resultString); - }catch { - response = resultString; } - return new ResponseModel{ - //Sender should be aware of type T becuase of Generic function - Result = response + return new ResponseModel(){ + //Sender should be aware of type T becuase of Generic type + Result = (T)response }; } catch (System.Exception e) { - return new ResponseModel{Error = e.Message}; + return new ResponseModel{Error = e.Message}; } } //Returned in the event No other response has been returned - return new ResponseModel{Error = "Invalid Endpoint - Please try again later"}; + return new ResponseModel{Error = "Invalid Endpoint - Please try again later"}; } - public async Task Post(string Endpoint, Dictionary Headers, HttpContent Body){ + public async Task> Post(string Endpoint, Dictionary Headers, HttpContent Body){ this.HttpClient = new HttpClient(); this.HttpClient.DefaultRequestHeaders.Clear(); @@ -88,16 +87,58 @@ namespace EFB.Controllers.API response = JsonConvert.DeserializeObject(resultString); } - return new ResponseModel(){ - //Sender should be aware of type T becuase of Generic function - Result = response + return new ResponseModel(){ + //Sender should be aware of type T becuase of Generic type + Result = (T)response }; }catch(System.Exception e){ - return new ResponseModel{Error = e.Message}; + return new ResponseModel{Error = e.Message}; } } //Returned in the event No other response has been returned - return new ResponseModel{Error = "Invalid Endpoint - Please try again later"}; + return new ResponseModel{Error = "Invalid Endpoint - Please try again later"}; + + } + + + + public async Task> Put(string Endpoint, Dictionary Headers, HttpContent Body){ + + this.HttpClient = new HttpClient(); + this.HttpClient.DefaultRequestHeaders.Clear(); + + if (Headers != null) + { + foreach (var Header in Headers) + { + this.HttpClient.DefaultRequestHeaders.Add(Header.Key, Header.Value); + } + } + + if (Form.FormAuthenticator.ValidateEndpoint(Endpoint)) + { + try{//Try statement to catch errors in the process of making the request + var pendingResult = this.HttpClient.PutAsync(Endpoint, Body); + var result = await pendingResult; + string resultString = result.Content.ReadAsStringAsync().Result; + + object response = resultString; + + if (typeof(T) != typeof(string)) + {//If the user requests string for return type + response = JsonConvert.DeserializeObject(resultString); + } + + return new ResponseModel(){ + //Sender should be aware of type T becuase of Generic type + Result = (T)response + }; + }catch(System.Exception e){ + return new ResponseModel{Error = e.Message}; + } + } + //Returned in the event No other response has been returned + return new ResponseModel{Error = "Invalid Endpoint - Please try again later"}; } diff --git a/Controllers/RouteController.cs b/Controllers/RouteController.cs index 78da5c6..acd5164 100644 --- a/Controllers/RouteController.cs +++ b/Controllers/RouteController.cs @@ -72,7 +72,7 @@ namespace EFB.Controllers //Make initial Route Request var requestRoute = API.Post("https://api.autorouter.aero/v1.0/router", headerData, content); - ResponseModel responseRoute = await requestRoute; + ResponseModel responseRoute = await requestRoute; if (responseRoute.Error == null) {//Update User session and add route ID @@ -83,6 +83,8 @@ namespace EFB.Controllers user.Route = route; HttpContext.Session.SetObject("User", user); + return await Poll(); + } TempData["Error"] = responseRoute.Error; @@ -105,12 +107,33 @@ namespace EFB.Controllers public async Task Poll(){ if (HttpContext.Session.GetString("User") != null) {//If the user is currently logged in - UserModel User = HttpContext.Session.GetObject("User"); + UserModel user = HttpContext.Session.GetObject("User"); - if (User.Route != null) + if (user.Route != null) {//If the user has a route object (e.g, they have been to the route page) //Make calls to the server to fetch route + bool collected = false; + int count = 0; + + APIInterface API = new APIInterface(); + + Dictionary headerData = new Dictionary(); + headerData.Add("Authorization", $"Bearer {user.Token.TokenValue}"); + + while (collected == false && count <= 5) + { + count ++; + + //Make Polling Request + var pollingRequest = API.Put>($"https://api.autorouter.aero/v1.0/router/{user.Route.RouteID}/longpoll", headerData, null); + + ResponseModel> responsePoll = await pollingRequest; + + Console.WriteLine(responsePoll); + + } + return RedirectToAction("Index", "Route"); }else{ diff --git a/Controllers/UserController.cs b/Controllers/UserController.cs index d961576..07d893c 100644 --- a/Controllers/UserController.cs +++ b/Controllers/UserController.cs @@ -47,7 +47,7 @@ namespace EFB.Controllers var request = API.Post("https://api.autorouter.aero/v1.0/oauth2/token", null, content); //Wait for the response to come through - ResponseModel response = await request; + ResponseModel response = await request; if (response.Error != null) { @@ -57,7 +57,7 @@ namespace EFB.Controllers }else{ //Type cast required but we know response will be of known type - LoginResponse login = (LoginResponse)response.Result; + LoginResponse login = response.Result; //Generate User Session if (login.error == null) diff --git a/Models/JSON/PollResponse.cs b/Models/JSON/PollResponse.cs new file mode 100644 index 0000000..5169d10 --- /dev/null +++ b/Models/JSON/PollResponse.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace EFB.Models.JSON +{ + [JsonArray] + public class PollResponse + { + [JsonProperty(PropertyName = "cmdname")] + public string Command { get; set; } + + [JsonProperty(PropertyName = "fpl")] + public string FlightPlan { get; set; } + } + +} \ No newline at end of file diff --git a/Models/ResponseModel.cs b/Models/ResponseModel.cs index debfb08..92f2f32 100644 --- a/Models/ResponseModel.cs +++ b/Models/ResponseModel.cs @@ -5,11 +5,10 @@ using System.Threading.Tasks; namespace EFB.Models { - public class ResponseModel + public class ResponseModel { //Object should be of known type from sender - public object Result { get; set; } = null; - + public T Result { get; set; } = default(T); public string Error { get; set; } = null; } From b61b767194a91bebe5aa0b02f3070ddbd332f77d Mon Sep 17 00:00:00 2001 From: Luke Else Date: Tue, 4 Jan 2022 23:26:41 +0000 Subject: [PATCH 4/8] Update RouteController.cs Polling feature still inop, JSON doesn't deserialise becuase the array has no name in the JSON. Could potentially add a name to the start artificially in order to force the JSON to parse? --- Controllers/RouteController.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Controllers/RouteController.cs b/Controllers/RouteController.cs index acd5164..d73ddd3 100644 --- a/Controllers/RouteController.cs +++ b/Controllers/RouteController.cs @@ -130,6 +130,8 @@ namespace EFB.Controllers ResponseModel> responsePoll = await pollingRequest; + + //put request returns JSON that cannot be serialised by default Console.WriteLine(responsePoll); } From 18bf369a1b40c2e596856a245f398c20c1146ee1 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Wed, 5 Jan 2022 15:24:15 +0000 Subject: [PATCH 5/8] Fixed Poll Response Poll response now works and accepts a list of responses from the server, in theory one of which should be the route response --- Controllers/RouteController.cs | 16 ++++++++++++---- Models/JSON/PollResponse.cs | 1 - 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Controllers/RouteController.cs b/Controllers/RouteController.cs index d73ddd3..0087324 100644 --- a/Controllers/RouteController.cs +++ b/Controllers/RouteController.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using System.Threading; using System.Collections.Generic; using System.Text; using System.Net.Http; @@ -115,6 +116,7 @@ namespace EFB.Controllers //Make calls to the server to fetch route bool collected = false; int count = 0; + string route; APIInterface API = new APIInterface(); @@ -123,19 +125,25 @@ namespace EFB.Controllers while (collected == false && count <= 5) { - count ++; - //Make Polling Request var pollingRequest = API.Put>($"https://api.autorouter.aero/v1.0/router/{user.Route.RouteID}/longpoll", headerData, null); ResponseModel> responsePoll = await pollingRequest; - //put request returns JSON that cannot be serialised by default - Console.WriteLine(responsePoll); + if (responsePoll.Result[count].Command == "solution") + { + collected = true; + route = responsePoll.Result[count].FlightPlan; + break; + } + + Thread.Sleep(5000); + count ++; } + return RedirectToAction("Index", "Route"); }else{ diff --git a/Models/JSON/PollResponse.cs b/Models/JSON/PollResponse.cs index 5169d10..3c353e9 100644 --- a/Models/JSON/PollResponse.cs +++ b/Models/JSON/PollResponse.cs @@ -6,7 +6,6 @@ using Newtonsoft.Json; namespace EFB.Models.JSON { - [JsonArray] public class PollResponse { [JsonProperty(PropertyName = "cmdname")] From f2e852fcf01e496ce43ea9ae1742ff729dc1ca9b Mon Sep 17 00:00:00 2001 From: Luke Else Date: Wed, 5 Jan 2022 20:56:28 +0000 Subject: [PATCH 6/8] Route Polling Complete App now fetched a route, still needs to be moved into a Linked List --- Controllers/RouteController.cs | 77 ++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/Controllers/RouteController.cs b/Controllers/RouteController.cs index 0087324..aa52e1b 100644 --- a/Controllers/RouteController.cs +++ b/Controllers/RouteController.cs @@ -43,18 +43,19 @@ namespace EFB.Controllers return View("Error!"); } - public async Task New(string departure, string arrival, string cruise){ + public async Task New(string departure, string arrival, string cruise) + { UserModel user = HttpContext.Session.GetObject("User"); if (!(user == null || user.Token.IsExpired())) {//If the user is still authenticated if (FormAuthenticator.ValidateICAOCode(departure) && FormAuthenticator.ValidateICAOCode(arrival)) {//If the user has entered valid ICAOs - + uint cruiseAlt; if (uint.TryParse(cruise, out cruiseAlt) && FormAuthenticator.ValidateCruiseAlt(cruiseAlt)) {//If the cruise altitude if within limits. - + //Submit route request... APIInterface API = new APIInterface(); @@ -62,14 +63,15 @@ namespace EFB.Controllers Dictionary headerData = new Dictionary(); headerData.Add("Authorization", $"Bearer {user.Token.TokenValue}"); - RouteRequest routeRequest = new RouteRequest(){ + RouteRequest routeRequest = new RouteRequest() + { departure = departure, destination = arrival, preferredminlevel = cruiseAlt / 1000, preferredmaxlevel = cruiseAlt / 1000, }; StringContent content = new StringContent(JsonConvert.SerializeObject(routeRequest), Encoding.UTF8, "application/json"); - + //Make initial Route Request var requestRoute = API.Post("https://api.autorouter.aero/v1.0/router", headerData, content); @@ -77,7 +79,8 @@ namespace EFB.Controllers if (responseRoute.Error == null) {//Update User session and add route ID - RouteModel route = new RouteModel(){ + RouteModel route = new RouteModel() + { RouteID = responseRoute.Result.ToString() }; @@ -105,18 +108,19 @@ namespace EFB.Controllers } - public async Task Poll(){ + public async Task Poll() + { if (HttpContext.Session.GetString("User") != null) {//If the user is currently logged in UserModel user = HttpContext.Session.GetObject("User"); if (user.Route != null) {//If the user has a route object (e.g, they have been to the route page) - + //Make calls to the server to fetch route bool collected = false; int count = 0; - string route; + string route = ""; APIInterface API = new APIInterface(); @@ -127,32 +131,71 @@ namespace EFB.Controllers { //Make Polling Request var pollingRequest = API.Put>($"https://api.autorouter.aero/v1.0/router/{user.Route.RouteID}/longpoll", headerData, null); - + ResponseModel> responsePoll = await pollingRequest; - if (responsePoll.Result[count].Command == "solution") + int routePos = responsePoll.Result.Count - 1; + if (responsePoll.Result[routePos].Command == "solution") { collected = true; - route = responsePoll.Result[count].FlightPlan; + route = responsePoll.Result[routePos].FlightPlan; break; } Thread.Sleep(5000); - count ++; - + count++; + } + if (collected) + { + //fill in route + string finalRoute = ParseRoute(route); + TempData["Error"] = finalRoute; + return RedirectToAction("Index", "Route"); + } + + TempData["Error"] = "Unable to get route!"; return RedirectToAction("Index", "Route"); - }else{ + } + else + { return RedirectToAction("Index", "Route"); } - - }else{ + + } + else + { return RedirectToAction("Index", "Route"); } } + + private string ParseRoute(string route){ + TempData["Error"] = route; + + route.Replace('/', ' '); + var routeArr = route.Split(' '); + + string finalRoute = ""; + + foreach (var item in routeArr) + { + var waypoint = item.Split('/')[0]; + if (waypoint.Length <= 7 && waypoint.Length >= 3 && !waypoint.Contains('-')) + { + finalRoute += $"{waypoint} "; + + if (waypoint.Length == 7 && finalRoute.Length > 8) + break; + + } + } + + return finalRoute; + + } } } \ No newline at end of file From 1e27081f520ceeb7518f54e2da1542012074837d Mon Sep 17 00:00:00 2001 From: Luke Else Date: Sun, 9 Jan 2022 15:36:52 +0000 Subject: [PATCH 7/8] Updated Models --- Controllers/UserController.cs | 2 +- Models/Route/IWaypoint.cs | 1 + Models/Route/NavaidModel.cs | 5 +++++ Models/Route/WaypointModel.cs | 18 ++++-------------- Models/UserModel.cs | 3 ++- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Controllers/UserController.cs b/Controllers/UserController.cs index 07d893c..c79bd27 100644 --- a/Controllers/UserController.cs +++ b/Controllers/UserController.cs @@ -64,7 +64,7 @@ namespace EFB.Controllers { UserModel user = new UserModel{ EMail = email, - Token = new TokenModel{ + UserToken = new TokenModel{ TokenValue = login.access_token, Expiration = DateTime.UtcNow.AddSeconds(login.expires_in) } diff --git a/Models/Route/IWaypoint.cs b/Models/Route/IWaypoint.cs index 793fa93..1c6944f 100644 --- a/Models/Route/IWaypoint.cs +++ b/Models/Route/IWaypoint.cs @@ -15,5 +15,6 @@ namespace EFB.Models.Route public IWaypoint Next { get; set; } public IWaypoint Previous { get; set; } public bool Visited { get; set; } + } } \ No newline at end of file diff --git a/Models/Route/NavaidModel.cs b/Models/Route/NavaidModel.cs index b353b9e..95686c3 100644 --- a/Models/Route/NavaidModel.cs +++ b/Models/Route/NavaidModel.cs @@ -17,5 +17,10 @@ namespace EFB.Models.Route public IWaypoint Previous { get; set; } = null; public bool Visited { get; set; } = false; + public NavaidModel(string name, string airway, int frequency){ + Name = name; + Airway = Airway; + Frequency = frequency; + } } } \ No newline at end of file diff --git a/Models/Route/WaypointModel.cs b/Models/Route/WaypointModel.cs index ab2e239..abf9c1a 100644 --- a/Models/Route/WaypointModel.cs +++ b/Models/Route/WaypointModel.cs @@ -16,20 +16,10 @@ namespace EFB.Models.Route public IWaypoint Previous { get; set; } = null; public bool Visited { get; set; } - - - - - - - - - - - - - - + public WaypointModel(string name, string airway){ + Name = name; + Airway = Airway; + } } } \ No newline at end of file diff --git a/Models/UserModel.cs b/Models/UserModel.cs index 500b82e..f8179dd 100644 --- a/Models/UserModel.cs +++ b/Models/UserModel.cs @@ -18,10 +18,11 @@ namespace EFB.Models */ public object Id { get; init; } public string EMail { get; init; } - public TokenModel Token { get; set; } = null; + public TokenModel UserToken { get; set; } = null; //Contains the most recent route generated by the user through the App public RouteModel Route { get; set; } = null; + public TokenModel RouteToken { get; set; } = null; //Contains the most recently stored position of the user in the simulator public object SimPosition { get; set; } = null; From 0e1a00536cbc87c11947d0a7d784582eee9d7c6d Mon Sep 17 00:00:00 2001 From: Luke Else Date: Sun, 9 Jan 2022 17:03:52 +0000 Subject: [PATCH 8/8] Route Object Generation Complete --- Controllers/RouteController.cs | 68 ++++++++++---------------- Models/Route/NavaidModel.cs | 5 +- Models/Route/WaypointModel.cs | 2 +- Models/RouteModel.cs | 87 +++++++++++++++++++++++++++++++++- 4 files changed, 112 insertions(+), 50 deletions(-) diff --git a/Controllers/RouteController.cs b/Controllers/RouteController.cs index aa52e1b..392fed0 100644 --- a/Controllers/RouteController.cs +++ b/Controllers/RouteController.cs @@ -29,7 +29,7 @@ namespace EFB.Controllers { //Check the user has a valid login UserModel user = HttpContext.Session.GetObject("User"); - if (user == null || user.Route != null || user.Token.IsExpired()) + if (user == null || user.UserToken.IsExpired()) { return RedirectToAction("Index", "Home"); } @@ -46,7 +46,7 @@ namespace EFB.Controllers public async Task New(string departure, string arrival, string cruise) { UserModel user = HttpContext.Session.GetObject("User"); - if (!(user == null || user.Token.IsExpired())) + if (!(user == null || user.UserToken.IsExpired())) {//If the user is still authenticated if (FormAuthenticator.ValidateICAOCode(departure) && FormAuthenticator.ValidateICAOCode(arrival)) {//If the user has entered valid ICAOs @@ -61,7 +61,7 @@ namespace EFB.Controllers //Prepare data to be send off with request (route) Dictionary headerData = new Dictionary(); - headerData.Add("Authorization", $"Bearer {user.Token.TokenValue}"); + headerData.Add("Authorization", $"Bearer {user.UserToken.TokenValue}"); RouteRequest routeRequest = new RouteRequest() { @@ -79,15 +79,15 @@ namespace EFB.Controllers if (responseRoute.Error == null) {//Update User session and add route ID - RouteModel route = new RouteModel() + TokenModel routeToken = new TokenModel() { - RouteID = responseRoute.Result.ToString() + TokenValue = responseRoute.Result.ToString() }; - user.Route = route; + user.RouteToken = routeToken; HttpContext.Session.SetObject("User", user); - return await Poll(); + return await Poll(departure, arrival, cruiseAlt); } @@ -108,29 +108,29 @@ namespace EFB.Controllers } - public async Task Poll() + public async Task Poll(string departure, string arrival, uint cruise) { if (HttpContext.Session.GetString("User") != null) {//If the user is currently logged in UserModel user = HttpContext.Session.GetObject("User"); - if (user.Route != null) + if (user.RouteToken != null) {//If the user has a route object (e.g, they have been to the route page) //Make calls to the server to fetch route bool collected = false; - int count = 0; - string route = ""; + int pollCount = 0; + string routeString = ""; APIInterface API = new APIInterface(); Dictionary headerData = new Dictionary(); - headerData.Add("Authorization", $"Bearer {user.Token.TokenValue}"); + headerData.Add("Authorization", $"Bearer {user.UserToken.TokenValue}"); - while (collected == false && count <= 5) + while (collected == false && pollCount < 3) { //Make Polling Request - var pollingRequest = API.Put>($"https://api.autorouter.aero/v1.0/router/{user.Route.RouteID}/longpoll", headerData, null); + var pollingRequest = API.Put>($"https://api.autorouter.aero/v1.0/router/{user.RouteToken.TokenValue}/longpoll", headerData, null); ResponseModel> responsePoll = await pollingRequest; @@ -139,25 +139,28 @@ namespace EFB.Controllers if (responsePoll.Result[routePos].Command == "solution") { collected = true; - route = responsePoll.Result[routePos].FlightPlan; + routeString = responsePoll.Result[routePos].FlightPlan; break; } - Thread.Sleep(5000); - count++; + Thread.Sleep(3000); + pollCount++; } if (collected) { //fill in route - string finalRoute = ParseRoute(route); + string finalRoute = RouteModel.ParseRoute(routeString); - TempData["Error"] = finalRoute; + RouteModel route = RouteModel.StringToRoute(departure, arrival, cruise, finalRoute); + user.Route = route; + HttpContext.Session.SetObject("User", user); + return RedirectToAction("Index", "Route"); } - TempData["Error"] = "Unable to get route!"; + TempData["Error"] = $"Unable to get route after {pollCount} Attempts!"; return RedirectToAction("Index", "Route"); } @@ -173,29 +176,6 @@ namespace EFB.Controllers } } - private string ParseRoute(string route){ - TempData["Error"] = route; - - route.Replace('/', ' '); - var routeArr = route.Split(' '); - - string finalRoute = ""; - - foreach (var item in routeArr) - { - var waypoint = item.Split('/')[0]; - if (waypoint.Length <= 7 && waypoint.Length >= 3 && !waypoint.Contains('-')) - { - finalRoute += $"{waypoint} "; - - if (waypoint.Length == 7 && finalRoute.Length > 8) - break; - - } - } - - return finalRoute; - - } + } } \ No newline at end of file diff --git a/Models/Route/NavaidModel.cs b/Models/Route/NavaidModel.cs index 95686c3..ed147cd 100644 --- a/Models/Route/NavaidModel.cs +++ b/Models/Route/NavaidModel.cs @@ -17,10 +17,9 @@ namespace EFB.Models.Route public IWaypoint Previous { get; set; } = null; public bool Visited { get; set; } = false; - public NavaidModel(string name, string airway, int frequency){ + public NavaidModel(string name, string airway){ Name = name; - Airway = Airway; - Frequency = frequency; + Airway = airway; } } } \ No newline at end of file diff --git a/Models/Route/WaypointModel.cs b/Models/Route/WaypointModel.cs index abf9c1a..1acc0bf 100644 --- a/Models/Route/WaypointModel.cs +++ b/Models/Route/WaypointModel.cs @@ -18,7 +18,7 @@ namespace EFB.Models.Route public WaypointModel(string name, string airway){ Name = name; - Airway = Airway; + Airway = airway; } } diff --git a/Models/RouteModel.cs b/Models/RouteModel.cs index 2e874af..544aa74 100644 --- a/Models/RouteModel.cs +++ b/Models/RouteModel.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using EFB.Models.Route; +using EFB.Controllers.Form; +using System.Net.Http; namespace EFB.Models { @@ -13,12 +15,93 @@ namespace EFB.Models Route only becomes populated after route is recieved from autorouter API */ - public string RouteID { get; init; } - public WaypointModel Departure { get; set; } = null; public WaypointModel Arrival { get; set; } = null; public IWaypoint Current { get; set; } = null; public uint Cruise { get; set; } = 0; + public RouteModel(string departure, string departureRoute, string arrival, string arrivalRoute, uint cruise){ + if (FormAuthenticator.ValidateICAOCode(departure)) + { + Departure = new WaypointModel(departure, departureRoute); + } + + if (FormAuthenticator.ValidateICAOCode(arrival)) + { + Arrival = new WaypointModel(arrival, arrivalRoute); + } + + if (FormAuthenticator.ValidateCruiseAlt(cruise)) + { + Cruise = cruise; + } + } + + //Generate a route Object + public static RouteModel StringToRoute(string departure, string arrival, uint cruise, string routeString){ + string[] routeTemp = routeString.Split(" "); + + //Set departure and arrival route + string departureRoute = routeTemp[0]; + string arrivalRoute = routeTemp[routeTemp.Length - 2]; + + RouteModel route = new RouteModel(departure, departureRoute, arrival, arrivalRoute, cruise); + route.Departure.Airway = routeTemp[0]; + + route.Current = route.Departure; + + for (var i = 1; i < routeTemp.Length-1; i+=2) + {//Already used first item, continue itterating over every other item + IWaypoint next; + + //Populate 'next' waypoint + if (routeTemp[i].Length > 3) + {//waypoint Type + next = new WaypointModel(routeTemp[i], routeTemp[i+1]); + }else + {//Navaid Type + next = new NavaidModel(routeTemp[i], routeTemp[i+1]); + } + + next.Previous = route.Current; + route.Current.Next = next; + route.Current = next; + } + + //Connect end of route (linked list) + route.Current.Airway = null; + route.Current.Next = route.Arrival; + route.Arrival.Previous = route.Current; + + route.Current = null; + + return route; + } + + + + //Generate a route String + public static string ParseRoute(string route){ + route.Replace('/', ' '); + var routeArr = route.Split(' '); + + string finalRoute = ""; + + foreach (var item in routeArr) + { + var waypoint = item.Split('/')[0]; + if (waypoint.Length <= 7 && waypoint.Length >= 3 && !waypoint.Contains('-')) + { + finalRoute += $"{waypoint} "; + + if (waypoint.Length == 7 && finalRoute.Length > 8) + break; + + } + } + + return finalRoute; + } } + } \ No newline at end of file