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.**
+[](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