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:
committed by
Torsten (PC)
parent
9c7b682a36
commit
88f6686809
@@ -337,7 +337,8 @@ int WebSocketServer::wsCallback(struct lws *wsi,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe Mainadmin-Rechte
|
// Prüfe Mainadmin-Rechte und sende Antwort asynchron
|
||||||
|
// (nicht während des Callbacks, um Verbindungsprobleme zu vermeiden)
|
||||||
try {
|
try {
|
||||||
if (!instance || !instance->isMainAdmin(ud->userId)) {
|
if (!instance || !instance->isMainAdmin(ud->userId)) {
|
||||||
std::cerr << "[RECEIVE] getConnections: Zugriff verweigert für User " << ud->userId << std::endl;
|
std::cerr << "[RECEIVE] getConnections: Zugriff verweigert für User " << ud->userId << std::endl;
|
||||||
@@ -352,7 +353,8 @@ int WebSocketServer::wsCallback(struct lws *wsi,
|
|||||||
break;
|
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 connections = instance->getActiveConnections();
|
||||||
json response = {
|
json response = {
|
||||||
{"event", "getConnectionsResponse"},
|
{"event", "getConnectionsResponse"},
|
||||||
@@ -360,11 +362,26 @@ int WebSocketServer::wsCallback(struct lws *wsi,
|
|||||||
{"data", connections}
|
{"data", connections}
|
||||||
};
|
};
|
||||||
if (instance && wsi) {
|
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());
|
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) {
|
} catch (const std::exception &e) {
|
||||||
std::cerr << "[RECEIVE] Fehler bei getConnections: " << e.what() << std::endl;
|
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 {
|
} else {
|
||||||
std::cout << "[RECEIVE] Unbekanntes Event: " << event << std::endl;
|
std::cout << "[RECEIVE] Unbekanntes Event: " << event << std::endl;
|
||||||
@@ -393,12 +410,34 @@ int WebSocketServer::wsCallback(struct lws *wsi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!messageToSend.empty()) {
|
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
|
// 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()];
|
unsigned char buf[LWS_PRE + messageToSend.length()];
|
||||||
memcpy(buf + LWS_PRE, messageToSend.c_str(), messageToSend.length());
|
memcpy(buf + LWS_PRE, messageToSend.c_str(), messageToSend.length());
|
||||||
lws_write(wsi, buf + LWS_PRE, messageToSend.length(), LWS_WRITE_TEXT);
|
int ret = lws_write(wsi, buf + LWS_PRE, messageToSend.length(), LWS_WRITE_TEXT);
|
||||||
std::cout << "[WRITEABLE] Nachricht erfolgreich gesendet" << std::endl;
|
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
|
// 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
|
// Nur wenn die Queue leer war, den Callback aufrufen
|
||||||
// (sonst wird er bereits durch den WRITEABLE-Handler aufgerufen)
|
// (sonst wird er bereits durch den WRITEABLE-Handler aufgerufen)
|
||||||
if (wasEmpty) {
|
if (wasEmpty) {
|
||||||
// Verwende lws_cancel_service, um den Service zu benachrichtigen, anstatt
|
// lws_callback_on_writable kann sicher während eines Callbacks aufgerufen werden
|
||||||
// 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(wsi);
|
lws_callback_on_writable(wsi);
|
||||||
}
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user