Enhance WebSocket server message handling and error responses

- Improve asynchronous message sending to prevent connection issues during callbacks.
- Add error response handling for failed connection retrieval, ensuring clients receive feedback on errors.
- Implement message size checks to prevent oversized messages from being sent, enhancing stability and reliability.
This commit is contained in:
Torsten Schulz (local)
2025-11-20 16:47:02 +01:00
committed by Torsten (PC)
parent 9c7b682a36
commit 88f6686809

View File

@@ -337,7 +337,8 @@ int WebSocketServer::wsCallback(struct lws *wsi,
break;
}
// Prüfe Mainadmin-Rechte
// Prüfe Mainadmin-Rechte und sende Antwort asynchron
// (nicht während des Callbacks, um Verbindungsprobleme zu vermeiden)
try {
if (!instance || !instance->isMainAdmin(ud->userId)) {
std::cerr << "[RECEIVE] getConnections: Zugriff verweigert für User " << ud->userId << std::endl;
@@ -352,7 +353,8 @@ int WebSocketServer::wsCallback(struct lws *wsi,
break;
}
// Hole aktive Verbindungen
// Hole aktive Verbindungen und sende Antwort
// Wichtig: getActiveConnections() sollte schnell sein und keine langen Operationen durchführen
json connections = instance->getActiveConnections();
json response = {
{"event", "getConnectionsResponse"},
@@ -360,11 +362,26 @@ int WebSocketServer::wsCallback(struct lws *wsi,
{"data", connections}
};
if (instance && wsi) {
// Sende die Nachricht, aber nicht während des Callbacks
// Die Nachricht wird in die Queue gelegt und beim nächsten WRITEABLE gesendet
instance->sendMessageToConnection(wsi, response.dump());
std::cout << "[RECEIVE] getConnections: Verbindungen an Mainadmin gesendet" << std::endl;
std::cout << "[RECEIVE] getConnections: Verbindungen an Mainadmin gesendet (" << response.dump().length() << " Bytes)" << std::endl;
}
} catch (const std::exception &e) {
std::cerr << "[RECEIVE] Fehler bei getConnections: " << e.what() << std::endl;
// Sende Fehlerantwort
try {
json errorResponse = {
{"event", "getConnectionsResponse"},
{"success", false},
{"error", std::string("Fehler beim Abrufen der Verbindungen: ") + e.what()}
};
if (instance && wsi) {
instance->sendMessageToConnection(wsi, errorResponse.dump());
}
} catch (...) {
// Ignoriere Fehler beim Senden der Fehlerantwort
}
}
} else {
std::cout << "[RECEIVE] Unbekanntes Event: " << event << std::endl;
@@ -393,12 +410,34 @@ int WebSocketServer::wsCallback(struct lws *wsi,
}
if (!messageToSend.empty()) {
// Prüfe ob Nachricht zu groß ist (max 4096 Bytes)
if (messageToSend.length() > 4096) {
std::cerr << "[WRITEABLE] Warnung: Nachricht zu groß (" << messageToSend.length() << " Bytes), wird abgeschnitten" << std::endl;
messageToSend = messageToSend.substr(0, 4096);
}
// Nachricht senden
std::cout << "[WRITEABLE] Sende Nachricht: " << messageToSend << std::endl;
std::cout << "[WRITEABLE] Sende Nachricht (" << messageToSend.length() << " Bytes): " << (messageToSend.length() > 100 ? messageToSend.substr(0, 100) + "..." : messageToSend) << std::endl;
unsigned char buf[LWS_PRE + messageToSend.length()];
memcpy(buf + LWS_PRE, messageToSend.c_str(), messageToSend.length());
lws_write(wsi, buf + LWS_PRE, messageToSend.length(), LWS_WRITE_TEXT);
std::cout << "[WRITEABLE] Nachricht erfolgreich gesendet" << std::endl;
int ret = lws_write(wsi, buf + LWS_PRE, messageToSend.length(), LWS_WRITE_TEXT);
if (ret < 0) {
std::cerr << "[WRITEABLE] Fehler beim Senden: lws_write returned " << ret << " - Verbindung wird möglicherweise geschlossen" << std::endl;
// Bei Fehler: Verbindung wird wahrscheinlich geschlossen, entferne aus Queue
{
std::lock_guard<std::mutex> lock(ud->messageQueueMutex);
// Leere die Queue, da die Verbindung nicht mehr funktioniert
while (!ud->messageQueue.empty()) {
ud->messageQueue.pop();
}
}
// Keine weitere Aktion - die Verbindung wird durch libwebsockets geschlossen
return -1; // Signalisiert libwebsockets, dass die Verbindung geschlossen werden soll
} else if (ret != static_cast<int>(messageToSend.length())) {
std::cerr << "[WRITEABLE] Warnung: Nur " << ret << " von " << messageToSend.length() << " Bytes gesendet" << std::endl;
} else {
std::cout << "[WRITEABLE] Nachricht erfolgreich gesendet (" << ret << " Bytes)" << std::endl;
}
// Wenn noch weitere Nachrichten in der Queue sind, wieder schreibbereit machen
{
@@ -711,10 +750,7 @@ void WebSocketServer::sendMessageToConnection(struct lws *wsi, const std::string
// Nur wenn die Queue leer war, den Callback aufrufen
// (sonst wird er bereits durch den WRITEABLE-Handler aufgerufen)
if (wasEmpty) {
// Verwende lws_cancel_service, um den Service zu benachrichtigen, anstatt
// lws_callback_on_writable direkt aufzurufen (sicherer während Callbacks)
lws_cancel_service(context);
// Alternativ: lws_callback_on_writable(wsi) sollte auch funktionieren
// lws_callback_on_writable kann sicher während eines Callbacks aufgerufen werden
lws_callback_on_writable(wsi);
}
} catch (const std::exception &e) {