Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+318
View File
@@ -0,0 +1,318 @@
/**
* MainHandlerSqlite for SituationReplay
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLSE, 2016-01-13
*/
#include "main_handler_sqlite.h"
#include "db_reader.h"
#include "static_publisher.h"
#include "handler_situation_replay_sqlite.h"
#include <DDS/DDSConnector/dds_connector.h>
#include <ngldb/db_service_handler.h>
#include <ngldb/nsqlquery.h>
#include <LtsScriptTimeline/track_entry.h>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QSet>
#include <QSqlError>
namespace SituationReplay
{
MainHandlerSqlite::MainHandlerSqlite()
: m_curFilterArrayIdx(-1)
, m_curOverlayArrayIdx(-1)
, m_handlerSrp(nullptr)
, m_staticPublisher(nullptr)
, m_ddsInterface(nullptr)
, m_dbHandler(nullptr)
, m_logger(getLogger("MainHandlerSqlite"))
{}
MainHandlerSqlite::~MainHandlerSqlite()
{
m_dbSqlite.close();
m_dbSqlite = QSqlDatabase();
m_staticPublisher = nullptr;
m_dbReader = nullptr;
m_handlerSrp = nullptr;
m_ddsInterface = nullptr;
m_dbHandler = nullptr;
}
bool MainHandlerSqlite::initDb(const ReplayInformation &replayInformation,
const QVector<FilterInformation> &filter,
const QVector<FilterInformation> &overlays)
{
if (!m_ddsInterface)
{
WARNING_LOG(m_logger) << "dds must be initialized first!";
return false;
}
m_replay = replayInformation;
// sort filter & overlays by begin time
const auto cbSort = [](const FilterInformation &a, const FilterInformation &b)
{
if (a.relativeTimeSpan.begin != b.relativeTimeSpan.begin)
return a.relativeTimeSpan.begin < b.relativeTimeSpan.begin;
return a.overlayId < b.overlayId;
};
m_filter = filter;
std::sort(m_filter.begin(), m_filter.end(), cbSort);
m_curFilterArrayIdx = -1;
m_overlays = overlays;
std::sort(m_overlays.begin(), m_overlays.end(), cbSort);
m_curOverlayArrayIdx = -1;
m_staticPublisher = nullptr;
m_handlerSrp = nullptr;
m_dbReader = nullptr;
m_dbHandler = nullptr;
if (m_dbSqlite.isOpen())
{
m_dbSqlite.close();
m_dbSqlite = QSqlDatabase();
QSqlDatabase::removeDatabase(QStringLiteral("sqliteDb"));
}
// initialize database
m_dbSqlite = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), QStringLiteral("sqliteDb"));
m_dbSqlite.setDatabaseName(replayInformation.databaseFilePath);
if (!m_dbSqlite.open())
{
const QString err = m_dbSqlite.lastError().nativeErrorCode();
FATAL_LOG(m_logger) << "Error opening database '" << replayInformation.databaseFilePath << "'";
FATAL_LOG(m_logger) << m_dbSqlite.lastError().driverText() << " "
<< m_dbSqlite.lastError().databaseText() << " " << err;
return false;
}
const QString stmt(QStringLiteral("SELECT id FROM exercise"));
NSqlQuery q(stmt, m_dbSqlite);
const int partitionIdIn = (q.execAndFetch() ? q.value(0).toInt() : 0);
m_dbHandler = std::make_shared<DbHandler>();
if (!m_dbHandler->init(partitionIdIn, m_dbSqlite))
{
ERROR_LOG(m_logger) << "Initialisation dbHandler failed.";
return false;
}
DEBUG_LOG(m_logger) << "opening sqlite db successful";
m_dbReader = std::make_shared<DbReader>(m_ddsInterface->ddsReplay(), partitionIdIn, false);
if (!m_dbReader->init(m_dbHandler->db()->database()))
{
ERROR_LOG(m_logger) << "Could not initialize database reader";
return false;
}
// read project specific data from database
// publish project specific data
// initialize the specific handler
if (!initSrpHandler(partitionIdIn, m_ddsInterface->ddsReplay()->getPartitionId(),
replayInformation.timeSpan.begin, replayInformation.timeSpan.end))
{
ERROR_LOG(m_logger) << "Could not initialize situation replay handler";
return false;
}
if (!initStaticPublisher())
return false;
if (!loadReplayConfig(replayInformation.replayConfigPath))
return false;
return true;
}
bool MainHandlerSqlite::initDds(const SituationReplay::ConnectionParams &output)
{
// initialize DDS
m_ddsInterface = std::make_shared<DdsHandler>(output);
if (!m_ddsInterface->init())
return false;
return true;
}
std::shared_ptr<DDSConnector::DdsConnector> MainHandlerSqlite::ddsReplay() const
{
return m_ddsInterface->ddsReplay();
}
bool MainHandlerSqlite::initSrpHandler(int partitionIdIn, int partitionIdOut, qint64 beginTime, qint64 endTime)
{
m_handlerSrp.reset(new HandlerSituationReplaySqlite(m_ddsInterface, m_dbReader));
if (!m_handlerSrp->init(partitionIdIn, partitionIdOut, beginTime, endTime))
return false;
connect(m_handlerSrp.get(), &HandlerSituationReplaySqlite::replayTimeChanged,
this, &MainHandlerSqlite::onReplayTimeChanged);
connect(m_handlerSrp.get(), &HandlerSituationReplaySqlite::started,
this, &MainHandlerSqlite::onReplayTimeMaybeJumped);
connect(m_handlerSrp.get(), &HandlerSituationReplaySqlite::resumed,
this, &MainHandlerSqlite::onReplayTimeMaybeJumped);
return true;
}
bool MainHandlerSqlite::initStaticPublisher()
{
m_staticPublisher.reset(new StaticPublisher(m_ddsInterface, m_dbSqlite));
connect(m_staticPublisher.get(), &StaticPublisher::fileContentAvailable,
this, &MainHandlerSqlite::fileContentAvailable);
return true;
}
bool MainHandlerSqlite::loadReplayConfig(const QString &replayConfigPath)
{
QFile f(replayConfigPath);
if (!f.open(QIODevice::ReadOnly))
{
WARNING_LOG(m_logger) << "Could not open '" << replayConfigPath << "' for reading - no replay config loaded";
return false;
}
QJsonParseError error;
const QJsonDocument doc(QJsonDocument::fromJson(f.readAll(), &error));
if (error.error != QJsonParseError::NoError)
{
WARNING_LOG(m_logger) << "Could not parse replay config loaded json file: " << error.errorString();
return false;
}
const QJsonObject obj = doc.object();
const double replaySpeed = obj[QStringLiteral("speed")].toDouble(1.0);
emit initialReplaySpeed(replaySpeed);
return true;
}
void MainHandlerSqlite::onReplayTimeChanged(qint64 curTime)
{
maybeApplyNextFilter(curTime);
maybeAddNewOverlay(curTime);
removeOutdatedOverlays(curTime);
}
void MainHandlerSqlite::onReplayTimeMaybeJumped(qint64 curTime)
{
replayTimeMaybeJumpedFilter(curTime);
replayTimeMaybeJumpedOverlays(curTime);
}
void MainHandlerSqlite::maybeApplyNextFilter(qint64 curTime)
{
const int nextIdx = findNextIndex(curTime,
m_curFilterArrayIdx,
m_filter);
if (nextIdx < 0)
return;
m_curFilterArrayIdx = nextIdx;
emit applyCurentFilter(m_filter.at(m_curFilterArrayIdx));
}
void MainHandlerSqlite::replayTimeMaybeJumpedFilter(qint64 curTime)
{
const qint64 curTimeRelative = curTime - m_replay.timeSpan.begin;
m_curFilterArrayIdx = -1;
for (int i = 0; i < m_filter.size(); ++i)
{
const auto &filter = m_filter.at(i);
if (filter.relativeTimeSpan.begin > curTimeRelative)
break;
m_curFilterArrayIdx = i;
}
if (m_curFilterArrayIdx >= 0 && m_curFilterArrayIdx < m_filter.size())
emit applyCurentFilter(m_filter.at(m_curFilterArrayIdx));
}
void MainHandlerSqlite::maybeAddNewOverlay(qint64 curTime)
{
// more than one overlay can start at curTime
while (true)
{
const int nextIdx = findNextIndex(curTime,
m_curOverlayArrayIdx,
m_overlays);
if (nextIdx < 0)
return;
m_curOverlayArrayIdx = nextIdx;
m_currentVisibleOverlays += m_overlays.at(nextIdx);
DEBUG_LOG(m_logger) << "Showing new overlay with id " << m_overlays.at(m_curOverlayArrayIdx).overlayId
<< " at time " << curTime;
emit applyNewOverlay(m_overlays.at(m_curOverlayArrayIdx).overlayId);
}
}
void MainHandlerSqlite::removeOutdatedOverlays(qint64 curTime)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " curTime = "<< curTime
<< " m_currentVisibleOverlays.size()= "<< m_currentVisibleOverlays.size();
const qint64 curTimeRelative = curTime - m_replay.timeSpan.begin + m_replay.relativeTimeSpan.begin; // + m_replay.relativeTimeSpan.begin
for (int i = m_currentVisibleOverlays.size() - 1; i >= 0; --i)
{
const qint64 endTime = m_currentVisibleOverlays.at(i).relativeTimeSpan.end;
DEBUG_LOG(m_logger) << LOGFUNCTION << " curTimeRelative = " << curTimeRelative << " endTime = " << endTime;
if (curTimeRelative > endTime)
{
emit removeOverlay(m_currentVisibleOverlays.at(i).overlayId);
m_currentVisibleOverlays.removeAt(i);
}
}
}
void MainHandlerSqlite::replayTimeMaybeJumpedOverlays(qint64 curTime)
{
// not really optimal
QSet<int> oldOverlayIds;
oldOverlayIds.reserve(m_currentVisibleOverlays.size());
for (const FilterInformation &overlay : qAsConst(m_currentVisibleOverlays))
oldOverlayIds += overlay.overlayId;
m_curOverlayArrayIdx = -1;
m_currentVisibleOverlays.clear();
maybeAddNewOverlay(curTime);
for (const FilterInformation &overlay : qAsConst(m_currentVisibleOverlays))
oldOverlayIds -= overlay.overlayId;
for (const int overlayId : qAsConst(oldOverlayIds))
emit removeOverlay(overlayId);
}
// struct ReplayInformation
// {
// int id = 0;
// TimeSpan timeSpan; // playbackTime msec since epoche
// TimeSpan relativeTimeSpan; // timeInPresentation msec since begin SCRIPT
int MainHandlerSqlite::findNextIndex(qint64 curTime, int curIdx, const QVector<FilterInformation> &data) const
{
const int nextIdx = curIdx + 1;
if (nextIdx < 0 || nextIdx >= data.size())
return -1;
const qint64 curTimeRelative = (curTime - m_replay.timeSpan.begin) + m_replay.relativeTimeSpan.begin;
// ^abs ^absBgn cur Topic/Replay + timeInPresentation since begin SCRIPT
// example: 1645787949000 - 1645787949000 + 375000
// startTime: msec, rel. to begin of SCRIPT
const qint64 startTime = data.at(nextIdx).relativeTimeSpan.begin;
DEBUG_LOG(m_logger) << LOGFUNCTION << " curTimeRelative = " << curTimeRelative << " startTime = " << startTime;
if (curTimeRelative < startTime)
return -1;
return nextIdx;
}
} // namespace SituationReplay