diff --git a/IOTManagment/.vscode/launch.json b/IOTManagment/.vscode/launch.json
new file mode 100644
index 0000000..2b2ec5b
--- /dev/null
+++ b/IOTManagment/.vscode/launch.json
@@ -0,0 +1,35 @@
+{
+ "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}/API-Web/bin/Debug/net6.0/API-Web.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/API-Web",
+ "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+)"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "sourceFileMap": {
+ "/Views": "${workspaceFolder}/Views"
+ }
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/IOTManagment/.vscode/tasks.json b/IOTManagment/.vscode/tasks.json
new file mode 100644
index 0000000..f637419
--- /dev/null
+++ b/IOTManagment/.vscode/tasks.json
@@ -0,0 +1,41 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/API-Web/API-Web.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/API-Web/API-Web.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "--project",
+ "${workspaceFolder}/API-Web/API-Web.csproj"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/IOTManagment/API-Web/API-Web.csproj b/IOTManagment/API-Web/API-Web.csproj
index bf91fc4..9738fee 100644
--- a/IOTManagment/API-Web/API-Web.csproj
+++ b/IOTManagment/API-Web/API-Web.csproj
@@ -9,6 +9,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/IOTManagment/IOTManagment.sln b/IOTManagment/IOTManagment.sln
index d90b72b..e1fecf2 100644
--- a/IOTManagment/IOTManagment.sln
+++ b/IOTManagment/IOTManagment.sln
@@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Services\Services.csproj", "{14640077-5376-4D81-92C0-5EC70D84E54E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{D92E85EE-E28A-4B66-8A88-83AE6EDDB1B4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -33,6 +35,10 @@ Global
{14640077-5376-4D81-92C0-5EC70D84E54E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14640077-5376-4D81-92C0-5EC70D84E54E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14640077-5376-4D81-92C0-5EC70D84E54E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D92E85EE-E28A-4B66-8A88-83AE6EDDB1B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D92E85EE-E28A-4B66-8A88-83AE6EDDB1B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D92E85EE-E28A-4B66-8A88-83AE6EDDB1B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D92E85EE-E28A-4B66-8A88-83AE6EDDB1B4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/IOTManagment/Model/Class1.cs b/IOTManagment/Model/Class1.cs
deleted file mode 100644
index 2572ecc..0000000
--- a/IOTManagment/Model/Class1.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Model
-{
- public class Class1
- {
-
- }
-}
\ No newline at end of file
diff --git a/IOTManagment/Model/Messages/Message.cs b/IOTManagment/Model/Messages/Message.cs
new file mode 100644
index 0000000..6f800f7
--- /dev/null
+++ b/IOTManagment/Model/Messages/Message.cs
@@ -0,0 +1,32 @@
+using Model.Nodes;
+using System;
+using System.Net;
+
+namespace Model.Messages
+{
+ public class Message
+ {
+ public Guid messageId { get; set; } = Guid.NewGuid();
+ public string messageBody { get; } // = PayloadBody
+ public MessageType messageType { get; }
+ public string senderIP { get; }
+ public int senderPort { get; }
+
+ public Message(string messageBody, MessageType messageType, string senderIP,int senderPort)
+ {
+ this.messageBody = messageBody;
+ this.messageType = messageType;
+ this.senderIP = senderIP;
+ this.senderPort = senderPort;
+ }
+ }
+
+ public enum MessageType
+ {
+ CONNECT=1,
+ FORWARD=2,
+ RESPONSEAPI=3,
+ QUERY = 4,
+ STOP = 5,
+ };
+}
\ No newline at end of file
diff --git a/IOTManagment/Model/Messages/SelectVariableResult.cs b/IOTManagment/Model/Messages/SelectVariableResult.cs
new file mode 100644
index 0000000..4fddd0a
--- /dev/null
+++ b/IOTManagment/Model/Messages/SelectVariableResult.cs
@@ -0,0 +1,14 @@
+using Model.Queries.Variables;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Messages
+{
+ public class SelectVariableResult : SelectVariable
+ {
+ public double? Value { get; set; }
+ }
+}
diff --git a/IOTManagment/Model/Nodes/Enum/DataType.cs b/IOTManagment/Model/Nodes/Enum/DataType.cs
new file mode 100644
index 0000000..ecee4ef
--- /dev/null
+++ b/IOTManagment/Model/Nodes/Enum/DataType.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Nodes.Enum
+{
+ public enum DataType
+ {
+ TEMPERATURE_CPU = 1,
+ TEMPERATURE_GPU = 2,
+ TEST_VAR = 3,
+ }
+}
diff --git a/IOTManagment/Model/Nodes/Enum/NodeType.cs b/IOTManagment/Model/Nodes/Enum/NodeType.cs
new file mode 100644
index 0000000..409ae19
--- /dev/null
+++ b/IOTManagment/Model/Nodes/Enum/NodeType.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Nodes.Enum
+{
+ public enum NodeType
+ {
+ SENSOR = 1,
+ NODE = 2,
+ ROUTENODE = 3,
+ ROOT = 4
+ }
+}
diff --git a/IOTManagment/Model/Nodes/Enum/Status.cs b/IOTManagment/Model/Nodes/Enum/Status.cs
new file mode 100644
index 0000000..c78e948
--- /dev/null
+++ b/IOTManagment/Model/Nodes/Enum/Status.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Nodes.Enum
+{
+ public enum Status
+ {
+ INACTIVE = 0,
+ ACTIVE = 1
+ }
+}
diff --git a/IOTManagment/Model/Nodes/INode.cs b/IOTManagment/Model/Nodes/INode.cs
new file mode 100644
index 0000000..f3a97a6
--- /dev/null
+++ b/IOTManagment/Model/Nodes/INode.cs
@@ -0,0 +1,26 @@
+using Model.Nodes.Enum;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Nodes
+{
+ public interface INode
+ {
+
+ public string? Parent { get; set; }
+ public int? ParentPort { get; set; }
+
+ public string Address { get; set; }
+ public int AddressPort { get; set; }
+
+ public NodeType Type { get; set; }
+ public Status Status { get; set; }
+ public DataType DataType { get; set; }
+
+
+ }
+}
diff --git a/IOTManagment/Model/Nodes/Node.cs b/IOTManagment/Model/Nodes/Node.cs
new file mode 100644
index 0000000..ed65aad
--- /dev/null
+++ b/IOTManagment/Model/Nodes/Node.cs
@@ -0,0 +1,26 @@
+using Model.Nodes.Enum;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+
+namespace Model.Nodes
+{
+ public class Node : INode
+ {
+ public string? Parent { get; set; }
+ public int? ParentPort { get; set; }
+
+ public string Address { get; set; }
+ public int AddressPort { get; set; }
+
+ public NodeType Type { get; set; }
+ public Status Status { get; set; }
+ public DataType DataType { get; set; }
+
+
+ }
+}
diff --git a/IOTManagment/Model/Queries/Enums/SelectOperator.cs b/IOTManagment/Model/Queries/Enums/SelectOperator.cs
new file mode 100644
index 0000000..36fd348
--- /dev/null
+++ b/IOTManagment/Model/Queries/Enums/SelectOperator.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Queries.Enums
+{
+ public enum SelectOperator
+ {
+ None,
+ Sum
+ }
+}
diff --git a/IOTManagment/Model/Queries/Enums/WhereExpOperator.cs b/IOTManagment/Model/Queries/Enums/WhereExpOperator.cs
new file mode 100644
index 0000000..6b9b0d8
--- /dev/null
+++ b/IOTManagment/Model/Queries/Enums/WhereExpOperator.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Queries.Enums
+{
+ public enum WhereExpOperator
+ {
+ GreaterThan,
+ LessThan,
+ LessThanOrEqual,
+ GreaterThenOrEqual,
+ NotEqual,
+ Equal
+ }
+}
diff --git a/IOTManagment/Model/Queries/Enums/WhereOperator.cs b/IOTManagment/Model/Queries/Enums/WhereOperator.cs
new file mode 100644
index 0000000..b134770
--- /dev/null
+++ b/IOTManagment/Model/Queries/Enums/WhereOperator.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Queries.Enums
+{
+ public enum WhereOperator
+ {
+ None,
+ And,
+ Or
+ }
+}
diff --git a/IOTManagment/Model/Queries/Expressions/WhereExpression.cs b/IOTManagment/Model/Queries/Expressions/WhereExpression.cs
new file mode 100644
index 0000000..acccdd7
--- /dev/null
+++ b/IOTManagment/Model/Queries/Expressions/WhereExpression.cs
@@ -0,0 +1,16 @@
+using Model.Queries.Enums;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Queries.Expressions
+{
+ public class WhereExpression
+ {
+ public string exp1 { get; set; }
+ public string exp2 { get; set; }
+ public WhereExpOperator Operator { get; set; }
+ }
+}
diff --git a/IOTManagment/Model/Queries/Query.cs b/IOTManagment/Model/Queries/Query.cs
new file mode 100644
index 0000000..e4b7de4
--- /dev/null
+++ b/IOTManagment/Model/Queries/Query.cs
@@ -0,0 +1,17 @@
+using Model.Queries.Statements;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Queries
+{
+ public class Query
+ {
+ public Guid Id { get; set; } = Guid.NewGuid();
+ public SelectStatement SelectStatement { get; set; }
+ public IntervalStatement IntervalStatement { get; set; }
+ public WhereStatement? WhereStatement { get; set; }
+ }
+}
diff --git a/IOTManagment/Model/Queries/Statements/IntervalStatement.cs b/IOTManagment/Model/Queries/Statements/IntervalStatement.cs
new file mode 100644
index 0000000..c76e8aa
--- /dev/null
+++ b/IOTManagment/Model/Queries/Statements/IntervalStatement.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Queries.Statements
+{
+ public class IntervalStatement
+ {
+ public int Interval { get; set; }
+ }
+}
diff --git a/IOTManagment/Model/Queries/Statements/SelectStatement.cs b/IOTManagment/Model/Queries/Statements/SelectStatement.cs
new file mode 100644
index 0000000..c033cc6
--- /dev/null
+++ b/IOTManagment/Model/Queries/Statements/SelectStatement.cs
@@ -0,0 +1,14 @@
+using Model.Queries.Variables;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Queries.Statements
+{
+ public class SelectStatement
+ {
+ public List Variables { get; set; } = new List();
+ }
+}
diff --git a/IOTManagment/Model/Queries/Statements/WhereStatement.cs b/IOTManagment/Model/Queries/Statements/WhereStatement.cs
new file mode 100644
index 0000000..a2e069c
--- /dev/null
+++ b/IOTManagment/Model/Queries/Statements/WhereStatement.cs
@@ -0,0 +1,18 @@
+using Model.Queries.Enums;
+using Model.Queries.Variables;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Queries.Statements
+{
+ public class WhereStatement
+ {
+ public List Variables { get; set; } = new List();
+ public WhereOperator Operator { get; set; }
+
+
+ }
+}
diff --git a/IOTManagment/Model/Queries/Variables/SelectVariable.cs b/IOTManagment/Model/Queries/Variables/SelectVariable.cs
new file mode 100644
index 0000000..23d379a
--- /dev/null
+++ b/IOTManagment/Model/Queries/Variables/SelectVariable.cs
@@ -0,0 +1,15 @@
+using Model.Queries.Enums;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Queries.Variables
+{
+ public class SelectVariable
+ {
+ public string Variable { get; set; }
+ public SelectOperator Operator { get; set; }
+ }
+}
diff --git a/IOTManagment/Model/Queries/Variables/WhereVariable.cs b/IOTManagment/Model/Queries/Variables/WhereVariable.cs
new file mode 100644
index 0000000..39f8c87
--- /dev/null
+++ b/IOTManagment/Model/Queries/Variables/WhereVariable.cs
@@ -0,0 +1,17 @@
+using Model.Queries.Enums;
+using Model.Queries.Expressions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model.Queries.Variables
+{
+ public class WhereVariable
+ {
+ public List Expressions { get; set; } = new List(); // < > =
+ public List Operators { get; set; } = new List(); // AND OR
+
+ }
+}
diff --git a/IOTManagment/NodeEngine/Jobs/QueryExecutionJob.cs b/IOTManagment/NodeEngine/Jobs/QueryExecutionJob.cs
new file mode 100644
index 0000000..3bdf0d7
--- /dev/null
+++ b/IOTManagment/NodeEngine/Jobs/QueryExecutionJob.cs
@@ -0,0 +1,46 @@
+using Model.Messages;
+using Model.Queries;
+using Model.Queries.Statements;
+using NodeEngine.Networking;
+using NodeEngine.Services;
+using Quartz;
+using Serilog;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.ServiceModel.Channels;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace NodeEngine.Jobs
+{
+ public class QueryExecutionJob : IJob
+ {
+
+ public async Task Execute(IJobExecutionContext context)
+ {
+ SensorManager sensorManager = new SensorManager();
+ QueryHandler handler = new QueryHandler(sensorManager);
+
+ JobDataMap dataMap = context.JobDetail.JobDataMap;
+ SelectStatement? selectStatement = JsonSerializer.Deserialize(dataMap.GetString("Select"));
+ WhereStatement? whereStatement = JsonSerializer.Deserialize(dataMap.GetString("Where"));
+
+ if(whereStatement != null && handler.CheckWhereStatement(whereStatement))
+ {
+ IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(dataMap.GetString("IP")), int.Parse(dataMap.GetString("Port")));
+ Log.Logger.Information("Job-Query has been evaluated returning true");
+
+ // Select The data specified and send it to parent //TODO : make payload with data
+ string payload = JsonSerializer.Serialize(handler.GetSelectResults(selectStatement));
+
+ var msg = new Model.Messages.Message(payload, MessageType.RESPONSEAPI,null,-1); // TODO: add local ip and port
+ var sender = new NetworkSender(endPoint, JsonSerializer.Serialize(msg));
+ var senderThread = new Thread(() => sender.SendMessage());
+ senderThread.Start();
+ }
+ }
+ }
+}
diff --git a/IOTManagment/NodeEngine/Networking/MessageHandler.cs b/IOTManagment/NodeEngine/Networking/MessageHandler.cs
new file mode 100644
index 0000000..da33936
--- /dev/null
+++ b/IOTManagment/NodeEngine/Networking/MessageHandler.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Net;
+using System.Text.Json;
+using Model.Messages;
+using Model.Queries;
+using NodeEngine.Services;
+using Serilog;
+
+namespace NodeEngine.Networking
+{
+ public class MessageHandler
+ {
+ List nodeChildren;
+ QueryScheduler scheduler;
+ IPEndPoint parentEndPoint;
+ public MessageHandler(IPEndPoint parent)
+ {
+ nodeChildren = new List();
+ scheduler = new QueryScheduler();
+ parentEndPoint = parent;
+ }
+
+ public async void HandleMessage(string message)
+ {
+ try
+ {
+ var msg = JsonSerializer.Deserialize(message);
+
+ // MessageType
+ switch (msg.messageType)
+ {
+ case MessageType.CONNECT:
+ {
+ Console.WriteLine("MessageType: CONNECT");
+ var node = new IPEndPoint(IPAddress.Parse(msg.senderIP), msg.senderPort);
+ if (nodeChildren.Any(x => x.Address.Equals(IPAddress.Parse(msg.senderIP))))
+ {
+ Console.WriteLine("Node already exists.");
+ break;
+ }
+ nodeChildren.Add(node);
+ break;
+ }
+ case MessageType.FORWARD:
+ {
+ Console.WriteLine("MessageType: FOWARD");
+
+ foreach (IPEndPoint child in nodeChildren)
+ {
+ var sender = new NetworkSender(child, message);
+ sender.SendMessage();
+ }
+
+ //TODO: Do something to Query
+
+ break;
+ }
+ case MessageType.RESPONSEAPI:
+ {
+ Console.WriteLine("MessageType: RESPONSEAPI");
+ break;
+ }
+ case MessageType.QUERY:
+ {
+ Console.WriteLine("MessageType: QUERY");
+ Query q = JsonSerializer.Deserialize(msg.messageBody);
+ if (q == null) throw new Exception("Query is null");
+
+ await scheduler.AddQueryJobAsync(q,parentEndPoint);
+ foreach (IPEndPoint child in nodeChildren)
+ {
+ var sender = new NetworkSender(child, message);
+ sender.SendMessage();
+ }
+ break;
+ }
+ case MessageType.STOP:
+ {
+ Console.WriteLine($"MessageType: STOP QUERY {msg.messageBody}");
+
+ try
+ {
+ var id = JsonSerializer.Deserialize(msg.messageBody);
+ await scheduler.RemoveQueryjobAsync(id);
+
+ foreach (IPEndPoint child in nodeChildren)
+ {
+ var sender = new NetworkSender(child, message);
+ sender.SendMessage();
+ }
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Could not parse {msg.messageBody} as GUID");
+ Console.WriteLine(e);
+ }
+ break;
+ }
+ default:
+ // TODO: Handle if no type is given
+ Log.Warning("No msgType: " + message);
+ break;
+ }
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Could not deserialize. Message: {message}");
+ Console.WriteLine($"Exception: {e}");
+ }
+ }
+ }
+}
+
diff --git a/IOTManagment/NodeEngine/Networking/NetworkListener.cs b/IOTManagment/NodeEngine/Networking/NetworkListener.cs
new file mode 100644
index 0000000..af65e16
--- /dev/null
+++ b/IOTManagment/NodeEngine/Networking/NetworkListener.cs
@@ -0,0 +1,38 @@
+using System;
+using NetMQ.Sockets;
+using NetMQ;
+
+namespace NodeEngine.Networking
+{
+ public class NetworkListener
+ {
+
+ MessageHandler messageHandler;
+ public NetworkListener(MessageHandler handler)
+ {
+ messageHandler = handler;
+ }
+
+ public void StartListener()
+ {
+ using (var listener = new PullSocket())
+ {
+ Console.WriteLine("Started Listening on port 6001...");
+ listener.Bind("tcp://0.0.0.0:6001");
+
+ while (true)
+ {
+ // Listen for messsages
+ string msg = listener.ReceiveFrameString();
+ Console.WriteLine("Received frame: {0}", msg);
+
+
+ // Handle the Message
+ messageHandler.HandleMessage(msg);
+ }
+ }
+
+ }
+ }
+}
+
diff --git a/IOTManagment/NodeEngine/Networking/NetworkSender.cs b/IOTManagment/NodeEngine/Networking/NetworkSender.cs
new file mode 100644
index 0000000..563cc8f
--- /dev/null
+++ b/IOTManagment/NodeEngine/Networking/NetworkSender.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Net;
+using NetMQ;
+using NetMQ.Sockets;
+using Model.Messages;
+
+namespace NodeEngine.Networking
+{
+ public class NetworkSender
+ {
+ IPEndPoint Receiver;
+ string Message;
+
+ public NetworkSender(IPEndPoint receiver, string message)
+ {
+ this.Receiver = receiver;
+ this.Message = message;
+ }
+
+ public void SendMessage()
+ {
+ var sender = new PushSocket();
+
+ Console.WriteLine("Connecting to socket...");
+ sender.Connect($"tcp://{Receiver.Address}:{Receiver.Port}");
+
+ sender.SendFrame(Message);
+
+ Console.WriteLine("Message sent. Closing thread.");
+
+ }
+ }
+}
+
diff --git a/IOTManagment/NodeEngine/NodeEngine.csproj b/IOTManagment/NodeEngine/NodeEngine.csproj
index 74abf5c..2aac0d2 100644
--- a/IOTManagment/NodeEngine/NodeEngine.csproj
+++ b/IOTManagment/NodeEngine/NodeEngine.csproj
@@ -1,4 +1,4 @@
-
+
Exe
@@ -7,4 +7,29 @@
enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/IOTManagment/NodeEngine/Program.cs b/IOTManagment/NodeEngine/Program.cs
index 3751555..5ae6301 100644
--- a/IOTManagment/NodeEngine/Program.cs
+++ b/IOTManagment/NodeEngine/Program.cs
@@ -1,2 +1,81 @@
// See https://aka.ms/new-console-template for more information
-Console.WriteLine("Hello, World!");
+using NodeEngine.Services;
+using Services;
+using System.Net;
+using System.Text.Json;
+using NodeEngine.Jobs;
+using Model.Queries;
+using Model.Queries.Statements;
+using Serilog;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.DependencyInjection;
+using NodeEngine.Networking;
+using Model.Messages;
+using System.Net.Sockets;
+using Model.Nodes;
+using Model.Nodes.Enum;
+
+// Setup logger
+var log = new LoggerConfiguration()
+ .MinimumLevel.Information()
+ .WriteTo.Console()
+ .CreateLogger();
+// Set global logger
+Log.Logger = log;
+// create log factory for scheduler
+var logFactory = new LoggerFactory()
+ .AddSerilog(log);
+// sets the logger for the Scheduler
+Quartz.Logging.LogContext.SetCurrentLogProvider(logFactory);
+
+// Setup Receiver for CONNECT Message
+Console.WriteLine("Enter Connection ip");
+var recieverIp = Console.ReadLine();
+Console.WriteLine("Enter Connection Port");
+int recieverPort = int.Parse(Console.ReadLine());
+
+var reciever = new IPEndPoint(IPAddress.Parse(recieverIp), recieverPort);
+MessageHandler handler = new MessageHandler(reciever);
+
+// Listener (OBS: LISTNER SHOULD RUN FIRST - CAN'T SEND WITHOUT LISTENER)
+var listener = new NetworkListener(handler);
+var listenerThread = new Thread(() => listener.StartListener());
+listenerThread.Start();
+Console.WriteLine("Started Listener on port 6001");
+
+// Get Local IP Address
+string nodeIp = default;
+
+var host = Dns.GetHostEntry(Dns.GetHostName());
+foreach (var localIp in host.AddressList)
+{
+ if (localIp.AddressFamily == AddressFamily.InterNetwork && localIp.ToString() != "127.0.0.1")
+ {
+ nodeIp = localIp.ToString();
+ Console.WriteLine("IP Address of this node = " + nodeIp);
+ }
+}
+
+//EndPoint
+var NodeEndPoint = new IPEndPoint(IPAddress.Parse(nodeIp), 6001);
+
+//Node & serialization
+var node = new Node
+{
+ Parent = recieverIp,
+ ParentPort = recieverPort,
+ Address = nodeIp,
+ AddressPort = 6001,
+ Type = NodeType.NODE,
+ Status = Status.ACTIVE,
+ DataType = DataType.TEMPERATURE_CPU,
+};
+
+var jsonNode = JsonSerializer.Serialize(node);
+
+// Sender-connect message to server.
+var msg = new Message(jsonNode, MessageType.CONNECT, nodeIp, 6001);
+var json = JsonSerializer.Serialize(msg);
+var sender = new NetworkSender(reciever, json);
+var senderThread = new Thread(() => sender.SendMessage());
+senderThread.Start();
\ No newline at end of file
diff --git a/IOTManagment/NodeEngine/Services/IQueryHandler.cs b/IOTManagment/NodeEngine/Services/IQueryHandler.cs
new file mode 100644
index 0000000..e9314e6
--- /dev/null
+++ b/IOTManagment/NodeEngine/Services/IQueryHandler.cs
@@ -0,0 +1,18 @@
+using Model.Messages;
+using Model.Queries.Statements;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NodeEngine.Services
+{
+ public interface IQueryHandler
+ {
+ public bool CheckWhereStatement(WhereStatement statement);
+
+ public ListGetSelectResults(SelectStatement statement);
+
+ }
+}
diff --git a/IOTManagment/NodeEngine/Services/ISensorManager.cs b/IOTManagment/NodeEngine/Services/ISensorManager.cs
new file mode 100644
index 0000000..75aeca9
--- /dev/null
+++ b/IOTManagment/NodeEngine/Services/ISensorManager.cs
@@ -0,0 +1,14 @@
+using Model.Nodes.Enum;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NodeEngine.Services
+{
+ public interface ISensorManager
+ {
+ public string GetSensorData(DataType type);
+ }
+}
diff --git a/IOTManagment/NodeEngine/Services/QueryHandler.cs b/IOTManagment/NodeEngine/Services/QueryHandler.cs
new file mode 100644
index 0000000..9d1d033
--- /dev/null
+++ b/IOTManagment/NodeEngine/Services/QueryHandler.cs
@@ -0,0 +1,165 @@
+using Model.Messages;
+using Model.Nodes.Enum;
+using Model.Queries.Enums;
+using Model.Queries.Expressions;
+using Model.Queries.Statements;
+using Model.Queries.Variables;
+using Serilog;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+namespace NodeEngine.Services
+{
+ public class QueryHandler : IQueryHandler
+ {
+ private readonly ISensorManager sensorManager;
+ public QueryHandler(SensorManager sensorManager)
+ {
+ this.sensorManager = sensorManager;
+ }
+
+
+ public bool CheckWhereStatement(WhereStatement statement)
+ {
+ try
+ {
+ switch (statement.Operator)
+ {
+ case WhereOperator.None:
+ return CheckVariable(statement.Variables[0]);
+ case WhereOperator.And:
+ return CheckVariable(statement.Variables[0]) && CheckVariable(statement.Variables[0]);
+ case WhereOperator.Or:
+ return CheckVariable(statement.Variables[0]) || CheckVariable(statement.Variables[0]);
+ default:
+ break;
+ }
+ return false;
+ }
+ catch (Exception ex)
+ {
+
+ throw;
+ }
+ }
+
+
+ private bool CheckVariable(WhereVariable variable)
+ {
+ if (variable == null) return false;
+ bool result = CheckExpression(variable.Expressions.First());
+ variable.Expressions.RemoveAt(0);
+
+ foreach (var op in variable.Operators)
+ {
+ switch (op)
+ {
+ case WhereOperator.And:
+ bool res = CheckExpression(variable.Expressions.First());
+ variable.Expressions.RemoveAt(0);
+ if(res) result = true;
+ break;
+ case WhereOperator.Or:
+ if (result == false) return false;
+ result = CheckExpression(variable.Expressions.First());
+ variable.Expressions.RemoveAt(0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ // checks and evals the expression and returns if the expression is true or not
+ private bool CheckExpression(WhereExpression exp)
+ {
+ try
+ {
+ switch (exp.Operator)
+ {
+ case WhereExpOperator.GreaterThan:
+ return GetExpValue(exp.exp1) > GetExpValue(exp.exp2);
+ case WhereExpOperator.LessThan:
+ return GetExpValue(exp.exp1) < GetExpValue(exp.exp2);
+ case WhereExpOperator.LessThanOrEqual:
+ return GetExpValue(exp.exp1) <= GetExpValue(exp.exp2);
+ case WhereExpOperator.GreaterThenOrEqual:
+ return GetExpValue(exp.exp1) >= GetExpValue(exp.exp2);
+ case WhereExpOperator.NotEqual:
+ return GetExpValue(exp.exp1) != GetExpValue(exp.exp2);
+ case WhereExpOperator.Equal:
+ return GetExpValue(exp.exp1) == GetExpValue(exp.exp2);
+ default:
+ throw new ArgumentException("Unkown Operator");
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Logger.Error("Error when checking expression with message: " + ex.Message);
+ throw;
+ }
+ }
+
+ private double GetExpValue(string exp)
+ {
+ try
+ {
+ // check if the exp is a datatype, if yes then gets the data from sensor
+ if (Enum.GetNames(typeof(DataType)).Any(x => x.ToLower() == exp))
+ {
+ DataType dataType = Enum.Parse(exp,true);
+ string data = sensorManager.GetSensorData(dataType);
+ Double result = -1;
+
+ if (dataType == DataType.TEMPERATURE_CPU)
+ {
+ result = double.Parse(data) / 1000;
+ }
+
+ if (dataType == DataType.TEMPERATURE_GPU)
+ {
+ data = data.Replace("temp=", "");
+ data = data.Replace("'C", "");
+ result = double.Parse(data);
+ }
+
+ if (dataType == DataType.TEST_VAR)
+ {
+ result = double.Parse(data);
+ }
+
+ return result;
+ }
+
+ return double.Parse(exp);
+ }
+ catch (Exception ex)
+ {
+ Log.Logger.Error("A Error happened, when trying to get expressions value with message: " + ex.Message);
+ throw;
+ }
+ }
+
+ public List GetSelectResults(SelectStatement statement)
+ {
+ List result = new List();
+
+ foreach (SelectVariable variable in statement.Variables)
+ {
+ SelectVariableResult resultItem = new SelectVariableResult()
+ {
+ Variable = variable.Variable,
+ Operator = variable.Operator,
+ Value = GetExpValue(variable.Variable)
+ };
+ result.Add(resultItem);
+ }
+ return result;
+ }
+ }
+}
diff --git a/IOTManagment/NodeEngine/Services/QueryScheduler.cs b/IOTManagment/NodeEngine/Services/QueryScheduler.cs
new file mode 100644
index 0000000..e5959b4
--- /dev/null
+++ b/IOTManagment/NodeEngine/Services/QueryScheduler.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Quartz.Impl;
+using Quartz;
+using Model.Queries;
+using NodeEngine.Jobs;
+using System.Text.Json;
+using System.Net;
+
+namespace NodeEngine.Services
+{
+ public class QueryScheduler : IDisposable
+ {
+
+ IScheduler scheduler;
+
+ public QueryScheduler()
+ {
+
+ // using defaults
+ StdSchedulerFactory factory = new StdSchedulerFactory();
+
+ scheduler = factory.GetScheduler().Result;
+ scheduler.Start().Wait();
+
+ }
+
+ public async Task AddQueryJobAsync(Query query, IPEndPoint parent)
+ {
+ int interval = query.IntervalStatement.Interval;
+
+ string selectStatement = JsonSerializer.Serialize(query.SelectStatement);
+
+ string whereStatement = JsonSerializer.Serialize(query.WhereStatement);
+
+ // create the job and inputs the query data into the jobs datamap as String
+ IJobDetail job = JobBuilder.Create()
+ .WithIdentity($"Job-{query.Id}", "Queries")
+ .UsingJobData("Select", selectStatement)
+ .UsingJobData("Where", whereStatement)
+ .UsingJobData("IP",parent.Address.ToString())
+ .UsingJobData("Port",parent.Port.ToString())
+ .Build();
+
+ // Create the jobs trigger with the interval specified in the given query
+ ITrigger trigger = TriggerBuilder.Create()
+ .WithIdentity($"Trigger-{query.Id}", "QETriggers")
+ .StartNow()
+ .WithSimpleSchedule(x => x
+ .WithInterval(TimeSpan.FromMilliseconds(interval))
+ .RepeatForever())
+ .Build();
+
+ // Schedule the job using The created trigger
+ await scheduler.ScheduleJob(job, trigger);
+
+ }
+
+ // Remove a job from the schedule
+ public async Task RemoveQueryjobAsync(Guid queryId)
+ {
+ await scheduler.DeleteJob(new JobKey($"Job-{queryId}", "Queries"));
+ }
+
+ public void Dispose()
+ {
+ scheduler.Shutdown();
+
+ }
+
+
+ }
+}
diff --git a/IOTManagment/NodeEngine/Services/SensorManager.cs b/IOTManagment/NodeEngine/Services/SensorManager.cs
new file mode 100644
index 0000000..637b625
--- /dev/null
+++ b/IOTManagment/NodeEngine/Services/SensorManager.cs
@@ -0,0 +1,58 @@
+using Model.Nodes.Enum;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NodeEngine.Services
+{
+ public class SensorManager : ISensorManager
+ {
+
+ // TODO: Add commands for more datatypes
+ public string GetSensorData(DataType type)
+ {
+
+ switch (type)
+ {
+ case DataType.TEMPERATURE_CPU:
+ return ExecuteCommand("cat /sys/class/thermal/thermal_zone0/temp");
+ case DataType.TEMPERATURE_GPU:
+ return ExecuteCommand("vcgencmd measure_temp");
+ case DataType.TEST_VAR:
+ Random rnd = new Random();
+ return (rnd.NextDouble() * (80 - 0) + 0).ToString();
+ default:
+ return null;
+
+ }
+
+ }
+
+ // IMPORTANT: Commands will only work when running on linux system
+ private string ExecuteCommand(string command)
+ {
+ string result = "";
+ using (System.Diagnostics.Process proc = new System.Diagnostics.Process())
+ {
+ proc.StartInfo.FileName = "/bin/bash";
+ proc.StartInfo.Arguments = "-c \" " + command + " \"";
+ proc.StartInfo.UseShellExecute = false;
+ proc.StartInfo.RedirectStandardOutput = true;
+ proc.StartInfo.RedirectStandardError = true;
+ proc.Start();
+
+ result += proc.StandardOutput.ReadToEnd();
+ result += proc.StandardError.ReadToEnd();
+
+ proc.WaitForExit();
+ }
+ return result;
+ }
+ }
+
+
+
+}
diff --git a/IOTManagment/Server/Networking/MessageHandler.cs b/IOTManagment/Server/Networking/MessageHandler.cs
new file mode 100644
index 0000000..3bbdd1f
--- /dev/null
+++ b/IOTManagment/Server/Networking/MessageHandler.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Net;
+using System.Text.Json;
+using Model.Messages;
+using Model.Nodes;
+using Model.Queries;
+using Services;
+
+namespace Server.Networking
+{
+ public class MessageHandler
+ {
+ List nodeChildren;
+ private readonly ITopologyManager _topologyManager;
+ private IPEndPoint localIp = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 6000);
+
+ public MessageHandler(ITopologyManager topologyManager)
+ {
+ _topologyManager = topologyManager;
+ nodeChildren = new List();
+ }
+
+ public void HandleMessage(string message)
+ {
+ Console.WriteLine("Received something");
+ try
+ {
+ var msg = JsonSerializer.Deserialize(message);
+
+ // MessageType
+ switch (msg.messageType)
+ {
+ case MessageType.CONNECT:
+ {
+ Console.WriteLine("MessageType: CONNECT");
+ var node = JsonSerializer.Deserialize(msg.messageBody);
+ var NodeEndPoint = new IPEndPoint(IPAddress.Parse(node.Address), node.AddressPort);
+ if (nodeChildren.Any(x => x.Address.Equals(IPAddress.Parse(msg.senderIP))))
+ {
+ Console.WriteLine($"Node {msg.senderIP} reconnected.");
+ break;
+ }
+ _topologyManager.AddNode(NodeEndPoint, node);
+ nodeChildren.Add(NodeEndPoint);
+ break;
+ }
+
+ case MessageType.FORWARD:
+ {
+ Console.WriteLine("MessageType: FORWARD");
+
+ // Serialize message
+ var sendMsg = JsonSerializer.Serialize(msg);
+
+ foreach (IPEndPoint child in nodeChildren)
+ {
+ var sender = new NetworkSender(child, sendMsg);
+ sender.SendMessage();
+ }
+
+ break;
+ }
+ case MessageType.RESPONSEAPI:
+ {
+ Console.WriteLine("MessageType: RESPONSEAPI");
+ var varResults = JsonSerializer.Deserialize>(msg.messageBody);
+
+ foreach (var item in varResults)
+ {
+ Console.WriteLine($"{item.Variable} has the value: {item.Value}");
+ }
+ break;
+ }
+ default:
+ // TODO: Handle if no type is given
+ Console.WriteLine("No msgType" + msg);
+ break;
+ }
+ }
+ catch
+ {
+ Console.WriteLine($"Could not deserialize. Message: {message}");
+ }
+ }
+
+ public void SendStop(Guid id)
+ {
+ string body = JsonSerializer.Serialize(id);
+ Message msg = new Message(body, MessageType.STOP, localIp.Address.ToString(), localIp.Port);
+ // Serialize message
+ var sendMsg = JsonSerializer.Serialize(msg);
+
+ foreach (IPEndPoint child in nodeChildren)
+ {
+ var sender = new NetworkSender(child, sendMsg);
+ sender.SendMessage();
+ }
+ }
+
+ public void SendQuery(Query query)
+ {
+ string body = JsonSerializer.Serialize(query);
+ Message msg = new Message(body, MessageType.QUERY,localIp.Address.ToString(), localIp.Port);
+ // Serialize message
+ var sendMsg = JsonSerializer.Serialize(msg);
+
+ foreach (IPEndPoint child in nodeChildren)
+ {
+ var sender = new NetworkSender(child, sendMsg);
+ sender.SendMessage();
+ }
+ }
+ }
+}
+
diff --git a/IOTManagment/Server/Networking/NetworkListener.cs b/IOTManagment/Server/Networking/NetworkListener.cs
new file mode 100644
index 0000000..2951b35
--- /dev/null
+++ b/IOTManagment/Server/Networking/NetworkListener.cs
@@ -0,0 +1,36 @@
+using System;
+using NetMQ;
+using NetMQ.Sockets;
+using Model.Messages;
+
+namespace Server.Networking
+{
+ public class NetworkListener
+ {
+ private readonly MessageHandler _messageHandler;
+ public NetworkListener(MessageHandler messageHandler)
+ {
+ _messageHandler = messageHandler;
+ }
+
+ public void StartListener()
+ {
+ using (var listener = new PullSocket())
+ {
+ listener.Bind("tcp://0.0.0.0:6000");
+ while (true)
+ {
+ // Listen for messsages
+ string msg = listener.ReceiveFrameString();
+ Console.WriteLine("Received frame: {0}", msg);
+
+
+ // Handle the Message
+ _messageHandler.HandleMessage(msg);
+ }
+ }
+
+
+ }
+ }
+}
diff --git a/IOTManagment/Server/Networking/NetworkSender.cs b/IOTManagment/Server/Networking/NetworkSender.cs
new file mode 100644
index 0000000..5d3c39b
--- /dev/null
+++ b/IOTManagment/Server/Networking/NetworkSender.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Net;
+using NetMQ;
+using NetMQ.Sockets;
+using Model.Messages;
+
+namespace Server.Networking
+{
+ public class NetworkSender
+ {
+ IPEndPoint receiver;
+ string message;
+
+ public NetworkSender(IPEndPoint receiver, string message)
+ {
+ this.receiver = receiver;
+ this.message = message;
+ }
+
+ public void SendMessage()
+ {
+ var sender = new PushSocket();
+
+ Console.WriteLine("Connecting to socket...");
+ sender.Connect($"tcp://{receiver.Address}:{receiver.Port}");
+
+ sender.SendFrame(message);
+
+ Console.WriteLine("Message sent. Closing thread.");
+
+ }
+ }
+}
+
diff --git a/IOTManagment/Server/Program.cs b/IOTManagment/Server/Program.cs
new file mode 100644
index 0000000..47814ad
--- /dev/null
+++ b/IOTManagment/Server/Program.cs
@@ -0,0 +1,356 @@
+using NetMQ.Sockets;
+using NetMQ;
+using Model.Messages;
+using Services;
+using System.Threading;
+using System.Text.Json;
+using Server.Networking;
+using System.Net;
+using Model.Queries;
+using Model.Nodes;
+
+
+
+Console.WriteLine("Server starting...");
+
+TopologyManager topologyManager = new();
+
+MessageHandler messageHandler = new(topologyManager);
+QueryParser queryParser = new QueryParser();
+List queries = new List();
+// Listener
+var listener = new NetworkListener(messageHandler);
+var listenerThread = new Thread(() => listener.StartListener());
+listenerThread.Start();
+Console.WriteLine("Started Listener on port 6000");
+
+
+Console.Clear();
+while (true)
+{
+ printCommands(0);
+ string input = Console.ReadLine().ToLower().Trim();
+ bool isActive = true;
+
+ switch (input)
+ {
+ case "stop"://Shutdown console-application
+ Environment.Exit(0);
+ break;
+ case "query":
+ //Query options
+ Console.Clear();
+ while (isActive) {
+ printCommands(1);
+ string options = Console.ReadLine().ToLower().Trim();
+ switch (options)
+ {
+ case "input":
+ // Gets query string from console and parses it, and sends it out to child nodes
+ bool innerIsActive = true;
+ Console.WriteLine("Input Query:");
+ while (innerIsActive)
+ {
+ string query = Console.ReadLine().Trim();
+ if (query == "quit") { Console.Clear(); break; }
+ if (query != "")
+ {
+ try
+ {
+ Query q = queryParser.ParserQuery(query);
+ queries.Add(q);
+ messageHandler.SendQuery(q);
+ Console.Clear();
+ colorConsole("Query sent", ConsoleColor.Yellow, ConsoleColor.Black);
+ break;
+ }
+ catch (Exception ex)
+ {
+ colorConsole("Incorrect format: Use Query formating", ConsoleColor.Red, ConsoleColor.White);
+ Console.WriteLine("Re-enter query or write quit");
+ }
+ }
+ else
+ {
+ Console.WriteLine("Re-enter Query or write quit");
+ }
+ }
+ break;
+ case "info": //TODO: Create list of all queries
+ Console.Clear();
+ int counter = 1;
+ Console.Clear();
+ Console.WriteLine(" Active Quries ");
+ Console.WriteLine("----------------------------------------");
+
+ if (queries.Count() == 0)
+ {
+ colorConsole("No Active quries...", ConsoleColor.Red, ConsoleColor.White);
+ Console.WriteLine("");
+ break;
+ }
+ foreach (Query x in queries)
+ {
+ Console.WriteLine($"{counter}| QueryId: {x.Id}");
+ Console.WriteLine("----------------------------------------");
+ counter++;
+ }
+ break;
+ case "stop": //TODO: send a stop message and remove query from list
+ Console.WriteLine("Input query id");
+ Guid id = default;
+ while (true)
+ {
+ string value = Console.ReadLine().Trim();
+ if (value == "quit") { Console.Clear(); break; }
+ if (value != "")
+ {
+ Guid.TryParse(value, out id);
+ var foundQ = queries.Where(x => x.Id == id).FirstOrDefault();
+ if (foundQ != null)
+ {
+ Console.Clear();
+ queries.Remove(foundQ);
+ colorConsole($"Query removed {id}", ConsoleColor.Yellow, ConsoleColor.Black);
+ messageHandler.SendStop(id);
+ break;
+ }
+ else { colorConsole("No such Query found", ConsoleColor.Red, ConsoleColor.White); Console.WriteLine("Please re-enter query id or write quit"); }
+ }
+ else
+ {
+ Console.WriteLine("Re-enter query id or write quit");
+ }
+ }
+ break;
+ case "-help":
+ Console.Clear();
+ break;
+ case "back":
+ Console.Clear();
+ isActive = false;
+ break;
+ default:
+ Console.Clear();
+ colorConsole("Unknown option. Use '-help' for an overview of options", ConsoleColor.Red, ConsoleColor.White);
+ break;
+ }
+ }
+ break;
+ case "nodes":
+ Console.Clear();
+ while (isActive)
+ {
+ printCommands(2);
+ string option = Console.ReadLine().ToLower().Trim();
+ switch (option)
+ {
+ case "all":
+ var listofnodes = topologyManager.GetIPAdresses().Values.ToList();
+ int counter = 1;
+ Console.Clear();
+ Console.WriteLine(" Active Nodes ");
+ Console.WriteLine("----------------------------------------");
+
+ if (listofnodes.Count() == 0)
+ {
+ colorConsole("No Active nodes...", ConsoleColor.Red, ConsoleColor.White);
+ Console.WriteLine("");
+
+ break;
+ }
+ foreach (var tmp in listofnodes)
+ {
+ Console.WriteLine($"{counter}| NodeIP: {tmp.Address}:{tmp.AddressPort}");
+ Console.WriteLine("----------------------------------------");
+ counter++;
+ }
+ Console.WriteLine("");
+ break;
+
+ case "node":
+ Console.WriteLine("Enter IPEndPoint:");
+ bool innerIsActive = true;
+
+ string parseIp = default;
+ IPEndPoint ip = default(IPEndPoint);
+ while (innerIsActive)
+ {
+ parseIp = Console.ReadLine().ToLower().Trim();
+ if (parseIp == "quit") { Console.Clear(); break; }
+ if (parseIp != "")
+ {
+ try
+ {
+ IPEndPoint.TryParse(parseIp, out ip);
+ var node = topologyManager.GetNodeByIP(ip);
+ if (node != null)
+ {
+ #region META data printed
+ Console.Clear();
+ colorConsole("------------------INFO-------------------",ConsoleColor.Yellow,ConsoleColor.Black);
+ Console.WriteLine($"NodeIP: {node.Address}:{node.AddressPort}");
+ Console.WriteLine("----------------------------------------");
+ Console.WriteLine($"Parent: {node.Parent}:{node.ParentPort}");
+ Console.WriteLine($"Type: {node.Type}");
+ Console.WriteLine($"Status: {node.Status}");
+ Console.WriteLine($"DataType: {node.DataType}");
+ Console.WriteLine("");
+ #endregion
+ break;
+ }
+ else
+ {
+ Console.WriteLine($"No such IPEndPoint exists: {ip}");
+ Console.WriteLine("Re-enter IPEndPoint or write quit");
+ }
+ }
+ catch (Exception ex)
+ {
+ colorConsole("Incorrect format: Use IP formating", ConsoleColor.Red, ConsoleColor.White);
+ Console.WriteLine("Re-enter IPEndPoint or write quit");
+ }
+ }else {
+ Console.WriteLine("Re-enter IPEndPoint or write quit");
+ }
+ }
+ break;
+ case "back":
+ Console.Clear();
+ isActive = false;
+ break;
+ case "-help":
+ Console.Clear();
+ break;
+ default:
+ Console.Clear();
+ colorConsole("Unknown option. Use '-help' to see all options", ConsoleColor.Red, ConsoleColor.White);
+ break;
+ }
+ }
+ break;
+ case "clear":
+ Console.Clear();
+ break;
+ case "-help":
+ Console.Clear();
+ break;
+ case "logo":
+ Console.Clear();
+ printCommands(3);
+ break;
+ default:
+ Console.Clear();
+ colorConsole("Unknown command. Use '-help' to see all commands",ConsoleColor.Red,ConsoleColor.White);
+ break;
+ }
+}
+
+static void printCommands(int index)
+{
+ switch(index)
+ {
+ case 0: //Main
+ #region Main Printstatement
+ colorConsole("__________MAIN___________", ConsoleColor.DarkGreen, ConsoleColor.White);
+ colorConsole("Available commands: ", ConsoleColor.DarkGreen, ConsoleColor.White);
+ colorConsoleSame("stop ", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - Shutdown console-application.");
+ colorConsoleSame("query", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - Query interface.");
+ colorConsoleSame("nodes", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - Node interface.");
+ colorConsoleSame("clear", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - Clears the current Console text.");
+ Console.WriteLine("Please enter a command:");
+ #endregion
+ break;
+ case 1: //Query
+ #region Query Printstatement
+ colorConsole("__________QUERY___________", ConsoleColor.DarkGreen, ConsoleColor.White);
+ colorConsole("Available options: ", ConsoleColor.DarkGreen, ConsoleColor.White);
+ colorConsoleSame("input", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - Send query to nodes");
+ colorConsoleSame("info ", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - List of all current quries");
+ colorConsoleSame("stop ", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - Specific node by id");
+ colorConsoleSame("back ", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - Go back to previous 'page'");
+ #endregion
+ break;
+ case 2://Node
+ #region Node Printstatement
+ colorConsole("___________NODE___________", ConsoleColor.DarkGreen, ConsoleColor.White);
+ colorConsole("Select a following option:", ConsoleColor.DarkGreen, ConsoleColor.White);
+ colorConsoleSame("all ", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - Displays all current nodes");
+ colorConsoleSame("node", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - Displays information about a specific node via IPEndPoint");
+ colorConsoleSame("back", ConsoleColor.White, ConsoleColor.Blue);
+ Console.WriteLine(" - Go back to previous 'page'");
+ #endregion
+ break;
+ case 3://Funny
+ #region logo
+ //Normal
+ /*
+ colorConsole(@"###########################################", ConsoleColor.White, ConsoleColor.Black);
+ colorConsole(@"# ______ _ #", ConsoleColor.White, ConsoleColor.Black);
+ colorConsole(@"# |___ / | | #", ConsoleColor.White, ConsoleColor.Black);
+ colorConsole(@"# / / ___ _ __ ___ ___ __| | ___ #", ConsoleColor.White, ConsoleColor.Black);
+ colorConsole(@"# / / / _ \ '_ \ / __/ _ \ / _` |/ _ \ #", ConsoleColor.White, ConsoleColor.Black);
+ colorConsole(@"# / /_| __/ | | | (_| (_) | (_| | __/ #", ConsoleColor.White, ConsoleColor.Black);
+ colorConsole(@"# /_____\___|_| |_|\___\___/ \__,_|\___| #", ConsoleColor.White, ConsoleColor.Black);
+ colorConsole(@"# #", ConsoleColor.White, ConsoleColor.Black);
+ colorConsole(@"###########################################", ConsoleColor.White, ConsoleColor.Black);
+ */
+
+ //Ukraine-flag
+
+ colorConsole(@"###########################################", ConsoleColor.Blue, ConsoleColor.White);
+ colorConsole(@"# ______ _ #", ConsoleColor.Blue, ConsoleColor.White);
+ colorConsole(@"# |___ / | | #", ConsoleColor.Blue, ConsoleColor.White);
+ colorConsole(@"# / / ___ _ __ ___ ___ __| | ___ #", ConsoleColor.Blue, ConsoleColor.White);
+ colorConsole(@"# / / / _ \ '_ \ / __/ _ \ / _` |/ _ \ #", ConsoleColor.Blue, ConsoleColor.White);
+ colorConsole(@"# / /_| __/ | | | (_| (_) | (_| | __/ #", ConsoleColor.Yellow, ConsoleColor.Black);
+ colorConsole(@"# /_____\___|_| |_|\___\___/ \__,_|\___| #", ConsoleColor.Yellow, ConsoleColor.Black);
+ colorConsole(@"# #", ConsoleColor.Yellow, ConsoleColor.Black);
+ colorConsole(@"###########################################", ConsoleColor.Yellow, ConsoleColor.Black);
+
+
+ #endregion
+ break;
+ }
+
+}
+
+static void colorConsoleSame(string text, ConsoleColor back, ConsoleColor fore)
+{
+ Console.ForegroundColor = fore;
+ Console.BackgroundColor = back;
+ Console.Write(text);
+ Console.ResetColor();
+}
+
+static void colorConsole(string text, ConsoleColor back, ConsoleColor fore)
+{
+ Console.ForegroundColor = fore;
+ Console.BackgroundColor = back;
+ Console.WriteLine(text);
+ Console.ResetColor();
+}
+
+
+// Sender
+/*var msg = new Message(Guid.NewGuid(), "hej fra server", MessageType.CONNECT, "127.0.0.1", 6000);
+var json = JsonSerializer.Serialize(msg);
+var sender = new NetworkSender(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6000), json);
+var senderThread = new Thread(() => sender.SendMessage());
+senderThread.Start();
+
+var msg2 = new Message(Guid.NewGuid(), "hej fra server 2", MessageType.CONNECT, "127.0.0.1", 6001);
+var json2 = JsonSerializer.Serialize(msg2);
+var sender2 = new NetworkSender(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6001), json2);
+var senderThread2 = new Thread(() => sender2.SendMessage());
+senderThread2.Start();*/
\ No newline at end of file
diff --git a/IOTManagment/Server/Server.csproj b/IOTManagment/Server/Server.csproj
new file mode 100644
index 0000000..6399176
--- /dev/null
+++ b/IOTManagment/Server/Server.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/IOTManagment/Services/Class1.cs b/IOTManagment/Services/Class1.cs
deleted file mode 100644
index 3ca3ace..0000000
--- a/IOTManagment/Services/Class1.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Services
-{
- public class Class1
- {
-
- }
-}
\ No newline at end of file
diff --git a/IOTManagment/Services/ClientService.cs b/IOTManagment/Services/ClientService.cs
new file mode 100644
index 0000000..ae90d99
--- /dev/null
+++ b/IOTManagment/Services/ClientService.cs
@@ -0,0 +1,28 @@
+using System;
+using NetMQ;
+using NetMQ.Sockets;
+
+namespace Services
+{
+ public class ClientService
+ {
+ public ClientService()
+ {
+
+ }
+
+ public void BuildClient()
+ {
+ using (var client = new RequestSocket())
+ {
+ Console.WriteLine("Starting Client...");
+ client.Connect("tcp://127.0.0.1:6000");
+ client.SendFrame("Hello");
+ var msg = client.ReceiveFrameString();
+ Console.WriteLine("From Server: {0}", msg);
+ //client.ReceiveFrameString();
+ }
+ }
+ }
+}
+
diff --git a/IOTManagment/Services/CommunicationService.cs b/IOTManagment/Services/CommunicationService.cs
new file mode 100644
index 0000000..87d9638
--- /dev/null
+++ b/IOTManagment/Services/CommunicationService.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Net;
+using Model.Messages;
+
+namespace Services
+{
+ public class CommunicationService : ICommunicationService
+ {
+ public void SendMessage(IPAddress ip, Message outgoing)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void ReceiveMessage(Message incoming)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/IOTManagment/Services/Helpers/IntervalParseHelper.cs b/IOTManagment/Services/Helpers/IntervalParseHelper.cs
new file mode 100644
index 0000000..a51a633
--- /dev/null
+++ b/IOTManagment/Services/Helpers/IntervalParseHelper.cs
@@ -0,0 +1,22 @@
+using Model.Queries.Statements;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Services.Helpers
+{
+ public class IntervalParseHelper
+ {
+ public IntervalStatement ParseInterval(string statement)
+ {
+ int interval = int.Parse(statement);
+
+ return new IntervalStatement
+ {
+ Interval = interval,
+ };
+ }
+ }
+}
diff --git a/IOTManagment/Services/Helpers/SelectParseHelper.cs b/IOTManagment/Services/Helpers/SelectParseHelper.cs
new file mode 100644
index 0000000..890fd42
--- /dev/null
+++ b/IOTManagment/Services/Helpers/SelectParseHelper.cs
@@ -0,0 +1,51 @@
+using Model.Queries.Enums;
+using Model.Queries.Statements;
+using Model.Queries.Variables;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Services.Helpers
+{
+ public class SelectParseHelper
+ {
+
+ public SelectStatement ParseSelect (string selectStatement)
+ {
+ SelectStatement ResultStatment = new SelectStatement ();
+
+ string[] statements = selectStatement.Split (',');
+
+ foreach (string statement in statements)
+ {
+ if(statement.Contains('(')) // if contains ( then an operator is present
+ {
+ ResultStatment.Variables.Add(new SelectVariable
+ {
+ Variable = statement.Split('(', ')')[1],
+ Operator = GetOperator (statement),
+ });
+ } else
+ {
+ ResultStatment.Variables.Add(new SelectVariable
+ {
+ Variable = statement,
+ Operator = SelectOperator.None
+ });
+ }
+ }
+
+ return ResultStatment;
+ }
+
+
+ public SelectOperator GetOperator (string statement)
+ {
+ string ops = (statement.Split('(')[0]).ToLower();
+
+ return Enum.Parse(ops,true);
+ }
+ }
+}
diff --git a/IOTManagment/Services/Helpers/WhereParseHelper.cs b/IOTManagment/Services/Helpers/WhereParseHelper.cs
new file mode 100644
index 0000000..4388663
--- /dev/null
+++ b/IOTManagment/Services/Helpers/WhereParseHelper.cs
@@ -0,0 +1,128 @@
+using Model.Queries.Enums;
+using Model.Queries.Expressions;
+using Model.Queries.Statements;
+using Model.Queries.Variables;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace Services.Helpers
+{
+ public class WhereParseHelper
+ {
+ public WhereStatement ParseWhere(string whereStatment)
+ {
+ whereStatment = whereStatment.Replace(" ", string.Empty);
+ var variables = whereStatment.Split('(', ')').Where(x => !string.IsNullOrEmpty(x)).ToArray();
+
+ WhereStatement statement = new WhereStatement();
+
+ foreach (string expr in variables)
+ {
+ if(!CheckIfOperator(expr))
+ {
+ statement.Variables.Add(ParseVariable(expr));
+ // the expr is a variable
+
+ } else
+ {
+ statement.Operator = ParseOperator(expr);
+ }
+ }
+
+ return statement;
+ }
+
+
+ private bool CheckIfOperator(string expr)
+ {
+ switch (expr)
+ {
+ case "&&":
+ return true;
+ break;
+ case "||":
+ return true;
+ break;
+ default:
+ return false;
+ break;
+ }
+ }
+
+ private WhereVariable ParseVariable(string expr)
+ {
+ var variable = new WhereVariable();
+
+ string pattern = @"(&&|\|\|)";
+ string[] operators = Regex.Matches(expr, pattern).Select(x => x.Value).ToArray();
+
+ foreach (var ops in operators)
+ {
+ variable.Operators.Add(ParseOperator(ops));
+ }
+
+ var exprs = expr.Split(new[] { "&&", "||" }, StringSplitOptions.TrimEntries);
+ foreach (var item in exprs)
+ {
+ var x = item.Split(new[] { "<", ">","<=",">=","=","!=" }, StringSplitOptions.TrimEntries);
+
+ variable.Expressions.Add(new WhereExpression
+ {
+ exp1 = x[0],
+ exp2 = x[1],
+ Operator = ParseExpOperator(item.Replace(x[0], "").Replace(x[1], ""))
+ });
+ }
+
+ return variable;
+ }
+
+ private WhereExpOperator ParseExpOperator(string ops)
+ {
+ switch (ops)
+ {
+ case "<":
+ return WhereExpOperator.LessThan;
+ break;
+ case ">":
+ return WhereExpOperator.GreaterThan;
+ break;
+ case "<=":
+ return WhereExpOperator.LessThanOrEqual;
+ break;
+ case">=":
+ return WhereExpOperator.GreaterThenOrEqual;
+ break;
+ case"=":
+ return WhereExpOperator.Equal;
+ break;
+ case"!=":
+ return WhereExpOperator.NotEqual;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(ops), ops);
+ break;
+ }
+ }
+
+ private WhereOperator ParseOperator(string ops)
+ {
+ switch (ops)
+ {
+ case "||":
+ return WhereOperator.Or;
+ break;
+ case "&&":
+ return WhereOperator.And;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(ops), ops);
+ break;
+ }
+ }
+ }
+}
diff --git a/IOTManagment/Services/ICommunicationService.cs b/IOTManagment/Services/ICommunicationService.cs
new file mode 100644
index 0000000..8eb8f15
--- /dev/null
+++ b/IOTManagment/Services/ICommunicationService.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Net;
+using Model.Messages;
+
+namespace Services
+{
+ public interface ICommunicationService
+ {
+
+ void SendMessage(IPAddress ip, Message outgoing);
+ void ReceiveMessage(Message incoming);
+ }
+}
+
diff --git a/IOTManagment/Services/ITopologyManager.cs b/IOTManagment/Services/ITopologyManager.cs
new file mode 100644
index 0000000..cac349a
--- /dev/null
+++ b/IOTManagment/Services/ITopologyManager.cs
@@ -0,0 +1,29 @@
+using Model.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Services
+{
+ public interface ITopologyManager
+ {
+ /*
+ ˄ 0
+ | / | \
+ | / | \
+ | 0 0 0 Communication needs to go both ways (missing child atm) How should the proper data-structure look/build like.
+ | / \ / \ / \
+ | 0 0 0 0 0 0
+ ˅
+ */
+
+ //TODO: Maybe change the Key-type from object to something comparable?
+ Dictionary IPAdresses { get; }
+ public void AddNode(IPEndPoint nodeAdd, INode Node);
+
+ public void UpdateNode(IPEndPoint nodeAdd, INode node);
+ }
+}
diff --git a/IOTManagment/Services/QueryParser.cs b/IOTManagment/Services/QueryParser.cs
new file mode 100644
index 0000000..382f577
--- /dev/null
+++ b/IOTManagment/Services/QueryParser.cs
@@ -0,0 +1,40 @@
+using Model.Queries;
+using Services.Helpers;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Services
+{
+ public class QueryParser
+ {
+ SelectParseHelper SelectParser;
+ IntervalParseHelper IntervalParser;
+ WhereParseHelper WhereParser;
+ public QueryParser()
+ {
+ SelectParser = new SelectParseHelper();
+ IntervalParser = new IntervalParseHelper();
+ WhereParser = new WhereParseHelper();
+ }
+ public Query ParserQuery(string query)
+ {
+ // TODO: ERROR HANDLING
+ // split the different statement parts
+ string[] statmenets = query.ToLower().Split(new []{"select","interval","where"},StringSplitOptions.TrimEntries);
+
+ var selectStatement = SelectParser.ParseSelect(statmenets[1]);
+ var intervalStatement = IntervalParser.ParseInterval(statmenets[2]);
+ var whereStatemennt = WhereParser.ParseWhere(statmenets[3]);
+
+ return new Query
+ {
+ SelectStatement = selectStatement,
+ IntervalStatement = intervalStatement,
+ WhereStatement = whereStatemennt
+ };
+ }
+ }
+}
diff --git a/IOTManagment/Services/Services.csproj b/IOTManagment/Services/Services.csproj
index 132c02c..bf5de91 100644
--- a/IOTManagment/Services/Services.csproj
+++ b/IOTManagment/Services/Services.csproj
@@ -1,4 +1,4 @@
-
+
net6.0
@@ -6,4 +6,14 @@
enable
+
+
+
+
+
+
+
+
+
+
diff --git a/IOTManagment/Services/TopologyManager.cs b/IOTManagment/Services/TopologyManager.cs
new file mode 100644
index 0000000..39c139e
--- /dev/null
+++ b/IOTManagment/Services/TopologyManager.cs
@@ -0,0 +1,42 @@
+using Model.Nodes;
+using System;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Services
+{
+ public class TopologyManager : ITopologyManager
+ {
+
+ public Dictionary IPAdresses { get;}
+
+ public TopologyManager() {
+ IPAdresses = new Dictionary();
+ }
+
+ public void AddNode(IPEndPoint nodeAdd, INode node)
+ {
+ IPAdresses.Add(nodeAdd, node);
+ }
+
+ public void UpdateNode(IPEndPoint nodeAdd, INode node)
+ {
+ IPAdresses[nodeAdd] = node;
+ }
+
+ public Dictionary GetIPAdresses()
+ {
+ return IPAdresses;
+ }
+
+ public INode GetNodeByIP(IPEndPoint ip) {
+ if (!IPAdresses.ContainsKey(ip))
+ {
+ return null;
+ }
+ return IPAdresses[ip];
+ }
+ }
+}