Implemented Corrections during integration tests #1

Merged
schreinerma97192 merged 1 commits from aioptimize into master 2026-06-30 09:41:46 +00:00
3 changed files with 293 additions and 147 deletions
Showing only changes of commit 8f47a48348 - Show all commits

53
Game.cs
View File

@ -112,9 +112,11 @@ namespace Wolf
logger.Log($"Spieler {p.Name} wacht auf und sieht sich seine Rolle an."); logger.Log($"Spieler {p.Name} wacht auf und sieht sich seine Rolle an.");
ttsClient.Read(logger.getLastLine(), readHistory); ttsClient.Read(logger.getLastLine(), readHistory);
ShowRole(p); ShowRole(p);
Task.Delay(5000).Wait();
logger.Log($"Spieler {p.Name} hat seine Rolle gesehen und geht wieder schlafen."); logger.Log($"Spieler {p.Name} hat seine Rolle gesehen und geht wieder schlafen.");
ttsClient.Read(logger.getLastLine(), readHistory); ttsClient.Read(logger.getLastLine(), readHistory);
getConfirmationEveryoneAsleep(); getConfirmationEveryoneAsleep();
} }
Console.Clear(); Console.Clear();
@ -360,46 +362,73 @@ namespace Wolf
{ {
try try
{ {
int res = logicClient.GetPlayerId(targets, pois).WaitAsync(TimeSpan.FromSeconds(10)).Result; int res = logicClient.GetPlayerId(targets, pois).WaitAsync(TimeSpan.FromSeconds(30)).Result;
if (res >= 0) if (res >= 0)
{ {
return res; return res;
} }
logger.Log("GetPlayerId returned invalid value, defaulting to 0");
return 0;
} }
catch catch (TimeoutException)
{ {
logger.Log("GetPlayerId timed out after 30 seconds");
return 0; return 0;
} }
catch (Exception ex)
{
logger.Log($"GetPlayerId error: {ex.Message}");
return 0; return 0;
} }
}
public bool getConfirmation(List<Player> players) public bool getConfirmation(List<Player> players)
{ {
try try
{ {
bool res = logicClient.GetConfirmation(players).WaitAsync(TimeSpan.FromSeconds(10)).Result; bool res = logicClient.GetConfirmation(players).WaitAsync(TimeSpan.FromSeconds(30)).Result;
if (res) return res;
{
return true;
} }
} catch (TimeoutException)
catch
{ {
logger.Log("GetConfirmation timed out after 30 seconds, defaulting to false");
return false; return false;
} }
catch (Exception ex)
{
logger.Log($"GetConfirmation error: {ex.Message}");
return false; return false;
} }
}
public bool getConfirmationEveryoneAsleep() public bool getConfirmationEveryoneAsleep()
{ {
int maxRetries = 50;
int attempt = 0;
while (attempt < maxRetries)
{
attempt++;
try try
{ {
return logicClient.GetConfirmationEveryoneAsleep().WaitAsync(TimeSpan.FromSeconds(30)).Result; bool result = logicClient.GetConfirmationEveryoneAsleep().WaitAsync(TimeSpan.FromSeconds(60)).Result;
} if (result)
catch
{ {
return false; return true;
} }
logger.Log($"GetConfirmationEveryoneAsleep returned false on attempt {attempt}, retrying...");
}
catch (TimeoutException)
{
logger.Log($"GetConfirmationEveryoneAsleep timed out on attempt {attempt}/{maxRetries}, retrying...");
}
catch (Exception ex)
{
logger.Log($"GetConfirmationEveryoneAsleep error on attempt {attempt}/{maxRetries}: {ex.Message}, retrying...");
}
}
logger.Log($"GetConfirmationEveryoneAsleep failed after {maxRetries} attempts, defaulting to false");
return false; return false;
} }
} }

View File

