diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 5aa510a..2f37b95 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -1,19 +1,18 @@ # This workflow will build a .NET project # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net -name: Build backend Windows NET +name: Build backend NET on: push: - branches: [ "master" ] + branches: [ "master", "GitActions" ] pull_request: branches: [ "master" ] jobs: - build: - + build-windows: runs-on: windows-latest - + defaults: run: working-directory: ./backend/HomeServer-Backend-win @@ -30,3 +29,59 @@ jobs: run: dotnet build --no-restore # - name: Test # run: dotnet test --no-build --verbosity normal + + build-ubuntu: + runs-on: ubuntu-latest + # strategy: + # matrix: + # python_ver: ["3.12"] + + steps: + + - uses: actions/checkout@v4 + + # Setup .NET + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + # Build project + - name: Build backend + working-directory: ./backend/HomeServer-Backend-win + run: | + dotnet restore + dotnet build --configuration Release + + # Run backend in background + - name: Start backend + working-directory: ./backend/HomeServer-Backend-win + run: | + dotnet run --configuration Release & + echo $! > backend_pid.txt + + # Wait before running tests + - name: Wait for server to start + run: sleep 5 + + # Setup Python + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + # Run Python Discovery Test + - name: Run Discovery tests + working-directory: ./backend/Tests + run: python3 Discovery_Test.py + + # Run Python test script + - name: Run API tests + working-directory: ./backend/Tests + run: python3 API_Test.py + + # Stop backend process after tests + - name: Stop backend + if: always() + run: | + kill $(cat backend/HomeServer-Backend-win/backend_pid.txt) || true diff --git a/Readme.md b/Readme.md index d23a82b..d0a1a4b 100644 --- a/Readme.md +++ b/Readme.md @@ -4,6 +4,8 @@ **A powerful, extensible backend for Windows process management,
automation, and monitoring — accessible via a modern TCP API.** +[![Build backend Windows NET badge](https://github.com/nadav26740/HomeServer/actions/workflows/dotnet.yml/badge.svg)](https://github.com/nadav26740/HomeServer/actions/workflows/dotnet.yml) + --- diff --git a/backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs b/backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs index 4603ed9..76bed41 100644 --- a/backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs +++ b/backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs @@ -81,6 +81,8 @@ public async Task StartAsync() public void Start() { + Running = true; + _listener.Start(); Logger.LogInfo($"Server started. Listening on {_ipAddress}:{_port}"); @@ -98,6 +100,7 @@ public void Start() } finally { + Logger.LogWarn("Server Listener Stopped"); _listener.Stop(); } } diff --git a/backend/HomeServer-Backend-win/Core/ServerCore.cs b/backend/HomeServer-Backend-win/Core/ServerCore.cs index 0de5a53..2063a5a 100644 --- a/backend/HomeServer-Backend-win/Core/ServerCore.cs +++ b/backend/HomeServer-Backend-win/Core/ServerCore.cs @@ -77,10 +77,20 @@ public void LoadData() // TODO: // Load Config.. - ProcessSlaveArgs[]? procSlaves = ProcessConfigSave.ReadSlaveProcessData("processes.json"); + ProcessSlaveArgs[]? procSlaves = null; + try + { + procSlaves = ProcessConfigSave.ReadSlaveProcessData("processes.json"); + } + catch (Exception ex) + { + Logger.LogError($"Failed to read process configuration: {ex.Message}"); + } + if (procSlaves == null || procSlaves.Length == 0) { Logger.LogWarn("No process slaves found in the config file. Please check your configuration."); + return; } else { @@ -95,14 +105,28 @@ public void LoadData() // Load all data from the config file } + /// + /// Running server synced for headless + /// public void Start() { Logger.LogInfo("Server Core Start has been called"); - server_task = m_TcpServer.StartAsync(); + m_Manager.ForceStart(); Discovery_task = m_DiscoveryListener.StartAsyncListening(); + m_TcpServer.Start(); + } + + /// + /// Running Server core async for console + /// + public void AsyncStart() + { + Logger.LogInfo("Server Core Start has been called"); m_Manager.ForceStart(); + Discovery_task = m_DiscoveryListener.StartAsyncListening(); + server_task = m_TcpServer.StartAsync(); } public void Shutdown() diff --git a/backend/HomeServer-Backend-win/Program.cs b/backend/HomeServer-Backend-win/Program.cs index a11d8fc..3cb8060 100644 --- a/backend/HomeServer-Backend-win/Program.cs +++ b/backend/HomeServer-Backend-win/Program.cs @@ -120,7 +120,7 @@ private static async Task Main(string[] args) { Console.WriteLine(GetSplashMessage()); Console.WriteLine("Press any key to start test"); - Console.ReadKey(); + //Console.ReadKey(); Console.WriteLine("Home Server test Starting..."); await using ServerCore Core = new ServerCore(); @@ -130,17 +130,12 @@ private static async Task Main(string[] args) Logger.LogInfo("Starting server..."); Core.Start(); - Logger.LogInfo("Server started successfully!"); - - Console.WriteLine("========================== Press any key to stop =========================="); - Console.ReadKey(); Logger.LogInfo("Stopping server..."); // Core.Shutdown(); Logger.LogInfo("Server stopped successfully!"); Console.WriteLine("Home Server test completed. Press any key to exit."); - Console.ReadKey(); } } } diff --git a/backend/API-Gateway/Tester.py b/backend/Tests/API_Test.py similarity index 60% rename from backend/API-Gateway/Tester.py rename to backend/Tests/API_Test.py index 9e8e2a7..b10abf9 100644 --- a/backend/API-Gateway/Tester.py +++ b/backend/Tests/API_Test.py @@ -1,6 +1,5 @@ import socket import time -import json IP = "127.0.0.1" PORT = 3391 @@ -27,12 +26,6 @@ def main(): global totalRunTime print("Searching for server") - if discover_server(): - print(f"{bcolors.OKGREEN} Server found {IP}:{str(PORT)} {bcolors.ENDC}") - - else: - print(f"{bcolors.FAIL} Failed to find server! {bcolors.ENDC}") - return -1 print("=====================Starting API Tests=======================") TestAPI('{"Path":"/api/process/start", "Type":"UPDATE", "Data":"Minecraft Server"}') @@ -74,47 +67,6 @@ def TestAPI(message): print("\n\n") -def discover_server(timeout=5): - global IP - global PORT - global totalRunTime - - # Create a UDP socket - Succeeded = False - client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - client_socket.settimeout(timeout) # timeout in seconds - - # Broadcast address - broadcast_address = ('192.168.50.255', DISCOVERY_PORT) - - try: - # Send discovery message - client_socket.sendto(DISCOVERY_MESSAGE.encode('utf-8'), broadcast_address) - print(f"Broadcasted discovery request to {broadcast_address}") - - # Wait for response from server - data, server_addr = client_socket.recvfrom(BUFFER_SIZE) - - StartTime = time.perf_counter() - response = data.decode('utf-8') - elapsed_time = time.perf_counter() - StartTime - totalRunTime += elapsed_time - - print(f"Received response: '{response}' from {server_addr[0]}:{server_addr[1]}") - print(f"{bcolors.OKCYAN}{bcolors.BOLD} Answer time: {(elapsed_time * 1000):.0f} ms{bcolors.ENDC}") - - PORT = json.loads(response)["Port"] - IP = str(server_addr[0]) - - Succeeded = True - - except socket.timeout: - print("No server response received within timeout.") - finally: - client_socket.close() - return Succeeded - if __name__ == "__main__": main() \ No newline at end of file diff --git a/backend/Tests/Discovery_Test.py b/backend/Tests/Discovery_Test.py new file mode 100644 index 0000000..652befd --- /dev/null +++ b/backend/Tests/Discovery_Test.py @@ -0,0 +1,73 @@ +import socket +import time + +IP = "127.0.0.1" +PORT = 3391 + +BROADCAST_ADDRESS = ('255.255.255.255', 50130) +BUFFER_SIZE = 1024 +DISCOVERY_MESSAGE = "DISCOVER_LOCAL_HOMESERVER" + +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKCYAN = '\033[96m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + + +def main(): + if discover_server(): + print(f"{bcolors.OKGREEN} Server found {IP} {bcolors.ENDC}") + + else: + print(f"{bcolors.FAIL} Failed to find server! {bcolors.ENDC}") + exit(1) + + +def discover_server(timeout=5): + global IP + global PORT + global totalRunTime + + # Create a UDP socket + Succeeded = False + client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + client_socket.settimeout(timeout) # timeout in seconds + + # Broadcast address + broadcast_address = BROADCAST_ADDRESS + + try: + # Send discovery message + client_socket.sendto(DISCOVERY_MESSAGE.encode('utf-8'), broadcast_address) + print(f"Broadcasted discovery request to {broadcast_address}") + + # Wait for response from server + data, server_addr = client_socket.recvfrom(BUFFER_SIZE) + + StartTime = time.perf_counter() + response = data.decode('utf-8') + elapsed_time = time.perf_counter() - StartTime + + print(f"Received response: '{response}' from {server_addr[0]}:{server_addr[1]}") + print(f"{bcolors.OKCYAN}{bcolors.BOLD} Answer time: {(elapsed_time * 1000):.0f} ms{bcolors.ENDC}") + + IP = str(server_addr[0]) + + Succeeded = True + + except socket.timeout: + print("No server response received within timeout.") + finally: + client_socket.close() + return Succeeded + + +if __name__ == "__main__": + main() \ No newline at end of file