Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 60 additions & 5 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
2 changes: 2 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

**A powerful, extensible backend for Windows process management,<br/> 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)

</div>

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@

/// TODO: add time checker and logger
public event ClientMessageHandler? ClientMessageResponder;
public event EventHandler? ServerStopped;

Check warning on line 23 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-windows

The event 'SimpleTcpServer.ServerStopped' is never used

Check warning on line 23 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu

The event 'SimpleTcpServer.ServerStopped' is never used

Check warning on line 23 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-windows

The event 'SimpleTcpServer.ServerStopped' is never used

Check warning on line 23 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu

The event 'SimpleTcpServer.ServerStopped' is never used
public event EventHandler? ServerStarted;

Check warning on line 24 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-windows

The event 'SimpleTcpServer.ServerStarted' is never used

Check warning on line 24 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu

The event 'SimpleTcpServer.ServerStarted' is never used

Check warning on line 24 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-windows

The event 'SimpleTcpServer.ServerStarted' is never used

Check warning on line 24 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu

The event 'SimpleTcpServer.ServerStarted' is never used
public event EventHandler? ClientConnected;

Check warning on line 25 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-windows

The event 'SimpleTcpServer.ClientConnected' is never used

Check warning on line 25 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu

The event 'SimpleTcpServer.ClientConnected' is never used

Check warning on line 25 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-windows

The event 'SimpleTcpServer.ClientConnected' is never used

Check warning on line 25 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu

The event 'SimpleTcpServer.ClientConnected' is never used


private readonly TcpListener _listener;
private readonly int _port;
private readonly string _ipAddress;

Check warning on line 30 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-windows

Field 'SimpleTcpServer._ipAddress' is never assigned to, and will always have its default value null

Check warning on line 30 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu

Field 'SimpleTcpServer._ipAddress' is never assigned to, and will always have its default value null

Check warning on line 30 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-windows

Field 'SimpleTcpServer._ipAddress' is never assigned to, and will always have its default value null

Check warning on line 30 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu

Field 'SimpleTcpServer._ipAddress' is never assigned to, and will always have its default value null
private bool Running = false;

public int Port => _port;
Expand All @@ -40,7 +40,7 @@
/// </summary>
public string[] AllowedIPS = { };

public SimpleTcpServer(int port)

Check warning on line 43 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-windows

Non-nullable field '_ipAddress' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 43 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu

Non-nullable field '_ipAddress' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 43 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-windows

Non-nullable field '_ipAddress' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 43 in backend/HomeServer-Backend-win/Communication/SimpleTcpServer.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu

Non-nullable field '_ipAddress' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.
{
_port = port;
_listener = new TcpListener(IPAddress.Any, _port);
Expand Down Expand Up @@ -81,6 +81,8 @@

public void Start()
{
Running = true;

_listener.Start();
Logger.LogInfo($"Server started. Listening on {_ipAddress}:{_port}");

Expand All @@ -98,6 +100,7 @@
}
finally
{
Logger.LogWarn("Server Listener Stopped");
_listener.Stop();
}
}
Expand Down
28 changes: 26 additions & 2 deletions backend/HomeServer-Backend-win/Core/ServerCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -95,14 +105,28 @@ public void LoadData()
// Load all data from the config file
}

/// <summary>
/// Running server synced for headless
/// </summary>
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();
}

/// <summary>
/// Running Server core async for console
/// </summary>
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()
Expand Down
7 changes: 1 addition & 6 deletions backend/HomeServer-Backend-win/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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();
}
}
}
48 changes: 0 additions & 48 deletions backend/API-Gateway/Tester.py → backend/Tests/API_Test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import socket
import time
import json

IP = "127.0.0.1"
PORT = 3391
Expand All @@ -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"}')
Expand Down Expand Up @@ -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()
73 changes: 73 additions & 0 deletions backend/Tests/Discovery_Test.py
Original file line number Diff line number Diff line change
@@ -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()
Loading