Compare commits
12 Commits
8ac4a3d693
...
docker
Author | SHA1 | Date | |
---|---|---|---|
1fc6d2bbcd | |||
3f9bf384b0 | |||
e783f8c614 | |||
c418188481 | |||
ec5ca51602 | |||
eff67b7697 | |||
e271e49374 | |||
5316df08a5 | |||
10af903706 | |||
eda71069a4 | |||
8be3b0fa02 | |||
0252f115c6 |
24
.dockerignore
Normal file
24
.dockerignore
Normal file
@ -0,0 +1,24 @@
|
||||
**/.classpath
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
README.md
|
14
.vscode/launch.json
vendored
14
.vscode/launch.json
vendored
@ -2,19 +2,14 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"name": ".NET Core Launch (web)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/bin/Debug/net5.0/EFB.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"stopAtEntry": false,
|
||||
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
@ -30,6 +25,15 @@
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
},
|
||||
{
|
||||
"name": "Docker .NET Core Launch",
|
||||
"type": "docker",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "docker-run: debug",
|
||||
"netCore": {
|
||||
"appProject": "${workspaceFolder}/EFB.csproj"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
56
.vscode/tasks.json
vendored
56
.vscode/tasks.json
vendored
@ -37,6 +37,62 @@
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"type": "docker-build",
|
||||
"label": "docker-build: debug",
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"dockerBuild": {
|
||||
"tag": "efb:dev",
|
||||
"target": "base",
|
||||
"dockerfile": "${workspaceFolder}/Dockerfile",
|
||||
"context": "${workspaceFolder}",
|
||||
"pull": true
|
||||
},
|
||||
"netCore": {
|
||||
"appProject": "${workspaceFolder}/EFB.csproj"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "docker-build",
|
||||
"label": "docker-build: release",
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"dockerBuild": {
|
||||
"tag": "efb:latest",
|
||||
"dockerfile": "${workspaceFolder}/Dockerfile",
|
||||
"context": "${workspaceFolder}",
|
||||
"pull": true
|
||||
},
|
||||
"netCore": {
|
||||
"appProject": "${workspaceFolder}/EFB.csproj"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "docker-run",
|
||||
"label": "docker-run: debug",
|
||||
"dependsOn": [
|
||||
"docker-build: debug"
|
||||
],
|
||||
"dockerRun": {},
|
||||
"netCore": {
|
||||
"appProject": "${workspaceFolder}/EFB.csproj",
|
||||
"enableDebugging": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "docker-run",
|
||||
"label": "docker-run: release",
|
||||
"dependsOn": [
|
||||
"docker-build: release"
|
||||
],
|
||||
"dockerRun": {},
|
||||
"netCore": {
|
||||
"appProject": "${workspaceFolder}/EFB.csproj"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -23,18 +23,17 @@ namespace EFB.Controllers
|
||||
public IActionResult Index()
|
||||
{
|
||||
//Check to see what point on the application the user is at and where they should be sent
|
||||
UserModel User = HttpContext.Session.GetObject<UserModel>("User");
|
||||
if (User != null)
|
||||
UserModel user = HttpContext.Session.GetObject<UserModel>("User");
|
||||
if (user == null)
|
||||
{
|
||||
if (User.Route == null)
|
||||
{
|
||||
return RedirectToAction("Index", "Route");
|
||||
}else{
|
||||
return RedirectToAction("Index", "App");
|
||||
}
|
||||
}else{
|
||||
return RedirectToAction("Index", "Home");
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
if (user.Route == null)
|
||||
{
|
||||
return RedirectToAction("Index", "Route");
|
||||
}
|
||||
|
||||
return View(user);
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
|
87
Controllers/FlightsimController.cs
Normal file
87
Controllers/FlightsimController.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using EFB.Sessions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using EFB.Models;
|
||||
using EFB.MongoData;
|
||||
using EFB.Models.Route;
|
||||
|
||||
namespace EFB.Controllers
|
||||
{
|
||||
//[Route("[controller]")]
|
||||
public class FlightsimController : Controller
|
||||
{
|
||||
private readonly ILogger<FlightsimController> _logger;
|
||||
|
||||
public FlightsimController(ILogger<FlightsimController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
//Retrieve and Check current user status
|
||||
UserModel user = HttpContext.Session.GetObject<UserModel>("User");
|
||||
if(user == null){
|
||||
TempData["Error"] = "You must be logged in before you are able to view the FlightSim Page";
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
//Retrieve the user's latest sim position and construct it into FlightsimModel
|
||||
if (user.Route == null){
|
||||
TempData["Error"] = "You must have a route planned before you are able to view the Flightsim page";
|
||||
return RedirectToAction("Index", "Route");
|
||||
}
|
||||
|
||||
SimPositionModel latestPositionModel = await Mongo.GetLatestData(user.EMail);
|
||||
|
||||
RouteModel route = await RouteModel.StringToRoute(user.Departure, user.Arrival, user.Cruise, user.Route);
|
||||
IWaypoint closest = DetermineClosest(route, latestPositionModel.LatestPosition);
|
||||
|
||||
return View(new FlightsimModel(latestPositionModel, closest));
|
||||
|
||||
}
|
||||
|
||||
private IWaypoint DetermineClosest(RouteModel route, SimPosition currentPosition){
|
||||
IWaypoint closest = null;
|
||||
float closestDistance = float.MaxValue;
|
||||
//Assuming that we are on the earth for simplicity
|
||||
IWaypoint waypoint = route.Departure;
|
||||
while (waypoint.Next != null)
|
||||
{
|
||||
int earthRadius = 6371;
|
||||
float distanceLat = DegreesToRadians(waypoint.Latitude - currentPosition.Latitude);
|
||||
float distanceLon = DegreesToRadians(waypoint.Longitude - currentPosition.Longitude);
|
||||
|
||||
float latitude1 = DegreesToRadians(currentPosition.Latitude);
|
||||
float latitude2 = DegreesToRadians(waypoint.Latitude);
|
||||
|
||||
var a = Math.Sin(distanceLat/2) * Math.Sin(distanceLat/2) + Math.Sin(distanceLon/2) * Math.Sin(distanceLon/2) * Math.Cos(latitude1) * Math.Cos(latitude2);
|
||||
var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1-a));
|
||||
|
||||
float distance = (float)(earthRadius * c);
|
||||
|
||||
if (distance < closestDistance)
|
||||
{
|
||||
closest = waypoint;
|
||||
closestDistance = distance;
|
||||
}
|
||||
waypoint = waypoint.Next;
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
private float DegreesToRadians(float degrees){
|
||||
return (float)(degrees * Math.PI / 180);
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View("Error!");
|
||||
}
|
||||
}
|
||||
}
|
@ -46,154 +46,150 @@ namespace EFB.Controllers
|
||||
public async Task<IActionResult> New(string departure, string arrival, string cruise)
|
||||
{
|
||||
UserModel user = HttpContext.Session.GetObject<UserModel>("User");
|
||||
if (!(user == null || user.UserToken.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
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
uint cruiseAlt;
|
||||
if (!FormAuthenticator.ValidateICAOCode(departure) || !FormAuthenticator.ValidateICAOCode(arrival))
|
||||
{//If the user has entered valid ICAOs
|
||||
TempData["Error"] = "Invalid Departure or Arrival ICAO";
|
||||
return RedirectToAction("Index", "Route");
|
||||
}
|
||||
|
||||
uint cruiseAlt;
|
||||
|
||||
if (uint.TryParse(cruise, out cruiseAlt) && FormAuthenticator.ValidateCruiseAlt(cruiseAlt))
|
||||
{//If the cruise altitude if within limits.
|
||||
if (uint.TryParse(cruise, out cruiseAlt) && FormAuthenticator.ValidateCruiseAlt(cruiseAlt))
|
||||
{//If the cruise altitude if within limits.
|
||||
|
||||
//Submit route request...
|
||||
APIInterface API = new APIInterface();
|
||||
//Submit route request...
|
||||
APIInterface API = new APIInterface();
|
||||
|
||||
//Prepare data to be send off with request (route)
|
||||
Dictionary<string, string> headerData = new Dictionary<string, string>();
|
||||
headerData.Add("Authorization", $"Bearer {user.UserToken.TokenValue}");
|
||||
//Prepare data to be send off with request (route)
|
||||
Dictionary<string, string> headerData = new Dictionary<string, string>();
|
||||
headerData.Add("Authorization", $"Bearer {user.UserToken.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<string>("https://api.autorouter.aero/v1.0/router", headerData, content);
|
||||
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<string>("https://api.autorouter.aero/v1.0/router", headerData, content);
|
||||
|
||||
ResponseModel<string> responseRoute = await requestRoute;
|
||||
ResponseModel<string> responseRoute = await requestRoute;
|
||||
|
||||
if (responseRoute.Error == null)
|
||||
{//Update User session and add route ID
|
||||
TokenModel routeToken = new TokenModel()
|
||||
{
|
||||
TokenValue = responseRoute.Result.ToString()
|
||||
};
|
||||
if (responseRoute.Error == null)
|
||||
{//Update User session and add route ID
|
||||
TokenModel routeToken = new TokenModel()
|
||||
{
|
||||
TokenValue = responseRoute.Result.ToString()
|
||||
};
|
||||
|
||||
user.RouteToken = routeToken;
|
||||
HttpContext.Session.SetObject("User", user);
|
||||
user.RouteToken = routeToken;
|
||||
HttpContext.Session.SetObject("User", user);
|
||||
|
||||
return await Poll(departure, arrival, cruiseAlt);
|
||||
|
||||
}
|
||||
|
||||
TempData["Error"] = responseRoute.Error;
|
||||
return RedirectToAction("Index", "Route");
|
||||
|
||||
}
|
||||
TempData["Error"] = "Invalid Cruise Altitude";
|
||||
TempData["Departure"] = departure;
|
||||
TempData["Arrival"] = arrival;
|
||||
return RedirectToAction("Index", "Route");
|
||||
return await Poll(departure, arrival, cruiseAlt);
|
||||
|
||||
}
|
||||
TempData["Error"] = "Invalid Departure or Arrival ICAO";
|
||||
|
||||
TempData["Error"] = responseRoute.Error;
|
||||
return RedirectToAction("Index", "Route");
|
||||
|
||||
}
|
||||
return RedirectToAction("Index", "Home");
|
||||
TempData["Error"] = "Invalid Cruise Altitude";
|
||||
TempData["Departure"] = departure;
|
||||
TempData["Arrival"] = arrival;
|
||||
return RedirectToAction("Index", "Route");
|
||||
}
|
||||
|
||||
|
||||
public async Task<IActionResult> 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<UserModel>("User");
|
||||
|
||||
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 pollCount = 0;
|
||||
string routeString = "";
|
||||
|
||||
APIInterface API = new APIInterface();
|
||||
Dictionary<string, string> headerData = new Dictionary<string, string>();
|
||||
|
||||
/*-----Chart Fetching Operations--------*/
|
||||
|
||||
var requestDepartureCharts = ChartModel.FetchAsync(departure);
|
||||
var requestArrivalCharts = ChartModel.FetchAsync(arrival);
|
||||
|
||||
/*----------------------------------*/
|
||||
|
||||
//Run route Polling
|
||||
headerData.Add("Authorization", $"Bearer {user.UserToken.TokenValue}");
|
||||
|
||||
while (collected == false && pollCount < 15)
|
||||
{
|
||||
//Make Polling Request
|
||||
var pollingRequest = API.Put<List<PollResponse>>($"https://api.autorouter.aero/v1.0/router/{user.RouteToken.TokenValue}/longpoll", headerData, null);
|
||||
|
||||
ResponseModel<List<PollResponse>> responsePoll = await pollingRequest;
|
||||
|
||||
foreach (var item in responsePoll.Result)
|
||||
{
|
||||
if (item.Command == "fpl" || item.Command == "solution")
|
||||
{
|
||||
collected = true;
|
||||
routeString = item.FlightPlan;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(3000);
|
||||
pollCount++;
|
||||
|
||||
}
|
||||
|
||||
if (collected)
|
||||
{
|
||||
//Get Response from Charts
|
||||
ChartList departureCharts = await requestDepartureCharts;
|
||||
if (departureCharts != null)
|
||||
{
|
||||
user.DepartureCharts = new ChartModel(departure, departureCharts);
|
||||
}
|
||||
|
||||
ChartList arrivalCharts = await requestArrivalCharts;
|
||||
if (arrivalCharts != null)
|
||||
{
|
||||
user.ArrivalCharts = new ChartModel(arrival, arrivalCharts);
|
||||
}
|
||||
|
||||
//fill in route
|
||||
string finalRoute = RouteModel.ParseRoute(routeString);
|
||||
user.Route = finalRoute;
|
||||
HttpContext.Session.SetObject("User", user);
|
||||
|
||||
return RedirectToAction("Index", "Route");
|
||||
}
|
||||
|
||||
TempData["Error"] = $"Unable to get route after {pollCount} Attempts!";
|
||||
return RedirectToAction("Index", "Route");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return RedirectToAction("Index", "Route");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HttpContext.Session.GetString("User") == null)
|
||||
{//If the user is not currently logged in
|
||||
TempData["Error"] = "Please login before trying to plan a route";
|
||||
return RedirectToAction("Index", "Route");
|
||||
}
|
||||
|
||||
UserModel user = HttpContext.Session.GetObject<UserModel>("User");
|
||||
|
||||
if (user.RouteToken == null)
|
||||
{//If the user has a route object (e.g, they have been to the route page)
|
||||
return RedirectToAction("Index", "Route");
|
||||
}
|
||||
//Make calls to the server to fetch route
|
||||
bool collected = false;
|
||||
int pollCount = 0;
|
||||
string routeString = "";
|
||||
|
||||
APIInterface API = new APIInterface();
|
||||
Dictionary<string, string> headerData = new Dictionary<string, string>();
|
||||
|
||||
/*-----Chart Fetching Operations--------*/
|
||||
|
||||
var requestDepartureCharts = ChartModel.FetchAsync(departure);
|
||||
var requestArrivalCharts = ChartModel.FetchAsync(arrival);
|
||||
|
||||
/*----------------------------------*/
|
||||
|
||||
//Run route Polling
|
||||
headerData.Add("Authorization", $"Bearer {user.UserToken.TokenValue}");
|
||||
|
||||
while (collected == false && pollCount < 15)
|
||||
{
|
||||
//Make Polling Request
|
||||
var pollingRequest = API.Put<List<PollResponse>>($"https://api.autorouter.aero/v1.0/router/{user.RouteToken.TokenValue}/longpoll", headerData, null);
|
||||
|
||||
ResponseModel<List<PollResponse>> responsePoll = await pollingRequest;
|
||||
|
||||
foreach (var item in responsePoll.Result)
|
||||
{
|
||||
if (item.Command == "notvalid" || item.Command == "solution")
|
||||
{
|
||||
collected = true;
|
||||
routeString = item.FlightPlan;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(3000);
|
||||
pollCount++;
|
||||
|
||||
}
|
||||
|
||||
if (collected)
|
||||
{
|
||||
//Get Response from Charts
|
||||
ChartList departureCharts = await requestDepartureCharts;
|
||||
if (departureCharts != null)
|
||||
{
|
||||
user.DepartureCharts = new ChartModel(departure, departureCharts);
|
||||
}
|
||||
|
||||
ChartList arrivalCharts = await requestArrivalCharts;
|
||||
if (arrivalCharts != null)
|
||||
{
|
||||
user.ArrivalCharts = new ChartModel(arrival, arrivalCharts);
|
||||
}
|
||||
|
||||
//fill in route
|
||||
string finalRoute = RouteModel.ParseRoute(routeString);
|
||||
user.Route = finalRoute;
|
||||
user.Departure = departure;
|
||||
user.Arrival = arrival;
|
||||
user.Cruise = cruise;
|
||||
HttpContext.Session.SetObject("User", user);
|
||||
|
||||
return RedirectToAction("Index", "App");
|
||||
}
|
||||
|
||||
TempData["Error"] = $"Unable to get route after {pollCount} Attempts!";
|
||||
return RedirectToAction("Index", "Route");
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,63 +31,58 @@ namespace EFB.Controllers
|
||||
|
||||
public async Task<IActionResult> Login(string email, string password){
|
||||
|
||||
if (Form.FormAuthenticator.ValidateEMail(email))
|
||||
if (!Form.FormAuthenticator.ValidateEMail(email))
|
||||
{
|
||||
//API Helper
|
||||
APIInterface API = new APIInterface();
|
||||
|
||||
//Dictionary of Formdata to be encoded
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>();
|
||||
|
||||
formData.Add("grant_type", "client_credentials");
|
||||
formData.Add("client_id", email);
|
||||
formData.Add("client_secret", password);
|
||||
|
||||
HttpContent content = new FormUrlEncodedContent(formData);
|
||||
|
||||
var request = API.Post<Models.JSON.LoginResponse>("https://api.autorouter.aero/v1.0/oauth2/token", null, content);
|
||||
|
||||
//Wait for the response to come through
|
||||
ResponseModel<LoginResponse> response = await request;
|
||||
|
||||
if (response.Error != null)
|
||||
{
|
||||
TempData["Error"] = response.Error;
|
||||
TempData["email"] = email;
|
||||
return RedirectToAction("Index", "Home");
|
||||
}else{
|
||||
|
||||
//Type cast required but we know response will be of known type
|
||||
LoginResponse login = response.Result;
|
||||
|
||||
//Generate User Session
|
||||
if (login.error == null)
|
||||
{
|
||||
UserModel user = new UserModel{
|
||||
EMail = email,
|
||||
UserToken = new TokenModel{
|
||||
TokenValue = login.access_token,
|
||||
Expiration = DateTime.UtcNow.AddSeconds(login.expires_in)
|
||||
}
|
||||
};
|
||||
|
||||
//Using Session Extensions (Store the user session)
|
||||
HttpContext.Session.SetObject("User", user);
|
||||
return RedirectToAction("Index", "App");
|
||||
}else{
|
||||
TempData["Error"] = login.error_description;
|
||||
TempData["email"] = email;
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}else{
|
||||
TempData["Error"] = "Please enter a valid E-Mail";
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
//API Helper
|
||||
APIInterface API = new APIInterface();
|
||||
|
||||
//Dictionary of Formdata to be encoded
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>();
|
||||
|
||||
formData.Add("grant_type", "client_credentials");
|
||||
formData.Add("client_id", email);
|
||||
formData.Add("client_secret", password);
|
||||
|
||||
HttpContent content = new FormUrlEncodedContent(formData);
|
||||
|
||||
var request = API.Post<Models.JSON.LoginResponse>("https://api.autorouter.aero/v1.0/oauth2/token", null, content);
|
||||
|
||||
//Wait for the response to come through
|
||||
ResponseModel<LoginResponse> response = await request;
|
||||
|
||||
if (response.Error != null)
|
||||
{
|
||||
TempData["Error"] = response.Error;
|
||||
TempData["email"] = email;
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
//Type cast required but we know response will be of known type
|
||||
LoginResponse login = response.Result;
|
||||
|
||||
//Generate User Session
|
||||
if (login.error != null)
|
||||
{
|
||||
TempData["Error"] = login.error_description;
|
||||
TempData["email"] = email;
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
UserModel user = new UserModel{
|
||||
EMail = email,
|
||||
UserToken = new TokenModel{
|
||||
TokenValue = login.access_token,
|
||||
Expiration = DateTime.UtcNow.AddSeconds(login.expires_in)
|
||||
}
|
||||
};
|
||||
|
||||
//Using Session Extensions (Store the user session)
|
||||
HttpContext.Session.SetObject("User", user);
|
||||
return RedirectToAction("Index", "App");
|
||||
|
||||
}
|
||||
|
||||
public IActionResult Logout(){
|
||||
|
26
Dockerfile
Normal file
26
Dockerfile
Normal file
@ -0,0 +1,26 @@
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:5.0-focal AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 5000
|
||||
|
||||
ENV ASPNETCORE_URLS=http://+:5000
|
||||
|
||||
# Creates a non-root user with an explicit UID and adds permission to access the /app folder
|
||||
# For more info, please refer to https://aka.ms/vscode-docker-dotnet-configure-containers
|
||||
RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app
|
||||
USER appuser
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:5.0-focal AS build
|
||||
WORKDIR /src
|
||||
COPY ["EFB.csproj", "./"]
|
||||
RUN dotnet restore "EFB.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/."
|
||||
RUN dotnet build "EFB.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "EFB.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "EFB.dll"]
|
@ -5,5 +5,8 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
|
||||
<PackageReference Include="MySql.Data" Version="*"/>
|
||||
<PackageReference Include="MongoDB.Driver" Version="*"/>
|
||||
<PackageReference Include="MongoDB.Bson" Version="*"/>
|
||||
<PackageReference Include="libmetar" Version="*"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
32
Metar/Metar.cs
Normal file
32
Metar/Metar.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using libmetar.Services;
|
||||
|
||||
namespace EFB.Metar
|
||||
{
|
||||
public static class Metar
|
||||
{
|
||||
private static MetarService metarService { get; set; } = new MetarService();
|
||||
private static TafService tafService { get; set; } = new TafService();
|
||||
|
||||
|
||||
public static async Task<string> GetMETAR(string ICAO){
|
||||
return (await metarService.GetRawAsync(ICAO)).Raw;
|
||||
}
|
||||
|
||||
public static async Task<List<string>> GetTAF(string ICAO){
|
||||
var downloadedTAF = (await tafService.GetRawAsync(ICAO)).RawSplit;
|
||||
List<string> TAF = new List<string>();
|
||||
|
||||
foreach (var line in downloadedTAF)
|
||||
{
|
||||
TAF.Add(line);
|
||||
}
|
||||
return TAF;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -63,7 +63,7 @@ namespace EFB.Models
|
||||
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>();
|
||||
|
||||
formData.Add("token", Environment.GetEnvironmentVariable("ChartFoxAPIKey", EnvironmentVariableTarget.User));
|
||||
formData.Add("token", Environment.GetEnvironmentVariable("ChartFoxAPIKey"));
|
||||
FormUrlEncodedContent body = new FormUrlEncodedContent(formData);
|
||||
|
||||
//make Charts request
|
||||
|
19
Models/FlightsimModel.cs
Normal file
19
Models/FlightsimModel.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EFB.Models.Route;
|
||||
|
||||
namespace EFB.Models
|
||||
{
|
||||
public class FlightsimModel
|
||||
{
|
||||
public SimPositionModel CurrentPosition { get; set; }
|
||||
public IWaypoint Closest { get; set; }
|
||||
public FlightsimModel(SimPositionModel position, IWaypoint closest)
|
||||
{
|
||||
CurrentPosition = position;
|
||||
Closest = closest;
|
||||
}
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ namespace EFB.Models
|
||||
}
|
||||
|
||||
public static async Task<NavdataModel[]> Populate(){
|
||||
string password = Environment.GetEnvironmentVariable("MySQLPassword", EnvironmentVariableTarget.User);
|
||||
string password = Environment.GetEnvironmentVariable("MySQLPassword");
|
||||
MySqlConnection con = new MySqlConnection($"server=server.luke-else.co.uk;userid=root;password={password};database=EFB");
|
||||
con.Open();
|
||||
|
||||
@ -54,11 +54,11 @@ namespace EFB.Models
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
int id = reader.GetInt32(0);
|
||||
string name = reader.GetString(1);
|
||||
string type = reader.GetString(2);
|
||||
string latitude = reader.GetString(4);
|
||||
string longitude = reader.GetString(5);
|
||||
int id = reader.GetInt32("id");
|
||||
string name = reader.GetString("name");
|
||||
string type = reader.GetString("type");
|
||||
string latitude = reader.GetString("latitude");
|
||||
string longitude = reader.GetString("longitude");
|
||||
|
||||
if (type == "VOR" || type == "NDB")
|
||||
{
|
||||
|
@ -8,8 +8,8 @@ namespace EFB.Models.Route
|
||||
public interface IWaypoint
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Longitude { get; set; }
|
||||
public string Latitude { get; set; }
|
||||
public float Longitude { get; set; }
|
||||
public float Latitude { get; set; }
|
||||
|
||||
public string Airway { get; set; }
|
||||
public IWaypoint Next { get; set; }
|
||||
|
@ -8,8 +8,8 @@ namespace EFB.Models.Route
|
||||
public class NavaidModel:IWaypoint
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Longitude { get; set; }
|
||||
public string Latitude { get; set; }
|
||||
public float Longitude { get; set; }
|
||||
public float Latitude { get; set; }
|
||||
public int Frequency { get; set; }
|
||||
|
||||
public string Airway { get; set; }
|
||||
@ -17,9 +17,11 @@ namespace EFB.Models.Route
|
||||
public IWaypoint Previous { get; set; } = null;
|
||||
public bool Visited { get; set; } = false;
|
||||
|
||||
public NavaidModel(string name, string airway){
|
||||
public NavaidModel(string name, string airway, float longitude, float latitude){
|
||||
Name = name;
|
||||
Airway = airway;
|
||||
Longitude = longitude;
|
||||
Latitude = latitude;
|
||||
}
|
||||
}
|
||||
}
|
@ -8,17 +8,19 @@ namespace EFB.Models.Route
|
||||
public class WaypointModel:IWaypoint
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Longitude { get; set; }
|
||||
public string Latitude { get; set; }
|
||||
public float Longitude { get; set; }
|
||||
public float Latitude { get; set; }
|
||||
|
||||
public string Airway { get; set; }
|
||||
public IWaypoint Next { get; set; } = null;
|
||||
public IWaypoint Previous { get; set; } = null;
|
||||
public bool Visited { get; set; }
|
||||
|
||||
public WaypointModel(string name, string airway){
|
||||
public WaypointModel(string name, string airway, float longitude, float latitude){
|
||||
Name = name;
|
||||
Airway = airway;
|
||||
Longitude = longitude;
|
||||
Latitude = latitude;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,15 +19,15 @@ namespace EFB.Models
|
||||
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){
|
||||
public RouteModel(string departure, string departureRoute, string arrival, string arrivalRoute, uint cruise){
|
||||
if (FormAuthenticator.ValidateICAOCode(departure))
|
||||
{
|
||||
Departure = new WaypointModel(departure, departureRoute);
|
||||
Departure = new WaypointModel(departure, departureRoute, 0, 0);
|
||||
}
|
||||
|
||||
if (FormAuthenticator.ValidateICAOCode(arrival))
|
||||
{
|
||||
Arrival = new WaypointModel(arrival, arrivalRoute);
|
||||
Arrival = new WaypointModel(arrival, arrivalRoute, 0, 0);
|
||||
}
|
||||
|
||||
if (FormAuthenticator.ValidateCruiseAlt(cruise))
|
||||
@ -53,7 +53,8 @@ namespace EFB.Models
|
||||
}
|
||||
|
||||
//Generate a route Object
|
||||
public static RouteModel StringToRoute(string departure, string arrival, uint cruise, string routeString){
|
||||
public static async Task<RouteModel> StringToRoute(string departure, string arrival, uint cruise, string routeString){
|
||||
var navdataFetch = NavdataModel.Populate();
|
||||
string[] routeTemp = routeString.Split(" ");
|
||||
|
||||
//Set departure and arrival route
|
||||
@ -65,17 +66,34 @@ namespace EFB.Models
|
||||
|
||||
route.Current = route.Departure;
|
||||
|
||||
NavdataModel[] navdata = await navdataFetch;
|
||||
navdata = NavdataModel.MergeSort(ref navdata, 0, navdata.Length - 1);
|
||||
|
||||
for (var i = 1; i < routeTemp.Length-1; i+=2)
|
||||
{//Already used first item, continue itterating over every other item
|
||||
IWaypoint next;
|
||||
|
||||
NavdataModel currentWaypoint = NavdataModel.BinarySearch(ref navdata, 0, navdata.Length-1, routeTemp[i]);
|
||||
if (currentWaypoint == null)
|
||||
{
|
||||
currentWaypoint = new NavdataModel(0, routeTemp[i], null, "0", "0");
|
||||
}
|
||||
//Populate 'next' waypoint
|
||||
if (routeTemp[i].Length > 3)
|
||||
{//waypoint Type
|
||||
next = new WaypointModel(routeTemp[i], routeTemp[i+1]);
|
||||
next = new WaypointModel(
|
||||
routeTemp[i],
|
||||
routeTemp[i+1],
|
||||
float.Parse(currentWaypoint.Longitude),
|
||||
float.Parse(currentWaypoint.Latitude)
|
||||
);
|
||||
}else
|
||||
{//Navaid Type
|
||||
next = new NavaidModel(routeTemp[i], routeTemp[i+1]);
|
||||
next = new NavaidModel(
|
||||
routeTemp[i],
|
||||
routeTemp[i+1],
|
||||
float.Parse(currentWaypoint.Longitude),
|
||||
float.Parse(currentWaypoint.Latitude)
|
||||
);
|
||||
}
|
||||
|
||||
next.Previous = route.Current;
|
||||
@ -90,6 +108,15 @@ namespace EFB.Models
|
||||
|
||||
route.Current = route.Departure;
|
||||
|
||||
//Assign departure and arrival coordinate positions
|
||||
NavdataModel departureNav = NavdataModel.BinarySearch(ref navdata, 0, navdata.Length - 1, departure);
|
||||
NavdataModel arrivalNav = NavdataModel.BinarySearch(ref navdata, 0, navdata.Length - 1, arrival);
|
||||
route.Departure.Latitude = float.Parse(departureNav.Latitude);
|
||||
route.Departure.Longitude = float.Parse(departureNav.Longitude);
|
||||
route.Arrival.Latitude = float.Parse(arrivalNav.Latitude);
|
||||
route.Arrival.Latitude = float.Parse(arrivalNav.Longitude);
|
||||
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
|
53
Models/SimPositionModel.cs
Normal file
53
Models/SimPositionModel.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace EFB.Models
|
||||
{
|
||||
public class SimPositionModel
|
||||
{
|
||||
[BsonId]
|
||||
public ObjectId Id { get; set; }
|
||||
public string EMail { get; set; } = "";
|
||||
public DateTime LatestPacketUpdate { get; set; }
|
||||
public SimPosition LatestPosition { get; set; } = null;
|
||||
|
||||
public SimPositionModel(string email, SimPosition position){
|
||||
EMail = email;
|
||||
LatestPacketUpdate = DateTime.Now;
|
||||
LatestPosition = position;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class SimPosition
|
||||
{
|
||||
public float Latitude { get; set; }
|
||||
public float Longitude { get; set; }
|
||||
public int Altitude { get; set; }
|
||||
|
||||
public SimPosition(float latitude, float longitude, int altitude){
|
||||
Latitude = latitude;
|
||||
Longitude = longitude;
|
||||
Altitude = altitude;
|
||||
}
|
||||
|
||||
//**Packet Processing not required**//
|
||||
|
||||
// public SimPosition(Packet[] data){
|
||||
// if (data[0].Data != null)
|
||||
// {
|
||||
// //Use Linq to search through the packets for a given id and use that data
|
||||
// Latitude = (data.Where(x => x.Id == 22).Select(x => x.Data[0]).ToArray())[0];
|
||||
// Longitude = (data.Where(x => x.Id == 23).Select(x => x.Data[0]).ToArray())[0];
|
||||
// Altitude = Convert.ToInt32((data.Where(x => x.Id == 24).Select(x => x.Data[0]).ToArray())[0]);
|
||||
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
@ -21,7 +21,12 @@ namespace EFB.Models
|
||||
public TokenModel UserToken { get; set; } = null;
|
||||
|
||||
//Contains the most recent route generated by the user through the App
|
||||
public string Departure { get; set; }
|
||||
public string Route { get; set; }
|
||||
public string Arrival { get; set; }
|
||||
public uint Cruise { get; set; }
|
||||
|
||||
|
||||
public TokenModel RouteToken { get; set; } = null;
|
||||
|
||||
//Contains the Departure and Arrival Charts for the user's route
|
||||
|
30
Mongo/Mongo.cs
Normal file
30
Mongo/Mongo.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Driver;
|
||||
using MongoDB.Bson;
|
||||
using EFB.Models;
|
||||
|
||||
namespace EFB.MongoData
|
||||
{
|
||||
public class Mongo
|
||||
{
|
||||
//function that is responsible to getting the user's latest sim position from the MongoDB
|
||||
public static async Task<SimPositionModel> GetLatestData(string email){
|
||||
MongoClient client = new MongoClient(
|
||||
Environment.GetEnvironmentVariable("MongoDBConnectionString")
|
||||
);
|
||||
MongoDatabaseBase database = (MongoDatabaseBase)client.GetDatabase("EFB");
|
||||
MongoCollectionBase<SimPositionModel> collection = (MongoCollectionBase<SimPositionModel>)database.GetCollection<SimPositionModel>("Simdata");
|
||||
|
||||
FilterDefinition<SimPositionModel> filter = Builders<SimPositionModel>.Filter.Eq(x => x.EMail, email);
|
||||
var data = await collection.FindAsync<SimPositionModel>(filter).Result.ToListAsync();
|
||||
if (data.Count > 0)
|
||||
{
|
||||
return data[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
48
Views/App/Index.cshtml
Normal file
48
Views/App/Index.cshtml
Normal file
@ -0,0 +1,48 @@
|
||||
@using EFB.Metar;
|
||||
@model EFB.Models.UserModel;
|
||||
@{
|
||||
ViewData["Title"] = "Welcome";
|
||||
}
|
||||
|
||||
<div class="row d-flex">
|
||||
<div class="card-body col-md-12 bg-primary">
|
||||
<div class="container jumbotron">
|
||||
<h3>Current Session - @Model.EMail</h3>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
|
||||
<div class="row d-flex">
|
||||
<div class="col-md-6">
|
||||
<h4>Departure</h4>
|
||||
@Model.Departure
|
||||
|
||||
<br />
|
||||
|
||||
@await Metar.GetMETAR(Model.Departure)
|
||||
|
||||
<h4>Cruise</h4>
|
||||
@Model.Cruise ft
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h4>Arrival</h4>
|
||||
@Model.Arrival
|
||||
|
||||
<br />
|
||||
|
||||
@await Metar.GetMETAR(Model.Arrival)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<h4>Route</h4>
|
||||
@Model.Route
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
@using Newtonsoft.Json;
|
||||
@using EFB.Metar;
|
||||
@model EFB.Models.ViewChartModel;
|
||||
@{
|
||||
ViewData["Title"] = "Welcome";
|
||||
@ -80,6 +81,10 @@
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
|
||||
<br />
|
||||
<h4>Current Weather</h4>
|
||||
@await Metar.GetMETAR(@Model.Charts.ICAO);
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -99,4 +104,6 @@
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
53
Views/Flightsim/Index.cshtml
Normal file
53
Views/Flightsim/Index.cshtml
Normal file
@ -0,0 +1,53 @@
|
||||
@model EFB.Models.FlightsimModel;
|
||||
@{
|
||||
ViewData["Title"] = "Welcome";
|
||||
}
|
||||
|
||||
<div class="row d-flex">
|
||||
<div class="card-body col-md-6 bg-primary">
|
||||
<div class="container jumbotron">
|
||||
<h3>Current Position</h3>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<h5 style="color: gray;">Last Updated at: @Model.CurrentPosition.LatestPacketUpdate.ToString()</h5>
|
||||
|
||||
<div class="row d-flex">
|
||||
<div class="col-md-6">
|
||||
<h4>Latitude</h4>
|
||||
@Model.CurrentPosition.LatestPosition.Latitude
|
||||
|
||||
<h4>Longitude</h4>
|
||||
@Model.CurrentPosition.LatestPosition.Longitude
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h4>Altitude</h4>
|
||||
@Model.CurrentPosition.LatestPosition.Altitude ft
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body col-md-6 bg-success">
|
||||
<div class="container jumbotron">
|
||||
<h3>Closest Waypoint</h3>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<h4>@Model.Closest.Name -> @Model.Closest.Airway</h4>
|
||||
|
||||
<h4>Latitude</h4>
|
||||
@Model.Closest.Latitude
|
||||
|
||||
<h4>Longitude</h4>
|
||||
@Model.Closest.Longitude
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
<a class="nav-link text-light" asp-area="" asp-controller="Charts" asp-action="Index">Charts</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-light" asp-area="" asp-controller="" asp-action="Index">FlightSim</a>
|
||||
<a class="nav-link text-light" asp-area="" asp-controller="Flightsim" asp-action="Index">FlightSim</a>
|
||||
</li>
|
||||
|
||||
@{
|
||||
|
16
docker-compose.debug.yml
Normal file
16
docker-compose.debug.yml
Normal file
@ -0,0 +1,16 @@
|
||||
# Please refer https://aka.ms/HTTPSinContainer on how to setup an https developer certificate for your ASP .NET Core service.
|
||||
|
||||
version: '3.4'
|
||||
|
||||
services:
|
||||
efb:
|
||||
image: efb
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./Dockerfile
|
||||
ports:
|
||||
- 5000:5000
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
volumes:
|
||||
- ~/.vsdbg:/remote_debugger:rw
|
16
docker-compose.yml
Normal file
16
docker-compose.yml
Normal file
@ -0,0 +1,16 @@
|
||||
# Please refer https://aka.ms/HTTPSinContainer on how to setup an https developer certificate for your ASP .NET Core service.
|
||||
|
||||
version: '3.4'
|
||||
|
||||
services:
|
||||
efb:
|
||||
image: efb
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./Dockerfile
|
||||
ports:
|
||||
- 80:5000
|
||||
environment:
|
||||
- MongoDBConnectionString=
|
||||
- MySQLPassword=
|
||||
- ChartFoxAPIKey=
|
Reference in New Issue
Block a user