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 @@ - - -