252 lines
9.1 KiB
C++
Executable File
252 lines
9.1 KiB
C++
Executable File
/**
|
||
* @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
|