diff --git a/netxml2kml/Data/DatabaseContext.cs b/netxml2kml/Data/DatabaseContext.cs index 19c8d8c..51e317e 100644 --- a/netxml2kml/Data/DatabaseContext.cs +++ b/netxml2kml/Data/DatabaseContext.cs @@ -11,7 +11,7 @@ public sealed class DatabaseContext : DbContext private string DbPath { get; } - public DatabaseContext() + public DatabaseContext(string dbName = "netxml2kml.sqlite3.db") { var folder = Environment.SpecialFolder.LocalApplicationData; var path = Path.Join(Environment.GetFolderPath(folder), "netxml2kml"); @@ -21,7 +21,8 @@ public sealed class DatabaseContext : DbContext Directory.CreateDirectory(path); } - DbPath = Path.Join(path, "netxml2kml.sqlite3.db"); + DbPath = Path.Join(path, dbName); + Database.EnsureCreated(); } protected override void OnModelCreating(ModelBuilder modelBuilder) diff --git a/netxml2kml/Methods/CliOptionsHandlers.cs b/netxml2kml/Methods/CliOptionsHandlers.cs index 99d832b..633bd81 100644 --- a/netxml2kml/Methods/CliOptionsHandlers.cs +++ b/netxml2kml/Methods/CliOptionsHandlers.cs @@ -1,3 +1,5 @@ +using Microsoft.EntityFrameworkCore; +using netxml2kml.Data; using netxml2kml.Models; namespace netxml2kml.Methods; @@ -5,13 +7,193 @@ namespace netxml2kml.Methods; public static class CliOptionsHandlers { public static void UniversalHandler(FileInfo? inputFile, - FileInfo? outputFile) + FileInfo? outputFile, bool useDatabase, string? sqlQuery) { - + if (inputFile != null && outputFile != null) + { + var wirelessNetworks = Helpers.DeserializeXml(inputFile); + + if (useDatabase) + { + AddWirelessNetworksToDatabase(wirelessNetworks); + } + + if (sqlQuery != null) + { + FilterWirelessNetworksInMemory(ref wirelessNetworks, sqlQuery); + } + + var kmlString = GetKmlString(wirelessNetworks); + Helpers.WriteStringToFile(kmlString, outputFile); + } + else if (inputFile != null && outputFile == null && useDatabase) + { + var wirelessNetworks = Helpers.DeserializeXml(inputFile); + + if (sqlQuery != null) + { + FilterWirelessNetworksInMemory(ref wirelessNetworks, sqlQuery); + } + + AddWirelessNetworksToDatabase(wirelessNetworks); + } + else if (inputFile == null && outputFile != null && useDatabase) + { + string kmlString; + + if (sqlQuery != null) + { + kmlString = GetKmlString(FilterWirelessNetworksFromDatabase(sqlQuery)); + } + else + { + kmlString = GetKmlString(FilterWirelessNetworksFromDatabase("SELECT * FROM WirelessNetworks")); + } + + Helpers.WriteStringToFile(kmlString, outputFile); + } + else if (inputFile == null && outputFile == null && useDatabase && + sqlQuery != null) + { + using var dbContext = new DatabaseContext(); + Console.WriteLine(dbContext.Database.ExecuteSqlRaw(sqlQuery)); + } } - private static string GenerateKml(WirelessNetwork[] wirelessNetworks) + private static string GetKmlString(IEnumerable wirelessNetworks) { return "test"; } + + private static void AddWirelessNetworksToDatabase(IEnumerable wirelessNetworks) + { + using var dbContext = new DatabaseContext(); + + foreach (var wirelessNetwork in wirelessNetworks) + { + // If wireless network has wireless clients – add all clients to + // the database or update their LastUpdateDate + if (wirelessNetwork.WirelessConnections != null) + { + foreach (var wirelessConnection in wirelessNetwork.WirelessConnections) + { + var client = wirelessConnection.WirelessClient; + + // Add new client to the DB if it is not present + if (!dbContext.WirelessClients.Any(wc => + wc.Mac == client.Mac)) + { + dbContext.WirelessClients.Add(client); + } + // Update LastUpdateDate if the client is present in the DB + else if (dbContext.WirelessClients.Any(wc => + wc.Mac == client.Mac)) + { + var dbClient = dbContext.WirelessClients + .First(wc => wc.Mac == client.Mac); + + if (dbClient.LastUpdateDate < client.FirstSeenDate) + { + dbClient.LastUpdateDate = client.FirstSeenDate; + } + } + } + } + + // If wireless network has wireless clients – add a wireless + // connections to the database or update their LastUpdateDate + if (wirelessNetwork.WirelessConnections != null) + { + foreach (var wirelessConnection in wirelessNetwork.WirelessConnections) + { + var client = wirelessConnection.WirelessClient; + + // Add new connection to the DB if it is not present + if (!dbContext.WirelessConnections.Any(wc => + wc.WirelessClientMac == client.Mac && + wc.WirelessNetworkBssid == wirelessNetwork.Bssid)) + { + dbContext.WirelessConnections.Add(new WirelessConnection + { + WirelessClientMac = client.Mac, + WirelessNetworkBssid = wirelessNetwork.Bssid, + FirstSeenDate = client.FirstSeenDate, + LastUpdateDate = client.LastUpdateDate + }); + } + // Update LastUpdateDate if the connection is present in the DB + else if (dbContext.WirelessConnections.Any(wc => + wc.WirelessClientMac == client.Mac && + wc.WirelessNetworkBssid == wirelessNetwork.Bssid)) + { + var dbConnection = dbContext.WirelessConnections.First( + wc => wc.WirelessClientMac == client.Mac && + wc.WirelessNetworkBssid == wirelessNetwork.Bssid); + var connectedClient = wirelessNetwork + .WirelessConnections + .First(wc => wc.WirelessClient.Mac == client.Mac) + .WirelessClient; + + if (dbConnection.LastUpdateDate < connectedClient.FirstSeenDate) + { + dbConnection.LastUpdateDate = + connectedClient.FirstSeenDate; + } + } + } + } + + // Set wireless connections to null since we manually added + // connections to the database context + wirelessNetwork.WirelessConnections = null; + + // Add new network to the DB if it is not present + if (!dbContext.WirelessNetworks.Any(wn => + wn.Bssid == wirelessNetwork.Bssid)) + { + dbContext.Add(wirelessNetwork); + } + // Update LastUpdateDate & MaxSignalDmb if + // the network is present in the DB + else if (dbContext.WirelessNetworks.Any(wn => + wn.Bssid == wirelessNetwork.Bssid)) + { + var dbNetwork = dbContext.WirelessNetworks.First(wn => + wn.Bssid == wirelessNetwork.Bssid); + + if (dbNetwork.MaxSignalDbm < wirelessNetwork.MaxSignalDbm) + { + dbNetwork.MaxLatitude = wirelessNetwork.MaxLatitude; + dbNetwork.MaxLongitude = wirelessNetwork.MaxLongitude; + dbNetwork.MaxAltitude = wirelessNetwork.MaxAltitude; + dbNetwork.MaxSignalDbm = wirelessNetwork.MaxSignalDbm; + } + + if (dbNetwork.LastUpdateDate < wirelessNetwork.FirstSeenDate) + { + dbNetwork.LastUpdateDate = wirelessNetwork.FirstSeenDate; + } + } + } + + dbContext.SaveChanges(); + } + + private static void FilterWirelessNetworksInMemory( + ref WirelessNetwork[] wirelessNetworks, string sqlQuery) + { + using var dbContext = new DatabaseContext("InMemoryFiltering.sqlite3.db"); + + dbContext.WirelessNetworks.AddRange(wirelessNetworks); + dbContext.SaveChanges(); + wirelessNetworks = dbContext.WirelessNetworks.FromSqlRaw(sqlQuery).ToArray(); + + dbContext.Database.EnsureDeleted(); + } + + private static WirelessNetwork[] FilterWirelessNetworksFromDatabase(string sqlQuery) + { + using var dbContext = new DatabaseContext(); + return dbContext.WirelessNetworks.FromSqlRaw(sqlQuery).ToArray(); + } } \ No newline at end of file diff --git a/netxml2kml/Methods/Helpers.cs b/netxml2kml/Methods/Helpers.cs index c90c651..5fcec44 100644 --- a/netxml2kml/Methods/Helpers.cs +++ b/netxml2kml/Methods/Helpers.cs @@ -102,4 +102,11 @@ public static class Helpers return new DateTime(year, month, day, hour, minute, second); } + + public static void WriteStringToFile(string str, FileInfo file) + { + var writer = new StreamWriter(file.OpenWrite()); + writer.Write(str); + writer.Close(); + } } \ No newline at end of file diff --git a/netxml2kml/Program.cs b/netxml2kml/Program.cs index 4a08501..7132287 100644 --- a/netxml2kml/Program.cs +++ b/netxml2kml/Program.cs @@ -17,12 +17,22 @@ class Program aliases: new[] {"-o", "--output"}, description: "The name of the file to be created."); + var databaseOption = new Option( + aliases: new[] {"-d", "--use-database"}, + description: "Use database. Save/retrieve wireless networks and clients to/from sqlite database."); + + var queryOption = new Option( + aliases: new[] {"-q", "--query"}, + description: "Filter input using sql query."); + var rootCommand = new RootCommand("netxml2kml – .netxml to .kml converter."); rootCommand.AddOption(inputOption); rootCommand.AddOption(outputOption); + rootCommand.AddOption(databaseOption); + rootCommand.AddOption(queryOption); rootCommand.SetHandler(CliOptionsHandlers.UniversalHandler, - inputOption, outputOption); + inputOption, outputOption, databaseOption, queryOption); return await rootCommand.InvokeAsync(args); }