diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/META-INF/MANIFEST.MF b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/META-INF/MANIFEST.MF
deleted file mode 100644
index 6a25437..0000000
--- a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,5 +0,0 @@
-Manifest-Version: 1.0
-Main-Class: com.company.Main
-Class-Path: C:\Users\omar\Desktop\RemoteMonitor\RemoteMonitor Desktop\sr
- c\main\java\com\company\Main.java
-
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/Config.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/Config.class
index e5342d2..027fc68 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/Config.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/Config.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/ConfigurationManager$1.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/ConfigurationManager$1.class
index 65c076a..de2e9ac 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/ConfigurationManager$1.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/ConfigurationManager$1.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/ConfigurationManager.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/ConfigurationManager.class
index 4e1fde1..e55e2be 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/ConfigurationManager.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/ConfigurationManager.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/Main.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/Main.class
index 15ac7e3..bfc5f54 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/Main.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/com/company/Main.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/CPU.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/CPU.class
index 243cdbd..530bae7 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/CPU.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/CPU.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/Component.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/Component.class
index e11fcc9..777864b 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/Component.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/Component.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/ComponentManager.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/ComponentManager.class
index 5c47170..15bf79a 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/ComponentManager.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/ComponentManager.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/GPU.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/GPU.class
index 69e86e7..1b85ccf 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/GPU.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/GPU.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/PhysicalDisk.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/PhysicalDisk.class
index ba7c7e3..6f4dc8b 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/PhysicalDisk.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/PhysicalDisk.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/Ram.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/Ram.class
index 64ec8fb..7c6112f 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/Ram.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/components/Ram.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI$1.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI$1.class
new file mode 100644
index 0000000..22579f2
Binary files /dev/null and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI$1.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI$2.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI$2.class
new file mode 100644
index 0000000..a27122c
Binary files /dev/null and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI$2.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI$3.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI$3.class
new file mode 100644
index 0000000..5a7d675
Binary files /dev/null and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI$3.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI.class
new file mode 100644
index 0000000..9d53ef7
Binary files /dev/null and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/gui/ServerGUI.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/main.iml b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/main.iml
deleted file mode 100644
index b107a2d..0000000
--- a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/main.iml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/ClientHandler.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/ClientHandler.class
new file mode 100644
index 0000000..3360966
Binary files /dev/null and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/ClientHandler.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/KeywordGenerator.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/KeywordGenerator.class
index 8e8768f..a2083e0 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/KeywordGenerator.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/KeywordGenerator.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/MultiUserServer.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/MultiUserServer.class
new file mode 100644
index 0000000..f1fc584
Binary files /dev/null and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/MultiUserServer.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/Server.class b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/Server.class
index 85372e1..ad3001b 100644
Binary files a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/Server.class and b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/networking/Server.class differ
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/.gitignore b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/.gitignore
deleted file mode 100644
index 13566b8..0000000
--- a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/misc.xml b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/misc.xml
deleted file mode 100644
index 20f033c..0000000
--- a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/misc.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/modules.xml b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/modules.xml
deleted file mode 100644
index 122a905..0000000
--- a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/vcs.xml b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/vcs.xml
deleted file mode 100644
index 4fce1d8..0000000
--- a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/main.iml b/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/main.iml
deleted file mode 100644
index b107a2d..0000000
--- a/RemoteMonitor Desktop/out/production/RemoteMonitor Desktop/out/production/main/main.iml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/RemoteMonitor Desktop/src/main/java/com/company/Main.java b/RemoteMonitor Desktop/src/main/java/com/company/Main.java
index d2640cb..83f25b6 100644
--- a/RemoteMonitor Desktop/src/main/java/com/company/Main.java
+++ b/RemoteMonitor Desktop/src/main/java/com/company/Main.java
@@ -1,51 +1,94 @@
package com.company;
import components.ComponentManager;
-import networking.Server;
+import networking.MultiUserServer;
+import gui.ServerGUI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class Main {
+ private static final Logger logger = LoggerFactory.getLogger(Main.class);
+
public static void main(String[] args) throws Exception {
+ // Check if GUI mode is requested
+ boolean useGUI = args.length > 0 && "--gui".equals(args[0]);
+
+ if (useGUI || hasDisplay()) {
+ // Launch GUI mode
+ try {
+ System.out.println("Starting Remote Monitor Server GUI...");
+ ServerGUI.main(args);
+ } catch (Exception e) {
+ System.err.println("Failed to start GUI mode, falling back to console mode: " + e.getMessage());
+ runConsoleMode();
+ }
+ } else {
+ // Run console mode
+ runConsoleMode();
+ }
+ }
+
+ private static void runConsoleMode() throws Exception {
clearTerminal();
ConfigurationManager configurationManager = new ConfigurationManager();
ComponentManager componentManager = new ComponentManager();
- while(true)
- {
- Server server = new Server(configurationManager.getLocalIp(), configurationManager.getPort(), configurationManager.getKeyword());
- componentManager.updateAll();
- System.out.println("Connection Information");
- System.out.println("Local connection IP: " + configurationManager.getLocalIp() + " Port: " + configurationManager.getPort());
- System.out.println("Keyword: " + configurationManager.getKeyword());
+
+ System.out.println("=== Remote Monitor Multi-User Server ===");
+ System.out.println("Connection Information:");
+ System.out.println("Local IP: " + configurationManager.getLocalIp());
+ System.out.println("Port: " + configurationManager.getPort());
+ System.out.println("Keyword: " + configurationManager.getKeyword());
+ System.out.println("========================================");
+ System.out.println("Tip: Run with --gui flag for graphical interface");
+ System.out.println("========================================");
+
+ // Create and start the multi-user server
+ MultiUserServer server = new MultiUserServer(
+ configurationManager.getLocalIp(),
+ configurationManager.getPort(),
+ configurationManager.getKeyword(),
+ componentManager
+ );
+
+ // Add shutdown hook to gracefully stop the server
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ System.out.println("\nShutting down server...");
+ server.stop();
+ }));
+
+ try {
+ // Start the server (this will run indefinitely)
server.start();
- System.out.println(server.getConnectedIp() + " successfully connected\n");
-
- while (server.isConnected()) {
- String read = server.read();
-
- if (read != null && read.equals("data request")) {
- System.out.println("Client requested data");
- componentManager.updateAll();
- if (server.write(componentManager.toJson())) {
- System.out.println("Successfully sent data to the client");
- } else {
- System.out.println("Failed to send data to the client");
-
- }
- }
-
+ } catch (Exception e) {
+ System.err.println("Server error: " + e.getMessage());
+ logger.error("Server error", e);
+ } finally {
+ server.stop();
+ }
+ }
+
+ private static boolean hasDisplay() {
+ try {
+ // Try to detect if we're in a headless environment
+ String headless = System.getProperty("java.awt.headless");
+ if ("true".equals(headless)) {
+ return false;
}
- System.out.println("Connection disconnected");
- System.out.println("Restarting server..."+"\n");
- server.closeServer();
-
-
+
+ // Check for DISPLAY environment variable on Linux/macOS
+ String display = System.getenv("DISPLAY");
+ if (System.getProperty("os.name").toLowerCase().contains("linux") &&
+ (display == null || display.trim().isEmpty())) {
+ return false;
+ }
+
+ return true;
+ } catch (Exception e) {
+ return false;
}
-
-
}
public static void clearTerminal() throws IOException {
if (System.getProperty("os.name").contains("Windows"))
diff --git a/RemoteMonitor Desktop/src/main/java/components/ComponentManager.java b/RemoteMonitor Desktop/src/main/java/components/ComponentManager.java
index 08c5277..fe9c69a 100644
--- a/RemoteMonitor Desktop/src/main/java/components/ComponentManager.java
+++ b/RemoteMonitor Desktop/src/main/java/components/ComponentManager.java
@@ -26,19 +26,52 @@ public ComponentManager()
ram = new Ram();
gpus = new ArrayList();
disks = new ArrayList();
- List gpuJ = JSensors.get.components().gpus;
- List graphicsCards = new SystemInfo().getHardware().getGraphicsCards();
- List hwDiskStoreList = new SystemInfo().getHardware().getDiskStores();
- List diskJ = JSensors.get.components().disks;
- for (int i = 0; i < gpuJ.size(); i++)
- {
- gpus.add(new GPU(graphicsCards.get(i), gpuJ.get(i)));
+
+ try {
+ List gpuJ = JSensors.get.components().gpus;
+ List graphicsCards = new SystemInfo().getHardware().getGraphicsCards();
+ List hwDiskStoreList = new SystemInfo().getHardware().getDiskStores();
+ List diskJ = JSensors.get.components().disks;
+
+ // Initialize GPUs - match OSHI and JSensors data safely
+ int gpuCount = Math.min(gpuJ != null ? gpuJ.size() : 0,
+ graphicsCards != null ? graphicsCards.size() : 0);
+ for (int i = 0; i < gpuCount; i++) {
+ try {
+ gpus.add(new GPU(graphicsCards.get(i), gpuJ.get(i)));
+ } catch (Exception e) {
+ System.err.println("Error initializing GPU " + i + ": " + e.getMessage());
+ }
+ }
+
+ // Initialize Disks - match OSHI and JSensors data safely
+ int diskCount = Math.min(diskJ != null ? diskJ.size() : 0,
+ hwDiskStoreList != null ? hwDiskStoreList.size() : 0);
+ for (int i = 0; i < diskCount; i++) {
+ try {
+ disks.add(new PhysicalDisk(hwDiskStoreList.get(i), diskJ.get(i)));
+ } catch (Exception e) {
+ System.err.println("Error initializing Disk " + i + ": " + e.getMessage());
+ }
+ }
+
+ // If no JSensors disks but OSHI disks exist, create them without JSensors data
+ if ((diskJ == null || diskJ.isEmpty()) && hwDiskStoreList != null && !hwDiskStoreList.isEmpty()) {
+ for (HWDiskStore hwDisk : hwDiskStoreList) {
+ try {
+ disks.add(new PhysicalDisk(hwDisk, null));
+ } catch (Exception e) {
+ System.err.println("Error initializing Disk (OSHI only): " + e.getMessage());
+ }
+ }
+ }
+
+ System.out.println("ComponentManager initialized: " + gpus.size() + " GPUs, " + disks.size() + " Disks");
+
+ } catch (Exception e) {
+ System.err.println("Error initializing ComponentManager: " + e.getMessage());
+ e.printStackTrace();
}
- for (int i = 0; i < hwDiskStoreList.size(); i++)
- {
- disks.add(new PhysicalDisk(hwDiskStoreList.get(i), diskJ.get(i)));
- }
-
}
public void updateAll()
diff --git a/RemoteMonitor Desktop/src/main/java/components/GPU.java b/RemoteMonitor Desktop/src/main/java/components/GPU.java
index 2319851..43246e7 100644
--- a/RemoteMonitor Desktop/src/main/java/components/GPU.java
+++ b/RemoteMonitor Desktop/src/main/java/components/GPU.java
@@ -24,10 +24,27 @@ public GPU(GraphicsCard gpu, Gpu gpu2)
public void update()
{
try {
- temperature = jgpu.sensors.temperatures.get(0).value;
+ if (jgpu != null && jgpu.sensors != null && jgpu.sensors.temperatures != null && !jgpu.sensors.temperatures.isEmpty()) {
+ temperature = jgpu.sensors.temperatures.get(0).value;
+ } else {
+ temperature = 0; // No temperature data available
+ }
}
- catch (Exception e){}
- usage = jgpu.sensors.loads.get(0).value;
+ catch (Exception e){
+ temperature = 0; // Fallback if temperature reading fails
+ }
+
+ try {
+ if (jgpu != null && jgpu.sensors != null && jgpu.sensors.loads != null && !jgpu.sensors.loads.isEmpty()) {
+ usage = jgpu.sensors.loads.get(0).value;
+ } else {
+ usage = 0; // No usage data available
+ }
+ }
+ catch (Exception e){
+ usage = 0; // Fallback if usage reading fails
+ }
+
lastUpdated = System.currentTimeMillis();
}
diff --git a/RemoteMonitor Desktop/src/main/java/components/PhysicalDisk.java b/RemoteMonitor Desktop/src/main/java/components/PhysicalDisk.java
index 796196d..35739af 100644
--- a/RemoteMonitor Desktop/src/main/java/components/PhysicalDisk.java
+++ b/RemoteMonitor Desktop/src/main/java/components/PhysicalDisk.java
@@ -20,14 +20,21 @@ public PhysicalDisk(HWDiskStore hwDiskStore, Disk Jdisk)
componentName = diskStore.getModel();
componentType = "Disk";
partitions = diskStore.getPartitions();
- jdisk = Jdisk;
+ jdisk = Jdisk; // This can be null if JSensors doesn't detect the disk
}
public void update()
{
partitions = diskStore.getPartitions();
setAvailableCapacity();
- temperature = checkTemp(jdisk.sensors.loads);
+
+ // Only try to get temperature if JSensors data is available
+ if (jdisk != null && jdisk.sensors != null && jdisk.sensors.loads != null) {
+ temperature = checkTemp(jdisk.sensors.loads);
+ } else {
+ temperature = 0; // No temperature data available
+ }
+
lastUpdated = System.currentTimeMillis();
}
public long getAvailableCapacity() {
diff --git a/RemoteMonitor Desktop/src/main/java/gui/ServerGUI.java b/RemoteMonitor Desktop/src/main/java/gui/ServerGUI.java
new file mode 100644
index 0000000..145d4c1
--- /dev/null
+++ b/RemoteMonitor Desktop/src/main/java/gui/ServerGUI.java
@@ -0,0 +1,388 @@
+package gui;
+
+import com.company.ConfigurationManager;
+import components.ComponentManager;
+import networking.MultiUserServer;
+
+import javax.swing.*;
+import javax.swing.border.TitledBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class ServerGUI extends JFrame {
+ private ConfigurationManager configManager;
+ private ComponentManager componentManager;
+ private AtomicReference serverRef = new AtomicReference<>();
+
+ // UI Components
+ private JLabel statusLabel;
+ private JLabel ipLabel;
+ private JLabel portLabel;
+ private JLabel keywordLabel;
+ private JLabel clientCountLabel;
+ private JButton startStopButton;
+ private JTextArea logArea;
+ private JPanel clientListPanel;
+ private Timer clientUpdateTimer;
+
+ public ServerGUI() {
+ initializeComponents();
+ setupUI();
+ setupEventHandlers();
+ updateConnectionInfo();
+ }
+
+ private void initializeComponents() {
+ try {
+ configManager = new ConfigurationManager();
+ componentManager = new ComponentManager();
+ } catch (Exception e) {
+ JOptionPane.showMessageDialog(this,
+ "Failed to initialize application: " + e.getMessage(),
+ "Initialization Error",
+ JOptionPane.ERROR_MESSAGE);
+ System.exit(1);
+ }
+ }
+
+ private void setupUI() {
+ setTitle("Remote Monitor Server");
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ setMinimumSize(new Dimension(800, 600));
+
+ // Set look and feel
+ try {
+ for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
+ if ("Nimbus".equals(info.getName())) {
+ UIManager.setLookAndFeel(info.getClassName());
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Use default look and feel
+ }
+
+ // Create main layout
+ setLayout(new BorderLayout(10, 10));
+ ((JComponent) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+ // Create header
+ add(createHeader(), BorderLayout.NORTH);
+
+ // Create center content
+ add(createCenter(), BorderLayout.CENTER);
+
+ // Create footer
+ add(createFooter(), BorderLayout.SOUTH);
+
+ pack();
+ setLocationRelativeTo(null);
+ }
+
+ private JPanel createHeader() {
+ JPanel header = new JPanel(new BorderLayout());
+ header.setBackground(new Color(0, 123, 167));
+ header.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
+
+ JLabel titleLabel = new JLabel("Remote Monitor Server", JLabel.CENTER);
+ titleLabel.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 24));
+ titleLabel.setForeground(Color.WHITE);
+
+ statusLabel = new JLabel("Server Stopped", JLabel.CENTER);
+ statusLabel.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16));
+ statusLabel.setForeground(new Color(255, 228, 225));
+
+ header.add(titleLabel, BorderLayout.CENTER);
+ header.add(statusLabel, BorderLayout.SOUTH);
+
+ return header;
+ }
+
+ private JPanel createCenter() {
+ JPanel center = new JPanel(new BorderLayout(10, 10));
+
+ // Left panel - Server Info
+ JPanel leftPanel = createServerInfoPanel();
+ leftPanel.setPreferredSize(new Dimension(300, 0));
+
+ // Right panel - Logs
+ JPanel rightPanel = createLogsPanel();
+
+ center.add(leftPanel, BorderLayout.WEST);
+ center.add(rightPanel, BorderLayout.CENTER);
+
+ return center;
+ }
+
+ private JPanel createServerInfoPanel() {
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.setBorder(BorderFactory.createTitledBorder(
+ BorderFactory.createEtchedBorder(),
+ "Server Information",
+ TitledBorder.LEFT,
+ TitledBorder.TOP,
+ new Font(Font.SANS_SERIF, Font.BOLD, 14)
+ ));
+
+ // Connection info
+ JPanel infoPanel = new JPanel(new GridLayout(4, 1, 5, 5));
+ infoPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+ ipLabel = new JLabel("IP: Loading...");
+ portLabel = new JLabel("Port: Loading...");
+ keywordLabel = new JLabel("Keyword: Loading...");
+ clientCountLabel = new JLabel("Connected Clients: 0");
+
+ Font monoFont = new Font(Font.MONOSPACED, Font.PLAIN, 12);
+ ipLabel.setFont(monoFont);
+ portLabel.setFont(monoFont);
+ keywordLabel.setFont(monoFont);
+
+ infoPanel.add(ipLabel);
+ infoPanel.add(portLabel);
+ infoPanel.add(keywordLabel);
+ infoPanel.add(clientCountLabel);
+
+ // Client list
+ clientListPanel = new JPanel();
+ clientListPanel.setLayout(new BoxLayout(clientListPanel, BoxLayout.Y_AXIS));
+ clientListPanel.setBorder(BorderFactory.createTitledBorder("Connected Clients"));
+
+ JScrollPane clientScrollPane = new JScrollPane(clientListPanel);
+ clientScrollPane.setPreferredSize(new Dimension(280, 200));
+ clientScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+
+ panel.add(infoPanel, BorderLayout.NORTH);
+ panel.add(clientScrollPane, BorderLayout.CENTER);
+
+ return panel;
+ }
+
+ private JPanel createLogsPanel() {
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.setBorder(BorderFactory.createTitledBorder(
+ BorderFactory.createEtchedBorder(),
+ "Server Logs",
+ TitledBorder.LEFT,
+ TitledBorder.TOP,
+ new Font(Font.SANS_SERIF, Font.BOLD, 14)
+ ));
+
+ logArea = new JTextArea();
+ logArea.setEditable(false);
+ logArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
+ logArea.setBackground(new Color(248, 248, 248));
+
+ JScrollPane scrollPane = new JScrollPane(logArea);
+ scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+
+ JButton clearLogsButton = new JButton("Clear Logs");
+ clearLogsButton.addActionListener(e -> logArea.setText(""));
+
+ panel.add(scrollPane, BorderLayout.CENTER);
+ panel.add(clearLogsButton, BorderLayout.SOUTH);
+
+ return panel;
+ }
+
+ private JPanel createFooter() {
+ JPanel footer = new JPanel(new FlowLayout());
+
+ startStopButton = new JButton("Start Server");
+ startStopButton.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 14));
+ startStopButton.setPreferredSize(new Dimension(120, 35));
+
+ JButton configButton = new JButton("Configuration");
+ configButton.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 14));
+ configButton.setPreferredSize(new Dimension(120, 35));
+
+ JButton exitButton = new JButton("Exit");
+ exitButton.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 14));
+ exitButton.setPreferredSize(new Dimension(120, 35));
+
+ footer.add(startStopButton);
+ footer.add(configButton);
+ footer.add(exitButton);
+
+ // Add action listeners
+ startStopButton.addActionListener(e -> toggleServer());
+ configButton.addActionListener(e -> showConfigDialog());
+ exitButton.addActionListener(e -> {
+ stopServer();
+ System.exit(0);
+ });
+
+ return footer;
+ }
+
+ private void setupEventHandlers() {
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ int choice = JOptionPane.showConfirmDialog(
+ ServerGUI.this,
+ "Are you sure you want to exit?",
+ "Confirm Exit",
+ JOptionPane.YES_NO_OPTION
+ );
+ if (choice == JOptionPane.YES_OPTION) {
+ stopServer();
+ System.exit(0);
+ }
+ }
+ });
+ }
+
+ private void toggleServer() {
+ if (serverRef.get() == null) {
+ startServer();
+ } else {
+ stopServer();
+ }
+ }
+
+ private void startServer() {
+ SwingWorker worker = new SwingWorker() {
+ @Override
+ protected Void doInBackground() throws Exception {
+ try {
+ MultiUserServer server = new MultiUserServer(
+ configManager.getLocalIp(),
+ configManager.getPort(),
+ configManager.getKeyword(),
+ componentManager
+ );
+
+ serverRef.set(server);
+
+ SwingUtilities.invokeLater(() -> {
+ statusLabel.setText("Server Running");
+ statusLabel.setForeground(Color.GREEN);
+ startStopButton.setText("Stop Server");
+ logMessage("Server started successfully");
+ startClientMonitoring();
+ });
+
+ // This will block until server stops
+ server.start();
+
+ } catch (Exception e) {
+ SwingUtilities.invokeLater(() -> {
+ JOptionPane.showMessageDialog(ServerGUI.this,
+ "Failed to start server: " + e.getMessage(),
+ "Server Error",
+ JOptionPane.ERROR_MESSAGE);
+ logMessage("Server start failed: " + e.getMessage());
+ });
+ }
+ return null;
+ }
+ };
+ worker.execute();
+ }
+
+ private void stopServer() {
+ MultiUserServer currentServer = serverRef.getAndSet(null);
+ if (currentServer != null) {
+ try {
+ currentServer.stop();
+ statusLabel.setText("Server Stopped");
+ statusLabel.setForeground(new Color(255, 228, 225));
+ startStopButton.setText("Start Server");
+ clientCountLabel.setText("Connected Clients: 0");
+ clientListPanel.removeAll();
+ clientListPanel.revalidate();
+ clientListPanel.repaint();
+ logMessage("Server stopped");
+
+ if (clientUpdateTimer != null) {
+ clientUpdateTimer.stop();
+ }
+ } catch (Exception e) {
+ logMessage("Error stopping server: " + e.getMessage());
+ }
+ }
+ }
+
+ private void startClientMonitoring() {
+ if (clientUpdateTimer != null) {
+ clientUpdateTimer.stop();
+ }
+
+ clientUpdateTimer = new Timer(2000, new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ MultiUserServer currentServer = serverRef.get();
+ if (currentServer != null) {
+ updateClientList(currentServer);
+ } else {
+ clientUpdateTimer.stop();
+ }
+ }
+ });
+ clientUpdateTimer.start();
+ }
+
+ private void updateClientList(MultiUserServer server) {
+ try {
+ int clientCount = server.getConnectedClientCount();
+ clientCountLabel.setText("Connected Clients: " + clientCount);
+
+ clientListPanel.removeAll();
+
+ server.getConnectedClients().forEach((id, client) -> {
+ JLabel clientLabel = new JLabel("• " + client.getConnectedIp());
+ clientLabel.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 12));
+ clientLabel.setForeground(new Color(102, 102, 102));
+ clientListPanel.add(clientLabel);
+ });
+
+ clientListPanel.revalidate();
+ clientListPanel.repaint();
+
+ } catch (Exception e) {
+ logMessage("Error updating client list: " + e.getMessage());
+ }
+ }
+
+ private void updateConnectionInfo() {
+ ipLabel.setText("IP: " + configManager.getLocalIp());
+ portLabel.setText("Port: " + configManager.getPort());
+ keywordLabel.setText("Keyword: " + configManager.getKeyword());
+ }
+
+ private void showConfigDialog() {
+ String message = String.format(
+ "Server Configuration:\n\n" +
+ "IP Address: %s\n" +
+ "Port: %d\n" +
+ "Keyword: %s\n\n" +
+ "Configuration is automatically loaded from config.json",
+ configManager.getLocalIp(),
+ configManager.getPort(),
+ configManager.getKeyword()
+ );
+
+ JOptionPane.showMessageDialog(this, message, "Configuration", JOptionPane.INFORMATION_MESSAGE);
+ }
+
+ private void logMessage(String message) {
+ SwingUtilities.invokeLater(() -> {
+ String timestamp = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
+ logArea.append("[" + timestamp + "] " + message + "\n");
+ logArea.setCaretPosition(logArea.getDocument().getLength());
+ });
+ }
+
+ public static void main(String[] args) {
+ SwingUtilities.invokeLater(() -> {
+ new ServerGUI().setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/RemoteMonitor Desktop/src/main/java/networking/ClientHandler.java b/RemoteMonitor Desktop/src/main/java/networking/ClientHandler.java
new file mode 100644
index 0000000..5b6520c
--- /dev/null
+++ b/RemoteMonitor Desktop/src/main/java/networking/ClientHandler.java
@@ -0,0 +1,157 @@
+package networking;
+
+import components.ComponentManager;
+import java.io.*;
+import java.net.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class ClientHandler implements Runnable {
+ private Socket clientSocket;
+ private PrintWriter writer;
+ private BufferedReader reader;
+ private String keyword;
+ private String clientId;
+ private String connectedIp;
+ private AtomicBoolean isAuthenticated;
+ private AtomicBoolean isConnected;
+ private ComponentManager componentManager;
+ private MultiUserServer server;
+
+ public ClientHandler(Socket clientSocket, String keyword, ComponentManager componentManager, MultiUserServer server) {
+ this.clientSocket = clientSocket;
+ this.keyword = keyword;
+ this.componentManager = componentManager;
+ this.server = server;
+ this.connectedIp = clientSocket.getRemoteSocketAddress().toString();
+ this.clientId = generateClientId();
+ this.isAuthenticated = new AtomicBoolean(false);
+ this.isConnected = new AtomicBoolean(true);
+ }
+
+ @Override
+ public void run() {
+ try {
+ writer = new PrintWriter(clientSocket.getOutputStream(), true);
+ reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+
+ System.out.println("New client connection from: " + connectedIp + " (ID: " + clientId + ")");
+
+ if (!authenticate()) {
+ System.out.println("Authentication failed for client: " + connectedIp);
+ writer.println("failed");
+ closeConnection();
+ return;
+ }
+
+ System.out.println("Client authenticated successfully: " + connectedIp + " (ID: " + clientId + ")");
+ writer.println("connected");
+
+ // Wait for confirmation
+ String response = reader.readLine();
+ if (!"received".equals(response)) {
+ closeConnection();
+ return;
+ }
+
+ // Handle client requests
+ handleClientRequests();
+
+ } catch (IOException e) {
+ System.out.println("Client connection error for " + connectedIp + ": " + e.getMessage());
+ } finally {
+ closeConnection();
+ }
+ }
+
+ private boolean authenticate() throws IOException {
+ try {
+ String receivedKeyword = reader.readLine();
+ if (receivedKeyword != null && receivedKeyword.equals(keyword)) {
+ isAuthenticated.set(true);
+ return true;
+ } else {
+ System.out.println(connectedIp + " tried connecting with wrong keyword: \"" + receivedKeyword + "\"");
+ return false;
+ }
+ } catch (Exception e) {
+ System.out.println("Authentication error for " + connectedIp + ": " + e.getMessage());
+ return false;
+ }
+ }
+
+ private void handleClientRequests() {
+ try {
+ String request;
+ while (isConnected.get() && (request = reader.readLine()) != null) {
+ System.out.println("Client " + clientId + " requested: " + request);
+
+ if ("data request".equals(request)) {
+ handleDataRequest();
+ } else if ("disconnected".equals(request)) {
+ System.out.println("Client " + clientId + " requested disconnection");
+ break;
+ } else {
+ System.out.println("Unknown request from client " + clientId + ": " + request);
+ }
+ }
+ } catch (IOException e) {
+ System.out.println("Error handling requests for client " + clientId + ": " + e.getMessage());
+ }
+ }
+
+ private void handleDataRequest() throws IOException {
+ try {
+ // Update component data
+ componentManager.updateAll();
+ String jsonData = componentManager.toJson();
+
+ writer.println(jsonData);
+
+ // Wait for confirmation
+ String response = reader.readLine();
+ if ("received".equals(response)) {
+ System.out.println("Successfully sent data to client " + clientId);
+ } else {
+ System.out.println("Failed to confirm data delivery to client " + clientId);
+ }
+ } catch (Exception e) {
+ System.out.println("Error sending data to client " + clientId + ": " + e.getMessage());
+ isConnected.set(false);
+ }
+ }
+
+ private void closeConnection() {
+ isConnected.set(false);
+ try {
+ if (reader != null) reader.close();
+ if (writer != null) writer.close();
+ if (clientSocket != null && !clientSocket.isClosed()) {
+ clientSocket.close();
+ }
+ server.removeClient(clientId);
+ System.out.println("Client disconnected: " + connectedIp + " (ID: " + clientId + ")");
+ } catch (IOException e) {
+ System.out.println("Error closing connection for client " + clientId + ": " + e.getMessage());
+ }
+ }
+
+ private String generateClientId() {
+ return "CLIENT_" + System.currentTimeMillis() + "_" + Math.random();
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public String getConnectedIp() {
+ return connectedIp;
+ }
+
+ public boolean isConnected() {
+ return isConnected.get();
+ }
+
+ public boolean isAuthenticated() {
+ return isAuthenticated.get();
+ }
+}
\ No newline at end of file
diff --git a/RemoteMonitor Desktop/src/main/java/networking/MultiUserServer.java b/RemoteMonitor Desktop/src/main/java/networking/MultiUserServer.java
new file mode 100644
index 0000000..83701ef
--- /dev/null
+++ b/RemoteMonitor Desktop/src/main/java/networking/MultiUserServer.java
@@ -0,0 +1,145 @@
+package networking;
+
+import components.ComponentManager;
+import java.io.IOException;
+import java.net.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.Map;
+
+public class MultiUserServer {
+ private int listeningPort;
+ private String keyword;
+ private ServerSocket serverSocket;
+ private AtomicBoolean isRunning;
+ private ExecutorService threadPool;
+ private ComponentManager componentManager;
+ private Map connectedClients;
+ private String localIp;
+
+ public MultiUserServer(String ip, int port, String connectionKeyword, ComponentManager componentManager) throws IOException {
+ this.localIp = ip;
+ this.listeningPort = port;
+ this.keyword = connectionKeyword;
+ this.componentManager = componentManager;
+ this.isRunning = new AtomicBoolean(false);
+ this.threadPool = Executors.newCachedThreadPool();
+ this.connectedClients = new ConcurrentHashMap<>();
+ this.serverSocket = new ServerSocket(listeningPort, 0, InetAddress.getByName(ip));
+ }
+
+ public void start() {
+ if (isRunning.get()) {
+ System.out.println("Server is already running!");
+ return;
+ }
+
+ isRunning.set(true);
+ System.out.println("Multi-user server started on " + localIp + ":" + listeningPort);
+ System.out.println("Keyword: " + keyword);
+ System.out.println("Waiting for client connections...");
+
+ while (isRunning.get()) {
+ try {
+ Socket clientSocket = serverSocket.accept();
+
+ if (!isRunning.get()) {
+ clientSocket.close();
+ break;
+ }
+
+ // Create a new client handler for each connection
+ ClientHandler clientHandler = new ClientHandler(clientSocket, keyword, componentManager, this);
+ connectedClients.put(clientHandler.getClientId(), clientHandler);
+
+ // Execute client handler in a separate thread
+ threadPool.execute(clientHandler);
+
+ System.out.println("Total connected clients: " + connectedClients.size());
+
+ } catch (IOException e) {
+ if (isRunning.get()) {
+ System.err.println("Error accepting client connection: " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ public void stop() {
+ if (!isRunning.get()) {
+ return;
+ }
+
+ isRunning.set(false);
+ System.out.println("Stopping multi-user server...");
+
+ // Close all client connections
+ for (ClientHandler client : connectedClients.values()) {
+ // ClientHandler.closeConnection() will be called automatically
+ }
+ connectedClients.clear();
+
+ // Shutdown thread pool
+ threadPool.shutdown();
+ try {
+ if (!threadPool.awaitTermination(5, TimeUnit.SECONDS)) {
+ threadPool.shutdownNow();
+ }
+ } catch (InterruptedException e) {
+ threadPool.shutdownNow();
+ Thread.currentThread().interrupt();
+ }
+
+ // Close server socket
+ try {
+ if (serverSocket != null && !serverSocket.isClosed()) {
+ serverSocket.close();
+ }
+ } catch (IOException e) {
+ System.err.println("Error closing server socket: " + e.getMessage());
+ }
+
+ System.out.println("Multi-user server stopped.");
+ }
+
+ public void removeClient(String clientId) {
+ connectedClients.remove(clientId);
+ System.out.println("Client removed. Total connected clients: " + connectedClients.size());
+ }
+
+ public int getConnectedClientCount() {
+ return connectedClients.size();
+ }
+
+ public boolean isRunning() {
+ return isRunning.get();
+ }
+
+ public String getLocalIp() {
+ return localIp;
+ }
+
+ public int getPort() {
+ return listeningPort;
+ }
+
+ public String getKeyword() {
+ return keyword;
+ }
+
+ public Map getConnectedClients() {
+ return new ConcurrentHashMap<>(connectedClients);
+ }
+
+ // Method to broadcast data to all connected clients (if needed in future)
+ public void broadcastToAllClients(String data) {
+ for (ClientHandler client : connectedClients.values()) {
+ try {
+ // This would require adding a broadcast method to ClientHandler
+ // For now, we'll keep the individual request-response model
+ } catch (Exception e) {
+ System.err.println("Error broadcasting to client " + client.getClientId() + ": " + e.getMessage());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Components/CPU.cs b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Components/CPU.cs
index 32ea9e0..615336f 100644
--- a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Components/CPU.cs
+++ b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Components/CPU.cs
@@ -19,6 +19,18 @@ public CPU(string name, double temp, double componentUsage, int coreAmount, long
componentType = "CPU";
update(temp, componentUsage, coreAmount, maxSpeed, currentSpeeds, fanSpeeds);
}
+ public CPU()
+ {
+ componentName = "CPU";
+ componentType = "CPU";
+ temperature = 0;
+ usage = 0;
+ cores = 0;
+ speed = 0;
+ currentSpeed = new long[0];
+ fanSpeed = new int[0];
+ }
+
public CPU(JObject json)
{
componentName = json["componentName"].ToString();
diff --git a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Components/Ram.cs b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Components/Ram.cs
index 4262337..9dccb38 100644
--- a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Components/Ram.cs
+++ b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Components/Ram.cs
@@ -11,6 +11,15 @@ public class Ram : Component
public long memoryTotal;
public long memoryAvailable;
+ public Ram()
+ {
+ componentType = "Ram";
+ componentName = "RAM";
+ memoryTotal = 0;
+ memoryAvailable = 0;
+ usage = 0;
+ }
+
public Ram(string name, long ramTotal, long availableRam)
{
componentType = "Ram";
diff --git a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Connection.xaml b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Connection.xaml
index 141d592..817129c 100644
--- a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Connection.xaml
+++ b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Connection.xaml
@@ -2,19 +2,121 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+ BackgroundColor="#F5F5F5">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Connection.xaml.cs b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Connection.xaml.cs
index 7f28fe2..11b2994 100644
--- a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Connection.xaml.cs
+++ b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Connection.xaml.cs
@@ -34,9 +34,18 @@ public MainPage(string text)
private async void Button_Clicked(object sender, EventArgs e)
{
error.Text = "";
+
+ if (string.IsNullOrWhiteSpace(ip.Text) || string.IsNullOrWhiteSpace(port.Text) || string.IsNullOrWhiteSpace(keyword.Text))
+ {
+ error.Text = "Please fill in all fields";
+ return;
+ }
+
try
{
connect.IsEnabled = false;
+ connect.Text = "Connecting...";
+
Client client = new Client(ip.Text, Convert.ToInt32(port.Text), keyword.Text);
bool connected = await client.ConnectAsync();
@@ -46,45 +55,56 @@ private async void Button_Clicked(object sender, EventArgs e)
Preferences.Set("ip", ip.Text);
Preferences.Set("port", port.Text);
Preferences.Set("keyword", keyword.Text);
+
error.TextColor = Color.Green;
error.Text = "Successfully connected!";
+
var newPage = new Monitor(JArray.Parse(await client.RequestDataAsync()), client);
var animation = new Animation(v => newPage.Opacity = v, 0, 1);
animation.Commit(newPage, "FadeAnimation", length: 500, easing: Easing.Linear);
await Navigation.PushAsync(newPage);
Navigation.RemovePage(Navigation.NavigationStack[Navigation.NavigationStack.Count - 2]);
-
}
else
{
- connect.IsEnabled = true;
-
- error.Text = "Failed to connect to server";
-
+ error.Text = "Failed to connect to server. Please check your connection details.";
}
}
+ catch (FormatException)
+ {
+ error.Text = "Please enter a valid port number";
+ }
catch (Exception ex)
{
- connect.IsEnabled = true;
-
- error.Text = "Failed to connect to server";
+ error.Text = "Connection failed. Please check your network connection.";
Debug.WriteLine(ex);
}
-
+ finally
+ {
+ connect.IsEnabled = true;
+ connect.Text = "Connect";
+ }
}
private void setFields()
{
- string ip = Preferences.Get("ip", "");
- int port = Convert.ToInt32(Preferences.Get("port", ""));
- string keyword = Preferences.Get("keyword", "");
-
- this.ip.Text = ip;
- this.port.Text = port.ToString();
- this.keyword.Text = keyword;
-
+ try
+ {
+ string ipValue = Preferences.Get("ip", "");
+ string portValue = Preferences.Get("port", "");
+ string keywordValue = Preferences.Get("keyword", "");
+
+ this.ip.Text = ipValue;
+ this.port.Text = portValue;
+ this.keyword.Text = keywordValue;
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error setting saved fields: {ex.Message}");
+ // Fields will remain empty if there's an error
+ }
}
}
}
diff --git a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Monitor.xaml b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Monitor.xaml
index 7f3be66..25bf676 100644
--- a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Monitor.xaml
+++ b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Monitor.xaml
@@ -2,69 +2,144 @@
+ BackgroundColor="#F5F5F5">
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
+
+
+
+
-
+
+
diff --git a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Monitor.xaml.cs b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Monitor.xaml.cs
index 4df8aab..cb6af6f 100644
--- a/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Monitor.xaml.cs
+++ b/RemoteMonitor Mobile/RemoteMonitor/RemoteMonitor/RemoteMonitor/Monitor.xaml.cs
@@ -16,182 +16,463 @@ public partial class Monitor : ContentPage
{
private Client _client;
private CPU _cpu;
- private GPU _gpu;
- private PhysicalDisk _disk;
+ private List _gpus;
+ private List _disks;
private Ram _ram;
+
public Monitor(Client client, GPU gpu, PhysicalDisk disk, Ram ram)
{
NavigationPage.SetHasNavigationBar(this, false);
-
InitializeComponent();
_client = client;
- _gpu = gpu;
- _disk = disk;
+ _gpus = new List { gpu };
+ _disks = new List { disk };
_ram = ram;
}
+
public Monitor(JArray jsonArray, Client c)
{
NavigationPage.SetHasNavigationBar(this, false);
-
InitializeComponent();
_client = c;
+ _gpus = new List();
+ _disks = new List();
- _cpu = new CPU(jsonArray[0].ToObject());
try
{
- _gpu = new GPU(jsonArray[1][0].ToObject());
+ // Parse CPU (index 0)
+ _cpu = new CPU(jsonArray[0].ToObject());
+
+ // Parse GPUs (index 1 - array of GPUs)
+ if (jsonArray[1] is JArray gpuArray && gpuArray.Count > 0)
+ {
+ foreach (JToken gpuToken in gpuArray)
+ {
+ try
+ {
+ _gpus.Add(new GPU(gpuToken.ToObject()));
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error parsing GPU: {ex.Message}");
+ }
+ }
+ }
+
+ if (_gpus.Count == 0)
+ {
+ _gpus.Add(new GPU()); // Add placeholder GPU
+ }
+ // Parse RAM (index 2)
+ _ram = new Ram(jsonArray[2].ToObject());
+
+ // Parse Disks (index 3 - array of Disks)
+ if (jsonArray[3] is JArray diskArray && diskArray.Count > 0)
+ {
+ foreach (JToken diskToken in diskArray)
+ {
+ try
+ {
+ _disks.Add(new PhysicalDisk(diskToken.ToObject()));
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error parsing Disk: {ex.Message}");
+ }
+ }
+ }
+
+ if (_disks.Count == 0)
+ {
+ _disks.Add(new PhysicalDisk()); // Add placeholder disk
+ }
}
- catch (Exception)
- {
- _gpu = new GPU();
- }
- _ram = new Ram(jsonArray[2].ToObject());
- try
- {
- _disk = new PhysicalDisk(jsonArray[3][0].ToObject());
- }
- catch (Exception)
+ catch (Exception ex)
{
-
- _disk = new PhysicalDisk();
+ Debug.WriteLine($"Error parsing component data: {ex.Message}");
+ // Initialize with empty components
+ _cpu = new CPU();
+ _ram = new Ram();
+ if (_gpus.Count == 0) _gpus.Add(new GPU());
+ if (_disks.Count == 0) _disks.Add(new PhysicalDisk());
}
-
- setFields();
+ SetFields();
}
+
public Monitor()
{
InitializeComponent();
}
+
private void Update(JArray jsonArray)
{
refreshControl.IsRefreshing = false;
- _cpu.update(jsonArray[0].ToObject());
+
try
{
- _gpu.update(jsonArray[1][0].ToObject());
- _disk.update(jsonArray[3][0].ToObject());
+ // Update CPU
+ _cpu.update(jsonArray[0].ToObject());
+
+ // Update GPUs
+ if (jsonArray[1] is JArray gpuArray)
+ {
+ for (int i = 0; i < Math.Min(_gpus.Count, gpuArray.Count); i++)
+ {
+ try
+ {
+ _gpus[i].update(gpuArray[i].ToObject());
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error updating GPU {i}: {ex.Message}");
+ }
+ }
+ }
+ // Update RAM
+ _ram.update(jsonArray[2].ToObject());
+
+ // Update Disks
+ if (jsonArray[3] is JArray diskArray)
+ {
+ for (int i = 0; i < Math.Min(_disks.Count, diskArray.Count); i++)
+ {
+ try
+ {
+ _disks[i].update(diskArray[i].ToObject());
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error updating Disk {i}: {ex.Message}");
+ }
+ }
+ }
+
+ SetFields();
+ lastUpdated.Text = "Last Updated: " + DateTime.Now.ToLocalTime().ToString("HH:mm:ss");
}
- catch (Exception)
+ catch (Exception ex)
{
-
+ Debug.WriteLine($"Error updating components: {ex.Message}");
+ connectionStatus.Text = "Update Error";
+ connectionStatus.TextColor = Color.Orange;
}
- _ram.update(jsonArray[2].ToObject());
-
+ }
- lastUpdated.Text = "Last Updated " + DateTime.Now.ToLocalTime().ToString();
+ private void SetFields()
+ {
+ try
+ {
+ SetCpuFields();
+ SetRamFields();
+ SetGpuFields();
+ SetDiskFields();
+
+ connectionStatus.Text = "Connected";
+ connectionStatus.TextColor = Color.LightGreen;
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error setting fields: {ex.Message}");
+ connectionStatus.Text = "Display Error";
+ connectionStatus.TextColor = Color.Orange;
+ }
}
- //sets the fields to the values of the components
- private void setFields()
+ private void SetCpuFields()
{
- //cpu
- if (_cpu.componentName != "")
- cpuName.Text = _cpu.componentName.Trim();
+ if (_cpu?.componentName != null && _cpu.componentName != "")
+ cpuName.Text = _cpu.componentName.Trim();
else
cpuName.Text = "CPU";
- if (_cpu.temperature != 0)
- cpuTemp.Text = "Temp: " + _cpu.temperature.ToString() + "°C";
+ if (_cpu?.temperature > 0)
+ cpuTemp.Text = $"Temp: {_cpu.temperature:F1}°C";
else
cpuTemp.Text = "Temp: N/A";
- cpuUsage.Text = "Usage: "+ Math.Round(_cpu.usage * 100,2) + "%";
+
+ cpuUsage.Text = $"Usage: {(_cpu?.usage * 100 ?? 0):F1}%";
+ cpuCores.Text = $"Cores: {_cpu?.cores ?? 0}";
+
try
{
- if (_cpu.fanSpeed[0] != 0)
- cpuFanSpeed.Text = "Fan: " + _cpu.fanSpeed[0].ToString() + "RPM";
+ if (_cpu?.fanSpeed != null && _cpu.fanSpeed.Length > 0 && _cpu.fanSpeed[0] != 0)
+ cpuFanSpeed.Text = $"Fan: {_cpu.fanSpeed[0]} RPM";
else
cpuFanSpeed.Text = "Fan: N/A";
}
- catch (Exception)
+ catch
{
cpuFanSpeed.Text = "Fan: N/A";
}
-
-
-
-
- //gpu
- if (_gpu.componentName != "")
- gpuName.Text = _gpu.componentName.Trim();
- else
- gpuName.Text = "GPU";
-
- if (_gpu.temperature != 0)
- gpuTemp.Text = "Temp: " + _gpu.temperature.ToString() + "°C";
- else
- gpuTemp.Text = "Temp: N/A";
- gpuUsage.Text = "Usage: " + _gpu.usage.ToString() + "%";
- gpuVRam.Text = "VramTotal: " + bytesToGigabytes(_gpu.vramTotal) + "GB";
+ }
- //ram
- if (_ram.componentName != "" || _ram.componentName == null)
- ramName.Text = _ram.componentName.Trim();
+ private void SetRamFields()
+ {
+ if (_ram?.componentName != null && _ram.componentName != "")
+ ramName.Text = _ram.componentName.Trim();
else
ramName.Text = "RAM";
- ramUsage.Text = "Usage: " + Math.Round(_ram.getUsage() * 100,2) + "%";
- ramAvailable.Text = "Available: " + bytesToGigabytes(_ram.getMemoryAvailable()) + "GB";
- ramTotal.Text = "Total: " + bytesToGigabytes(_ram.getMemoryTotal()) + "GB";
- //disk
- if (_disk.componentName != "")
- diskName.Text = _disk.componentName.Trim();
- else
- diskName.Text = "Disk";
- if (_disk.temperature != 0)
- diskTemp.Text = "Temp: " + _disk.temperature.ToString() + "°C";
- else
- diskTemp.Text = "Temp: N/A";
- diskUsage.Text = "Usage: "+_disk.usage.ToString() + "%";
- //convert to GB
- diskAvailable.Text = "Available: "+ bytesToGigabytes(_disk.availableCapacity) + "GB";
- diskTotal.Text = "Total: " + bytesToGigabytes(_disk.capacity) + "GB";
-
+ ramUsage.Text = $"Usage: {(_ram?.getUsage() * 100 ?? 0):F1}%";
+ ramAvailable.Text = $"Available: {BytesToGigabytes(_ram?.getMemoryAvailable() ?? 0):F1} GB";
+ ramTotal.Text = $"Total: {BytesToGigabytes(_ram?.getMemoryTotal() ?? 0):F1} GB";
}
- private double bytesToGigabytes(long bytes)
+
+ private void SetGpuFields()
{
- // Convert to gigabytes without rounding
- double gigabytes = bytes / (1024.0 * 1024.0 * 1024.0);
- // Round to two decimal places
- return Math.Round(gigabytes * 100.0) / 100.0;
+ gpuContainer.Children.Clear();
+
+ if (_gpus == null || _gpus.Count == 0)
+ {
+ var noGpuLabel = new Label
+ {
+ Text = "No GPUs detected",
+ TextColor = Color.Gray,
+ FontSize = 16,
+ HorizontalTextAlignment = TextAlignment.Center
+ };
+ gpuContainer.Children.Add(noGpuLabel);
+ return;
+ }
+
+ for (int i = 0; i < _gpus.Count; i++)
+ {
+ var gpu = _gpus[i];
+ var gpuFrame = CreateGpuFrame(gpu, i);
+ gpuContainer.Children.Add(gpuFrame);
+ }
}
- private async void RefreshView_Refreshing(object sender, EventArgs e)
+
+ private void SetDiskFields()
{
- try
+ diskContainer.Children.Clear();
+
+ if (_disks == null || _disks.Count == 0)
{
- string data = await _client.RequestDataAsync();
- Update(JArray.Parse(data));
- setFields();
+ var noDiskLabel = new Label
+ {
+ Text = "No disks detected",
+ TextColor = Color.Gray,
+ FontSize = 16,
+ HorizontalTextAlignment = TextAlignment.Center
+ };
+ diskContainer.Children.Add(noDiskLabel);
+ return;
+ }
+ for (int i = 0; i < _disks.Count; i++)
+ {
+ var disk = _disks[i];
+ var diskFrame = CreateDiskFrame(disk, i);
+ diskContainer.Children.Add(diskFrame);
}
- catch (Exception)
+ }
+
+ private Frame CreateGpuFrame(GPU gpu, int index)
+ {
+ var frame = new Frame
{
- _client.Disconnect();
- var newPage = new MainPage("Disconnected from server");
- var animation = new Animation(v => newPage.Opacity = v, 0, 1);
+ BackgroundColor = Color.FromHex("#F9F9F9"),
+ BorderColor = Color.FromHex("#E0E0E0"),
+ CornerRadius = 5,
+ Padding = 10,
+ Margin = new Thickness(0, 5)
+ };
- animation.Commit(newPage, "FadeAnimation", length: 500, easing: Easing.Linear);
- await Navigation.PushAsync(newPage);
- Navigation.RemovePage(Navigation.NavigationStack[Navigation.NavigationStack.Count - 2]);
+ var stackLayout = new StackLayout();
- }
+ var nameLabel = new Label
+ {
+ Text = !string.IsNullOrEmpty(gpu?.componentName) ? gpu.componentName.Trim() : $"GPU {index + 1}",
+ TextColor = Color.FromHex("#333333"),
+ FontAttributes = FontAttributes.Bold,
+ FontSize = 16
+ };
+
+ var grid = new Grid
+ {
+ RowDefinitions = new RowDefinitionCollection
+ {
+ new RowDefinition { Height = GridLength.Auto },
+ new RowDefinition { Height = GridLength.Auto }
+ },
+ ColumnDefinitions = new ColumnDefinitionCollection
+ {
+ new ColumnDefinition { Width = GridLength.Star },
+ new ColumnDefinition { Width = GridLength.Star }
+ }
+ };
+
+ var usageLabel = new Label
+ {
+ Text = $"Usage: {gpu?.usage ?? 0:F1}%",
+ TextColor = Color.Gray,
+ FontSize = 14
+ };
+
+ var tempLabel = new Label
+ {
+ Text = gpu?.temperature > 0 ? $"Temp: {gpu.temperature:F1}°C" : "Temp: N/A",
+ TextColor = Color.Gray,
+ FontSize = 14
+ };
+
+ var vramLabel = new Label
+ {
+ Text = $"VRAM: {BytesToGigabytes(gpu?.vramTotal ?? 0):F1} GB",
+ TextColor = Color.Gray,
+ FontSize = 14
+ };
+
+ grid.Children.Add(usageLabel, 0, 0);
+ grid.Children.Add(tempLabel, 1, 0);
+ grid.Children.Add(vramLabel, 0, 1);
+ Grid.SetColumnSpan(vramLabel, 2);
+
+ stackLayout.Children.Add(nameLabel);
+ stackLayout.Children.Add(grid);
+ frame.Content = stackLayout;
+
+ return frame;
+ }
+
+ private Frame CreateDiskFrame(PhysicalDisk disk, int index)
+ {
+ var frame = new Frame
+ {
+ BackgroundColor = Color.FromHex("#F9F9F9"),
+ BorderColor = Color.FromHex("#E0E0E0"),
+ CornerRadius = 5,
+ Padding = 10,
+ Margin = new Thickness(0, 5)
+ };
+
+ var stackLayout = new StackLayout();
+
+ var nameLabel = new Label
+ {
+ Text = !string.IsNullOrEmpty(disk?.componentName) ? disk.componentName.Trim() : $"Disk {index + 1}",
+ TextColor = Color.FromHex("#333333"),
+ FontAttributes = FontAttributes.Bold,
+ FontSize = 16
+ };
+
+ var grid = new Grid
+ {
+ RowDefinitions = new RowDefinitionCollection
+ {
+ new RowDefinition { Height = GridLength.Auto },
+ new RowDefinition { Height = GridLength.Auto }
+ },
+ ColumnDefinitions = new ColumnDefinitionCollection
+ {
+ new ColumnDefinition { Width = GridLength.Star },
+ new ColumnDefinition { Width = GridLength.Star }
+ }
+ };
+
+ var usageLabel = new Label
+ {
+ Text = $"Usage: {disk?.usage ?? 0:F1}%",
+ TextColor = Color.Gray,
+ FontSize = 14
+ };
+
+ var tempLabel = new Label
+ {
+ Text = disk?.temperature > 0 ? $"Temp: {disk.temperature:F1}°C" : "Temp: N/A",
+ TextColor = Color.Gray,
+ FontSize = 14
+ };
+ var availableLabel = new Label
+ {
+ Text = $"Available: {BytesToGigabytes(disk?.availableCapacity ?? 0):F1} GB",
+ TextColor = Color.Gray,
+ FontSize = 14
+ };
+
+ var totalLabel = new Label
+ {
+ Text = $"Total: {BytesToGigabytes(disk?.capacity ?? 0):F1} GB",
+ TextColor = Color.Gray,
+ FontSize = 14
+ };
+
+ grid.Children.Add(usageLabel, 0, 0);
+ grid.Children.Add(tempLabel, 1, 0);
+ grid.Children.Add(availableLabel, 0, 1);
+ grid.Children.Add(totalLabel, 1, 1);
+
+ stackLayout.Children.Add(nameLabel);
+ stackLayout.Children.Add(grid);
+ frame.Content = stackLayout;
+
+ return frame;
}
- //disconnect from server button
- private void Button_Clicked(object sender, EventArgs e)
+ private double BytesToGigabytes(long bytes)
{
- _client.Disconnect();
- var newPage = new MainPage("Disconnected from server");
+ return bytes / (1024.0 * 1024.0 * 1024.0);
+ }
+
+ private async void RefreshView_Refreshing(object sender, EventArgs e)
+ {
+ await RefreshData();
+ }
+
+ private async void RefreshButton_Clicked(object sender, EventArgs e)
+ {
+ refreshControl.IsRefreshing = true;
+ await RefreshData();
+ }
+
+ private async Task RefreshData()
+ {
+ try
+ {
+ connectionStatus.Text = "Refreshing...";
+ connectionStatus.TextColor = Color.Orange;
+
+ string data = await _client.RequestDataAsync();
+ Update(JArray.Parse(data));
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Refresh error: {ex.Message}");
+ await HandleDisconnection("Lost connection to server");
+ }
+ finally
+ {
+ refreshControl.IsRefreshing = false;
+ }
+ }
+
+ private async Task HandleDisconnection(string message)
+ {
+ try
+ {
+ _client?.Disconnect();
+ }
+ catch { }
+
+ connectionStatus.Text = "Disconnected";
+ connectionStatus.TextColor = Color.Red;
+
+ var newPage = new MainPage(message);
var animation = new Animation(v => newPage.Opacity = v, 0, 1);
animation.Commit(newPage, "FadeAnimation", length: 500, easing: Easing.Linear);
- Navigation.PushAsync(newPage);
+ await Navigation.PushAsync(newPage);
Navigation.RemovePage(Navigation.NavigationStack[Navigation.NavigationStack.Count - 2]);
-
}
+ private async void Button_Clicked(object sender, EventArgs e)
+ {
+ await HandleDisconnection("Disconnected from server");
+ }
}
}
\ No newline at end of file