nymea-remoteproxy/libnymea-remoteproxy/engine.cpp

270 lines
7.4 KiB
C++

// SPDX-License-Identifier: LGPL-3.0-or-later
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* nymea-remoteproxy
* Tunnel proxy server for the nymea remote access
*
* Copyright (C) 2013 - 2024, nymea GmbH
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
*
* This file is part of nymea-remoteproxy.
*
* nymea-remoteproxy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* nymea-remoteproxy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with nymea-remoteproxy. If not, see <https://www.gnu.org/licenses/>.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "engine.h"
#include "loggingcategories.h"
#include "../version.h"
namespace remoteproxy {
Engine *Engine::s_instance = nullptr;
Engine *Engine::instance()
{
if (!s_instance) {
qCDebug(dcEngine()) << "Create server engine";
s_instance = new Engine();
}
return s_instance;
}
void Engine::destroy()
{
qCDebug(dcEngine()) << "Destroy server engine";
if (s_instance) {
delete s_instance;
}
s_instance = nullptr;
}
bool Engine::exists()
{
return s_instance != nullptr;
}
void Engine::start(ProxyConfiguration *configuration)
{
if (!m_running)
qCDebug(dcEngine()) << "Start server engine";
// Clean up
clean();
m_configuration = configuration;
qCDebug(dcEngine()) << "Using configuration" << m_configuration;
// Tunnel proxy
// -------------------------------------
m_tunnelProxyServer = new TunnelProxyServer(this);
m_webSocketServerTunnelProxy = new WebSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
m_tcpSocketServerTunnelProxy = new TcpSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
m_unixSocketServerTunnelProxy = new UnixSocketServer(m_configuration->unixSocketFileName(), this);
// Configure websocket server
QUrl websocketServerTunnelProxyUrl;
websocketServerTunnelProxyUrl.setScheme(m_configuration->sslEnabled() ? "wss" : "ws");
websocketServerTunnelProxyUrl.setHost(m_configuration->webSocketServerTunnelProxyHost().toString());
websocketServerTunnelProxyUrl.setPort(m_configuration->webSocketServerTunnelProxyPort());
m_webSocketServerTunnelProxy->setServerUrl(websocketServerTunnelProxyUrl);
// Configure tcp socket server
QUrl tcpSocketServerTunnelProxyUrl;
tcpSocketServerTunnelProxyUrl.setScheme(m_configuration->sslEnabled() ? "ssl" : "tcp");
tcpSocketServerTunnelProxyUrl.setHost(m_configuration->tcpServerTunnelProxyHost().toString());
tcpSocketServerTunnelProxyUrl.setPort(m_configuration->tcpServerTunnelProxyPort());
m_tcpSocketServerTunnelProxy->setServerUrl(tcpSocketServerTunnelProxyUrl);
// Register the transport interfaces in the proxy server
m_tunnelProxyServer->registerTransportInterface(m_webSocketServerTunnelProxy);
m_tunnelProxyServer->registerTransportInterface(m_tcpSocketServerTunnelProxy);
m_tunnelProxyServer->registerTransportInterface(m_unixSocketServerTunnelProxy);
// Start the server
qCDebug(dcEngine()) << "Starting the tunnel proxy manager...";
m_tunnelProxyServer->startServer();
// Monitor server
// -------------------------------------
m_monitorServer = new MonitorServer(configuration->monitorSocketFileName(), this);
m_monitorServer->startServer();
if (configuration->logEngineEnabled())
m_logEngine->enable();
// Set running true in the next event loop
QMetaObject::invokeMethod(this, QString("setRunning").toLatin1().data(), Qt::QueuedConnection, Q_ARG(bool, true));
}
void Engine::stop()
{
if (m_running)
qCDebug(dcEngine()) << "Stop server engine";
clean();
setRunning(false);
}
bool Engine::running() const
{
return m_running;
}
QString Engine::serverName() const
{
return m_configuration->serverName();
}
ProxyConfiguration *Engine::configuration() const
{
return m_configuration;
}
TunnelProxyServer *Engine::tunnelProxyServer() const
{
return m_tunnelProxyServer;
}
UnixSocketServer *Engine::unixSocketServerTunnelProxy() const
{
return m_unixSocketServerTunnelProxy;
}
TcpSocketServer *Engine::tcpSocketServerTunnelProxy() const
{
return m_tcpSocketServerTunnelProxy;
}
WebSocketServer *Engine::webSocketServerTunnelProxy() const
{
return m_webSocketServerTunnelProxy;
}
MonitorServer *Engine::monitorServer() const
{
return m_monitorServer;
}
LogEngine *Engine::logEngine() const
{
return m_logEngine;
}
QVariantMap Engine::buildMonitorData(bool printAll)
{
QVariantMap monitorData;
monitorData.insert("serverName", m_configuration->serverName());
monitorData.insert("serverVersion", SERVER_VERSION_STRING);
monitorData.insert("apiVersion", API_VERSION_STRING);
monitorData.insert("tunnelProxyStatistic", tunnelProxyServer()->currentStatistics(printAll));
return monitorData;
}
Engine::Engine(QObject *parent) :
QObject(parent)
{
m_lastTimeStamp = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch();
m_timer = new QTimer(this);
m_timer->setSingleShot(false);
m_timer->setInterval(50);
connect(m_timer, &QTimer::timeout, this, &Engine::onTimerTick);
m_logEngine = new LogEngine(this);
}
Engine::~Engine()
{
stop();
}
void Engine::onTimerTick()
{
qint64 timestamp = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch();
qint64 deltaTime = timestamp - m_lastTimeStamp;
m_lastTimeStamp = timestamp;
m_currentTimeCounter += deltaTime;
if (m_currentTimeCounter >= 1000) {
// One second passed, do second tick
m_currentTimeCounter = 0;
if (m_tunnelProxyServer) {
m_tunnelProxyServer->tick();
}
}
}
void Engine::clean()
{
if (m_monitorServer) {
m_monitorServer->stopServer();
delete m_monitorServer;
m_monitorServer = nullptr;
}
if (m_tunnelProxyServer) {
m_tunnelProxyServer->stopServer();
delete m_tunnelProxyServer;
m_tunnelProxyServer = nullptr;
}
if (m_tcpSocketServerTunnelProxy) {
delete m_tcpSocketServerTunnelProxy;
m_tcpSocketServerTunnelProxy = nullptr;
}
if (m_webSocketServerTunnelProxy) {
delete m_webSocketServerTunnelProxy;
m_webSocketServerTunnelProxy = nullptr;
}
if (m_unixSocketServerTunnelProxy) {
delete m_unixSocketServerTunnelProxy;
m_unixSocketServerTunnelProxy = nullptr;
}
if (m_configuration) {
delete m_configuration;
m_configuration = nullptr;
}
}
void Engine::setRunning(bool running)
{
if (m_running == running)
return;
if (m_tunnelProxyServer)
m_tunnelProxyServer->setRunning(running);
qCDebug(dcEngine()) << "Engine is" << (running ? "now running." : "not running any more.");
if (running) {
m_timer->start();
} else {
m_timer->stop();
}
m_running = running;
emit runningChanged(m_running);
}
}