diff --git a/Things-to-know-Kim.txt b/Things-to-know-Kim.txt index 567e4d7eb..80ef6fb93 100644 --- a/Things-to-know-Kim.txt +++ b/Things-to-know-Kim.txt @@ -14,7 +14,7 @@ I'll reroute my emails to one of you for software updates. MARIOS: Please make sure to patch out the vulnerable npm packages in the frontend. - And in my opinion, get started on React or Testcafe Integration tests ;) + Get started on React or Testcafe Integration tests ;) You can add them into the Gitea Actions Pipeline, read the documentation on Github-actions and integration tests. Runner: diff --git a/csharp/App/Backend/Controller.cs b/csharp/App/Backend/Controller.cs index e01f2481c..d74099345 100644 --- a/csharp/App/Backend/Controller.cs +++ b/csharp/App/Backend/Controller.cs @@ -326,11 +326,20 @@ public class Controller : ControllerBase [HttpPost(nameof(CreateUser))] public async Task> CreateUser([FromBody] User newUser, Token authToken) { + var create = Db.GetSession(authToken).Create(newUser); + if (create) + { + var mail_success= await Db.SendNewUserEmail(newUser); + if (!mail_success) + { + Db.GetSession(authToken).Delete(newUser); + } + + return mail_success ? newUser.HidePassword():Unauthorized(); + } - return create && await Db.SendNewUserEmail(newUser) - ? newUser.HidePassword() - : Unauthorized() ; + return Unauthorized() ; } [HttpPost(nameof(CreateInstallation))] diff --git a/csharp/App/Backend/Program.cs b/csharp/App/Backend/Program.cs index 4d27d66ce..5350fe411 100644 --- a/csharp/App/Backend/Program.cs +++ b/csharp/App/Backend/Program.cs @@ -11,6 +11,7 @@ using Microsoft.OpenApi.Models; using InnovEnergy.Lib.Utils; using RabbitMQ.Client; + namespace InnovEnergy.App.Backend; public static class Program @@ -22,18 +23,10 @@ public static class Program Db.Init(); var builder = WebApplication.CreateBuilder(args); - - string vpnServerIp = "194.182.190.208"; - //string vpnServerIp = "127.0.0.1"; - WebsocketManager.Factory = new ConnectionFactory { HostName = vpnServerIp}; - WebsocketManager.Connection = WebsocketManager.Factory.CreateConnection(); - WebsocketManager.Channel = WebsocketManager.Connection.CreateModel(); - Console.WriteLine("Middleware subscribed to RabbitMQ queue, ready for receiving messages"); - WebsocketManager.Channel.QueueDeclare(queue: "statusQueue", durable: true, exclusive: false, autoDelete: false, arguments: null); - - WebsocketManager.StartRabbitMqConsumer(); + RabbitMqManager.InitializeEnvironment(); + RabbitMqManager.StartRabbitMqConsumer(); Console.WriteLine("Queue declared"); - WebsocketManager.InformInstallationsToSubscribeToRabbitMq(); + //WebsocketManager.InformInstallationsToSubscribeToRabbitMq(); WebsocketManager.MonitorInstallationTable(); builder.Services.AddControllers(); diff --git a/csharp/App/Backend/Websockets/RabbitMQManager.cs b/csharp/App/Backend/Websockets/RabbitMQManager.cs new file mode 100644 index 000000000..3c74a7d6c --- /dev/null +++ b/csharp/App/Backend/Websockets/RabbitMQManager.cs @@ -0,0 +1,304 @@ +using System.Drawing.Printing; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Text.Json; +using InnovEnergy.App.Backend.Database; +using InnovEnergy.App.Backend.DataTypes; +using RabbitMQ.Client; +using RabbitMQ.Client.Events; + +namespace InnovEnergy.App.Backend.Websockets; + +public static class RabbitMqManager +{ + + public static ConnectionFactory Factory = null!; + public static IConnection Connection = null!; + public static IModel Channel = null!; + + + public static void InitializeEnvironment() + { + + //string vpnServerIp = "194.182.190.208"; + string vpnServerIp = "10.2.0.11"; + + // ConnectionFactory factory = new ConnectionFactory(); + // factory.HostName = vpnServerIp; + // factory.AutomaticRecoveryEnabled = true; + // //factory.UserName = ""; + // //factory.Password = ""; + // factory.VirtualHost = "/"; + // factory.Port = 5672; + // + // //factory.AuthMechanisms = new IAuthMechanismFactory[] { new ExternalMechanismFactory() }; + // + // System.Diagnostics.Debug.WriteLine("2 "); + // + // X509Certificate2Collection certCollection = new X509Certificate2Collection(); + // X509Certificate2 certificate = new X509Certificate2("/etc/rabbitmq/testca/ca_certificate.pem"); + // certCollection.Add(certificate); + // + // factory.Ssl.Certs = certCollection; + // factory.Ssl.Enabled = true; + // factory.Ssl.ServerName = "Webserver-FrontAndBack"; + // factory.Ssl.Version = SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13; + // factory.Ssl.AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateChainErrors; + // factory.Ssl.CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => + // { + // if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) + // { + // // Log or debug information about the chain + // foreach (var chainElement in chain.ChainElements) + // { + // Console.WriteLine($"Element Subject: {chainElement.Certificate.Subject}"); + // Console.WriteLine($"Element Issuer: {chainElement.Certificate.Issuer}"); + // // Add more details as needed + // } + // } + // + // // Your custom validation logic + // return sslPolicyErrors == SslPolicyErrors.None; + // }; + + + Factory = new ConnectionFactory + { + HostName = vpnServerIp, + Port = 5672, + VirtualHost = "/", + UserName = "consumer", + Password = "faceaddb5005815199f8366d3d15ff8a", + //AuthMechanisms = new IAuthMechanismFactory[] { new ExternalMechanismFactory() }, + + // Ssl = new SslOption + // { + // Enabled = true, + // ServerName = "Webserver-FrontAndBack", + // //Roots = new X509Certificate2Collection { caCertificate }, + // //CertPath = "/etc/rabbitmq/testca/ca_certificate.pem", + // CertPath = "/etc/rabbitmq/client/client_certificate.pem", + // + // + // // CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => + // // { + // // //X509Certificate2 clientCertificate = new X509Certificate2("/etc/rabbitmq/client/client_certificate.pem"); + // // + // // //X509Certificate2 caCertificate = new X509Certificate2("/etc/openvpn/client/ca-certificate"); + // // X509Certificate2 caCertificate = new X509Certificate2("/etc/rabbitmq/testca/ca_certificate.pem"); + // // + // // + // // + // // Console.WriteLine(certificate.Subject); + // // Console.WriteLine("---------------------------------"); + // // //Console.WriteLine(certificate.GetPublicKey()); + // // // Your custom validation logic using the CA certificate + // // // Return true if the certificate is valid, false otherwise + // // return certificate.Issuer == caCertificate.Subject; + // // } + // CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => + // { + // X509Certificate2 caCertificate = new X509Certificate2("/etc/rabbitmq/testca/ca_certificate.pem"); + // + // // Add the CA certificate to the chain policy's extra store + // chain.ChainPolicy.ExtraStore.Add(caCertificate); + // + // // Check if the chain builds successfully + // bool chainIsValid = chain.Build((X509Certificate2)certificate); + // + // if (!chainIsValid) + // { + // Console.WriteLine("Certificate chain validation failed:"); + // + // // Print details of each chain status + // foreach (var chainStatus in chain.ChainStatus) + // { + // Console.WriteLine($"Chain Status: {chainStatus.Status}"); + // Console.WriteLine($"Chain Status Information: {chainStatus.StatusInformation}"); + // // Add more details as needed + // // Check if the failure is due to UntrustedRoot + // if (chainStatus.Status == X509ChainStatusFlags.UntrustedRoot) + // { + // // Manually check if the root certificate is the expected one + // if (certificate.Issuer == caCertificate.Subject) + // { + // Console.WriteLine("Manually trusting the root certificate."); + // chainIsValid = true; + // } + // } + // } + // + // + // } + // + // // Additional validation logic if needed + // Console.WriteLine($"Certificate Subject: {certificate.Subject}"+chainIsValid); + // + // // Return true if the certificate is valid + // return chainIsValid; + // } + + + //} + }; + + + + Connection = Factory.CreateConnection(); + Channel = Connection.CreateModel(); + Console.WriteLine("Middleware subscribed to RabbitMQ queue, ready for receiving messages"); + Channel.QueueDeclare(queue: "statusQueue", durable: true, exclusive: false, autoDelete: false, arguments: null); + } + + public static async Task StartRabbitMqConsumer() + { + var consumer = new EventingBasicConsumer(Channel); + consumer.Received += (_, ea) => + { + var body = ea.Body.ToArray(); + var message = Encoding.UTF8.GetString(body); + StatusMessage? receivedStatusMessage = JsonSerializer.Deserialize(message); + + lock (WebsocketManager.InstallationConnections) + { + //Consumer received a message + if (receivedStatusMessage != null) + { + Console.WriteLine("----------------------------------------------"); + Console.WriteLine("Received a message from installation: " + receivedStatusMessage.InstallationId + " and status is: " + receivedStatusMessage.Status); + var installationId = receivedStatusMessage.InstallationId; + + //This is a heartbit message, just update the timestamp for this installation. + //There is no need to notify the corresponding front-ends. + if (receivedStatusMessage.Type == MessageType.Heartbit) + { + Console.WriteLine("This is a heartbit message from installation: " + installationId); + } + else + { + //Traverse the Warnings list, and store each of them to the database + if (receivedStatusMessage.Warnings != null) + { + foreach (var warning in receivedStatusMessage.Warnings) + { + Warning newWarning = new Warning + { + InstallationId = receivedStatusMessage.InstallationId, + Description = warning.Description, + Date = warning.Date, + Time = warning.Time, + DeviceCreatedTheMessage = warning.CreatedBy, + Seen = false + }; + //Create a new warning and add it to the database + Db.HandleWarning(newWarning, receivedStatusMessage.InstallationId); + } + } + + + //Traverse the Alarm list, and store each of them to the database + if (receivedStatusMessage.Alarms != null) + { + Console.WriteLine("Add an alarm for installation "+receivedStatusMessage.InstallationId); + foreach (var alarm in receivedStatusMessage.Alarms) + { + Error newError = new Error + { + InstallationId = receivedStatusMessage.InstallationId, + Description = alarm.Description, + Date = alarm.Date, + Time = alarm.Time, + DeviceCreatedTheMessage = alarm.CreatedBy, + Seen = false + }; + //Create a new error and add it to the database + Db.HandleError(newError, receivedStatusMessage.InstallationId); + } + } + } + + var prevStatus = 0; + + //This installation id does not exist in our data structure, add it. + if (!WebsocketManager.InstallationConnections.ContainsKey(installationId)) + { + prevStatus = -2; + Console.WriteLine("Create new empty list for installation: " + installationId); + WebsocketManager.InstallationConnections[installationId] = new InstallationInfo + { + Status = receivedStatusMessage.Status, + Timestamp = DateTime.Now + }; + } + else + { + prevStatus = WebsocketManager.InstallationConnections[installationId].Status; + WebsocketManager.InstallationConnections[installationId].Status = receivedStatusMessage.Status; + WebsocketManager.InstallationConnections[installationId].Timestamp = DateTime.Now; + } + + //Console.WriteLine("----------------------------------------------"); + //Update all the connected front-ends regarding this installation + if(prevStatus != receivedStatusMessage.Status && WebsocketManager.InstallationConnections[installationId].Connections.Count > 0) + { + WebsocketManager.InformWebsocketsForInstallation(installationId); + } + + } + } + }; + Channel.BasicConsume(queue: "statusQueue", autoAck: true, consumer: consumer); + } + + public static void InformInstallationsToSubscribeToRabbitMq() + { + var installationIps = Db.Installations.Select(inst => inst.VpnIp).ToList(); + Console.WriteLine("Count is "+installationIps.Count); + var maxRetransmissions = 2; + + UdpClient udpClient = new UdpClient(); + udpClient.Client.ReceiveTimeout = 2000; + int port = 9000; + //Send a message to each installation and tell it to subscribe to the queue + using (udpClient) + { + for (int i = 0; i < installationIps.Count; i++) + { + if(installationIps[i]==""){continue;} + Console.WriteLine("-----------------------------------------------------------"); + Console.WriteLine("Trying to reach installation with IP: " + installationIps[i]); + //Try at most MAX_RETRANSMISSIONS times to reach an installation. + for (int j = 0; j < maxRetransmissions; j++) + { + string message = "This is a message from RabbitMQ server, you can subscribe to the RabbitMQ queue"; + byte[] data = Encoding.UTF8.GetBytes(message); + udpClient.Send(data, data.Length, installationIps[i], port); + + Console.WriteLine($"Sent UDP message to {installationIps[i]}:{port}: {message}"); + IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(installationIps[i]), port); + + try + { + byte[] replyData = udpClient.Receive(ref remoteEndPoint); + string replyMessage = Encoding.UTF8.GetString(replyData); + Console.WriteLine("Received " + replyMessage + " from installation " + installationIps[i]); + break; + } + catch (SocketException ex) + { + if (ex.SocketErrorCode == SocketError.TimedOut){Console.WriteLine("Timed out waiting for a response. Retry...");} + else{Console.WriteLine("Error: " + ex.Message);} + } + } + } + } + + Console.WriteLine("Start RabbitMQ Consumer"); + + } + +} \ No newline at end of file diff --git a/csharp/App/Backend/Websockets/WebsockerManager.cs b/csharp/App/Backend/Websockets/WebsockerManager.cs index ef4d9a107..643308e57 100644 --- a/csharp/App/Backend/Websockets/WebsockerManager.cs +++ b/csharp/App/Backend/Websockets/WebsockerManager.cs @@ -13,10 +13,7 @@ namespace InnovEnergy.App.Backend.Websockets; public static class WebsocketManager { public static Dictionary InstallationConnections = new Dictionary(); - public static ConnectionFactory Factory = null!; - public static IConnection Connection = null!; - public static IModel Channel = null!; - + public static void InformInstallationsToSubscribeToRabbitMq() { var installationIps = Db.Installations.Select(inst => inst.VpnIp).ToList(); @@ -82,99 +79,7 @@ public static class WebsocketManager } } - public static async Task StartRabbitMqConsumer() - { - var consumer = new EventingBasicConsumer(Channel); - consumer.Received += (_, ea) => - { - var body = ea.Body.ToArray(); - var message = Encoding.UTF8.GetString(body); - StatusMessage? receivedStatusMessage = JsonSerializer.Deserialize(message); - - lock (InstallationConnections) - { - //Consumer received a message - if (receivedStatusMessage != null) - { - Console.WriteLine("Received a message from installation: " + receivedStatusMessage.InstallationId + " and status is: " + receivedStatusMessage.Status); - Console.WriteLine("----------------------------------------------"); - Console.WriteLine("Update installation connection table"); - var installationId = receivedStatusMessage.InstallationId; - - //This is a heartbit message, just update the timestamp for this installation. - //There is no need to notify the corresponding front-ends. - if (receivedStatusMessage.Type == MessageType.Heartbit) - { - InstallationConnections[installationId].Timestamp = DateTime.Now; - } - else - { - //Traverse the Warnings list, and store each of them to the database - if (receivedStatusMessage.Warnings != null) - { - foreach (var warning in receivedStatusMessage.Warnings) - { - Warning newWarning = new Warning - { - InstallationId = receivedStatusMessage.InstallationId, - Description = warning.Description, - Date = warning.Date, - Time = warning.Time, - DeviceCreatedTheMessage = warning.CreatedBy, - Seen = false - }; - //Create a new warning and add it to the database - Db.HandleWarning(newWarning, receivedStatusMessage.InstallationId); - } - } - - //Traverse the Alarm list, and store each of them to the database - if (receivedStatusMessage.Alarms != null) - { - foreach (var alarm in receivedStatusMessage.Alarms) - { - Error newError = new Error - { - InstallationId = receivedStatusMessage.InstallationId, - Description = alarm.Description, - Date = alarm.Date, - Time = alarm.Time, - DeviceCreatedTheMessage = alarm.CreatedBy, - Seen = false - }; - //Create a new error and add it to the database - Db.HandleError(newError, receivedStatusMessage.InstallationId); - } - } - - //This installation id does not exist in our data structure, add it. - if (!InstallationConnections.ContainsKey(installationId)) - { - Console.WriteLine("Create new empty list for installation: " + installationId); - InstallationConnections[installationId] = new InstallationInfo - { - Status = receivedStatusMessage.Status, - Timestamp = DateTime.Now - }; - } - else - { - InstallationConnections[installationId].Status = receivedStatusMessage.Status; - InstallationConnections[installationId].Timestamp = DateTime.Now; - } - - Console.WriteLine("----------------------------------------------"); - //Update all the connected front-ends regarding this installation - if(InstallationConnections[installationId].Connections.Count > 0) - { - InformWebsocketsForInstallation(installationId); - } - } - } - } - }; - Channel.BasicConsume(queue: "statusQueue", autoAck: true, consumer: consumer); - } + //Inform all the connected websockets regarding installation "installationId" public static void InformWebsocketsForInstallation(int installationId) diff --git a/csharp/App/Middleware/InstallationInfo.cs b/csharp/App/Middleware/InstallationInfo.cs deleted file mode 100644 index 2e1f5bd79..000000000 --- a/csharp/App/Middleware/InstallationInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Net.WebSockets; - -namespace InnovEnergy.App.Middleware; - -public class InstallationInfo -{ - public int Status { get; set; } - public List Connections { get; } = new List(); -} \ No newline at end of file diff --git a/csharp/App/Middleware/Middleware.csproj b/csharp/App/Middleware/Middleware.csproj deleted file mode 100644 index 34fc15eab..000000000 --- a/csharp/App/Middleware/Middleware.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - InnovEnergy.App.Middleware - - - - - - - - - - - - diff --git a/csharp/App/Middleware/Program.cs b/csharp/App/Middleware/Program.cs deleted file mode 100644 index 7a5bd0ed4..000000000 --- a/csharp/App/Middleware/Program.cs +++ /dev/null @@ -1,66 +0,0 @@ -using InnovEnergy.App.Middleware; -using System; -using System.Net; -using System.Net.Sockets; -using System.Net.WebSockets; -using System.Text; -using InnovEnergy.Lib.Utils; - -internal class Program -{ - public static readonly object SharedDataLock = new object(); - - public static async Task Main(string[] args) - { - //For each installation id, we maintain a list of the connected clients - var installationConnections = new Dictionary(); - var installationsIds = new List {1}; - var installationIps = new List {"10.2.3.115"}; - var MAX_RETRANSMISSIONS = 2; - - RabbitMqConsumer.StartRabbitMqConsumer(installationConnections,SharedDataLock); - - UdpClient udpClient = new UdpClient(); - udpClient.Client.ReceiveTimeout = 2000; - int port = 9000; - //Send a message to each installation and tell it to subscribe to the queue - for (int i = 0; i < installationsIds.Count; i++) - { - using (udpClient) - { - //Try at most MAX_RETRANSMISSIONS times to reach an installation. - for (int j = 0; j < MAX_RETRANSMISSIONS; j++) - { - string message = "This is a message from RabbitMQ server, you can subscribe to the RabbitMQ queue"; - byte[] data = Encoding.UTF8.GetBytes(message); - udpClient.Send(data, data.Length, installationIps[i], port); - - Console.WriteLine($"Sent UDP message to {installationIps[i]}:{port}: {message}"); - IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(installationIps[i]), port); - - try - { - byte[] replyData = udpClient.Receive(ref remoteEndPoint); - string replyMessage = Encoding.UTF8.GetString(replyData); - Console.WriteLine("Received message from installation " + installationsIds[i]); - break; - } - catch (SocketException ex) - { - if (ex.SocketErrorCode == SocketError.TimedOut) - { - Console.WriteLine("Timed out waiting for a response. Retry..."); - } - else - { - Console.WriteLine("Error: " + ex.Message); - } - } - } - } - } - - Console.WriteLine("WebSocket server is running. Press Enter to exit."); - await WebSocketListener.StartServerAsync(installationConnections,SharedDataLock); - } -} \ No newline at end of file diff --git a/csharp/App/Middleware/RabbitMQConsumer.cs b/csharp/App/Middleware/RabbitMQConsumer.cs deleted file mode 100644 index 688f202b9..000000000 --- a/csharp/App/Middleware/RabbitMQConsumer.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Net.WebSockets; -using System.Text.Json; -namespace InnovEnergy.App.Middleware; -using System.Text; -using RabbitMQ.Client; -using RabbitMQ.Client.Events; - -public static class RabbitMqConsumer -{ - - private static ConnectionFactory _factory = null!; - private static IConnection _connection = null!; - private static IModel _channel= null!; - - public static void StartRabbitMqConsumer(Dictionary installationConnections, Object sharedDataLock) - { - string vpnServerIp = "194.182.190.208"; - _factory = new ConnectionFactory { HostName = "localhost" }; - _connection = _factory.CreateConnection(); - _channel = _connection.CreateModel(); - Console.WriteLine("Middleware subscribed to RabbitMQ queue, ready for receiving messages"); - _channel.QueueDeclare(queue: "statusQueue", durable: false, exclusive: false, autoDelete: false, arguments: null); - - var consumer = new EventingBasicConsumer(_channel); - consumer.Received += (_, ea) => Callback(installationConnections, sharedDataLock, ea); - - _channel.BasicConsume(queue: "statusQueue", autoAck: true, consumer: consumer); - - } - - private static void Callback(Dictionary installationConnections, Object sharedDataLock, BasicDeliverEventArgs ea) - { - var body = ea.Body.ToArray(); - var message = Encoding.UTF8.GetString(body); - StatusMessage? receivedStatusMessage = JsonSerializer.Deserialize(message); - - lock (sharedDataLock) - { - // Process the received message - if (receivedStatusMessage != null) - { - Console.WriteLine("Received a message from installation: " + receivedStatusMessage.InstallationId + " and status is: " + receivedStatusMessage.Status); - Console.WriteLine("----------------------------------------------"); - Console.WriteLine("Update installation connection table"); - var installationId = receivedStatusMessage.InstallationId; - - if (!installationConnections.ContainsKey(installationId)) - { - Console.WriteLine("Create new empty list for installation: " + installationId); - installationConnections[installationId] = new InstallationInfo - { - Status = receivedStatusMessage.Status - }; - } - - Console.WriteLine("----------------------------------------------"); - - foreach (var installationConnection in installationConnections) - { - if (installationConnection.Key == installationId && installationConnection.Value.Connections.Count > 0) - { - Console.WriteLine("Update all the connected websockets for installation " + installationId); - installationConnection.Value.Status = receivedStatusMessage.Status; - - var jsonObject = new - { - id = installationId, - status = receivedStatusMessage.Status - }; - - string jsonString = JsonSerializer.Serialize(jsonObject); - byte[] dataToSend = Encoding.UTF8.GetBytes(jsonString); - - foreach (var connection in installationConnection.Value.Connections) - { - connection.SendAsync( - new ArraySegment(dataToSend, 0, dataToSend.Length), - WebSocketMessageType.Text, - true, // Indicates that this is the end of the message - CancellationToken.None - ); - } - } - } - } - } - } -} \ No newline at end of file diff --git a/csharp/App/Middleware/StatusMessage.cs b/csharp/App/Middleware/StatusMessage.cs deleted file mode 100644 index fd96aa3df..000000000 --- a/csharp/App/Middleware/StatusMessage.cs +++ /dev/null @@ -1,8 +0,0 @@ - -namespace InnovEnergy.App.Middleware; - -public class StatusMessage -{ - public required int InstallationId { get; init; } - public required int Status { get; init; } -} \ No newline at end of file diff --git a/csharp/App/Middleware/WebSocketListener.cs b/csharp/App/Middleware/WebSocketListener.cs deleted file mode 100644 index 5abf6c263..000000000 --- a/csharp/App/Middleware/WebSocketListener.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System.Net; -using System.Net.WebSockets; -using System.Text; -using System.Text.Json; - -namespace InnovEnergy.App.Middleware; - -public static class WebSocketListener -{ - - public static async Task StartServerAsync(Dictionary installationConnections, Object sharedDataLock) - { - var listener = new HttpListener(); - listener.Prefixes.Add("http://127.0.0.1:8080/"); - - listener.Start(); - - //Http listener listens for connections. When it accepts a new connection, it creates a new Task to handle this connection - while (true) - { - var context = await listener.GetContextAsync(); - if (context.Request.IsWebSocketRequest) - { - var webSocketContext = await context.AcceptWebSocketAsync(null); - var webSocket = webSocketContext.WebSocket; - - // Add the connected WebSocket to the collection - Console.WriteLine("Accepted a new websocket connection"); - HandleWebSocketConnection(webSocket, installationConnections); - } - else - { - context.Response.StatusCode = 400; - context.Response.Close(); - } - } - - //We have a task per websocket connection - async Task HandleWebSocketConnection(WebSocket currentWebSocket, Dictionary installationConnections) - { - - var buffer = new byte[4096]; - - try - { - while (currentWebSocket.State == WebSocketState.Open) - { - //Listen for incoming messages on this WebSocket - var result = await currentWebSocket.ReceiveAsync(buffer, CancellationToken.None); - Console.WriteLine("Received a new message from websocket"); - if (result.MessageType != WebSocketMessageType.Text) - continue; - - var message = Encoding.UTF8.GetString(buffer, 0, result.Count); - var installationIds = JsonSerializer.Deserialize(message); - - lock (sharedDataLock) - { - //Each front-end will send the list of the installations it wants to access - //If this is a new key (installation id), initialize the list for this key and then add the websocket object for this client - //Then, report the status of each requested installation to the front-end that created the websocket connection - foreach (var installationId in installationIds) - { - if (!installationConnections.ContainsKey(installationId)) - { - Console.WriteLine("Create new empty list for installation id "+installationId); - installationConnections[installationId] = new InstallationInfo - { - Status = -2 - }; - } - - installationConnections[installationId].Connections.Add(currentWebSocket); - - var jsonObject = new - { - id = installationId, - status = installationConnections[installationId].Status - }; - - var jsonString = JsonSerializer.Serialize(jsonObject); - var dataToSend = Encoding.UTF8.GetBytes(jsonString); - - - currentWebSocket.SendAsync(dataToSend, - WebSocketMessageType.Text, - true, // Indicates that this is the end of the message - CancellationToken.None - ); - } - - Console.WriteLine("Printing installation connection list"); - Console.WriteLine("----------------------------------------------"); - foreach (var installationConnection in installationConnections) - { - Console.WriteLine("Installation ID: " + installationConnection.Key + " Number of Connections: " + installationConnection.Value.Connections.Count); - } - Console.WriteLine("----------------------------------------------"); - } - } - - //When the front-end terminates the connection, the following code will be executed - Console.WriteLine("The connection has been terminated"); - foreach (var installationConnection in installationConnections) - { - if (installationConnection.Value.Connections.Contains(currentWebSocket)) - { - installationConnection.Value.Connections.Remove(currentWebSocket); - } - } - - await currentWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Connection closed by server", CancellationToken.None); - //Print the installationConnections dictionary after deleting a websocket - Console.WriteLine("Print the installation connections list after deleting a websocket"); - Console.WriteLine("----------------------------------------------"); - foreach (var installationConnection in installationConnections) - { - Console.WriteLine("Installation ID: "+ installationConnection.Key+" Number of Connections: "+installationConnection.Value.Connections.Count); - } - Console.WriteLine("----------------------------------------------"); - } - catch (Exception ex) - { - Console.WriteLine("WebSocket error: " + ex.Message); - } - } - } -} - diff --git a/csharp/App/Middleware/deploy.sh b/csharp/App/Middleware/deploy.sh deleted file mode 100755 index d8017c7c0..000000000 --- a/csharp/App/Middleware/deploy.sh +++ /dev/null @@ -1 +0,0 @@ -dotnet publish Middleware.csproj -c Release -r linux-x64 --self-contained true -p:PublishTrimmed=false && rsync -av bin/Release/net6.0/linux-x64/publish/ ubuntu@194.182.190.208:~/middleware diff --git a/csharp/App/SaliMax/deploy_all_installations.sh b/csharp/App/SaliMax/deploy_all_installations.sh new file mode 100755 index 000000000..a136a5879 --- /dev/null +++ b/csharp/App/SaliMax/deploy_all_installations.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +dotnet_version='net6.0' +salimax_ip="$1" +username='ie-entwicklung' +root_password='Salimax4x25' + +set -e + +echo -e "\n============================ Build ============================\n" + +dotnet publish \ + ./SaliMax.csproj \ + -p:PublishTrimmed=false \ + -c Release \ + -r linux-x64 + +echo -e "\n============================ Deploy ============================\n" +ip_addresses=("10.2.3.115" "10.2.3.104" "10.2.4.33" "10.2.4.32" "10.2.4.36" "10.2.4.35" "10.2.4.154" "10.2.4.113" "10.2.4.29") + +for ip_address in "${ip_addresses[@]}"; do + rsync -v \ + --exclude '*.pdb' \ + ./bin/Release/$dotnet_version/linux-x64/publish/* \ + $username@"$ip_address":~/salimax + + ssh "$username"@"$ip_address" "cd salimax && echo '$root_password' | sudo -S ./restart" + + +echo "Deployed and ran commands on $ip_address" +done + + + diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index b9c6dbbeb..97dda2c66 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -4,6 +4,7 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reactive.Linq; using System.Reactive.Threading.Tasks; +using System.Security.Cryptography.X509Certificates; using System.Text; using Flurl.Http; using InnovEnergy.App.SaliMax.Devices; @@ -50,8 +51,9 @@ internal static class Program private static readonly Channel RelaysChannel ; private static readonly Channel BatteriesChannel ; - private const String VpnServerIp = "194.182.190.208"; - + //private const String VpnServerIp = "194.182.190.208"; + private const String VpnServerIp = "10.2.0.11"; + private static IPAddress? _controllerIpAddress; private static UdpClient _udpListener = null!; private static ConnectionFactory? _factory ; @@ -262,6 +264,7 @@ internal static class Program { var s3Bucket = Config.Load().S3?.Bucket; + //Every 15 iterations(30 seconds), the installation sends a heartbit message to the queue _heartBitInterval++; //When the controller boots, it tries to subscribe to the queue @@ -269,14 +272,9 @@ internal static class Program { _subscribeToQueueForTheFirstTime = true; SubscribeToQueue(currentSalimaxState, s3Bucket); - - if (_subscribedToQueue && currentSalimaxState.Status != _prevSalimaxState) - { - _prevSalimaxState = currentSalimaxState.Status; - } } //If already subscribed to the queue and the status has been changed, update the queue - else if (_subscribedToQueue && currentSalimaxState.Status != _prevSalimaxState) + if (_subscribedToQueue && currentSalimaxState.Status != _prevSalimaxState) { _prevSalimaxState = currentSalimaxState.Status; if (s3Bucket != null) @@ -284,6 +282,7 @@ internal static class Program } else if (_subscribedToQueue && _heartBitInterval>=15) { + //Send a heartbit to the backend Console.WriteLine("----------------------------------------Sending Heartbit----------------------------------------"); _heartBitInterval = 0; currentSalimaxState.Type = MessageType.Heartbit; @@ -317,14 +316,39 @@ internal static class Program { try { - _factory = new ConnectionFactory { HostName = VpnServerIp }; + //_factory = new ConnectionFactory { HostName = VpnServerIp }; + + _factory = new ConnectionFactory + { + HostName = VpnServerIp, + Port = 5672, + VirtualHost = "/", + UserName = "producer", + Password = "b187ceaddb54d5485063ddc1d41af66f", + // Ssl = new SslOption + // { + // Enabled = true, + // ServerName = VpnServerIp, // Disable hostname validation + // CertPath = "/etc/openvpn/client/client-certificate", + // + // CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => + // { + // X509Certificate2 caCertificate = new X509Certificate2("/etc/openvpn/client/ca-certificate"); + // //Console.WriteLine(caCertificate); + // //Console.WriteLine("---------------------------------"); + // //Console.WriteLine(certificate.GetPublicKey()); + // // Your custom validation logic using the CA certificate + // // Return true if the certificate is valid, false otherwise + // return certificate.Issuer == caCertificate.Subject; + // } + // } + }; + _connection = _factory.CreateConnection(); _channel = _connection.CreateModel(); - _channel.QueueDeclare(queue: "statusQueue", durable: true, exclusive: false, autoDelete: false, arguments: null); Console.WriteLine("The controller sends its status to the middleware for the first time"); - if (s3Bucket != null) InformMiddleware(currentSalimaxState); _subscribedToQueue = true; diff --git a/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx b/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx index f204ebf6a..e93a7aa98 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx @@ -48,8 +48,8 @@ function Configuration(props: ConfigurationProps) { } value={props.values.calibrationChargeForced.values[0].value} diff --git a/typescript/frontend-marios2/src/content/dashboards/Installations/installationForm.tsx b/typescript/frontend-marios2/src/content/dashboards/Installations/installationForm.tsx index 935666a8c..76a0916d5 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Installations/installationForm.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Installations/installationForm.tsx @@ -80,7 +80,7 @@ function installationForm(props: installationFormProps) { +
} - name="VpnIp" + name="vpnIp" value={formValues.vpnIp} onChange={handleChange} fullWidth diff --git a/typescript/frontend-marios2/src/content/dashboards/Users/UsersSearch.tsx b/typescript/frontend-marios2/src/content/dashboards/Users/UsersSearch.tsx index ea0fa2950..71e039321 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Users/UsersSearch.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Users/UsersSearch.tsx @@ -95,7 +95,7 @@ function UsersSearch() { >