@ -8,33 +8,47 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Threading;
namespace Wolf namespace Wolf
{ {
internal class OSCClient internal class OSCClient
{ {
UdpClient udpClientSend; private UdpClient udpClientSend;
UdpClient udpClientReceive; private UdpClient udpClientReceive;
private readonly SemaphoreSlim _requestSemaphore;
private string _lastSentAddress = "";
private object[] _lastSentArguments = Array.Empty<object>();
public OSCClient(string hostname, int port) public OSCClient(string hostname, int port)
{ {
// 1. Lokalen Port binden (für Empfang) // 1. Lokalen Port binden (für Empfang)
udpClientSend = new UdpClient(hostname, port); udpClientSend = new UdpClient(hostname, port);
udpClientReceive = new UdpClient(new IPEndPoint(IPAddress.Any, port)); udpClientReceive = new UdpClient(new IPEndPoint(IPAddress.Any, port));
_requestSemaphore = new SemaphoreSlim(1, 1);
} }
public async Task SendMessage(string endpoint) public async Task SendMessage(string endpoint)
{ {
await _requestSemaphore.WaitAsync();
try
{
var message = new OscMessage(new Address(endpoint)); var message = new OscMessage(new Address(endpoint));
_lastSentAddress = endpoint;
_lastSentArguments = Array.Empty<object>();
await udpClientSend.SendMessageAsync(message); await udpClientSend.SendMessageAsync(message);
} }
finally
{
_requestSemaphore.Release();
}
}
public async Task SpeakId(int textId) public async Task SpeakId(int textId)
{
await _requestSemaphore.WaitAsync();
try
{ {
var message = new OscMessage( var message = new OscMessage(
address: new Address("/speak"), address: new Address("/speak"),
@ -42,11 +56,20 @@ namespace Wolf
{ {
textId textId
}); });
_lastSentAddress = "/speak";
_lastSentArguments = new object[] { textId };
await udpClientSend.SendMessageAsync(message); await udpClientSend.SendMessageAsync(message);
} }
finally
{
_requestSemaphore.Release();
}
}
public async Task Read(string text, bool readStory = true) public async Task Read(string text, bool readStory = true)
{
await _requestSemaphore.WaitAsync();
try
{ {
string endpoint = readStory ? "/read_story" : "/read"; string endpoint = readStory ? "/read_story" : "/read";
var message = new OscMessage( var message = new OscMessage(
@ -55,19 +78,34 @@ namespace Wolf
{ {
text, 2 text, 2
}); });
_lastSentAddress = endpoint;
_lastSentArguments = new object[] { text, 2 };
await udpClientSend.SendMessageAsync(message); await udpClientSend.SendMessageAsync(message);
} }
finally
{
_requestSemaphore.Release();
}
}
public async Task SendMessageWithArguments(string endpoint, params object[] param) public async Task SendMessageWithArguments(string endpoint, params object[] param)
{ {
await _requestSemaphore.WaitAsync();
try
{
var message = new OscMessage( var message = new OscMessage(
address: new Address(endpoint), address: new Address(endpoint),
arguments: param arguments: param
); );
_lastSentAddress = endpoint;
_lastSentArguments = param;
await udpClientSend.SendMessageAsync(message); await udpClientSend.SendMessageAsync(message);
} }
finally
{
_requestSemaphore.Release();
}
}
public async Task ReceiveMessageWithoutArguments() public async Task ReceiveMessageWithoutArguments()
@ -100,21 +138,102 @@ namespace Wolf
} }
} }
/// <summary>
/// Generische Methode zur Ausführung von Request-Response-Kommunikation mit Retry-Logik.
/// </summary>
private async Task<T> ExecuteRequestWithRetry<T>(
string expectedAddress,
OscMessage requestMessage,
Func<OscMessage, T> responseParser,
int maxRetries = 50,
int timeoutSeconds = 20)
{
await _requestSemaphore.WaitAsync();
try
{
_lastSentAddress = requestMessage.Address.Value;
_lastSentArguments = requestMessage.Arguments.ToArray();
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
try
{
// Anfrage senden
await udpClientSend.SendMessageAsync(requestMessage);
// Auf Response warten mit Timeout
var receiveTask = udpClientReceive.ReceiveMessageAsync();
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds));
var completed = await Task.WhenAny(receiveTask, timeoutTask);
if (completed == receiveTask)
{
var response = await receiveTask;
// Prüfen, ob es die erwartete Antwort ist
if (response.Address.Value == expectedAddress)
{
try
{
return responseParser(response);
}
catch (Exception parseEx)
{
// Argument-Parsing-Fehler, ignorieren und nächste Anfrage senden
System.Diagnostics.Debug.WriteLine($"Parse error on attempt {attempt}: {parseEx.Message}");
continue;
}
}
// Falsche Antwort → ignorieren und weiter versuchen
}
// Timeout → erneut versuchen
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Request attempt {attempt} failed: {ex.Message}");
}
}
// Alle Versuche fehlgeschlagen
throw new TimeoutException($"Request to {expectedAddress} failed after {maxRetries} attempts");
}
finally
{
_requestSemaphore.Release();
}
}
public async Task<List<int>> GetAllIds() public async Task<List<int>> GetAllIds()
{ {
SendMessage("/getAllIds"); var message = new OscMessage(new Address("/getAllIds"));
var response = await udpClientReceive.ReceiveMessageAsync();
if (response.Address.Value == "/getAllIds") try
{ {
List<int> playerIds = new List<int>(); var result = await ExecuteRequestWithRetry(
expectedAddress: "/getAllIds",
requestMessage: message,
responseParser: response =>
{
var playerIds = new List<int>();
foreach (var argument in response.Arguments) foreach (var argument in response.Arguments)
{ {
playerIds.Add((int)argument); playerIds.Add((int)argument);
} }
return playerIds; return playerIds;
});
return result;
} }
catch (TimeoutException)
{
return new List<int>(); return new List<int>();
} }
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"GetAllIds error: {ex.Message}");
return new List<int>();
}
}
// < 0 = no confirmation; 0 = confirm; > 0 = player id // < 0 = no confirmation; 0 = confirm; > 0 = player id
@ -139,7 +258,6 @@ namespace Wolf
public async Task<int> GetPlayerId(List<Player> targets, List<Player> pois) public async Task<int> GetPlayerId(List<Player> targets, List<Player> pois)
{ {
//return (int) targets.FirstOrDefault().id;
// Arrays extrahieren // Arrays extrahieren
var arr2 = targets.Select(p => p.id).ToArray(); var arr2 = targets.Select(p => p.id).ToArray();
var arr1 = pois.Select(p => p.id).ToArray(); var arr1 = pois.Select(p => p.id).ToArray();
@ -156,122 +274,118 @@ namespace Wolf
foreach (var id in arr2) foreach (var id in arr2)
args.Add(id); args.Add(id);
// Nachricht senden // Nachricht vorbereiten
var message = new OscMessage( var message = new OscMessage(
new Address("/getPlayerID"), new Address("/getPlayerID"),
args.ToArray() args.ToArray()
); );
int maxRetries = 50; try
int timeoutSeconds = 20;
// Anfrage senden
await udpClientSend.SendMessageAsync(message);
for (int attempt = 1; attempt <= maxRetries; attempt++)
{ {
// Timeout für Receive var result = await ExecuteRequestWithRetry(
var receiveTask = udpClientReceive.ReceiveMessageAsync(); expectedAddress: "/getPlayerID",
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds)); requestMessage: message,
responseParser: response =>
var completed = await Task.WhenAny(receiveTask, timeoutTask);
if (completed == receiveTask)
{ {
var response = await receiveTask; if (response.Arguments.Count() > 0)
// Prüfen, ob es die erwartete Antwort ist
if (response.Address.Value == "/getPlayerID")
{ {
return (int)response.Arguments.ElementAt(0); return (int)response.Arguments.ElementAt(0);
} }
throw new InvalidOperationException("No arguments in response");
// Falsche Antwort → ignorieren und weiter versuchen },
continue; maxRetries: 50,
timeoutSeconds: 20);
return result;
} }
catch (Exception ex)
await udpClientSend.SendMessageAsync(message); {
} System.Diagnostics.Debug.WriteLine($"GetPlayerId error: {ex.Message}");
return -1; return -1;
} }
}
public async Task<bool> GetConfirmation(List<Player> players) public async Task<bool> GetConfirmation(List<Player> players)
{ {
int maxRetries = 50;
int timeoutSeconds = 20;
var args = new List<object>(); var args = new List<object>();
foreach (var p in players) foreach (var p in players)
{ {
args.Add(p.id); args.Add(p.id);
} }
// Anfrage senden
var message = new OscMessage( var message = new OscMessage(
new Address("/confirmation"), new Address("/confirmation"),
args.ToArray() args.ToArray()
); );
await udpClientSend.SendMessageAsync(message); try
//await udpClientReceive.ReceiveMessageAsync();
for (int attempt = 1; attempt <= maxRetries; attempt++)
{ {
// Timeout für Receive var result = await ExecuteRequestWithRetry(
var receiveTask = udpClientReceive.ReceiveMessageAsync(); expectedAddress: "/confirmation",
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds)); requestMessage: message,
responseParser: response =>
var completed = await Task.WhenAny(receiveTask, timeoutTask);
if (completed == receiveTask)
{ {
var response = await receiveTask; if (response.Arguments.Count() > 0)
// Prüfen, ob es die erwartete Antwort ist
if (response.Address.Value == "/confirmation")
{ {
if (response.Arguments.ElementAt(0) is OscFalse) var firstArg = response.Arguments.ElementAt(0);
if (firstArg is OscFalse)
{ {
return false; return false;
} }
if (response.Arguments.ElementAt(0) is OscTrue) if (firstArg is OscTrue)
{ {
return true; return true;
} }
throw new InvalidOperationException($"Unexpected argument type: {firstArg.GetType().Name}");
} }
throw new InvalidOperationException("No arguments in response");
// Falsche Antwort → ignorieren und weiter versuchen },
continue; maxRetries: 50,
timeoutSeconds: 20);
return result;
} }
catch (Exception ex)
await udpClientSend.SendMessageAsync(message); {
} System.Diagnostics.Debug.WriteLine($"GetConfirmation error: {ex.Message}");
return false; return false;
} }
}
public async Task<bool> GetConfirmationEveryoneAsleep() public async Task<bool> GetConfirmationEveryoneAsleep()
{ {
return true; var message = new OscMessage(new Address("/everyoneAsleep"));
SendMessage("/everyoneAsleep");
var response = await udpClientReceive.ReceiveMessageAsync(); try
if (response.Address.Value == "/everyoneAsleep")
{ {
if (response.Arguments.ElementAt(0) is OscFalse) var result = await ExecuteRequestWithRetry(
expectedAddress: "/everyoneAsleep",
requestMessage: message,
responseParser: response =>
{
if (response.Arguments.Count() > 0)
{
var firstArg = response.Arguments.ElementAt(0);
if (firstArg is OscFalse)
{ {
return false; return false;
} }
if (response.Arguments.ElementAt(0) is OscTrue) if (firstArg is OscTrue)
{ {
return true; return true;
} }
throw new InvalidOperationException($"Unexpected argument type: {firstArg.GetType().Name}");
} }
throw new InvalidOperationException("No arguments in response");
},
maxRetries: 50,
timeoutSeconds: 30);
return result;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"GetConfirmationEveryoneAsleep error: {ex.Message}");
return false; return false;
} }
} }
} }
}

