kopia lustrzana https://github.com/dl2alf/AirScout
942 wiersze
35 KiB
C#
942 wiersze
35 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Reflection;
|
|
using System.ComponentModel;
|
|
using System.Globalization;
|
|
using AirScout.PlaneFeeds.Plugin.MEFContract;
|
|
using System.Net;
|
|
using System.IO;
|
|
using System.Security.Cryptography;
|
|
using System.Xml.Serialization;
|
|
using System.Xml.Linq;
|
|
using System.ComponentModel.Composition;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace AirScout.PlaneFeeds.Plugin.VRSWebServer
|
|
{
|
|
|
|
public class VRSWebServerServerSettings
|
|
{
|
|
|
|
[Browsable(false)]
|
|
[DefaultValue("")]
|
|
[XmlIgnore]
|
|
public string DisclaimerAccepted { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[CategoryAttribute("Web Feed")]
|
|
[DescriptionAttribute("Save downloaded JSON to file")]
|
|
[DefaultValue(false)]
|
|
[XmlIgnore]
|
|
public bool SaveToFile { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[CategoryAttribute("Web Feed")]
|
|
[DescriptionAttribute("Base URL for website.")]
|
|
[DefaultValue("http://localhost:7780/VirtualRadar/AircraftList.json?ldv=%LASTDV%&stm=%UNIXTIME%&lat=%MYLAT%&lng=%MYLON%&fDstL=%MINDISTKM%&fDstU=%MAXDISTKM%&fAltL=%MINALTFT%&fAltU=%MAXALTFT%")]
|
|
public string URL { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[CategoryAttribute("Web Feed")]
|
|
[DescriptionAttribute("Username for Authentication (blank for anonymous)")]
|
|
[DefaultValue("")]
|
|
public string Username { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[CategoryAttribute("Web Feed")]
|
|
[DescriptionAttribute("Password for Authentication (blank for anonymous)")]
|
|
[DefaultValue("")]
|
|
[PasswordPropertyText(true)]
|
|
public string Password { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[CategoryAttribute("Web Feed (redundant)")]
|
|
[DescriptionAttribute("Base URL for redundant website.")]
|
|
public string URL2 { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[CategoryAttribute("Web Feed (redundant)")]
|
|
[DescriptionAttribute("Username for redundant Authentication (blank for anonymous)")]
|
|
[DefaultValue("")]
|
|
public string Username2 { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[CategoryAttribute("Web Feed (redundant)")]
|
|
[DescriptionAttribute("Password for redundant Authentication (blank for anonymous)")]
|
|
[DefaultValue("")]
|
|
[PasswordPropertyText(true)]
|
|
public string Password2 { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[CategoryAttribute("Web Feed (redundant)")]
|
|
[DescriptionAttribute("Share load between both redundant servers")]
|
|
[DefaultValue(true)]
|
|
public bool LoadShare { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[CategoryAttribute("Web Feed")]
|
|
[DescriptionAttribute("Use geometric altitude from GPS rather than barometric")]
|
|
[DefaultValue(false)]
|
|
public bool UseGeoAlt { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[CategoryAttribute("Web Feed")]
|
|
[DescriptionAttribute("Timeout for loading the site.")]
|
|
[DefaultValue(30)]
|
|
[XmlIgnore]
|
|
public int Timeout { get; set; }
|
|
|
|
public VRSWebServerServerSettings()
|
|
{
|
|
Default();
|
|
Load(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets all properties to their default value according to the [DefaultValue=] attribute
|
|
/// </summary>
|
|
public void Default()
|
|
{
|
|
// set all properties to their default values according to definition in [DeafultValue=]
|
|
foreach (var p in this.GetType().GetProperties())
|
|
{
|
|
try
|
|
{
|
|
// initialize all properties with default value if set
|
|
if (Attribute.IsDefined(p, typeof(DefaultValueAttribute)))
|
|
{
|
|
p.SetValue(this, ((DefaultValueAttribute)Attribute.GetCustomAttribute(
|
|
p, typeof(DefaultValueAttribute)))?.Value, null);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Cannot set default value of: " + p.Name + ", " + ex.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads settings from a XML-formatted configuration file into settings.
|
|
/// </summary>
|
|
/// <param name="loadall">If true, ignore the [XmlIgnore] attribute, e.g. load all settings available in the file.<br>If false, load only settings without [XmlIgore] attrbute.</br></param>
|
|
/// <param name="filename">The filename of the settings file.</param>
|
|
public void Load(bool loadall, string filename = "")
|
|
{
|
|
// use standard filename if empty
|
|
// be careful because Linux file system is case sensitive
|
|
if (String.IsNullOrEmpty(filename))
|
|
filename = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase.Replace(".dll", ".cfg").Replace(".DLL", ".CFG")).LocalPath;
|
|
// do nothing if file not exists
|
|
if (!File.Exists(filename))
|
|
return;
|
|
try
|
|
{
|
|
string xml = "";
|
|
using (StreamReader sr = new StreamReader(File.OpenRead(filename)))
|
|
{
|
|
xml = sr.ReadToEnd();
|
|
}
|
|
XDocument xdoc = XDocument.Parse(xml);
|
|
PropertyInfo[] properties = this.GetType().GetProperties();
|
|
foreach (PropertyInfo p in properties)
|
|
{
|
|
if (!loadall)
|
|
{
|
|
// check on XmlIgnore attribute, skip if set
|
|
object[] attr = p.GetCustomAttributes(typeof(XmlIgnoreAttribute), false);
|
|
if (attr.Length > 0)
|
|
continue;
|
|
}
|
|
try
|
|
{
|
|
// get matching element
|
|
XElement typenode = xdoc.Element(this.GetType().Name);
|
|
if (typenode != null)
|
|
{
|
|
XElement element = typenode.Element(p.Name);
|
|
if (element != null)
|
|
{
|
|
// fix issues with URL in V1.4.0.0 --> do not load URL from file if not containing filters
|
|
if ((p.Name != "URL") || (element.Value.ToString().Contains("?")))
|
|
{
|
|
p.SetValue(this, Convert.ChangeType(element.Value, p.PropertyType), null);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Ignoring property URL do to version conflict: " + element.Value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Error while loading property[" + p.Name + " from " + filename + ", " + ex.Message);
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Cannot load settings from " + filename + ", " + ex.Message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves settings from settings into a XML-formatted configuration file
|
|
/// </summary>
|
|
/// <param name="saveall">If true, ignore the [XmlIgnore] attribute, e.g. save all settings.<br>If false, save only settings without [XmlIgore] attrbute.</param>
|
|
/// <param name="filename">The filename of the settings file.</param>
|
|
public void Save(bool saveall, string filename = "")
|
|
{
|
|
// use standard filename if empty
|
|
// be careful because Linux file system is case sensitive
|
|
if (String.IsNullOrEmpty(filename))
|
|
filename = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase.Replace(".dll", ".cfg").Replace(".DLL", ".CFG")).LocalPath;
|
|
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
|
|
if (saveall)
|
|
{
|
|
// ovverride the XmlIgnore attributes to get all serialized
|
|
PropertyInfo[] properties = this.GetType().GetProperties();
|
|
foreach (PropertyInfo p in properties)
|
|
{
|
|
XmlAttributes attribs = new XmlAttributes { XmlIgnore = false };
|
|
overrides.Add(this.GetType(), p.Name, attribs);
|
|
}
|
|
}
|
|
try
|
|
{
|
|
using (StreamWriter sw = new StreamWriter(File.Create(filename)))
|
|
{
|
|
XmlSerializer s = new XmlSerializer(this.GetType(), overrides);
|
|
s.Serialize(sw, this);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new InvalidOperationException("[" + this.GetType().Name + "]: Cannot save settings to " + filename + ", " + ex.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
[Export(typeof(IPlaneFeedPlugin))]
|
|
[ExportMetadata("Name", "PlaneFeedPlugin")]
|
|
public class VRSWebServerPlugin : IPlaneFeedPlugin
|
|
{
|
|
private VRSWebServerServerSettings Settings = new VRSWebServerServerSettings();
|
|
|
|
VirtualRadar.Interface.WebSite.AircraftListJson AircraftList = null;
|
|
|
|
// last data version
|
|
private string LastDV { get; set; } = "";
|
|
|
|
// Load share counter
|
|
long Count1 = 0;
|
|
long Count2 = 0;
|
|
|
|
|
|
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
return "[WebFeed] VRS Web Server";
|
|
}
|
|
}
|
|
|
|
public string Info
|
|
{
|
|
get
|
|
{
|
|
return "Web feed from Virtual Radar Server\n\n" +
|
|
"(c) AirScout(www.airscout.eu)\n\n" +
|
|
"Gets either single or aggrated feed\n" +
|
|
"from a local or remote VRS instance.\n" +
|
|
"Be sure to select the desired feed as\n" +
|
|
"the default web server feed in the\n" +
|
|
"VRS Web server settings.\n\n" +
|
|
"See https://www.virtualradarserver.co.uk \n" +
|
|
"for details.\n\n" +
|
|
"Change hostname and/or port to your needs\n" +
|
|
"when getting data from a remote server.\n\n" +
|
|
"If the access is restricted, you can\n" +
|
|
"enter username and password here.\n\n" +
|
|
"";
|
|
}
|
|
}
|
|
|
|
public string Version
|
|
{
|
|
get
|
|
{
|
|
return Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
|
}
|
|
}
|
|
|
|
public bool HasSettings
|
|
{
|
|
get
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public bool CanImport
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool CanExport
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public string Disclaimer
|
|
{
|
|
get
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
|
|
public string DisclaimerAccepted
|
|
{
|
|
get
|
|
{
|
|
return Settings.DisclaimerAccepted;
|
|
}
|
|
set
|
|
{
|
|
Settings.DisclaimerAccepted = value;
|
|
}
|
|
}
|
|
|
|
public void ResetSettings()
|
|
{
|
|
Settings.Default();
|
|
}
|
|
|
|
public void LoadSettings()
|
|
{
|
|
Settings.Load(true);
|
|
}
|
|
|
|
public void SaveSettings()
|
|
{
|
|
Settings.Save(true);
|
|
}
|
|
|
|
public object GetSettings()
|
|
{
|
|
return this.Settings;
|
|
}
|
|
|
|
public void ImportSettings()
|
|
{
|
|
// nothing to do
|
|
}
|
|
|
|
public void ExportSettings()
|
|
{
|
|
// nothing to do
|
|
}
|
|
|
|
public void Start(PlaneFeedPluginArgs args)
|
|
{
|
|
// reset counters
|
|
Count1 = 0;
|
|
Count2 = 0;
|
|
}
|
|
|
|
public PlaneFeedPluginPlaneInfoList GetPlanes(PlaneFeedPluginArgs args)
|
|
{
|
|
// intialize variables
|
|
VarConverter VC = new VarConverter();
|
|
VC.AddVar("APPDIR", args.AppDirectory);
|
|
VC.AddVar("DATADIR", args.AppDataDirectory);
|
|
VC.AddVar("LOGDIR", args.LogDirectory);
|
|
VC.AddVar("DATABASEDIR", args.DatabaseDirectory);
|
|
VC.AddVar("MINLAT", args.MinLat);
|
|
VC.AddVar("MAXLAT", args.MaxLat);
|
|
VC.AddVar("MINLON", args.MinLon);
|
|
VC.AddVar("MAXLON", args.MaxLon);
|
|
VC.AddVar("MINALTM", args.MinAlt);
|
|
VC.AddVar("MAXALTM", args.MaxAlt);
|
|
VC.AddVar("MINALTFT", (int)UnitConverter.m_ft((double)args.MinAlt));
|
|
VC.AddVar("MAXALTFT", (int)UnitConverter.m_ft((double)args.MaxAlt));
|
|
VC.AddVar("UNIXTIME", SupportFunctions.DateTimeToUNIXTime(DateTime.UtcNow));
|
|
|
|
// calculate Max/Min distance for filter
|
|
VC.AddVar("MYLAT", args.MyLat);
|
|
VC.AddVar("MYLON", args.MyLon);
|
|
|
|
double mindist = 0;
|
|
double maxdist = 0;
|
|
|
|
// check the distance between MyLocation and edges of rect and take the maximum
|
|
maxdist = Math.Max(maxdist, LatLon.Distance(args.MyLat, args.MyLon, args.MinLat, args.MinLon));
|
|
maxdist = Math.Max(maxdist, LatLon.Distance(args.MyLat, args.MyLon, args.MaxLat, args.MinLon));
|
|
maxdist = Math.Max(maxdist, LatLon.Distance(args.MyLat, args.MyLon, args.MinLat, args.MaxLon));
|
|
maxdist = Math.Max(maxdist, LatLon.Distance(args.MyLat, args.MyLon, args.MaxLat, args.MaxLon));
|
|
|
|
VC.AddVar("MINDISTKM", mindist);
|
|
VC.AddVar("MAXDISTKM", maxdist);
|
|
|
|
VC.AddVar("LASTDV", LastDV);
|
|
|
|
// initialize plane info list
|
|
PlaneFeedPluginPlaneInfoList planes = new PlaneFeedPluginPlaneInfoList();
|
|
|
|
string url = "";
|
|
string json = "";
|
|
|
|
// if redundant servers --> calculate url according to redundancy and load sharing
|
|
if (!String.IsNullOrEmpty(Settings.URL2))
|
|
{
|
|
if (!Settings.LoadShare)
|
|
{
|
|
// no load sharing --> use URL1 by default, use URL2 if anything goes wrong
|
|
try
|
|
{
|
|
DateTime start1 = DateTime.UtcNow;
|
|
|
|
url = VC.ReplaceAllVars(Settings.URL);
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Mode=REDUNDANCY, LoadShare=OFF");
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Creating web request: " + url);
|
|
|
|
// get JSON data
|
|
json = VRSTlsClient.DownloadFile(url, Settings.Timeout * 1000, Settings.Username, Settings.Password);
|
|
|
|
// aggregate loading time
|
|
Count1 += (long)(DateTime.UtcNow - start1).Milliseconds;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DateTime start2 = DateTime.UtcNow;
|
|
|
|
url = VC.ReplaceAllVars(Settings.URL2);
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Mode=REDUNDANCY, LoadShare=OFF");
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Creating web request: " + url);
|
|
|
|
// get JSON data
|
|
json = VRSTlsClient.DownloadFile(url, Settings.Timeout * 1000, Settings.Username, Settings.Password);
|
|
|
|
// aggregate loading time
|
|
Count2 += (long)(DateTime.UtcNow - start2).Milliseconds;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// load sharing --> use URL with lowest overall loading time first, use the other if anything goes wrong
|
|
if (Count1 <= Count2)
|
|
{
|
|
try
|
|
{
|
|
DateTime start1 = DateTime.UtcNow;
|
|
|
|
url = VC.ReplaceAllVars(Settings.URL);
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Mode=REDUNDANCY, LoadShare=ON, Count1=" + Count1.ToString() + ",Count2=" + Count2.ToString());
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Creating web request: " + url);
|
|
|
|
// get JSON data
|
|
json = VRSTlsClient.DownloadFile(url, Settings.Timeout * 1000, Settings.Username, Settings.Password);
|
|
|
|
// aggregate loading time
|
|
Count1 += (long)(DateTime.UtcNow - start1).Milliseconds;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DateTime start2 = DateTime.UtcNow;
|
|
|
|
url = VC.ReplaceAllVars(Settings.URL2);
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Mode=REDUNDANCY, LoadShare=ON, Count1=" + Count1.ToString() + ",Count2=" + Count2.ToString());
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Creating web request: " + url);
|
|
|
|
// get JSON data
|
|
json = VRSTlsClient.DownloadFile(url, Settings.Timeout * 1000, Settings.Username2, Settings.Password2);
|
|
|
|
// aggregate loading time
|
|
Count2 += (long)(DateTime.UtcNow - start2).Milliseconds;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
DateTime start2 = DateTime.UtcNow;
|
|
|
|
url = VC.ReplaceAllVars(Settings.URL2);
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Mode=REDUNDANCY, LoadShare=ON, Count1=" + Count1.ToString() + ",Count2=" + Count2.ToString());
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Creating web request: " + url);
|
|
|
|
// get JSON data
|
|
json = VRSTlsClient.DownloadFile(url, Settings.Timeout * 1000, Settings.Username2, Settings.Password2);
|
|
|
|
// aggregate loading time
|
|
Count2 += (long)(DateTime.UtcNow - start2).Milliseconds;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DateTime start1 = DateTime.UtcNow;
|
|
|
|
url = VC.ReplaceAllVars(Settings.URL);
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Mode=REDUNDANCY, LoadShare=ON, Count1=" + Count1.ToString() + ",Count2=" + Count2.ToString());
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Creating web request: " + url);
|
|
|
|
// get JSON data
|
|
json = VRSTlsClient.DownloadFile(url, Settings.Timeout * 1000, Settings.Username, Settings.Password);
|
|
|
|
// aggregate loading time
|
|
Count1 += (long)(DateTime.UtcNow - start1).Milliseconds;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no redundancy --> simple load from URL1
|
|
|
|
// reset counters
|
|
Count1 = 0;
|
|
Count2 = 0;
|
|
|
|
url = VC.ReplaceAllVars(Settings.URL);
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Mode=SIMPLE");
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Creating web request: " + url);
|
|
|
|
// get JSON data
|
|
json = VRSTlsClient.DownloadFile(url, Settings.Timeout * 1000, Settings.Username, Settings.Password);
|
|
|
|
}
|
|
|
|
// save raw data to file if enabled
|
|
if (Settings.SaveToFile)
|
|
{
|
|
using (StreamWriter sw = new StreamWriter(args.TmpDirectory + Path.DirectorySeparatorChar + this.GetType().Name + "_" + DateTime.UtcNow.ToString("yyyy-MM-dd HH_mm_ss") + ".json"))
|
|
{
|
|
sw.WriteLine(json);
|
|
}
|
|
}
|
|
|
|
// reset counters if before getting too near to overflow
|
|
if ((Count1 > long.MaxValue / 2) || (Count2 > long.MaxValue / 2))
|
|
{
|
|
Count1 = 0;
|
|
Count2 = 0;
|
|
}
|
|
|
|
bool writetofile = false;
|
|
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Analyzing data");
|
|
try
|
|
{
|
|
// deserialize JSON
|
|
AircraftList = JsonConvert.DeserializeObject<VirtualRadar.Interface.WebSite.AircraftListJson>(json);
|
|
|
|
// keep latest data version
|
|
LastDV = AircraftList.LastDataVersion;
|
|
|
|
// get planes
|
|
foreach (VirtualRadar.Interface.WebSite.AircraftJson ac in AircraftList.Aircraft)
|
|
{
|
|
try
|
|
{
|
|
PlaneFeedPluginPlaneInfo plane = new PlaneFeedPluginPlaneInfo();
|
|
// get hex first
|
|
plane.Hex = ac.Icao24.Trim().Replace("\"", "");
|
|
// get position
|
|
plane.Lat = (ac.Latitude == null) ? double.NaN : (double)ac.Latitude;
|
|
plane.Lon = (ac.Longitude == null) ? double.NaN : (double)ac.Longitude;
|
|
// get altitude
|
|
if (Settings.UseGeoAlt)
|
|
{
|
|
plane.Alt = (ac.GeometricAltitude == null) ? int.MinValue : (int)ac.GeometricAltitude;
|
|
}
|
|
else
|
|
{
|
|
plane.Alt = (ac.Altitude == null) ? int.MinValue : (int)ac.Altitude;
|
|
}
|
|
// get callsign
|
|
plane.Call = ac.Callsign;
|
|
// get registration
|
|
plane.Reg = ac.Registration;
|
|
// get track
|
|
plane.Track = (ac.Track == null) ? double.NaN : (double)ac.Track;
|
|
// get speed
|
|
plane.Speed = (ac.GroundSpeed == null) ? double.NaN : (double)ac.GroundSpeed;
|
|
// get position timestamp
|
|
// CAUTION!! time is UNIX time in milliseconds
|
|
long l = (ac.PositionTime == null) ? long.MinValue : (long)ac.PositionTime;
|
|
if (l != long.MinValue)
|
|
{
|
|
DateTime timestamp = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
|
|
timestamp = timestamp.AddMilliseconds(l);
|
|
plane.Time = timestamp;
|
|
}
|
|
else
|
|
{
|
|
// skip plane if no valid timestamp found
|
|
continue;
|
|
}
|
|
// get type info
|
|
plane.Type = ac.Type;
|
|
// get extended plane type info
|
|
plane.Manufacturer = ac.Manufacturer;
|
|
plane.Model = ac.Model;
|
|
int cat = (ac.WakeTurbulenceCategory == null) ? int.MinValue : (int)ac.WakeTurbulenceCategory;
|
|
switch (cat)
|
|
{
|
|
case 1: plane.Category = 1; break;
|
|
case 2: plane.Category = 2; break;
|
|
case 3: plane.Category = 3; break;
|
|
case 4: plane.Category = 4; break;
|
|
default: plane.Category = 0; break;
|
|
}
|
|
// do correction of A380 as "SuperHeavy" is not supported
|
|
if (plane.Type == "A388")
|
|
plane.Category = 4;
|
|
// get country
|
|
plane.Country = ac.Icao24Country;
|
|
// get departure airport
|
|
plane.From = ac.Origin;
|
|
// get destination airport
|
|
plane.To = ac.Destination;
|
|
// get vertical speed
|
|
plane.VSpeed = (ac.VerticalRate == null) ? int.MinValue : (int)ac.VerticalRate;
|
|
|
|
if (String.IsNullOrEmpty(plane.Reg))
|
|
{
|
|
writetofile = true;
|
|
}
|
|
|
|
// add plane to list
|
|
planes.Add(plane);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("[" + System.Reflection.MethodBase.GetCurrentMethod().Name + "]" + ex.Message);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing if something else goes wrong
|
|
}
|
|
Console.WriteLine("[" + this.GetType().Name + "]: Returning " + planes.Count + " planes");
|
|
|
|
return planes;
|
|
|
|
}
|
|
|
|
public void Stop(PlaneFeedPluginArgs args)
|
|
{
|
|
Settings.Save(true);
|
|
}
|
|
|
|
|
|
// end of Interface
|
|
|
|
|
|
/// <summary>
|
|
/// Decodes an OpenSSL-encrypted (AES256-CBC) string<br></br><br></br>
|
|
/// The equivalent encoding in PHP is like:<br></br><br></br>
|
|
/// $encrypt_method = "AES-256-CBC";<br></br>
|
|
/// $secret_key = hash('md5',$key);<br></br>
|
|
/// $encoded = openssl_encrypt($data, $encrypt_method, $secret_key);
|
|
/// </summary>
|
|
/// <param name="encrypteddata">The encrypted string (Base64 encoded).</param>
|
|
/// <param name="pwd">The password as a string.</param>
|
|
/// <returns></returns>
|
|
public static string OpenSSLDecrypt(string encrypteddata, string pwd)
|
|
{
|
|
// create a 32bit MD5 hash of the password
|
|
var hash = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(pwd));
|
|
StringBuilder sb = new StringBuilder();
|
|
// Loop through each byte of the hashed data
|
|
// and format each one as a hexadecimal string.
|
|
for (int i = 0; i < hash.Length; i++)
|
|
{
|
|
sb.Append(hash[i].ToString("x2"));
|
|
}
|
|
// use the MD5 hash as the key
|
|
byte[] key = Encoding.UTF8.GetBytes(sb.ToString());
|
|
//get the encrypted data as byte[]
|
|
byte[] encrypted = Convert.FromBase64String(encrypteddata);
|
|
//setup an empty iv
|
|
var iv = new byte[16];
|
|
// Declare the RijndaelManaged object used to decrypt the data.
|
|
RijndaelManaged aesAlg = null;
|
|
|
|
// Declare the string used to hold the decrypted text.
|
|
string decrypted;
|
|
|
|
// Create a RijndaelManaged object
|
|
// with the specified key and IV.
|
|
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
|
|
|
|
// Create a decrytor to perform the stream transform.
|
|
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
|
|
// Create the streams used for decryption.
|
|
using (MemoryStream ms = new MemoryStream(encrypted))
|
|
{
|
|
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
|
|
{
|
|
using (StreamReader sr = new StreamReader(cs))
|
|
{
|
|
// Read the decrypted bytes from the decrypting stream
|
|
// and place them in a string.
|
|
decrypted = sr.ReadToEnd();
|
|
sr.Close();
|
|
}
|
|
}
|
|
}
|
|
// return decrypted string
|
|
return decrypted;
|
|
}
|
|
|
|
[System.Diagnostics.DebuggerNonUserCode]
|
|
private string ReadPropertyString(dynamic o, string propertyname)
|
|
{
|
|
string s = null;
|
|
try
|
|
{
|
|
s = o[propertyname];
|
|
}
|
|
catch
|
|
{
|
|
|
|
}
|
|
return s;
|
|
}
|
|
|
|
[System.Diagnostics.DebuggerNonUserCode]
|
|
private int ReadPropertyInt(dynamic o, string propertyname)
|
|
{
|
|
int i = int.MinValue;
|
|
double d = ReadPropertyDouble(o, propertyname);
|
|
if ((d != double.MinValue) && (d >= int.MinValue) && (d <= int.MaxValue))
|
|
i = (int)d;
|
|
return i;
|
|
}
|
|
|
|
[System.Diagnostics.DebuggerNonUserCode]
|
|
private double ReadPropertyDouble(dynamic o, string propertyname)
|
|
{
|
|
double d = double.MinValue;
|
|
try
|
|
{
|
|
string s = o[propertyname].ToString(CultureInfo.InvariantCulture);
|
|
d = double.Parse(s, CultureInfo.InvariantCulture);
|
|
}
|
|
catch
|
|
{
|
|
// do nothing if something went wrong
|
|
}
|
|
return d;
|
|
}
|
|
|
|
[System.Diagnostics.DebuggerNonUserCode]
|
|
private long ReadPropertyLong(dynamic o, string propertyname)
|
|
{
|
|
long l = long.MinValue;
|
|
try
|
|
{
|
|
l = o[propertyname];
|
|
}
|
|
catch
|
|
{
|
|
// do nothing if something went wrong
|
|
}
|
|
return l;
|
|
}
|
|
|
|
[System.Diagnostics.DebuggerNonUserCode]
|
|
private bool ReadPropertyBool(dynamic o, string propertyname)
|
|
{
|
|
bool b = false;
|
|
try
|
|
{
|
|
string s = o[propertyname].ToString();
|
|
b = s.ToLower() == "true";
|
|
}
|
|
catch
|
|
{
|
|
// do nothing if something went wrong
|
|
}
|
|
return b;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// //////////////////////////////////////////// Helpers ////////////////////////////////////////////
|
|
/// </summary>
|
|
|
|
public static class SupportFunctions
|
|
{
|
|
public static int DateTimeToUNIXTime(DateTime dt)
|
|
{
|
|
if (dt == DateTime.MinValue)
|
|
return int.MinValue;
|
|
else if (dt == DateTime.MaxValue)
|
|
return int.MaxValue;
|
|
return (Int32)(dt.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
|
}
|
|
|
|
}
|
|
|
|
public static class LatLon
|
|
{
|
|
public class Earth
|
|
{
|
|
public static double Radius = 6371;
|
|
}
|
|
|
|
public static double Distance(double mylat, double mylon, double lat, double lon)
|
|
{
|
|
double R = Earth.Radius;
|
|
double dLat = (mylat - lat);
|
|
double dLon = (mylon - lon);
|
|
double a = Math.Sin(dLat / 180 * Math.PI / 2) * Math.Sin(dLat / 180 * Math.PI / 2) +
|
|
Math.Sin(dLon / 180 * Math.PI / 2) * Math.Sin(dLon / 180 * Math.PI / 2) * Math.Cos(mylat / 180 * Math.PI) * Math.Cos(lat / 180 * Math.PI);
|
|
return R * 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
|
|
}
|
|
|
|
|
|
}
|
|
public static class UnitConverter
|
|
{
|
|
public static double ft_m(double feet)
|
|
{
|
|
return feet / 3.28084;
|
|
}
|
|
|
|
public static double m_ft(double m)
|
|
{
|
|
return m * 3.28084;
|
|
}
|
|
|
|
public static double kts_kmh(double kts)
|
|
{
|
|
return kts * 1.852;
|
|
}
|
|
|
|
public static double kmh_kts(double kmh)
|
|
{
|
|
return kmh / 1.852;
|
|
}
|
|
|
|
public static double km_mi(double km)
|
|
{
|
|
return km * 1.609;
|
|
}
|
|
|
|
public static double mi_km(double mi)
|
|
{
|
|
return mi / 1.609;
|
|
}
|
|
}
|
|
|
|
public class VarConverter : Dictionary<string, object>
|
|
{
|
|
public readonly char VarSeparator = '%';
|
|
|
|
public void AddVar(string var, object value)
|
|
{
|
|
// adds a new var<>value pair to dictionary
|
|
object o;
|
|
if (this.TryGetValue(var, out o))
|
|
{
|
|
// item found --> update value
|
|
o = value;
|
|
}
|
|
else
|
|
{
|
|
// item not found --> add new
|
|
this.Add(var, value);
|
|
}
|
|
}
|
|
|
|
public object GetValue(string var)
|
|
{
|
|
// finds a var in dictionary and returns its value
|
|
object o;
|
|
if (this.TryGetValue(var, out o))
|
|
{
|
|
// item found --> return value
|
|
return o;
|
|
}
|
|
// item not found --> return null
|
|
return null;
|
|
}
|
|
|
|
public string ReplaceAllVars(string s)
|
|
{
|
|
// check for var separotors first
|
|
if (s.Contains(VarSeparator))
|
|
{
|
|
// OK, string is containing vars --> crack the string first and replace vars
|
|
try
|
|
{
|
|
string[] a = s.Split(VarSeparator);
|
|
// as we are always using a pair of separators the length of a[] must be odd
|
|
if (a.Length % 2 == 0)
|
|
throw new ArgumentException("Number of separators is not an even number.");
|
|
// create new string and replace all vars (on odd indices)
|
|
s = "";
|
|
for (int i = 0; i < a.Length; i++)
|
|
{
|
|
if (i % 2 == 0)
|
|
{
|
|
// cannot be not a var on that position
|
|
s = s + a[i];
|
|
}
|
|
else
|
|
{
|
|
// var identifier: upper the string and try to convert
|
|
a[i] = a[i].ToUpper();
|
|
object o;
|
|
if (this.TryGetValue(a[i], out o))
|
|
{
|
|
// convert floating points with invariant culture info
|
|
if (o.GetType() == typeof(double))
|
|
s = s + ((double)o).ToString(CultureInfo.InvariantCulture);
|
|
else if (o.GetType() == typeof(float))
|
|
s = s + ((float)o).ToString(CultureInfo.InvariantCulture);
|
|
else
|
|
s = s + o.ToString();
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException("Var identifier not found: " + a[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// throw an excecption
|
|
throw new ArgumentException("Error while parsing string for variables [" + ex.Message + "]: " + s);
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
}
|
|
|
|
}
|