Files
qt5-legatus-legacy/Lts/Common/LtsProjectionWorkstation/lts_projection_workstation.cpp
T
2026-08-13 18:33:10 +02:00

252 lines
9.1 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#include "lts_projection_workstation.h"
#include "WebSocket/message_factory.h"
#include "WebSocket/json_keys.h"
#include <LtsWebSocket/lts_web_socket_server.h>
#include <LtsSession/lts_session_data.h>
#include <nglsettings/nglsettings_connections.h>
#include <QGuiApplication>
#include <QUuid>
#include <QWebSocket>
#include <QTimer>
namespace LtsProjectionWorkstation
{
static LtsProjectionWorkstation *s_ltsProjectionWorkstation = nullptr;
LtsProjectionWorkstation *LtsProjectionWorkstation::getInstance()
{
if (!s_ltsProjectionWorkstation)
{
s_ltsProjectionWorkstation = new LtsProjectionWorkstation;
qAddPostRoutine(&cleanupLtsProjectionWorkstation);
}
return s_ltsProjectionWorkstation;
}
void LtsProjectionWorkstation::cleanupLtsProjectionWorkstation()
{
delete s_ltsProjectionWorkstation;
s_ltsProjectionWorkstation = nullptr;
}
bool LtsProjectionWorkstation::hasInstance()
{
return !!s_ltsProjectionWorkstation;
}
LtsProjectionWorkstation::LtsProjectionWorkstation(QObject *parent)
: QObject(parent)
, m_logger(getLogger("LtsProjetionWorkstation"))
, m_messageFactory(new MessageFactory(this, m_logger))
, m_webSocketServer(new LtsWebSocket::LtsWebSocketServer(m_messageFactory, this))
, m_pendingLoginRequest(nullptr)
, m_vncManager(new VncServerManager(m_logger, this))
{
connect(m_webSocketServer, &LtsWebSocket::LtsWebSocketServer::clientDisconnected,
this, &LtsProjectionWorkstation::clientDisconnected);
connect(m_webSocketServer, &LtsWebSocket::LtsWebSocketServer::clientConnected,
this, &LtsProjectionWorkstation::clientConnected);
int port = NGL::Connections::port(NGL::Connections::eConnection::PWS_WEBSOCKET);
if (m_webSocketServer->init(QStringLiteral("LtsProjectionWorkstation"), port))
{
if (m_vncManager->init(qApp->screens()))
m_vncManager->startScreens();
}
}
LtsProjectionWorkstation::~LtsProjectionWorkstation()
{
delete m_vncManager;
delete m_messageFactory;
delete m_webSocketServer;
}
LoginInformation LtsProjectionWorkstation::pendingLoginRequest()
{
if (!m_pendingLoginRequest)
return {};
LoginInformation result = *m_pendingLoginRequest;
INFO_LOG(m_logger) << " reset pendingLoginRequest..";
delete m_pendingLoginRequest;
m_pendingLoginRequest = nullptr;
return result;
}
void LtsProjectionWorkstation::handleMessage(LtsWebSocket::AbstractClientMessage *message)
{
CTS::LoginRequest *login = dynamic_cast<CTS::LoginRequest *>(message);
if (login) // if message is a login message
{
INFO_LOG(m_logger) << "Login request received!"
<< ", login->userId()=" << login->userId()
<< " with login->priority()=" << login->priority()
<< " ;;; m_lastLoginRequest.m_userId=" << m_lastLoginRequest.m_userId
<< ", m_priority=" << m_lastLoginRequest.m_priority;
if (login->userId() > 0 && login->priority() > 0 && login->exerciseId() > 0)
{
// if priority is higher than current logged in user
if ( login->userId() == m_lastLoginRequest.m_userId || // loginOfMine
(login->priority() > m_lastLoginRequest.m_priority)
)
{
// disconnect current connected user
m_webSocketServer->sendToAllClients( (new STC::DedicatedDisconnect(QUuid::createUuid().toString(), login->userId()))->toReplyMessage() );
// spent time for 'DedicatedDisconnect' to be processed (otherwise race condition):
// (In bad case the high priority user connects, but the vnc answers disconnected. So his btn is still "Connect" btn.)
DEBUG_LOG(m_logger) << "Login request received and DedicatedDisconnect distributed, wait some seconds...";
int i=0;
while(i<20) // 20 * 50ms = 1000ms
{
DEBUG_LOG(m_logger) << "Login request received and DedicatedDisconnect distributed, wait some seconds...i=" << i;
qApp->processEvents(QEventLoop::AllEvents, 50);
QThread::msleep(50);
++i;
}
INFO_LOG(m_logger) << "Login request received and DedicatedDisconnect distributed, wait some seconds... done";
// reply with vnc data
login->addReply((new STC::LoginRequestReply(QUuid::createUuid().toString(),
STC::LoginRequestReply::LoginSuccessful,
login->userId(),
m_vncManager->screens())
)->toReplyMessage());
// save login data for comparision
m_lastLoginRequest.m_userId = login->userId();
m_lastLoginRequest.m_priority = login->priority();
m_lastLoginRequest.m_exerciseId = login->exerciseId();
m_lastLoginRequest.m_settingsData = login->settingsData();
// handle login
slotLoginRequestReceived(login->userId(), login->exerciseId());
INFO_LOG(m_logger) << "Valid login request received -> userId: " << login->userId()
<< " priority: " << login->priority()
<< " exerciseId: " << login->exerciseId();
DEBUG_LOG(m_logger) << "Logging in now!";
}
else
{
login->addReply((new STC::LoginRequestReply(QUuid::createUuid().toString(),
STC::LoginRequestReply::OtherUser,
m_lastLoginRequest.m_userId,
QVector<VncScreen>())
)->toReplyMessage());
DEBUG_LOG(m_logger) << "Higher prioritized login received -> userId: " << login->userId()
<< " priority: " << login->priority()
<< " exerciseId: " << login->exerciseId();
DEBUG_LOG(m_logger) << "Last login data was -> userId: " << m_lastLoginRequest.m_userId
<< " priority: " << m_lastLoginRequest.m_priority
<< " exerciseId: " << m_lastLoginRequest.m_exerciseId;
}
}
else
ERROR_LOG(m_logger) << "invalid login request received -> userId: " << login->userId()
<< " priority: " << login->priority()
<< " exerciseId: " << login->exerciseId();
return;
}
CTS::LogoutRequest *logout = dynamic_cast<CTS::LogoutRequest *>(message);
if (logout)
{
DEBUG_LOG(m_logger) << "Logging out now!";
slotLogoutRequestReceived();
return;
}
CTS::DisconnectRequest *discon = dynamic_cast<CTS::DisconnectRequest *>(message);
if (discon)
{
// NLDEVCTRL-445: Projektion Filter und Kartenausschnitt:
// While working at NLDEVCTRL-445, an mistake occurerd:
// if (m_lastLoginRequest.m_userId = disconnectingUserId)
// ^
// - It is always true
// - it´s not relevant anymore, since the oversteered ows does not block anymore
// Therefore the disconnect happens early (no check necessary)
// -> simplfy be removing the obsolute if stmt
int disconnectingUserId = discon->userId();
INFO_LOG(m_logger) << "Disconnecting now! "
<< ", disconnectingUserId=" << disconnectingUserId
<< ", m_pendingLoginRequest=" << m_pendingLoginRequest;
m_lastLoginRequest = LoginInformation();
return;
}
}
void LtsProjectionWorkstation::slotLoginRequestReceived(int userId, int exerciseId)
{
INFO_LOG(m_logger) << "slotLoginRequestReceived.."
<< ", userId=" << userId
<< ", exerciseId=" << exerciseId;
delete m_pendingLoginRequest;
m_pendingLoginRequest = new LoginInformation(m_lastLoginRequest);
emit signalLoginRequestReceived(userId, exerciseId);
}
void LtsProjectionWorkstation::slotLogoutRequestReceived()
{
emit signalLogoutRequestReceived();
}
void LtsProjectionWorkstation::slotLogoffDone()
{
if (hasPendingLoginRequest())
return;
for (LtsWebSocket::ClientConnection *con : qAsConst(m_connections))
con->webSocket()->close();
}
void LtsProjectionWorkstation::clientDisconnected(LtsWebSocket::ClientConnection *client)
{
INFO_LOG(m_logger) << LOGFUNCTION << " START"
<< ", m_connections.size = " << m_connections.size();
m_connections.removeOne(client);
// check if unclean disconnect happend
if ( m_connections.size() == 0 && (m_lastLoginRequest.m_userId != 0 || m_lastLoginRequest.m_priority != 0))
{
INFO_LOG(m_logger) << LOGFUNCTION << " reset m_lastLoginRequest";
m_lastLoginRequest = LoginInformation(); // reset login data
}
INFO_LOG(m_logger) << LOGFUNCTION << " END"
<< ", m_connections.size = " << m_connections.size();
}
void LtsProjectionWorkstation::clientConnected(LtsWebSocket::ClientConnection *client)
{
m_connections.append(client);
}
void LtsProjectionWorkstation::setProjectionOperatorPreset(const QString &operatorName, const QString &operatorPassword)
{
m_projectionOperatorPreset.first = operatorName;
m_projectionOperatorPreset.second = operatorPassword;
}
} // namespace LtsProjectionWorkstation