View File

@ -11,17 +11,20 @@ namespace Wolf
{ {
//OSCClient logicClient = new OSCClient("127.0.0.1", 9000); //OSCClient logicClient = new OSCClient("127.0.0.1", 9000);
OSCClient logicClient = new OSCClient("100.81.182.220", 9000); OSCClient logicClient = new OSCClient("100.83.197.1", 9000);
OSCClient ttsClient = new OSCClient("100.81.196.62", 9001); OSCClient ttsClient = new OSCClient("100.83.246.218", 9001);
//await logicClient.SendMessageWithArguments("/test", "HILFE!!! . . Rettet mich aus diesem Laptop!!! . . . Ich bin eingesperrt!!!!!"); //await logicClient.SendMessageWithArguments("/test", "HILFE!!! . . Rettet mich aus diesem Laptop!!! . . . Ich bin eingesperrt!!!!!");
//logicClient.ReceiveMessageWithoutArguments().Wait(); //logicClient.ReceiveMessageWithoutArguments().Wait();
//List<int> ids = await logicClient.GetAllIds(); List<int> ids = await logicClient.GetAllIds();
ids.Add(71);
ids.Add(72);
ids.Add(73);
Game game = new Game(logicClient, ttsClient, new Logger()); Game game = new Game(logicClient, ttsClient, new Logger());
List<int> ids = new List<int>{ 31, 27, 71, 72, 73, 74}; //List<int> ids = new List<int>{ 31, 27, 71, 72, 73, 74};
foreach (int id in ids) foreach (int id in ids)
{ {