12 Commits

26 changed files with 717 additions and 217 deletions

24
.dockerignore Normal file
View 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
View File

@ -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
View File

@ -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"
}
}
]
}

View File

@ -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)]

View 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!");
}
}
}

View File

@ -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");
}

View File

@ -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
View 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"]

View File

@ -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
View 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;
}
}
}

View File

@ -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
View 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;
}
}
}

View File

@ -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")
{

View File

@ -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; }

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View 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]);
// }
// }
}
}

View File

@ -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
View 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
View 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>

View File

@ -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>

View 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>

View File

@ -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
View 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
View 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=