Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+182
@@ -0,0 +1,182 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
INCLUDE(MacroRTIDDSGen)
|
||||
INCLUDE(MacroCodeGenIdl)
|
||||
|
||||
SET(xml_FILE eem_service.xml)
|
||||
|
||||
#
|
||||
# --- Library svcEemCommon --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_common
|
||||
eem_export.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
)
|
||||
|
||||
# Generate eem_enums.idl / eem.idl
|
||||
CODEGEN_IDL_SVC(SRCS_common ${xml_FILE})
|
||||
# Generate eem_db_structs.cpp/.h
|
||||
CODEGEN_DATABASE_STRUCTS(SRCS_common ${xml_FILE})
|
||||
# Generate eem_db_impl.cpp/.h
|
||||
CODEGEN_DATABASE_SQL(SRCS_common ${xml_FILE})
|
||||
|
||||
# Generate *.cpp/*.hpp from idl
|
||||
RTIDDSGEN(SRCS_common eem_enums.idl)
|
||||
RTIDDSGEN(SRCS_common eem.idl)
|
||||
|
||||
# Generate eem_dt[s,c]_types.h, eem_ft[s,c]_types.h
|
||||
CODEGEN_TOPIC_TYPEDEFS(SRCS_common ${xml_FILE})
|
||||
|
||||
# generate eem_[d|f]tc.h
|
||||
CODEGEN_CLIENT_TOPICS_IFC(SRCS_common ${xml_FILE} PARTS DTC)
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV WS svcEemCommon SHARED ${SRCS_common})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcEemCommon
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(svcEemCommon
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
ddscore
|
||||
LtsCommandLineParser
|
||||
NGLLogger
|
||||
ngldb
|
||||
svcPdmCommon
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcEemCommon)
|
||||
|
||||
#
|
||||
# --- Library svcEemClient --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_client
|
||||
eem_export.h
|
||||
)
|
||||
# generate eem_[d|f]tc.h, eem_[d|f]tc_impl.[cpp|h]
|
||||
CODEGEN_CLIENT_TOPICS_IMPL(SRCS_client ${xml_FILE} PARTS DTC)
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV WS svcEemClient SHARED ${SRCS_client})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcEemClient
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(svcEemClient
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
ddsconnector
|
||||
PUBLIC
|
||||
svcEemCommon
|
||||
ddsftc
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcEemClient)
|
||||
|
||||
#
|
||||
# --- Library svcEemServer --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_server
|
||||
eem_export.h
|
||||
)
|
||||
# generate eem_[d|f]ts.h, eem_[d|f]ts_impl.[cpp|h]
|
||||
CODEGEN_SERVER_TOPICS(SRCS_server ${xml_FILE} PARTS DTS)
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV svcEemServer SHARED ${SRCS_server})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcEemServer
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(svcEemServer
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
ddsconnector
|
||||
ddsfts
|
||||
PUBLIC
|
||||
svcEemCommon
|
||||
ngldb
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcEemServer)
|
||||
|
||||
#
|
||||
# --- Topic Type Plugin --------------------------------------------------------------
|
||||
#
|
||||
CREATE_TOPIC_TYPE_PLUGIN(${xml_FILE})
|
||||
|
||||
#
|
||||
# --- Executable svcTimeLineManagement (sTLM) -------------------------------------------------
|
||||
#
|
||||
SET(SRCS_exe
|
||||
main.cpp
|
||||
main_handler.cpp
|
||||
main_handler.h
|
||||
dds_handler.cpp
|
||||
dds_handler.h
|
||||
handler_dynamic_participant_data.cpp
|
||||
handler_dynamic_participant_data.h
|
||||
handler_equipment_error_registration.cpp
|
||||
handler_equipment_error_registration.h
|
||||
handler_participant_event.cpp
|
||||
handler_participant_event.h
|
||||
settings.cpp
|
||||
settings.h
|
||||
web_socket_avs.cpp
|
||||
web_socket_avs.h
|
||||
web_socket_server.cpp
|
||||
web_socket_server.h
|
||||
${xml_FILE}
|
||||
)
|
||||
|
||||
# Generate eem.sql, eem.xml
|
||||
CODEGEN_SQL(SRCS_exe ${xml_FILE})
|
||||
|
||||
NGL_ADD_SVC_ICON(SRCS_exe)
|
||||
NGL_ADD_EXECUTABLE(AAR SV svcExerciseEventManagement ${SRCS_exe})
|
||||
NGL_TARGET_LINK_LIBRARIES(svcExerciseEventManagement
|
||||
Qt5::Core
|
||||
svcAlmServer
|
||||
svcFltServer
|
||||
svcMrkServer
|
||||
svcEvlServer
|
||||
|
||||
svcBldClient
|
||||
svcCesClient
|
||||
svcAesClient
|
||||
svcCoreClient
|
||||
svcEemCommon
|
||||
svcEemServer
|
||||
svcOssClient
|
||||
svcPpmClient
|
||||
svcAvmClient
|
||||
svcIsmCommon
|
||||
svcIsmClient
|
||||
svcPdmClient
|
||||
|
||||
ddsconnector
|
||||
nglsettings
|
||||
ProjectConfig
|
||||
LtsCommandLineParser
|
||||
LtsUtilsCoreHeaderOnly
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
ngltools
|
||||
Qt5::WebSockets
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcExerciseEventManagement)
|
||||
NGL_INSTALL(AAR SV FILES log4cxx_eem.props DESTINATION bin)
|
||||
NGL_ADD_TARGET_LINK(svcExerciseEventManagement sEEM)
|
||||
|
||||
# Uncomment if necessary
|
||||
#ADD_SUBDIRECTORY(UnitTests)
|
||||
ADD_SUBDIRECTORY(ModuleTests)
|
||||
ADD_SUBDIRECTORY(WebSocketServer)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
|
||||
IF(BUILD_TESTING AND BUILD_SV)
|
||||
|
||||
SET(SRCS_TEST_EEM
|
||||
eem_tests.cpp
|
||||
)
|
||||
SET(HDRS_TEST_EEM
|
||||
eem_tests.h
|
||||
)
|
||||
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(eemTests
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
# Testing FunctionTopic Functionality (FTC)
|
||||
ADD_EXECUTABLE(eemTests ${SRCS_TEST_EEM} ${HDRS_TEST_EEM})
|
||||
TARGET_LINK_LIBRARIES(eemTests
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
RTI::nddscpp2
|
||||
svcEemClient
|
||||
svcTabServer
|
||||
svcPpmServer
|
||||
svcBldServer
|
||||
svcGimServer
|
||||
svcCoreClient
|
||||
LtsCommandLineParser
|
||||
ddsconnector
|
||||
nglcoreapplication
|
||||
|
||||
)
|
||||
IF(NOT BUILD_RPM)
|
||||
NGL_INSTALL(AAR SV TARGETS eemTests DESTINATION bin/test)
|
||||
NGL_INSTALL(AAR SV FILES ../log4cxx_eem.props DESTINATION bin/test)
|
||||
ENDIF()
|
||||
|
||||
ENDIF()
|
||||
|
||||
@@ -0,0 +1,468 @@
|
||||
/**
|
||||
* Tlm Function Topic Module Test
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "eem_tests.h"
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QTest>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <LtsUtilsCore/json_object.h>
|
||||
|
||||
/* Module tests for ExerciseEventManagement
|
||||
* 1. Dynamic data
|
||||
* 2. IED Events
|
||||
* 3. Fire events
|
||||
* 4. Bite messages
|
||||
* 5. Hit Building
|
||||
* 6. Sanitation events
|
||||
*/
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
EemTests::EemTests(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_logger(getLogger("Test"))
|
||||
{}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
bool EemTests::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
bool bRet = true;
|
||||
DEBUG_LOG(m_logger) << "init begin";
|
||||
|
||||
m_testId = testId;
|
||||
|
||||
m_ddsConnector42 = std::make_shared<DDSConnector::DdsConnector>(domainId, IDL::PartitionType::Exercise, exerciseId);
|
||||
m_ddsConnector42->init();
|
||||
m_ddsConnector42->initPublisherSubscriber();
|
||||
|
||||
m_ppmDts = ParticipantManagement::Interface::Dts::create(m_ddsConnector42);
|
||||
bRet &= m_ppmDts->enableDynamicParticipantData();
|
||||
|
||||
m_tabDts = TrainingAreaBase::Interface::Dts::create(m_ddsConnector42);
|
||||
bRet &= m_tabDts->enableEquipmentGearEvent();
|
||||
bRet &= m_tabDts->enableEquipmentGearChargeState();
|
||||
bRet &= m_tabDts->enableEquipmentGearAssignment();
|
||||
bRet &= m_tabDts->enableEquipmentBite();
|
||||
|
||||
m_gimDts = GuezIedManagement::Interface::Dts::create(m_ddsConnector42);
|
||||
bRet &= m_gimDts->enableIed();
|
||||
|
||||
m_dtc = ExerciseEventManagement::Interface::Dtc::create(m_ddsConnector42);
|
||||
bRet &= m_dtc->enableEvent();
|
||||
|
||||
m_bldDts = Buildings::Interface::Dts::create(m_ddsConnector42);
|
||||
bRet &= m_bldDts->enableBuildingState();
|
||||
|
||||
DEBUG_LOG(m_logger) << "bRet: " << bRet;
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void EemTests::startTest()
|
||||
{
|
||||
INFO_LOG(m_logger) << "startTest m_testId = " << m_testId;
|
||||
|
||||
if (m_testId == 1) // publish dynamicParticipantData
|
||||
{
|
||||
const qint64 time = QDateTime::currentMSecsSinceEpoch();
|
||||
tryCreateDynamicParticipantData(1, ProjectDataManagement::VulnerabilityState::MediumDamage, time - 15000 * 60, 38);
|
||||
QTest::qWait(500);
|
||||
tryCreateDynamicParticipantData(2, ProjectDataManagement::VulnerabilityState::MediumDamage, time - 13000 * 30, 38);
|
||||
QTest::qWait(500);
|
||||
tryCreateDynamicParticipantData(1, ProjectDataManagement::VulnerabilityState::HeavyDamage, time - 10000 * 60, 38);
|
||||
QTest::qWait(500);
|
||||
tryCreateDynamicParticipantData(1, ProjectDataManagement::VulnerabilityState::MobilityKill, time - 8000 * 30, 38);
|
||||
QTest::qWait(500);
|
||||
tryCreateDynamicParticipantData(2, ProjectDataManagement::VulnerabilityState::MobilityKill, time - 6000 * 60, 38);
|
||||
QTest::qWait(500);
|
||||
tryCreateDynamicParticipantData(1, ProjectDataManagement::VulnerabilityState::CatastrophicKill, time - 4000 * 30, 38);
|
||||
QTest::qWait(500);
|
||||
tryCreateDynamicParticipantData(2, ProjectDataManagement::VulnerabilityState::CatastrophicKill, time - 2000, 38);
|
||||
QTest::qWait(500);
|
||||
}
|
||||
|
||||
if (m_testId == 2)
|
||||
{
|
||||
//ied
|
||||
const qint64 time = QDateTime::currentMSecsSinceEpoch();
|
||||
tryCreateIed(time - 1000 * 60);
|
||||
QTest::qWait(500);
|
||||
|
||||
// dynamic participant data for ied
|
||||
tryCreateDynamicParticipantData(1, ProjectDataManagement::VulnerabilityState::HeavyDamage, time + 1000 * 60, 49, ProjectDataManagement::StateChangeOriginator::ImprovisedExplosiveDevice);
|
||||
QTest::qWait(500);
|
||||
tryCreateDynamicParticipantData(1, ProjectDataManagement::VulnerabilityState::MobilityKill, time + 2000 * 60, 49, ProjectDataManagement::StateChangeOriginator::ImprovisedExplosiveDevice);
|
||||
QTest::qWait(500);
|
||||
tryCreateDynamicParticipantData(1, ProjectDataManagement::VulnerabilityState::CatastrophicKill, time + 3000 * 60, 70, ProjectDataManagement::StateChangeOriginator::ImprovisedExplosiveDevice);
|
||||
QTest::qWait(5000);
|
||||
|
||||
checkEvents(ProjectDataManagement::EventType::HitEffectSimulation, 3);
|
||||
}
|
||||
|
||||
if (m_testId == 3)
|
||||
trySendFireEvent();
|
||||
|
||||
if (m_testId == 4)
|
||||
trySendBiteMessage();
|
||||
|
||||
if (m_testId == 5)
|
||||
trySendBuildingState();
|
||||
|
||||
if (m_testId == 6)
|
||||
{
|
||||
const qint64 time = QDateTime::currentMSecsSinceEpoch();
|
||||
tryCreateDynamicParticipantData(2, ProjectDataManagement::VulnerabilityState::HeavyDamage, time - 10000 * 60, 0, ProjectDataManagement::StateChangeOriginator::Sanitation);
|
||||
QTest::qWait(500);
|
||||
tryCreateDynamicParticipantData(2, ProjectDataManagement::VulnerabilityState::MediumDamage, time - 8000 * 30, 0, ProjectDataManagement::StateChangeOriginator::Sanitation);
|
||||
QTest::qWait(500);
|
||||
tryCreateDynamicParticipantData(2, ProjectDataManagement::VulnerabilityState::LightDamage, time - 5000 * 30, 0, ProjectDataManagement::StateChangeOriginator::Sanitation);
|
||||
QTest::qWait(500);
|
||||
|
||||
checkEvents(ProjectDataManagement::EventType::Sanitation, 3);
|
||||
}
|
||||
|
||||
if (m_testId <= 0 || m_testId > 6)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Unknown test case: " << m_testId;
|
||||
failExit();
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void EemTests::tryCreateDynamicParticipantData(int participantId, ProjectDataManagement::VulnerabilityState vulnState, qint64 time, int chargeTypeId,
|
||||
ProjectDataManagement::StateChangeOriginator originator)
|
||||
{
|
||||
ParticipantManagement::DynamicParticipantData dp;
|
||||
const rti::core::int64 esTime = static_cast<rti::core::int64>(time);
|
||||
ParticipantManagement::StateInformation si;
|
||||
si.stateTime(esTime);
|
||||
si.vulnerabilityState(vulnState);
|
||||
if (chargeTypeId > 0)
|
||||
si.originatorChargeTypeId(chargeTypeId);
|
||||
si.originatorId(participantId + 1);
|
||||
si.originatorType(originator);
|
||||
si.vitality(100);
|
||||
if (originator == ProjectDataManagement::StateChangeOriginator::Sanitation)
|
||||
{
|
||||
si.sanitationResult(ParticipantManagement::SanitationResult::Sufficient);
|
||||
si.sanitationProceduresTaken(1);
|
||||
}
|
||||
|
||||
dp.participantId(participantId);
|
||||
//dp.isManipulated(true);
|
||||
dp.stateHistory().push_back(si);
|
||||
dp.sampleTime(esTime);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Publishing DynamicParticipantData for participant " << participantId ;
|
||||
if (!m_ppmDts->publish(dp))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting create DynamicParticipantData";
|
||||
failExit();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void EemTests::trySendFireEvent()
|
||||
{
|
||||
TrainingAreaBase::EquipmentGearAssignment gearAssigment;
|
||||
|
||||
gearAssigment.equipmentNumber(1002);
|
||||
gearAssigment.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
std::vector<TrainingAreaBase::Gear> gears;
|
||||
|
||||
gears.resize(2);
|
||||
gears[0].gearId(132456);
|
||||
gears[0].gearTypeId(1003); // Sniper
|
||||
gears[1].gearId(45778);
|
||||
gears[1].gearTypeId(1006); // HMG
|
||||
|
||||
gearAssigment.gears(gears);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Publish EquipmentGearAssigment";
|
||||
if (!m_tabDts->publish(gearAssigment))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while publishing EquipmentGearAssigment";
|
||||
failExit();
|
||||
}
|
||||
|
||||
TrainingAreaBase::EquipmentGearChargeState gearChargeState;
|
||||
|
||||
gearChargeState.equipmentNumber(1002);
|
||||
gearChargeState.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
|
||||
std::vector<TrainingAreaBase::GearCharge> vGearCharge;
|
||||
vGearCharge.resize(1);
|
||||
vGearCharge[0].gearId(132456);
|
||||
vGearCharge[0].gearTypeId(1003);
|
||||
vGearCharge[0].chargeTypeId(44);
|
||||
vGearCharge[0].remain(250);
|
||||
|
||||
gearChargeState.charge(vGearCharge);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Publish EquipmentGearChargeState";
|
||||
if (!m_tabDts->publish(gearChargeState))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while publishing EquipmentGearChargeState";
|
||||
failExit();
|
||||
}
|
||||
|
||||
TrainingAreaBase::EquipmentGearEvent gearEvent;
|
||||
gearEvent.equipmentNumber(1002);
|
||||
gearEvent.sampleTime(QDateTime::currentMSecsSinceEpoch()+1000);
|
||||
|
||||
TrainingAreaBase::GearCharge gc;
|
||||
gc.gearId(132456);
|
||||
gc.gearTypeId(1003);
|
||||
gc.chargeTypeId(44);
|
||||
gc.remain(200);
|
||||
gearEvent.chargeAmount(200);
|
||||
gearEvent.charge(gc);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Publish EquipmentGearEvent";
|
||||
if (!m_tabDts->publish(gearEvent))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while publishing EquipmentGearEvent";
|
||||
failExit();
|
||||
}
|
||||
|
||||
gearEvent.equipmentNumber(1003);
|
||||
gc.gearId(45678);
|
||||
gc.gearTypeId(1009);
|
||||
gc.chargeTypeId(9);
|
||||
gc.remain(350);
|
||||
gearEvent.chargeAmount(100);
|
||||
gearEvent.charge(gc);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Publish EquipmentGearEvent";
|
||||
if (!m_tabDts->publish(gearEvent))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while publishing EquipmentGearEvent";
|
||||
failExit();
|
||||
}
|
||||
|
||||
QTest::qWait(2000);
|
||||
|
||||
const QMap<qint64, ExerciseEventManagement::Event> events = m_dtc->events();
|
||||
|
||||
DEBUG_LOG(m_logger) << "events: " << events.size();
|
||||
|
||||
int noEvents = 0;
|
||||
for(const ExerciseEventManagement::Event &e : events)
|
||||
{
|
||||
INFO_LOG(m_logger) << "eventId: " << e.id() << ", eventType: " << e.eventTypeId().underlying();
|
||||
if (e.eventTypeId() == ProjectDataManagement::EventType_def::WeaponAssignment ||
|
||||
e.eventTypeId() == ProjectDataManagement::EventType_def::FireEvent)
|
||||
noEvents ++;
|
||||
}
|
||||
|
||||
if (noEvents != 5)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error number of events (" << QString::number(noEvents) << ") not as expected (5)";
|
||||
failExit();
|
||||
}
|
||||
|
||||
QTimer::singleShot(500, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void EemTests::trySendBiteMessage()
|
||||
{
|
||||
TrainingAreaBase::EquipmentBite bite;
|
||||
|
||||
bite.batteryState(2);
|
||||
bite.equipmentNumber(1002);
|
||||
bite.biteState(16);
|
||||
bite.configError(true);
|
||||
bite.configState(8);
|
||||
bite.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
|
||||
std::vector<TrainingAreaBase::EquipmentBiteError> beVec;
|
||||
beVec.resize(2);
|
||||
|
||||
beVec[0].canDeviceNumber(1000);
|
||||
beVec[0].errorNumber(23);
|
||||
beVec[0].subdeviceNumber(110);
|
||||
beVec[0].uniqueId(198765);
|
||||
|
||||
beVec[1].canDeviceNumber(1001);
|
||||
beVec[1].errorNumber(24);
|
||||
beVec[1].subdeviceNumber(111);
|
||||
beVec[1].uniqueId(9876);
|
||||
|
||||
bite.biteErrors(beVec);
|
||||
|
||||
if (!m_tabDts->publish(bite))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while publishing EquipmentBite";
|
||||
failExit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void EemTests::trySendBuildingState()
|
||||
{
|
||||
Buildings::BuildingState bState;
|
||||
|
||||
bState.id(301);
|
||||
bState.damagePercent(80);
|
||||
bState.damagePercentOld(0);
|
||||
bState.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
bState.vulnerabilityState(ProjectDataManagement::VulnerabilityState::CatastrophicKill);
|
||||
bState.structureElementId(26);
|
||||
// bState.aesId(1);
|
||||
// bState.assetId(10);
|
||||
// bState.chargeTypeId(44);
|
||||
// bState.originatorType(ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation);
|
||||
// bState.originatorParticipantId(6);
|
||||
|
||||
if (!m_bldDts->publish(bState))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while publishing building state";
|
||||
failExit();
|
||||
}
|
||||
|
||||
QTest::qWait(2000); // wait until it is really published
|
||||
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void EemTests::tryCreateIed(qint64 time)
|
||||
{
|
||||
GuezIedManagement::Ied ied;
|
||||
|
||||
ied.id(100);
|
||||
ied.name("Test IED");
|
||||
ied.partyId(4);
|
||||
ied.equipmentNumber(1003);
|
||||
ied.type(GuezIedManagement::IedType::IedBigPyro);
|
||||
ied.explosiveForce(100);
|
||||
ied.pairingState(GuezIedManagement::IedPairingState_def::NotPaired);
|
||||
ied.tacticalState(GuezIedManagement::IedTacticalState_def::TriggeredByControlDevice);
|
||||
ied.pyrotechnics(true);
|
||||
ied.symbol("AP6D|CMPL|10014000001103000000");
|
||||
const rti::core::int64 esTime = static_cast<rti::core::int64>(time);
|
||||
ied.sampleTime(esTime);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Publishing Ied " ;
|
||||
if (!m_gimDts->publish(ied))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting publish Ied";
|
||||
failExit();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void EemTests::checkEvents(const ProjectDataManagement::EventType &et, int expected)
|
||||
{
|
||||
const QMap<qint64, ExerciseEventManagement::Event> events = m_dtc->events();
|
||||
|
||||
DEBUG_LOG(m_logger) << "All published events: " << events.size();
|
||||
int noEvents = 0;
|
||||
|
||||
for (const ExerciseEventManagement::Event &e : events)
|
||||
{
|
||||
INFO_LOG(m_logger) << "eventId: " << e.id() << ", eventType: " << e.eventTypeId().underlying();
|
||||
if (e.eventTypeId() == et)
|
||||
{
|
||||
QJsonObject prop = LtsUtils::JsonObject::fromJson(e.properties());
|
||||
|
||||
int ot = prop[QStringLiteral("OriginatorType")].toInt();
|
||||
if (et == ProjectDataManagement::EventType::HitEffectSimulation && ot == 20) //ImprovisedExplosiveDevice
|
||||
noEvents ++;
|
||||
if (et == ProjectDataManagement::EventType::Sanitation && ot == 10) // Sanitation
|
||||
noEvents ++;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "No events: " << noEvents;
|
||||
|
||||
if (noEvents != expected)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error number of events (" << QString::number(noEvents) << ") not as expected (" << QString::number(expected) << ")";
|
||||
failExit();
|
||||
}
|
||||
|
||||
QTimer::singleShot(500, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void EemTests::failExit()
|
||||
{
|
||||
m_bTestsSuccessful = false;
|
||||
QTimer::singleShot(50, qApp, QCoreApplication::quit);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void EemTests::ExitSuccess()
|
||||
{
|
||||
m_bTestsSuccessful = true;
|
||||
QTimer::singleShot(50, qApp, QCoreApplication::quit);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser()
|
||||
{
|
||||
addOption({ QStringList() << QLatin1String("t") << QLatin1String("testId")
|
||||
, QLatin1String("TestId.")
|
||||
, QLatin1String("Default: -1 (Unknown)")
|
||||
, QLatin1String("0")
|
||||
});
|
||||
}
|
||||
int testId() const { return isSet(QLatin1String("t")) ? value(QLatin1String("t")).toInt() : -1; }
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
|
||||
int iRet = -1;
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return iRet;
|
||||
|
||||
app.createLogger("EEM", options.exerciseId());
|
||||
|
||||
std::unique_ptr<ExerciseEventManagement::EemTests> EemTests(new ExerciseEventManagement::EemTests);
|
||||
|
||||
if (!EemTests->init(options.domainId(), options.exerciseId(), options.testId()))
|
||||
return iRet;
|
||||
|
||||
EemTests->startTest();
|
||||
|
||||
STARTUP_LOG(app.baseLogger());
|
||||
|
||||
app.exec();
|
||||
|
||||
iRet = EemTests->testsSuccessful() ? 0 : 1;
|
||||
fprintf(stderr, "%d\n", iRet);
|
||||
|
||||
DEBUG_LOG(app.baseLogger()) << "** TEST result = " << iRet;
|
||||
|
||||
SHUTDOWN_LOG(app.baseLogger());
|
||||
|
||||
return iRet;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* ModuleTests for TimeLimeManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ParticipantManagement/ppm_dts.h>
|
||||
#include <TrainingAreaBase/tab_dts.h>
|
||||
#include <GuezIedManagement/gim_dts.h>
|
||||
#include <Proxies/Buildings/bld_dts.h>
|
||||
#include <ExerciseEventManagement/eem_dtc.h>
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <ExerciseEventManagement/logger.h>
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
class EemTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit EemTests(QObject *parent = nullptr);
|
||||
~EemTests() = default;
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId);
|
||||
|
||||
bool testsSuccessful() const
|
||||
{
|
||||
return m_bTestsSuccessful;
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
void startTest();
|
||||
protected Q_SLOTS:
|
||||
|
||||
void tryCreateDynamicParticipantData(int participantId, ProjectDataManagement::VulnerabilityState vulnState, qint64 time, int chargeTypeId,
|
||||
ProjectDataManagement::StateChangeOriginator originator = ProjectDataManagement::StateChangeOriginator::Participant);
|
||||
void trySendFireEvent();
|
||||
void trySendBiteMessage();
|
||||
void trySendBuildingState();
|
||||
void tryCreateIed(qint64 time);
|
||||
void checkEvents(const ProjectDataManagement::EventType &et, int expected);
|
||||
|
||||
void failExit();
|
||||
void ExitSuccess();
|
||||
private:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector42;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dts> m_ppmDts;
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dts> m_tabDts;
|
||||
std::shared_ptr<Buildings::Interface::Dts> m_bldDts;
|
||||
std::shared_ptr<GuezIedManagement::Interface::Dts> m_gimDts;
|
||||
std::shared_ptr<ExerciseEventManagement::Interface::Dtc> m_dtc;
|
||||
bool m_bTestsSuccessful{true};
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
int m_testId{0};
|
||||
};
|
||||
|
||||
} // namespace ExerciseEventManagement
|
||||
@@ -0,0 +1,22 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(websocket_SRCS
|
||||
main.cpp
|
||||
web_socket_handler.cpp
|
||||
web_socket_handler.h
|
||||
)
|
||||
|
||||
NGL_ADD_EXECUTABLE(AAR SV webSocketServer ${websocket_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(webSocketServer
|
||||
Qt5::WebSockets
|
||||
Qt5::Core
|
||||
Qt5::Network
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
svcEemCommon
|
||||
)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* main for TimeLineManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
|
||||
|
||||
#include "web_socket_handler.h"
|
||||
#include "../logger.h"
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
|
||||
app.createLogger("WebSocketServer", -1);
|
||||
|
||||
|
||||
int iRet = -3;
|
||||
{
|
||||
|
||||
ExerciseEventManagement::WebSocketHandler webSocketServer;
|
||||
|
||||
webSocketServer.init(7020);
|
||||
|
||||
STARTUP_LOG(app.baseLogger());
|
||||
|
||||
iRet = app.exec();
|
||||
|
||||
SHUTDOWN_LOG(app.baseLogger());
|
||||
}
|
||||
|
||||
return iRet;
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Websocket interface for building control unit
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-01-30
|
||||
*/
|
||||
|
||||
#include "web_socket_handler.h"
|
||||
#include <QWebSocket>
|
||||
#include <iostream>
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
|
||||
WebSocketHandler::WebSocketHandler(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_webSocketServer(new QWebSocketServer(QStringLiteral("AVS-Server"), QWebSocketServer::NonSecureMode, this))
|
||||
, m_timer(new QTimer())
|
||||
, m_logger(getLogger("Json.WebSocketHandler"))
|
||||
{
|
||||
connect(m_timer, &QTimer::timeout,
|
||||
this, &WebSocketHandler::onSendMessage);
|
||||
|
||||
m_timer->start(1000);
|
||||
|
||||
}
|
||||
|
||||
WebSocketHandler::~WebSocketHandler()
|
||||
{
|
||||
for (auto s : qAsConst(m_webSockets))
|
||||
{
|
||||
s->disconnect(this);
|
||||
s->close();
|
||||
}
|
||||
qDeleteAll(m_webSockets);
|
||||
}
|
||||
|
||||
bool WebSocketHandler::init(quint16 listenPort)
|
||||
{
|
||||
if (!m_webSocketServer->listen(QHostAddress::Any, listenPort))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not listen on port " << listenPort << " - aborting";
|
||||
return false;
|
||||
}
|
||||
// inform calling process via stdout about the port/url
|
||||
std::cout << "web socket listen port: " << m_webSocketServer->serverPort() << std::endl;
|
||||
std::cout << "web socket url: " << m_webSocketServer->serverUrl().toString() << std::endl;
|
||||
connect(m_webSocketServer, &QWebSocketServer::newConnection,
|
||||
this, &WebSocketHandler::onNewConnection);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebSocketHandler::sendTelegram(const QString &jsonStr)
|
||||
{
|
||||
if (!isConnected())
|
||||
return false;
|
||||
|
||||
ERROR_LOG(m_logger) << "jsonStr" << jsonStr;
|
||||
|
||||
bool bOk = false;
|
||||
for (QWebSocket *ws : qAsConst(m_webSockets))
|
||||
{
|
||||
if (ws->sendTextMessage(jsonStr))
|
||||
bOk = true;
|
||||
}
|
||||
|
||||
return bOk;
|
||||
}
|
||||
|
||||
|
||||
void WebSocketHandler::onNewConnection()
|
||||
{
|
||||
QWebSocket *ws = m_webSocketServer->nextPendingConnection();
|
||||
if (!ws)
|
||||
return;
|
||||
INFO_LOG(m_logger) << "New websocket connection from " << ws->peerAddress().toString() << ":" << ws->peerPort();
|
||||
|
||||
connect(ws, &QWebSocket::disconnected,
|
||||
this, &WebSocketHandler::onWebSocketDisconnected);
|
||||
|
||||
m_webSockets += ws;
|
||||
|
||||
emit webSocketConnected(ws);
|
||||
}
|
||||
|
||||
void WebSocketHandler::onSendMessage()
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Send message: ";
|
||||
|
||||
QJsonObject obj;
|
||||
|
||||
obj[QStringLiteral("eventTime")] = QJsonValue(QDateTime::currentMSecsSinceEpoch());
|
||||
|
||||
QString jsonStr = QString::fromUtf8(QJsonDocument(obj).toJson());
|
||||
sendTelegram(jsonStr);
|
||||
|
||||
}
|
||||
|
||||
void WebSocketHandler::onWebSocketDisconnected()
|
||||
{
|
||||
QWebSocket *ws = qobject_cast<QWebSocket *>(sender());
|
||||
if (!ws)
|
||||
return;
|
||||
m_webSockets.remove(ws);
|
||||
ws->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
} // namespace ExerciseEventManagement
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Websocket interface for building control unit
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-01-30
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QWebSocketServer>
|
||||
#include <memory>
|
||||
#include <QTimer>
|
||||
#include "../logger.h"
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
|
||||
class WebSocketHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WebSocketHandler(QObject *parent = nullptr);
|
||||
~WebSocketHandler();
|
||||
|
||||
bool init(quint16 listenPort);
|
||||
|
||||
bool isConnected() const
|
||||
{
|
||||
return !m_webSockets.isEmpty();
|
||||
}
|
||||
bool sendTelegram(const QString &jsonStr);
|
||||
|
||||
Q_SIGNALS:
|
||||
void webSocketConnected(QWebSocket *ws);
|
||||
private Q_SLOTS:
|
||||
void onNewConnection();
|
||||
void onWebSocketDisconnected();
|
||||
void onSendMessage();
|
||||
private:
|
||||
QWebSocketServer *m_webSocketServer;
|
||||
QSet<QWebSocket *> m_webSockets;
|
||||
QTimer *m_timer;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ExerciseEventManagement
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* DdsHandler for DDS
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-09-02
|
||||
*/
|
||||
|
||||
#include "dds_handler.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
|
||||
DdsHandler::DdsHandler(int domainId, int partitionId, IDL::PartitionType partitionType)
|
||||
: m_ddsConnector(std::make_shared<DDSConnector::DdsConnector>(domainId, partitionType, partitionId))
|
||||
, m_logger(getLogger("DdsHandler"))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "DdsHandler(" << domainId << ") for partition: " << m_ddsConnector->getDefaultPartition();
|
||||
}
|
||||
|
||||
DdsHandler::~DdsHandler()
|
||||
{
|
||||
}
|
||||
|
||||
bool DdsHandler::init(const QStringList &qosFileList)
|
||||
{
|
||||
TRACE_LOG(m_logger) << " START, this=" << this;
|
||||
|
||||
if (!m_ddsConnector->init(qosFileList))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing dds connections - aborting";
|
||||
return false;
|
||||
}
|
||||
|
||||
// default initialize Publisher and Subscriber
|
||||
m_ddsConnector->initPublisherSubscriber();
|
||||
|
||||
// has to be false, because Snapshot Data Topics can be very large and fragmentation is not supported for batched writers!
|
||||
m_ddsConnector->enableBatchedWriter(false);
|
||||
|
||||
// Pacemaker
|
||||
m_pacemaker = new Core::Pacemaker(m_ddsConnector);
|
||||
|
||||
m_ddsDts = ExerciseEventManagement::Interface::Dts::create(m_ddsConnector);
|
||||
|
||||
bool bRet = m_ddsDts->enableAll();
|
||||
INFO_LOG(m_logger) << "Dts initialised";
|
||||
|
||||
// Subsribe for InfrastructureManagement::MainStructureElement
|
||||
m_dtcIsm = InfrastructureManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
|
||||
TRACE_LOG(m_logger) << " END, this=" << this;
|
||||
return bRet;
|
||||
}
|
||||
|
||||
void DdsHandler::setRunningState(Core::RunningState rs)
|
||||
{
|
||||
if (!m_pacemaker)
|
||||
return;
|
||||
m_pacemaker->setNewState(rs);
|
||||
}
|
||||
|
||||
void DdsHandler::addPortToPacemaker(quint16 port, Core::PortType type)
|
||||
{
|
||||
if (!m_pacemaker)
|
||||
return;
|
||||
m_pacemaker->addPort(port, type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // Namespace ExerciseEventManagement
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* DdsHandler for DDS
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-09-02
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <DDS/Core/pacemaker.h>
|
||||
#include <ExerciseEventManagement/eem_dts.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include "logger.h"
|
||||
|
||||
class QThread;
|
||||
namespace Core
|
||||
{
|
||||
class Pacemaker;
|
||||
}
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
class DdsHandler final
|
||||
{
|
||||
public:
|
||||
DdsHandler(int domainId, int partitionId, IDL::PartitionType partitionType);
|
||||
~DdsHandler();
|
||||
|
||||
bool init(const QStringList &qosFileList = QStringList());
|
||||
|
||||
void setRunningState(Core::RunningState rs);
|
||||
void addPortToPacemaker(quint16 port, Core::PortType type);
|
||||
|
||||
std::shared_ptr<DDSConnector::DdsConnector> ddsConnector() const { return m_ddsConnector; }
|
||||
std::shared_ptr<ExerciseEventManagement::Interface::Dts> dts() const { return m_ddsDts; }
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> dtcIsm() const { return m_dtcIsm;} ///< Pointer to DTC InfrastructureManagement interface object
|
||||
|
||||
private:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
std::shared_ptr<ExerciseEventManagement::Interface::Dts> m_ddsDts;
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_dtcIsm; ///< Pointer to DTC InfrastructureManagement interface object
|
||||
|
||||
Core::Pacemaker *m_pacemaker = nullptr;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Export definitions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-08-04
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef EEM_COMMON_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define EEM_COMMON_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCEEMCOMMON_LIB)
|
||||
# define EEM_COMMON_EXPORT Q_DECL_EXPORT
|
||||
# ifndef WIN32
|
||||
# ifdef NDDSUSERDllExport
|
||||
# undef NDDSUSERDllExport
|
||||
# endif
|
||||
# define NDDSUSERDllExport Q_DECL_EXPORT
|
||||
# endif
|
||||
# else
|
||||
# define EEM_COMMON_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef EEM_CLIENT_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define EEM_CLIENT_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCEEMCLIENT_LIB)
|
||||
# define EEM_CLIENT_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define EEM_CLIENT_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef EEM_SERVER_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define EEM_SERVER_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCEEMSERVER_LIB)
|
||||
# define EEM_SERVER_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define EEM_SERVER_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<service namespace="ExerciseEventManagement" abbreviation="EEM" procNames="ExerciseEventManagement" exerciseDependency="Exercise" groups="ExercisePreparation,ExerciseExecution,ExercisePaused,ExerciseAfterActionReview" prio="4">
|
||||
<rcs>
|
||||
<Id Id="$Id$"/>
|
||||
<HeadURL HeadURL="$HeadURL$"/>
|
||||
<Author Author="$Author$"/>
|
||||
</rcs>
|
||||
<operatorRights offset="11">
|
||||
<guiPlugin name="ExerciseEventManagement" offset="1">
|
||||
<operatorRightGroup name="Exercise Event Management" description="Show Exercise Events">
|
||||
<operatorRight right="EventsDialogShow" value="1" description="Show the events dialog"/>
|
||||
<operatorRight right="HitEventsShow" value="2" description="Show Hit Events on Participants and Buildings"/>
|
||||
<operatorRight right="WeaponAssignmentEventsShow" value="3" description="Show Weapon Assignments to Participants"/>
|
||||
<operatorRight right="BiteMessageEventsShow" value="4" description="Show Bite Message Events"/>
|
||||
<operatorRight right="FireEventsShow" value="5" description="Show Participant Firing Events"/>
|
||||
<operatorRight right="ManipulationEventsShow" value="6" description="Show Manipulation Events"/>
|
||||
<operatorRight right="AvEventsShow" value="7" description="Show Audio-/Video Events"/>
|
||||
<operatorRight right="AesEventsShow" value="8" description="Show Area Effect Simulation Events"/>
|
||||
</operatorRightGroup>
|
||||
</guiPlugin>
|
||||
</operatorRights>
|
||||
<tables>
|
||||
<table name="eem_event">
|
||||
<column name="id" datatype="integer" isPrimaryKey="1">
|
||||
<sequence start="1" increment="1"/>
|
||||
</column>
|
||||
<column name="event_type_id" datatype="integer" isForeignKey="1"/>
|
||||
<column name="short_name" datatype="text"/>
|
||||
<column name="participant_id" datatype="integer" comment="no foreign key since parameter can contain -1"/>
|
||||
<column name="party_id" datatype="integer" comment="no foreign key since parameter can contain -1"/>
|
||||
<column name="equipment_number" datatype="integer"/>
|
||||
<column name="properties" datatype="jsonb"/>
|
||||
<column name="sample_time" datatype="bigint"/>
|
||||
<column name="position" datatype="point_3d"/>
|
||||
<foreignKey name="FK_eem_event_pdm_event_type">
|
||||
<source table="eem_event" column="event_type_id"/>
|
||||
<destination service="ProjectDataManagement" serviceAbbr="pdm" schema="pdm" table="pdm_event_type" column="id"/>
|
||||
</foreignKey>
|
||||
<constraint name="IDX_eem_event_sample_time" type="index">
|
||||
<column name="sample_time"/>
|
||||
</constraint>
|
||||
<constraint name="IDX_eem_event_event_type_id" type="index">
|
||||
<column name="event_type_id"/>
|
||||
</constraint>
|
||||
<constraint name="UQ_eem_event_event_type_id_sample_time_participant_id_party_id_" type="unique">
|
||||
<column name="event_type_id"/>
|
||||
<column name="sample_time"/>
|
||||
<column name="participant_id"/>
|
||||
<column name="party_id"/>
|
||||
<column name="equipment_number"/>
|
||||
<column name="properties"/>
|
||||
</constraint>
|
||||
</table>
|
||||
</tables>
|
||||
<views/>
|
||||
<dbServiceStructs>
|
||||
<serviceStruct name="EemEvent" table="eem_event"/>
|
||||
<table name="eem_event"/>
|
||||
</dbServiceStructs>
|
||||
<topicTypes>
|
||||
<topicType name="Event" isDataObject="1" routeToClient="0" routeToServer="0" routeInReplay="0" recordTopic="0">
|
||||
<column name="id" idlType="long long" isKey="1"/>
|
||||
<column name="sampleTime" idlType="long long"/>
|
||||
<column name="eventTypeId" idlType="ProjectDataManagement::EventType"/>
|
||||
<column name="participantId" idlType="long"/>
|
||||
<column name="partyId" idlType="long"/>
|
||||
<column name="equipmentNumber" idlType="long"/>
|
||||
<column name="properties" idlType="string" comment="<u>Properties fuer EventType </u><b><u>Hit</u></b><u>:</u> VulnerabilityState OriginatorId OriginatorType OriginatorChargeTypeId FriendlyFire Optional: OriginatorEquipmentNumber <u>Properties fuer EventType </u><b><u>FireEvent</u></b><u>:</u> GearId GearTypeId ChargeTypeId Remain <u>Properties fuer EventType </u><b><u>WeaponAssignment</u></b><u>:</u> GearId GearTypeId DryFire <u>Properties fuer EventType </u><b><u>Manipulation</u></b><u>:</u> DeviceType <u>Properties fuer EventType </u><b><u>BiteMessage</u></b><u>:</u> BatteryState BiteState ConfigState JSonArray BiteErrors: ErrorNo CanDeviceNumber SubDeviceNumber UniqueId <u>Properties fuer EventType </u><b><u>HitBuilding</u></b><u>:</u> <u> </u>ChargetTypeId damagePercent damagePercentOld AesId VunerabilityState OrigiatorParticipantId StructureElementId <u> </u><u>Properties fuer EventType </u><b><u>HitIndrect, HitMine, HitN, HitC, EnterDangerArea, LeaveDangerArea ..</u></b> <b><u>Alle EventTypes von CES</u></b><u>:</u> AesId FriendlyFire"/>
|
||||
<column name="position" idlType="Core::GeoPosition"/>
|
||||
</topicType>
|
||||
</topicTypes>
|
||||
<functionTopics/>
|
||||
<enumerations>
|
||||
<enumeration name="EnumDummy">
|
||||
<attribute key="Dummy" value="0"/>
|
||||
</enumeration>
|
||||
</enumerations>
|
||||
</service>
|
||||
@@ -0,0 +1,607 @@
|
||||
/**
|
||||
* Handler for infrastructure data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author:
|
||||
* Created by hjl, SLSE, 2016-09-21
|
||||
*/
|
||||
|
||||
#include "handler_dynamic_participant_data.h"
|
||||
#include <ExerciseEventManagement/eem_db.h>
|
||||
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
|
||||
#include "web_socket_server.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <QSet>
|
||||
#include <QtCore/QThread>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <LtsUtilsCore/json_object.h>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
using namespace ExerciseEventManagement;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
HandlerDynamicParticipantData::HandlerDynamicParticipantData(MainHandler *mainHandler,
|
||||
const std::shared_ptr<DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<DbHandler> &db,
|
||||
const std::shared_ptr<WebSocketEventServer> &eventServer)
|
||||
: m_ddsHandler(ddsHandler)
|
||||
, m_dbHandler(db)
|
||||
, m_eventServer(eventServer)
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("HandlerDynamicParticipantData"))
|
||||
{
|
||||
} // end of ctor()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
HandlerDynamicParticipantData::~HandlerDynamicParticipantData()
|
||||
{
|
||||
} // end of dtor()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool HandlerDynamicParticipantData::init()
|
||||
{
|
||||
INFO_LOG(m_logger) << "start init() DTC ParticipantManagement ";
|
||||
|
||||
// DTC ParticipantManagement
|
||||
m_ppmDtc = ParticipantManagement::Interface::Dtc::create(m_ddsHandler->ddsConnector());
|
||||
if (m_ppmDtc == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not create DTC ParticipantManagement";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Subscribe for DynamicParticipantData (for analyzing data)
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged,
|
||||
this, &HandlerDynamicParticipantData::onDynamicParticipantDataChanged);
|
||||
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantGearEventChanged,
|
||||
this, &HandlerDynamicParticipantData::onParticipantGearEventChanged);
|
||||
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
|
||||
this, &HandlerDynamicParticipantData::onParticipantChanged);
|
||||
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::biteChanged,
|
||||
this, &HandlerDynamicParticipantData::onBiteChanged);
|
||||
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged,
|
||||
this, &HandlerDynamicParticipantData::onParticipantPositionChanged);
|
||||
|
||||
|
||||
if (!m_ppmDtc->enableDynamicParticipantData() ||
|
||||
!m_ppmDtc->enableParticipantGearEvent() ||
|
||||
!m_ppmDtc->enableParticipant() ||
|
||||
!m_ppmDtc->enableBite() ||
|
||||
!m_ppmDtc->enableParticipantPosition())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "init() DTC ParticipantManagement failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bldDtc = Buildings::Interface::Dtc::create(m_ddsHandler->ddsConnector());
|
||||
|
||||
if (m_bldDtc == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not create DTC Buildings";
|
||||
return false;
|
||||
}
|
||||
|
||||
connect(m_bldDtc.get(), &Buildings::Interface::Dtc::buildingStateChanged,
|
||||
this, &HandlerDynamicParticipantData::onBuildingStateChanged);
|
||||
|
||||
if (!m_bldDtc->enableBuildingState())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Enable buildingState failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_aesDtc = AreaEffectSimulation::Interface::Dtc::create(m_ddsHandler->ddsConnector());
|
||||
|
||||
m_aesDtc->enableAesItemView();
|
||||
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
|
||||
this, &HandlerDynamicParticipantData::onAesItemViewChanged);
|
||||
|
||||
// Infrastructure Management
|
||||
auto dtcIsm = m_ddsHandler->dtcIsm();
|
||||
dtcIsm->enableMainStructureElement();
|
||||
|
||||
connect(dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
|
||||
this, &HandlerDynamicParticipantData::onMainStructureElementChanged);
|
||||
|
||||
// Get 'static' data for all MainStructureElements
|
||||
{
|
||||
auto cb = [this](const InfrastructureManagement::MainStructureElement & mse)
|
||||
{
|
||||
onMainStructureElementChanged(mse, DataModification::eAdded);
|
||||
};
|
||||
if (!dtcIsm->mainStructureElements(cb))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} // end of init()
|
||||
|
||||
void HandlerDynamicParticipantData::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
case DataModification::eModified:
|
||||
m_itemViews.insert(data.aesItemId(), data.aesTypeId());
|
||||
break;
|
||||
case DataModification::eRemoved:
|
||||
m_itemViews.remove(data.aesItemId());
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerDynamicParticipantData::tryCreateHitEvent(Database::EemEvent eData,
|
||||
const ParticipantManagement::StateInformation &stateInfo)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "tryCreateHitEvent";
|
||||
// special values - ignore
|
||||
const ProjectDataManagement::VulnerabilityState vulnState = stateInfo.vulnerabilityState();
|
||||
if (vulnState == ProjectDataManagement::VulnerabilityState_def::VulnerabilityBitsChanged ||
|
||||
vulnState == ProjectDataManagement::VulnerabilityState_def::TemporarySeverance)
|
||||
return;
|
||||
|
||||
// combat ready is no hit
|
||||
if (vulnState == ProjectDataManagement::VulnerabilityState_def::CombatReady)
|
||||
return;
|
||||
|
||||
// only handle 'real' hit events
|
||||
switch (stateInfo.originatorType().underlying())
|
||||
{
|
||||
case ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation:
|
||||
case ProjectDataManagement::StateChangeOriginator::ImprovisedExplosiveDevice:
|
||||
case ProjectDataManagement::StateChangeOriginator::DusMine:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::HitEffectSimulation;
|
||||
break;
|
||||
case ProjectDataManagement::StateChangeOriginator::Participant:
|
||||
case ProjectDataManagement::StateChangeOriginator::ObserverController:
|
||||
case ProjectDataManagement::StateChangeOriginator::ExerciseControl:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::Hit;
|
||||
break;
|
||||
case ProjectDataManagement::StateChangeOriginator::Sanitation:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::Sanitation;
|
||||
break;
|
||||
case ProjectDataManagement::StateChangeOriginator::Unknown:
|
||||
case ProjectDataManagement::StateChangeOriginator::WoundTreatmentDevice:
|
||||
case ProjectDataManagement::StateChangeOriginator::MaintainanceDevice:
|
||||
case ProjectDataManagement::StateChangeOriginator::FunctionalArea:
|
||||
case ProjectDataManagement::StateChangeOriginator::Initialization:
|
||||
case ProjectDataManagement::StateChangeOriginator::MedicalTimeout:
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("VulnerabilityState")] = vulnState.underlying();
|
||||
obj[QStringLiteral("OriginatorId")] = stateInfo.originatorId();
|
||||
obj[QStringLiteral("OriginatorType")] = stateInfo.originatorType().underlying();
|
||||
obj[QStringLiteral("OriginatorChargeTypeId")] = stateInfo.originatorChargeTypeId();
|
||||
|
||||
if (stateInfo.originatorType() == ProjectDataManagement::StateChangeOriginator::Participant)
|
||||
{
|
||||
ParticipantManagement::Participant originData = m_partMap.value(stateInfo.originatorId());
|
||||
if (originData.equipmentNumber().is_set())
|
||||
obj[QStringLiteral("OriginatorEquipmentNumber")] = originData.equipmentNumber().get();
|
||||
|
||||
if (originData.partyId() == eData.partyId)
|
||||
obj[QStringLiteral("FriendlyFire")] = true;
|
||||
else
|
||||
obj[QStringLiteral("FriendlyFire")] = false;
|
||||
}
|
||||
if (eData.eventTypeId == ProjectDataManagement::EventType::HitEffectSimulation)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Event HitEffectSimulation from originatorId = " << stateInfo.originatorId();
|
||||
obj[QStringLiteral("AesId")] = stateInfo.originatorId();
|
||||
obj[QStringLiteral("AesType")] = m_itemViews.value(stateInfo.originatorId()).underlying();
|
||||
AreaEffectSimulation::AesItem aesItem;
|
||||
if (m_aesDtc->aesItemFromId(stateInfo.originatorId(), aesItem))
|
||||
obj[QStringLiteral("AesName")] = QJsonValue(QString::fromStdString(aesItem.name()));
|
||||
}
|
||||
if (eData.eventTypeId == ProjectDataManagement::EventType::Sanitation)
|
||||
{
|
||||
// ignore these events
|
||||
if (stateInfo.sanitationProceduresTaken() == 0 && stateInfo.originatorChargeTypeId() == 0) //qualification
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Event sanitation ";
|
||||
|
||||
obj[QStringLiteral("Vitality")] = stateInfo.vitality();
|
||||
obj[QStringLiteral("SanitationResult")] = stateInfo.sanitationResult().underlying();
|
||||
obj[QStringLiteral("SanitationProceduresTaken")] = stateInfo.sanitationProceduresTaken();
|
||||
}
|
||||
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
eData.id = 0;
|
||||
if (eData.sampleTime <= 0)
|
||||
eData.sampleTime = stateInfo.stateTime();
|
||||
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
ERROR_LOG(m_logger) << "Error while inserting event data for participant: " << eData.participantId;
|
||||
else
|
||||
publishData(eData);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerDynamicParticipantData::onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data,
|
||||
DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "onDynamicParticipantDataChanged()"
|
||||
<< ", participantId: " << data.participantId()
|
||||
<< ", size stateHistory: " << data.stateHistory().size();
|
||||
|
||||
auto itLastDynData = m_lastDynData.find(data.participantId());
|
||||
// the first insert does not trigger any updates
|
||||
if (itLastDynData == m_lastDynData.end())
|
||||
{
|
||||
itLastDynData = m_lastDynData.insert(data.participantId(), data);
|
||||
return;
|
||||
}
|
||||
ParticipantManagement::DynamicParticipantData &lastDynData = itLastDynData.value();
|
||||
|
||||
// get corresponding participant data
|
||||
auto itParticipant = m_partMap.find(data.participantId());
|
||||
if (itParticipant == m_partMap.end())
|
||||
{
|
||||
m_ppmDtc->waitForHistoricalDataParticipant(2000);
|
||||
itParticipant = m_partMap.find(data.participantId());
|
||||
if (itParticipant == m_partMap.end())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Participant does not exist: participantId: " << data.participantId();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const ParticipantManagement::ParticipantPosition emptyPos;
|
||||
auto itParticipantPos = m_partPosMap.find(data.participantId());
|
||||
const ParticipantManagement::ParticipantPosition &pPos = itParticipantPos == m_partPosMap.end() ? emptyPos : itParticipantPos.value();
|
||||
const ParticipantManagement::Participant &pData = itParticipant.value();
|
||||
|
||||
Database::EemEvent eData;
|
||||
eData.participantId = data.participantId();
|
||||
eData.equipmentNumber = pData.equipmentNumber().is_set() ? pData.equipmentNumber().get() : -1;
|
||||
eData.partyId = pData.partyId();
|
||||
eData.sampleTime = data.sampleTime();
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::Unknown;
|
||||
eData.position = LtsUtils::QPoint3D(pPos.pos().lon(), pPos.pos().lat(), pPos.pos().z());
|
||||
|
||||
if (data.stateHistory() != lastDynData.stateHistory())
|
||||
{
|
||||
// we assume that the order of the state information do *not* change (it's current true: january 2020)
|
||||
for (size_t i = 0; i < data.stateHistory().size(); ++i)
|
||||
{
|
||||
if (i < lastDynData.stateHistory().size() &&
|
||||
data.stateHistory().at(i) == lastDynData.stateHistory().at(i))
|
||||
continue;
|
||||
tryCreateHitEvent(eData, data.stateHistory().at(i));
|
||||
}
|
||||
}
|
||||
|
||||
const auto gearIsKnown = [ &lastDynData](const ParticipantManagement::GearInformation & gi) -> bool
|
||||
{
|
||||
return std::any_of(lastDynData.gear().begin(), lastDynData.gear().end(),
|
||||
[&gi](const ParticipantManagement::GearInformation & other)
|
||||
{
|
||||
return gi.gearTypeId() == other.gearTypeId() && gi.gearId() == other.gearId();
|
||||
});
|
||||
};
|
||||
|
||||
for (const ParticipantManagement::GearInformation &gi : data.gear())
|
||||
{
|
||||
if (gearIsKnown(gi))
|
||||
continue;
|
||||
DEBUG_LOG(m_logger) << "Found new gear " << gi << " for participant " << data.participantId();
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("GearId")] = QJsonValue(gi.gearId());
|
||||
obj[QStringLiteral("GearTypeId")] = QJsonValue(gi.gearTypeId());
|
||||
obj[QStringLiteral("DryFire")] = QJsonValue(gi.chargeCounting());
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
eData.sampleTime = gi.lastUpdate();
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::WeaponAssignment;
|
||||
eData.id = 0;
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
ERROR_LOG(m_logger) << "Error while inserting event data for participant: " << data.participantId();
|
||||
else
|
||||
publishData(eData);
|
||||
}
|
||||
|
||||
if (data.manipulation() != lastDynData.manipulation())
|
||||
{
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::Manipulation;
|
||||
|
||||
const auto isOldManipulation = [&lastDynData](const ParticipantManagement::ManipulationInformation & mani) -> bool
|
||||
{
|
||||
auto it = std::find(lastDynData.manipulation().begin(), lastDynData.manipulation().end(), mani);
|
||||
return it != lastDynData.manipulation().end();
|
||||
};
|
||||
|
||||
// we can *not* assume that the old and the new manipulation is in the same order
|
||||
for (const auto &mani : data.manipulation())
|
||||
{
|
||||
if (isOldManipulation(mani))
|
||||
continue;
|
||||
const QJsonObject obj({{QStringLiteral("DeviceType"), mani.equipmentFunctionId()}});
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
eData.sampleTime = mani.manipulationTime();
|
||||
eData.id = 0;
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
ERROR_LOG(m_logger) << "Error while inserting event data for participant: " << data.participantId();
|
||||
else
|
||||
publishData(eData);
|
||||
}
|
||||
}
|
||||
|
||||
lastDynData = data;
|
||||
|
||||
} // end of onDynamicParticipantDataChanged()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerDynamicParticipantData::onParticipantGearEventChanged(const ParticipantManagement::ParticipantGearEvent &data,
|
||||
DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
// get corresponding participant data
|
||||
auto itParticipant = m_partMap.find(data.participantId());
|
||||
if (itParticipant == m_partMap.end())
|
||||
{
|
||||
m_ppmDtc->waitForHistoricalDataParticipant(2000);
|
||||
itParticipant = m_partMap.find(data.participantId());
|
||||
if (itParticipant == m_partMap.end())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Participant does not exist: participantId: " << data.participantId();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const ParticipantManagement::ParticipantPosition emptyPos;
|
||||
auto itParticipantPos = m_partPosMap.find(data.participantId());
|
||||
const ParticipantManagement::ParticipantPosition &pPos = itParticipantPos == m_partPosMap.end() ? emptyPos : itParticipantPos.value();
|
||||
const ParticipantManagement::Participant &pData = itParticipant.value();
|
||||
|
||||
Database::EemEvent eData;
|
||||
eData.id = 0;
|
||||
eData.participantId = data.participantId();
|
||||
eData.equipmentNumber = pData.equipmentNumber().is_set() ? pData.equipmentNumber().get() : -1;
|
||||
eData.partyId = pData.partyId();
|
||||
eData.sampleTime = data.sampleTime();
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::FireEvent;
|
||||
eData.position = LtsUtils::QPoint3D(pPos.pos().lon(), pPos.pos().lat(), pPos.pos().z());
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("GearId")] = QJsonValue(data.charge().gearId());
|
||||
obj[QStringLiteral("GearTypeId")] = QJsonValue(data.charge().gearTypeId());
|
||||
obj[QStringLiteral("ChargeTypeId")] = QJsonValue(data.charge().chargeTypeId());
|
||||
obj[QStringLiteral("Amount")] = QJsonValue(data.chargeAmount());
|
||||
if (data.charge().remain() >= 0)
|
||||
obj[QStringLiteral("Remain")] = QJsonValue(data.charge().remain());
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
eData.id = 0;
|
||||
|
||||
DEBUG_LOG(m_logger) << "create fire event for participant " << data.participantId();
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
ERROR_LOG(m_logger) << "Error while inserting event data for participant: " << data.participantId();
|
||||
else
|
||||
publishData(eData);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerDynamicParticipantData::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
case DataModification::eModified:
|
||||
DEBUG_LOG(m_logger) << "added/modified";
|
||||
m_partMap.insert(data.id(), data);
|
||||
DEBUG_LOG(m_logger) << "data.participantId: " << data.id()
|
||||
<< ", data.partyId: " << data.partyId()
|
||||
<< ". data.equipmentNumber: " << data.equipmentNumber();
|
||||
break;
|
||||
case DataModification::eRemoved:
|
||||
m_partMap.remove(data.id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerDynamicParticipantData::onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
case DataModification::eModified:
|
||||
m_partPosMap.insert(data.participantId(), data);
|
||||
DEBUG_LOG(m_logger) << "data.participantId: " << data.participantId()
|
||||
<< ", position lat: " << data.pos().lat()
|
||||
<< ", position lon: " << data.pos().lon();
|
||||
break;
|
||||
case DataModification::eRemoved:
|
||||
m_partPosMap.remove(data.participantId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerDynamicParticipantData::onBiteChanged(const ParticipantManagement::Bite &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
Database::EemEvent eData;
|
||||
|
||||
eData.id = 0;
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::BiteMessage;
|
||||
eData.equipmentNumber = data.equipmentNumber();
|
||||
eData.participantId = data.participantId();
|
||||
eData.sampleTime = data.sampleTime();
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("BatteryState")] = QJsonValue(data.batteryState());
|
||||
obj[QStringLiteral("BiteState")] = QJsonValue(data.biteState());
|
||||
obj[QStringLiteral("ConfigState")] = QJsonValue(data.configState());
|
||||
|
||||
QJsonArray array;
|
||||
for (const ParticipantManagement::BiteError &be : data.biteErrors())
|
||||
{
|
||||
QJsonObject object;
|
||||
object[QStringLiteral("ErrorNo")] = QJsonValue(be.errorNumber());
|
||||
object[QStringLiteral("CanDeviceNumber")] = QJsonValue(be.canDeviceNumber());
|
||||
object[QStringLiteral("SubdeviceNumber")] = QJsonValue(be.subdeviceNumber());
|
||||
object[QStringLiteral("UniqueId")] = QJsonValue(be.uniqueId());
|
||||
|
||||
array.append(object);
|
||||
}
|
||||
obj[QStringLiteral("BiteErrors")] = QJsonValue(array);
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
|
||||
ParticipantManagement::Participant part = m_partMap.value(data.participantId());
|
||||
if (part.id() > 0)
|
||||
{
|
||||
eData.partyId = part.partyId();
|
||||
|
||||
ParticipantManagement::ParticipantPosition pPos = m_partPosMap.value(eData.participantId);
|
||||
eData.position = LtsUtils::QPoint3D(pPos.pos().lon(), pPos.pos().lat(), pPos.pos().z());
|
||||
}
|
||||
else
|
||||
{
|
||||
eData.participantId = -1;
|
||||
eData.partyId = -1;
|
||||
}
|
||||
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
ERROR_LOG(m_logger) << "Error while inserting event data for participantId: " << data.participantId();
|
||||
else
|
||||
publishData(eData);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerDynamicParticipantData::onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved || data.damagePercent() <= 0) // only add hits
|
||||
return;
|
||||
|
||||
Database::EemEvent eData;
|
||||
|
||||
eData.id = 0;
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::HitBuilding;
|
||||
eData.sampleTime = data.sampleTime();
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("ChargeTypeId")] = QJsonValue(data.chargeTypeId());
|
||||
obj[QStringLiteral("damagePercent")] = QJsonValue(data.damagePercent());
|
||||
obj[QStringLiteral("damagePercentOld")] = QJsonValue(data.damagePercentOld());
|
||||
// obj[QStringLiteral("Name")] = QJsonValue(data.name());
|
||||
obj[QStringLiteral("VulnerabilityState")] = QJsonValue(data.vulnerabilityState().underlying());
|
||||
|
||||
if (data.originatorType() == ProjectDataManagement::StateChangeOriginator::Participant)
|
||||
{
|
||||
ParticipantManagement::Participant originData = m_partMap.value(data.originatorParticipantId());
|
||||
if (originData.equipmentNumber().is_set())
|
||||
obj[QStringLiteral("OriginatorEquipmentNumber")] = originData.equipmentNumber().get();
|
||||
}
|
||||
if (data.originatorType() == ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation)
|
||||
{
|
||||
obj[QStringLiteral("AesId")] = data.aesId();
|
||||
obj[QStringLiteral("AesType")] = m_itemViews.value(data.aesId()).underlying();
|
||||
AreaEffectSimulation::AesItem aesItem;
|
||||
if (m_aesDtc->aesItemFromId(data.aesId(), aesItem))
|
||||
obj[QStringLiteral("AesName")] = QJsonValue(QString::fromStdString(aesItem.name()));
|
||||
}
|
||||
|
||||
//obj[QStringLiteral("StructureElementId")] = QJsonValue(data.structureElementId());
|
||||
obj[QStringLiteral("MainStructureElementId")] = QJsonValue(data.id());
|
||||
|
||||
|
||||
QJsonArray contaminationArr;
|
||||
for (const auto &cs: data.contaminationStates())
|
||||
{
|
||||
QJsonArray roomArr;
|
||||
for (const auto &roomId : qAsConst(cs.rooms()))
|
||||
roomArr.append(QJsonValue(roomId));
|
||||
|
||||
contaminationArr.append(QJsonObject({{QStringLiteral("aesId") , cs.aesId()},
|
||||
{QStringLiteral("rooms"), roomArr}}));
|
||||
}
|
||||
obj[QStringLiteral("contaminationStates")] = contaminationArr;
|
||||
|
||||
int mainStructureElementId = data.id();
|
||||
Core::GeoPosition geoPosition = m_mainStructureElements.value(mainStructureElementId).geoPosition();
|
||||
LtsUtils::QPoint3D pos3D(geoPosition.lon(), geoPosition.lat(), geoPosition.z());
|
||||
eData.position = pos3D;
|
||||
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
ERROR_LOG(m_logger) << "Error while inserting event data for building ";
|
||||
else
|
||||
publishData(eData);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerDynamicParticipantData::publishData(const Database::EemEvent &data)
|
||||
{
|
||||
m_eventServer->sendEvent(Database::toJson(data));
|
||||
|
||||
ExerciseEventManagement::Event ddsData = toDdsData(data);
|
||||
|
||||
if (!m_ddsHandler->dts()->publish(ddsData))
|
||||
ERROR_LOG(m_logger) << "Error publishing event-data to dds";
|
||||
|
||||
// take data from dds-bus after 10s, we need just to make sure the recording service got it
|
||||
m_mainHandler->addEventIdToRemove(ddsData.id());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
ExerciseEventManagement::Event HandlerDynamicParticipantData::toDdsData(const Database::EemEvent &data)
|
||||
{
|
||||
ExerciseEventManagement::Event ddsData;
|
||||
|
||||
ddsData.id(data.id);
|
||||
ddsData.sampleTime(data.sampleTime);
|
||||
ddsData.participantId(data.participantId);
|
||||
ddsData.partyId(data.partyId);
|
||||
ddsData.equipmentNumber(data.equipmentNumber);
|
||||
ddsData.eventTypeId(data.eventTypeId);
|
||||
ddsData.properties(data.properties.toStdString());
|
||||
ddsData.position(Core::GeoPosition(data.position.x(), data.position.y(), data.position.z()));
|
||||
|
||||
if (data.eventTypeId == ProjectDataManagement::EventType_def::HitBuilding)
|
||||
{
|
||||
int mainStructureElementId = LtsUtils::JsonObject::fromJson(ddsData.properties()).valueOr<int>(QStringLiteral("MainStructureElementId"), 0);
|
||||
DEBUG_LOG(m_logger) << "MainStructureElementId=" << mainStructureElementId;
|
||||
ddsData.position(m_mainStructureElements.value(mainStructureElementId).geoPosition());
|
||||
}
|
||||
|
||||
return ddsData;
|
||||
}
|
||||
|
||||
// ///////////////////////////////////
|
||||
// I S M (InfrastructureManagement)
|
||||
// ///////////////////////////////////
|
||||
void HandlerDynamicParticipantData::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data, DataModification modType)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onMainStructureElementChanged";
|
||||
if (modType != DataModification::eAdded &&
|
||||
modType != DataModification::eModified)
|
||||
{
|
||||
m_mainStructureElements.remove(data.id());
|
||||
return;
|
||||
}
|
||||
|
||||
m_mainStructureElements.insert(data.id(), data);
|
||||
DEBUG_LOG(m_logger) << "Got MainStructureElement: " << data;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Handler for infrastructure data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by hjl, SLSE, 2016-09-21
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <Proxies/Buildings/bld_dtc.h>
|
||||
#include <Proxies/Buildings/bld.hpp>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QMap>
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
class WebSocketEventServer;
|
||||
|
||||
class HandlerDynamicParticipantData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HandlerDynamicParticipantData(MainHandler *mainHandler,
|
||||
const std::shared_ptr<DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<DbHandler> &db,
|
||||
const std::shared_ptr<WebSocketEventServer> &eventServer);
|
||||
|
||||
~HandlerDynamicParticipantData();
|
||||
|
||||
/**
|
||||
* Initialize the handler to manage information from infrastructure management
|
||||
*/
|
||||
bool init();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the shared pointer to PPM DTC Interface.
|
||||
*/
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> dtc() const
|
||||
{
|
||||
return m_ppmDtc;
|
||||
}
|
||||
|
||||
|
||||
private Q_SLOTS:
|
||||
void tryCreateHitEvent(Database::EemEvent eData,
|
||||
const ParticipantManagement::StateInformation &stateInfo);
|
||||
/**
|
||||
* Handle the signals from 'ParticipantManagement'
|
||||
*/
|
||||
void onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType);
|
||||
void onParticipantGearEventChanged(const ParticipantManagement::ParticipantGearEvent &data, DataModification modType);
|
||||
void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
|
||||
void onBiteChanged(const ParticipantManagement::Bite &data, DataModification modType);
|
||||
void onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType);
|
||||
void onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType);
|
||||
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType);
|
||||
/**
|
||||
* Handle MainStructureElement from 'ISM'
|
||||
*/
|
||||
void onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data, DataModification modType);
|
||||
|
||||
private: // methoden
|
||||
void publishData(const Database::EemEvent &data);
|
||||
ExerciseEventManagement::Event toDdsData(const Database::EemEvent &data);
|
||||
|
||||
private: // attributes
|
||||
std::shared_ptr<DdsHandler> m_ddsHandler; ///< Pointer to DDS handler
|
||||
std::shared_ptr<DbHandler> m_dbHandler;
|
||||
std::shared_ptr<WebSocketEventServer> m_eventServer;
|
||||
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc; ///< Pointer to DTC ParticipantManagement interface object
|
||||
std::shared_ptr<Buildings::Interface::Dtc> m_bldDtc; ///< Pointer to DTC ParticipantManagement interface object
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
|
||||
QHash<qint32, ParticipantManagement::Participant> m_partMap;
|
||||
QHash<qint32, ParticipantManagement::ParticipantPosition> m_partPosMap;
|
||||
QHash<qint32, ParticipantManagement::DynamicParticipantData> m_lastDynData;
|
||||
|
||||
QHash<int, AreaEffectSimulation::AesType> m_itemViews;
|
||||
QHash<int, InfrastructureManagement::MainStructureElement> m_mainStructureElements;
|
||||
|
||||
MainHandler *m_mainHandler;
|
||||
NGL::INGLLogger &m_logger; ///< Interface to the Logging-Facility
|
||||
|
||||
};
|
||||
} // namespace ExerciseEventManagement
|
||||
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Handler for infrastructure data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author:
|
||||
* Created by Christian Roeskens, NLSE, 2018-05-02
|
||||
*/
|
||||
|
||||
#include "handler_equipment_error_registration.h"
|
||||
#include "web_socket_server.h"
|
||||
#include "settings.h"
|
||||
#include "eem_db.h"
|
||||
|
||||
#include <OcSituationServer/oss.hpp>
|
||||
|
||||
#include <ProjectDataManagement/pdm_enums.hpp>
|
||||
|
||||
#include <QSet>
|
||||
#include <QtCore/QThread>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
using namespace ExerciseEventManagement;
|
||||
|
||||
HandlerEquipmentErrorRegistration::HandlerEquipmentErrorRegistration(MainHandler *mainHandler,
|
||||
const std::shared_ptr<DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<DbHandler> &db,
|
||||
const std::shared_ptr<WebSocketEventServer> &eventServer)
|
||||
: m_mainHandler(mainHandler)
|
||||
, m_ddsHandler(ddsHandler)
|
||||
, m_dbHandler(db)
|
||||
, m_eventServer(eventServer)
|
||||
, m_ossDtc(nullptr)
|
||||
, m_logger(getLogger("HandlerEquipmentErrorRegistration"))
|
||||
{
|
||||
} // end of ctor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
HandlerEquipmentErrorRegistration::~HandlerEquipmentErrorRegistration()
|
||||
{
|
||||
} // end of dtor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool HandlerEquipmentErrorRegistration::init()
|
||||
{
|
||||
INFO_LOG(m_logger) << "start init() DTC OcSituationServer ";
|
||||
|
||||
|
||||
// DTC OcSituationServer
|
||||
m_ossDtc = OcSituationServer::Interface::Dtc::create(m_ddsHandler->ddsConnector());
|
||||
if (m_ossDtc == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not create DTC OcSituationServer";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Subsribe for EquipmentErrorRegistration
|
||||
connect(m_ossDtc.get(), &OcSituationServer::Interface::Dtc::equipmentErrorRegistrationChanged,
|
||||
this, &HandlerEquipmentErrorRegistration::onEquipmentErrorRegistrationChanged);
|
||||
|
||||
if (!m_ossDtc->enableEquipmentErrorRegistration())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "init() DTC OcSituationServer failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// end of init()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerEquipmentErrorRegistration::onEquipmentErrorRegistrationChanged(const OcSituationServer::EquipmentErrorRegistration &data, DataModification modType)
|
||||
{
|
||||
INFO_LOG(m_logger) << "onEquipmentErrorRegistrationChanged()"
|
||||
<< ", equipmentNr: " << data.equipmentNumber()
|
||||
<< ", text: " << QString::fromStdString(data.text());
|
||||
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
Database::EemEvent eData;
|
||||
eData.sampleTime = data.sampleTime();
|
||||
eData.equipmentNumber = data.equipmentNumber();
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::EquipmentErrorReport;
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("text")] = QString::fromStdString(data.text());
|
||||
obj[QStringLiteral("device")] = QString::fromStdString(data.device());
|
||||
obj[QStringLiteral("participant")] = QString::fromStdString(data.participant());
|
||||
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
ERROR_LOG(m_logger) << "Error while inserting event into database";
|
||||
else
|
||||
publishData(eData);
|
||||
|
||||
}// end of onEquipmentErrorRegistrationChanged()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HandlerEquipmentErrorRegistration::publishData(const Database::EemEvent &data)
|
||||
{
|
||||
m_eventServer->sendEvent(Database::toJson(data));
|
||||
|
||||
ExerciseEventManagement::Event ddsData = toDdsData(data);
|
||||
|
||||
if (!m_ddsHandler->dts()->publish(ddsData))
|
||||
ERROR_LOG(m_logger) << "Error publishing event-data to dds";
|
||||
|
||||
// take data from dds-bus after 10s, we need just to make sure the recording service got it
|
||||
m_mainHandler->addEventIdToRemove(ddsData.id());
|
||||
}
|
||||
|
||||
ExerciseEventManagement::Event HandlerEquipmentErrorRegistration::toDdsData(const Database::EemEvent &data)
|
||||
{
|
||||
ExerciseEventManagement::Event ddsData;
|
||||
|
||||
ddsData.id(data.id);
|
||||
ddsData.sampleTime(data.sampleTime);
|
||||
ddsData.participantId(data.participantId);
|
||||
ddsData.partyId(data.partyId);
|
||||
ddsData.equipmentNumber(data.equipmentNumber);
|
||||
ddsData.eventTypeId(data.eventTypeId);
|
||||
ddsData.properties(data.properties.toStdString());
|
||||
ddsData.position(Core::GeoPosition(data.position.x(), data.position.y(), data.position.z()));
|
||||
|
||||
return ddsData;
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Handler for infrastructure data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Roeskens, SLSE, 2016-09-21
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <OcSituationServer/oss_dtc.h>
|
||||
//#include <Proxies/Buildings/bld_dtc.h>
|
||||
//#include <Proxies/Buildings/bld.hpp>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QMap>
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
|
||||
class HandlerEquipmentErrorRegistration : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HandlerEquipmentErrorRegistration(MainHandler *mainHandler,
|
||||
const std::shared_ptr<DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<DbHandler> &db,
|
||||
const std::shared_ptr<WebSocketEventServer> &eventServer);
|
||||
|
||||
~HandlerEquipmentErrorRegistration();
|
||||
|
||||
/**
|
||||
* Initialize the handler to manage information from infrastructure management
|
||||
*/
|
||||
bool init();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the shared pointer to OSS DTC Interface.
|
||||
*/
|
||||
std::shared_ptr<OcSituationServer::Interface::Dtc> dtc() const
|
||||
{
|
||||
return m_ossDtc;
|
||||
}
|
||||
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
* Handle the signals from 'OcSituationServer'
|
||||
*/
|
||||
void onEquipmentErrorRegistrationChanged(const OcSituationServer::EquipmentErrorRegistration &data, DataModification modType);
|
||||
|
||||
private: // methoden
|
||||
void publishData(const Database::EemEvent &data);
|
||||
ExerciseEventManagement::Event toDdsData(const Database::EemEvent &data);
|
||||
|
||||
private: // attributes
|
||||
MainHandler *m_mainHandler;
|
||||
|
||||
std::shared_ptr<DdsHandler> m_ddsHandler;
|
||||
std::shared_ptr<DbHandler> m_dbHandler;
|
||||
std::shared_ptr<WebSocketEventServer> m_eventServer;
|
||||
std::shared_ptr<OcSituationServer::Interface::Dtc> m_ossDtc;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
} // namespace ExerciseEventManagement
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
/**
|
||||
* Handler for infrastructure data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author:
|
||||
* Created by hjl, SLSE, 2016-09-21
|
||||
*/
|
||||
|
||||
#include "handler_participant_event.h"
|
||||
#include <ExerciseEventManagement/eem_db.h>
|
||||
|
||||
#include "web_socket_server.h"
|
||||
#include "settings.h"
|
||||
#include <ProjectDataManagement/pdm_enums.hpp>
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QTimer>
|
||||
|
||||
using namespace ExerciseEventManagement;
|
||||
|
||||
HandlerParticipantEvent::HandlerParticipantEvent(MainHandler *mainHandler,
|
||||
const std::shared_ptr<DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<DbHandler> &db,
|
||||
const std::shared_ptr<WebSocketEventServer> &eventServer)
|
||||
: m_ddsHandler(ddsHandler)
|
||||
, m_dbHandler(db)
|
||||
, m_eventServer(eventServer)
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("HandlerParticipantEvent"))
|
||||
{
|
||||
} // end of ctor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
HandlerParticipantEvent::~HandlerParticipantEvent()
|
||||
{
|
||||
} // end of dtor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool HandlerParticipantEvent::init()
|
||||
{
|
||||
INFO_LOG(m_logger) << "start init() DTC CentralEffectSimulation ";
|
||||
|
||||
// DTC CentralEffectSimulation
|
||||
m_cesDtc = CentralEffectSimulation::Interface::Dtc::create(m_ddsHandler->ddsConnector());
|
||||
if (!m_cesDtc)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not create DTC CentralEffectSimulation";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Subsribe for ParticipantEvent (for analyzing data)
|
||||
connect(m_cesDtc.get(), &CentralEffectSimulation::Interface::Dtc::participantEventChanged,
|
||||
this, &HandlerParticipantEvent::onParticipantEventChanged);
|
||||
|
||||
if (!m_cesDtc->enableParticipantEvent() )
|
||||
{
|
||||
ERROR_LOG(m_logger) << "init() DTC CentralEffectSimulation failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
// DTC ProjectDataManagement
|
||||
m_pdmDtc = ProjectDataManagement::Interface::Dtc::create(m_ddsHandler->ddsConnector());
|
||||
if (!m_pdmDtc)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not create DTC ProjectDataManagement";
|
||||
return false;
|
||||
}
|
||||
m_pdmDtc->enableChargeType();
|
||||
|
||||
m_aesDtc = AreaEffectSimulation::Interface::Dtc::create(m_ddsHandler->ddsConnector());
|
||||
|
||||
m_aesDtc->enableAll();
|
||||
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
|
||||
this, &HandlerParticipantEvent::onAesItemViewChanged);
|
||||
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleChanged,
|
||||
this, &HandlerParticipantEvent::onExplosionSingleChanged);
|
||||
|
||||
|
||||
return true;
|
||||
} // end of init()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HandlerParticipantEvent::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "AesItemId: " << data.aesItemId() << ", effectState: " << data.effectStateId();
|
||||
|
||||
Database::EemEvent eData = m_aesMap[data.id()];
|
||||
eData.sampleTime = data.effectStart();
|
||||
|
||||
if (data.partyId().is_set())
|
||||
eData.partyId = data.partyId().get();
|
||||
|
||||
switch(modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
m_itemViews.insert(data.aesItemId(), data.aesTypeId());
|
||||
DEBUG_LOG(m_logger) << "eAdded: AesItemId: " << data.aesItemId() << ", effectState: " << data.effectStateId();
|
||||
m_aesEffectState.insert(data.aesItemId(), data.effectStateId());
|
||||
|
||||
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtBorderline)
|
||||
{
|
||||
AreaEffectSimulation::AesItem aesItem;
|
||||
m_aesDtc->aesItemFromId(data.aesItemId(), aesItem);
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("AesId")] = QJsonValue(aesItem.id());
|
||||
obj[QStringLiteral("AesName")] = QJsonValue(QString::fromStdString(aesItem.name()));
|
||||
obj[QStringLiteral("AesType")] = QJsonValue(data.aesTypeId().underlying());
|
||||
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::Borderline;
|
||||
eData.position = LtsUtils::QPoint3D(data.boundingBoxBottomLeft().lon(),
|
||||
data.boundingBoxBottomLeft().lat(), 0.0);
|
||||
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
ERROR_LOG(m_logger) << "Error while inserting event data from AES ";
|
||||
else
|
||||
publishData(eData);
|
||||
}
|
||||
break;
|
||||
case DataModification::eModified:
|
||||
{
|
||||
AreaEffectSimulation::AesEffectState effectState = m_aesEffectState.value(data.aesItemId());
|
||||
|
||||
DEBUG_LOG(m_logger) << "eModified: AesItemId: " << data.aesItemId() << ", effectState: " << data.effectStateId();
|
||||
DEBUG_LOG(m_logger) << "effectState: " << effectState;
|
||||
|
||||
// insert event only once
|
||||
if (effectState != AreaEffectSimulation::AesEffectState::EsPrepared &&
|
||||
(effectState == AreaEffectSimulation::AesEffectState_def::EsActivated && data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsExpired))
|
||||
return;
|
||||
|
||||
INFO_LOG(m_logger) << "new/update event: aesId: " << data.aesItemId();
|
||||
|
||||
m_aesEffectState.insert(data.aesItemId(), data.effectStateId());
|
||||
m_itemViews.insert(data.aesItemId(), data.aesTypeId());
|
||||
eData.position = LtsUtils::QPoint3D(data.boundingBoxBottomLeft().lon(),
|
||||
data.boundingBoxBottomLeft().lat(), 0.0);
|
||||
|
||||
INFO_LOG(m_logger) << "aesType: " << data.aesTypeId();
|
||||
|
||||
switch (data.aesTypeId().underlying())
|
||||
{
|
||||
case AreaEffectSimulation::AesType::AtMineArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::MineArea;
|
||||
break;
|
||||
case AreaEffectSimulation::AesType::AtExplosionArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::HitEffectSimulation;
|
||||
break;
|
||||
case AreaEffectSimulation::AesType::AtExplosionCluster:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::ExplosionCluster;
|
||||
break;
|
||||
case AreaEffectSimulation::AesType::AtMineAreaSingleMines:
|
||||
return;
|
||||
case AreaEffectSimulation::AesType::AtNContamination:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::NContamination;
|
||||
break;
|
||||
case AreaEffectSimulation::AesType::AtBCContamination:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::BCContamination;
|
||||
break;
|
||||
case AreaEffectSimulation::AesType::AtBorderline:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::Borderline;
|
||||
break;
|
||||
case AreaEffectSimulation::AesType::AtDangerArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::DangerArea;
|
||||
break;
|
||||
case AreaEffectSimulation::AesType::AtFunctionalArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::FunctionalArea;
|
||||
break;
|
||||
case AreaEffectSimulation::AesType::AtMineCorridor:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::MineCorridor;
|
||||
break;
|
||||
case AreaEffectSimulation::AesType::AtTechnicalArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::TechnicalArea;
|
||||
break;
|
||||
case AreaEffectSimulation::AesType::AtGasPipe:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::GasPipe;
|
||||
break;
|
||||
// No ExerciseEvent for AesType
|
||||
default:
|
||||
{
|
||||
INFO_LOG(m_logger) << "No ExerciseEvent for AesType:" << data.aesTypeId().underlying();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AreaEffectSimulation::AesItem aesItem;
|
||||
m_aesDtc->aesItemFromId(data.aesItemId(), aesItem);
|
||||
|
||||
if (eData.eventTypeId == ProjectDataManagement::EventType::ExplosionCluster)
|
||||
{
|
||||
ProjectDataManagement::GearClass gearClass = m_pdmDtc->gearClassFromChargeTypeId(aesItem.chargeStruct().chargeTypeId());
|
||||
if (gearClass == ProjectDataManagement::GearClass_def::AirSupport)
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::AirSupport;
|
||||
}
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("AesId")] = QJsonValue(aesItem.id());
|
||||
obj[QStringLiteral("AesName")] = QJsonValue(QString::fromStdString(aesItem.name()));
|
||||
obj[QStringLiteral("AesType")] = QJsonValue(data.aesTypeId().underlying());
|
||||
if (data.aesTypeId().underlying() != AreaEffectSimulation::AesType::AtBorderline)
|
||||
{
|
||||
obj[QStringLiteral("duration")] = QJsonValue(aesItem.effectDuration());
|
||||
obj[QStringLiteral("ChargeTypeId")] = QJsonValue(data.chargeStruct().chargeTypeId());
|
||||
obj[QStringLiteral("endTime")] = QJsonValue(data.effectStart() + aesItem.effectDuration());
|
||||
}
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
|
||||
if (eData.id <= 0)
|
||||
{
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while inserting event data from AES ";
|
||||
break;
|
||||
}
|
||||
m_aesMap.insert(data.id(), eData);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_dbHandler->db()->update(eData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while updating event data from AES ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
publishData(eData);
|
||||
break;
|
||||
}
|
||||
case DataModification::eRemoved:
|
||||
{
|
||||
m_itemViews.remove(data.aesItemId());
|
||||
m_aesMap.remove(data.id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerParticipantEvent::onExplosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType)
|
||||
{
|
||||
|
||||
Database::EemEvent eData = m_aesMap[data.id()];
|
||||
if ( !data.effectStart().is_set())
|
||||
{
|
||||
return;
|
||||
}
|
||||
eData.sampleTime = data.effectStart().get();
|
||||
|
||||
if (data.partyId().is_set())
|
||||
eData.partyId = data.partyId().get();
|
||||
|
||||
switch(modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
m_aesEffectState.insert(data.id(), data.effectStateId());
|
||||
|
||||
break;
|
||||
case DataModification::eModified:
|
||||
{
|
||||
AreaEffectSimulation::AesEffectState effectState = m_aesEffectState.value(data.id());
|
||||
|
||||
// insert event only once
|
||||
if (effectState != AreaEffectSimulation::AesEffectState::EsPrepared &&
|
||||
(effectState == AreaEffectSimulation::AesEffectState_def::EsActivated && data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsExpired))
|
||||
return;
|
||||
|
||||
m_aesEffectState.insert(data.id(), data.effectStateId());
|
||||
//m_itemViews.insert(data.id(), data.aesTypeId());
|
||||
|
||||
eData.eventTypeId = ProjectDataManagement::EventType::FireEvent;
|
||||
|
||||
AreaEffectSimulation::AesItem aesItem;
|
||||
m_aesDtc->aesItemFromId(data.id(), aesItem);
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("AesId")] = QJsonValue(aesItem.id());
|
||||
obj[QStringLiteral("AesName")] = QJsonValue(QString::fromStdString(aesItem.name()));
|
||||
obj[QStringLiteral("AesType")] = QJsonValue(AreaEffectSimulation::AesType::AtExplosionSingle);
|
||||
obj[QStringLiteral("ChargeTypeId")] = QJsonValue(data.chargeStruct().chargeTypeId());
|
||||
obj[QStringLiteral("duration")] = QJsonValue(aesItem.effectDuration());
|
||||
obj[QStringLiteral("endTime")] = QJsonValue(data.effectStart().get() + aesItem.effectDuration());
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
|
||||
//const Core::GeoPosition geoPosition ( data.impactPosition().lon(), data.impactPosition().lat(), 0);
|
||||
const LtsUtils::QPoint3D pos3D (data.impactPosition().lon(), data.impactPosition().lat(), 0);
|
||||
eData.position = pos3D;
|
||||
|
||||
if (eData.id <= 0)
|
||||
{
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while inserting event data from AES ";
|
||||
break;
|
||||
}
|
||||
m_aesMap.insert(data.id(), eData);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_dbHandler->db()->update(eData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while updating event data from AES ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
publishData(eData);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DEBUG_LOG(m_logger) << "Nothing to do";
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerParticipantEvent::onParticipantEventChanged(const CentralEffectSimulation::ParticipantEvent &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
Database::EemEvent eData;
|
||||
|
||||
eData.participantId = data.participantId();
|
||||
eData.equipmentNumber = data.equipmentNumber();
|
||||
eData.partyId = data.partyId();
|
||||
eData.sampleTime = data.eventTime();
|
||||
eData.position = LtsUtils::QPoint3D(data.position().lon(), data.position().lat(), data.position().z());
|
||||
DEBUG_LOG(m_logger) << " onParticipantEventChanged "
|
||||
<< " position=" << data.position()
|
||||
<< " eData.position=" << eData.position;
|
||||
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::Unknown;
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("AesId")] = QJsonValue(data.aesItemId());
|
||||
obj[QStringLiteral("AesType")] = QJsonValue(m_itemViews.value(data.aesItemId()).underlying());
|
||||
obj[QStringLiteral("AesName")] = QJsonValue(QString::fromStdString(data.aesName()));
|
||||
obj[QStringLiteral("FriendlyFire")] = QJsonValue(data.friendlyFire());
|
||||
|
||||
switch(data.eventTypeId().underlying())
|
||||
{
|
||||
case ProjectDataManagement::EventType_def::HitEffectSimulation:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::HitEffectSimulation;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::HitMine:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::HitMine;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::HitN:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::HitN;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::HitC:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::HitC;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::EnterDangerArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::EnterDangerArea;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::LeaveDangerArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::LeaveDangerArea;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::EnterMineArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::EnterMineArea;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::LeaveMineArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::LeaveMineArea;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::EnterNuclear:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::EnterNuclear;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::LeaveNuclear:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::LeaveNuclear;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::CrossLocalBorderline:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::CrossLocalBorderline;
|
||||
obj[QStringLiteral("Global")] = QJsonValue(false);
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::CrossGlobalBorderline:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::CrossGlobalBorderline;
|
||||
obj[QStringLiteral("Global")] = QJsonValue(true);
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::EnterFunctionalArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::EnterFunctionalArea;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::LeaveFunctionalArea:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::LeaveFunctionalArea;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::EnterHazardDistance:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::EnterHazardDistance;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::LeaveHazardDistance:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::LeaveHazardDistance;
|
||||
break;
|
||||
case ProjectDataManagement::EventType_def::AirSupport:
|
||||
eData.eventTypeId = ProjectDataManagement::EventType_def::AirSupport;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
eData.properties = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
|
||||
|
||||
if (!m_dbHandler->db()->insert(eData))
|
||||
ERROR_LOG(m_logger) << "Error while inserting event data from CES ";
|
||||
else
|
||||
publishData(eData);
|
||||
|
||||
|
||||
} // end of onParticipantEventChanged()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HandlerParticipantEvent::publishData(const Database::EemEvent &data)
|
||||
{
|
||||
m_eventServer->sendEvent(Database::toJson(data));
|
||||
|
||||
ExerciseEventManagement::Event ddsData = toDdsData(data);
|
||||
|
||||
if (!m_ddsHandler->dts()->publish(ddsData))
|
||||
ERROR_LOG(m_logger) << "Error publishing event-data to dds";
|
||||
|
||||
// take data from dds-bus after 10s, we need just to make sure the recording service got it
|
||||
m_mainHandler->addEventIdToRemove(ddsData.id());
|
||||
}
|
||||
|
||||
ExerciseEventManagement::Event HandlerParticipantEvent::toDdsData(const Database::EemEvent &data)
|
||||
{
|
||||
ExerciseEventManagement::Event ddsData;
|
||||
|
||||
ddsData.id(data.id);
|
||||
ddsData.sampleTime(data.sampleTime);
|
||||
ddsData.participantId(data.participantId);
|
||||
ddsData.partyId(data.partyId);
|
||||
ddsData.equipmentNumber(data.equipmentNumber);
|
||||
ddsData.eventTypeId(data.eventTypeId);
|
||||
ddsData.properties(data.properties.toStdString());
|
||||
// Core::GeoPosition LtsUtils::QPoint3D
|
||||
Core::GeoPosition position(data.position.x(), data.position.y(),data.position.z());
|
||||
ddsData.position(position);
|
||||
return ddsData;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Handler for infrastructure data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by hjl, SLSE, 2016-09-21
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <CentralEffectSimulation/ces_dtc.h>
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <ProjectDataManagement/pdm_dtc.h>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QMap>
|
||||
|
||||
class QTimer;
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
|
||||
class HandlerParticipantEvent : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HandlerParticipantEvent(MainHandler *mainHandler,
|
||||
const std::shared_ptr<DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<DbHandler> &db,
|
||||
const std::shared_ptr<WebSocketEventServer> &eventServer);
|
||||
|
||||
~HandlerParticipantEvent();
|
||||
|
||||
/**
|
||||
* Initialize the handler to manage information from CES
|
||||
*/
|
||||
bool init();
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
* Handle the signals from 'CentralEffectSimulation'
|
||||
*/
|
||||
void onParticipantEventChanged(const CentralEffectSimulation::ParticipantEvent &data, DataModification modType);
|
||||
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType);
|
||||
void onExplosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType);
|
||||
|
||||
private: // methoden
|
||||
void publishData(const Database::EemEvent &data);
|
||||
ExerciseEventManagement::Event toDdsData(const Database::EemEvent &data);
|
||||
|
||||
|
||||
private: // attributes
|
||||
std::shared_ptr<DdsHandler> m_ddsHandler; ///< Pointer to DDS handler
|
||||
std::shared_ptr<DbHandler> m_dbHandler;
|
||||
std::shared_ptr<WebSocketEventServer> m_eventServer;
|
||||
std::shared_ptr<CentralEffectSimulation::Interface::Dtc> m_cesDtc; ///< Pointer to DTC ParticipantManagement interface object
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
|
||||
|
||||
QHash<int, AreaEffectSimulation::AesType> m_itemViews;
|
||||
QHash<int, AreaEffectSimulation::AesEffectState> m_aesEffectState;
|
||||
// <aesItemId, event>
|
||||
QMap<int, Database::EemEvent> m_aesMap;
|
||||
|
||||
MainHandler *m_mainHandler;
|
||||
NGL::INGLLogger &m_logger; ///< Interface to the Logging-Facility
|
||||
|
||||
};
|
||||
} // namespace ExerciseEventManagement
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
log4j.reset=true
|
||||
log4j.rootLogger=WARN, file
|
||||
|
||||
# Service: Exercise Event Management
|
||||
###########################################################
|
||||
|
||||
#log4j.logger.EEM=WARN
|
||||
#log4j.logger.EEM.main=WARN
|
||||
#log4j.logger.EEM.DbAdmin=INFO
|
||||
#log4j.logger.EEM.HandlerDynamicParticipantData=INFO
|
||||
#log4j.logger.EEM.Settings=INFO
|
||||
#log4j.logger.EEM.Publisher=INFO
|
||||
#log4j.logger.EEM.FtsImpl=INFO
|
||||
#log4j.logger.EEM.FtcImpl=INFO
|
||||
#log4j.logger.EEM.HandlerGetEvents=INFO
|
||||
#log4j.logger.EEM.Test=INFO
|
||||
#log4j.logger.EEM.WebSocketAvs=INFO
|
||||
|
||||
# AlarmManagement
|
||||
###########################################################
|
||||
|
||||
#log4j.logger.ALM.main=INFO
|
||||
#log4j.logger.ALM.DbAdmin=INFO
|
||||
#log4j.logger.ALM.DdsHandler=INFO
|
||||
#log4j.logger.ALM.HandlerConfigureAlarms=INFO
|
||||
#log4j.logger.ALM.HandlerParticipant=INFO
|
||||
#log4j.logger.ALM.HandlerEmergencyCall=INFO
|
||||
#log4j.logger.ALM.ObjectEmergencyCall=INFO
|
||||
#log4j.logger.ALM.Initialization=INFO
|
||||
#log4j.logger.ALM.HandlerAes=INFO
|
||||
#log4j.logger.ALM.MainHandler=INFO
|
||||
#log4j.logger.ALM.Settings=INFO
|
||||
#log4j.logger.ALM.Publisher=INFO
|
||||
#log4j.logger.ALM.FtsImpl=INFO
|
||||
#log4j.logger.ALM.FtcImpl=INFO
|
||||
|
||||
# File
|
||||
###########################################################
|
||||
log4j.appender.file=Lts::RollingFileAppender
|
||||
log4j.appender.file.MaxFileSize=1MB
|
||||
log4j.appender.file.MaxBackupIndex=9
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Console
|
||||
###########################################################
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern= %d %p %c %c{1} - %m (%-.30F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Syslog
|
||||
###########################################################
|
||||
log4j.appender.syslog=org.apache.log4j.SyslogAppender
|
||||
log4j.appender.syslog.Threshold=ERROR
|
||||
log4j.appender.syslog.SysLogHost=localhost
|
||||
log4j.appender.syslog.Facility=LOCAL7
|
||||
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
|
||||
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
|
||||
|
||||
|
||||
###########################################################
|
||||
###########################################################
|
||||
###########################################################
|
||||
# 1) Available Levels in LOG4CXX Version 0.10.0:
|
||||
# TRACE,
|
||||
# DEBUG,
|
||||
# INFO,
|
||||
# WARN,
|
||||
# ERROR
|
||||
# FATAL
|
||||
#
|
||||
# d = date/time
|
||||
# p = priority (Level)
|
||||
# c = category/channel
|
||||
# m = message
|
||||
# F = file
|
||||
# L = line
|
||||
# n = platform dependent line separator character or characters.
|
||||
# ....
|
||||
#
|
||||
# Examples for console:
|
||||
# a)
|
||||
# %d %p %c #%m# (%.50F:%L)%n
|
||||
# date/time
|
||||
# priority
|
||||
# category/channel
|
||||
# #message#
|
||||
# (Maximal 50Character des Filename von rechts:Line)
|
||||
# line separator
|
||||
#
|
||||
# b)
|
||||
# %d (%.15F:%L) %-5p %c |#| %m%n
|
||||
# date/time
|
||||
# (Maximal 15Character des Filename von rechts:Line)
|
||||
# priority, Right pad with spaces if the priority name is less than 5 characters long.
|
||||
# category/channel
|
||||
# message
|
||||
# line separator
|
||||
#
|
||||
# Examples for files:
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Building Config - logging facility
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name)
|
||||
{
|
||||
static const char ns[] = "EEM.";
|
||||
std::string loggerName;
|
||||
const size_t len = strlen(name);
|
||||
loggerName.reserve(sizeof(ns) + len);
|
||||
loggerName.append(ns, sizeof(ns) - 1);
|
||||
loggerName.append(name, len);
|
||||
|
||||
try
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
|
||||
getNGLLogger(loggerName);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
fprintf(stderr, "Error retrieving logger: %s", ex.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ExerciseEventManagement
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging for ExerciseEventManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include "eem_export.h"
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
using LOGGER_T = NGL::INGLLogger &;
|
||||
|
||||
EEM_COMMON_EXPORT LOGGER_T getLogger(const char *name);
|
||||
inline LOGGER_T getLogger(const QString &loggerName)
|
||||
{
|
||||
return getLogger(loggerName.toUtf8().constData());
|
||||
}
|
||||
} // namespace ExerciseEventManagement
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* main for ExerciseEventManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
#include <QNetworkProxy>
|
||||
#include <Evaluations/settings.h>
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "logger.h"
|
||||
#include "settings.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy());
|
||||
|
||||
LtsCommandLineParser::LtsCommandLineParser options;
|
||||
if (!options.init())
|
||||
return -1;
|
||||
app.createLogger("EEM", options.exerciseId());
|
||||
|
||||
ExerciseEventManagement::Settings::setIniFile(options.iniFile());
|
||||
Evaluations::Settings::setIniFile(options.iniFile());
|
||||
|
||||
int iRet = -3;
|
||||
{
|
||||
std::unique_ptr<ExerciseEventManagement::MainHandler> mainHandler(new ExerciseEventManagement::MainHandler);
|
||||
|
||||
if (!mainHandler->init(options.domainId(), options.exerciseId()))
|
||||
return iRet;
|
||||
|
||||
STARTUP_LOG(app.baseLogger());
|
||||
|
||||
iRet = app.exec();
|
||||
|
||||
SHUTDOWN_LOG(app.baseLogger());
|
||||
}
|
||||
|
||||
return iRet;
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* MainHandler for RecordingManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#include "main_handler.h"
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include "handler_dynamic_participant_data.h"
|
||||
#include "handler_participant_event.h"
|
||||
#include "handler_equipment_error_registration.h"
|
||||
#include "web_socket_avs.h"
|
||||
#include "web_socket_server.h"
|
||||
|
||||
#include <DDS/Core/pacemaker.h>
|
||||
#include <AlarmManagement/initialization.h>
|
||||
#include <FilterManagement/initialization.h>
|
||||
#include <MarkerManagement/initialization.h>
|
||||
#include <Evaluations/initialization.h>
|
||||
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
|
||||
MainHandler::MainHandler()
|
||||
: m_almService(nullptr)
|
||||
, m_fltService(nullptr)
|
||||
, m_mrkService(nullptr)
|
||||
, m_evlService(nullptr)
|
||||
, m_removeTimer(new QTimer(this))
|
||||
, m_logger(getLogger("MainHandler"))
|
||||
{
|
||||
connect(m_removeTimer, &QTimer::timeout, this, &MainHandler::onRemoveKeys);
|
||||
m_removeTimer->setInterval(5000);
|
||||
m_removeTimer->setSingleShot(false);
|
||||
m_removeTimer->start();
|
||||
}
|
||||
|
||||
MainHandler::~MainHandler()
|
||||
{
|
||||
delete m_almService;
|
||||
delete m_fltService;
|
||||
delete m_mrkService;
|
||||
delete m_evlService;
|
||||
|
||||
m_webSocketAvs = nullptr;
|
||||
m_webSocketEventServer = nullptr;
|
||||
|
||||
m_handlerEerEvent = nullptr;
|
||||
m_handlerPartEvent = nullptr;
|
||||
m_dynPartData = nullptr;
|
||||
|
||||
m_avmDtc = nullptr;
|
||||
m_ismDtc = nullptr;
|
||||
|
||||
m_ddsHandler = nullptr;
|
||||
m_dbHandler = nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool MainHandler::init(int domainId, int exerciseId)
|
||||
{
|
||||
bool bRet = initInternal(domainId, exerciseId);
|
||||
if (bRet)
|
||||
{
|
||||
INFO_LOG(m_logger) << "svcExerciseEventManagement successfully initialized";
|
||||
m_ddsHandler->setRunningState(Core::RunningState::Running);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing svcExerciseEventManagement...";
|
||||
if (m_ddsHandler)
|
||||
m_ddsHandler->setRunningState(Core::RunningState::StartingError);
|
||||
}
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
bool MainHandler::initInternal(int domainId, int exerciseId)
|
||||
{
|
||||
// initialize database
|
||||
m_dbHandler = std::make_shared<DbHandler>();
|
||||
if (!m_dbHandler->init(exerciseId, Settings::settings()))
|
||||
return false;
|
||||
|
||||
// initialize DDS
|
||||
m_ddsHandler = std::make_shared<DdsHandler>(domainId, exerciseId, IDL::PartitionType::Exercise);
|
||||
if (!m_ddsHandler->init())
|
||||
return false;
|
||||
|
||||
m_webSocketEventServer = std::make_shared<WebSocketEventServer>(m_dbHandler->db()->database());
|
||||
|
||||
if (!m_ismDtc)
|
||||
m_ismDtc = InfrastructureManagement::Interface::Dtc::create(m_ddsHandler->ddsConnector());
|
||||
m_ismDtc->enableMainStructureElement();
|
||||
|
||||
if (!m_avmDtc)
|
||||
m_avmDtc = AudioVideoManagement::Interface::Dtc::create(m_ddsHandler->ddsConnector());
|
||||
m_avmDtc->enableStreamName();
|
||||
|
||||
m_dynPartData = std::make_shared<HandlerDynamicParticipantData>(this, m_ddsHandler, m_dbHandler, m_webSocketEventServer);
|
||||
m_handlerPartEvent = std::make_shared<HandlerParticipantEvent>(this, m_ddsHandler, m_dbHandler, m_webSocketEventServer);
|
||||
m_handlerEerEvent = std::make_shared<HandlerEquipmentErrorRegistration>(this, m_ddsHandler, m_dbHandler, m_webSocketEventServer);
|
||||
|
||||
m_webSocketAvs = std::make_shared<WebSocketAvs>(this, m_ddsHandler, m_dbHandler, m_webSocketEventServer, m_avmDtc, m_ismDtc, exerciseId);
|
||||
m_webSocketAvs->setWsUrl(Settings::getWebSocketUrl());
|
||||
m_webSocketAvs->init();
|
||||
|
||||
m_almService = new AlarmManagement::Initialization;
|
||||
if (!m_almService->initialize(m_ddsHandler->ddsConnector(), m_dbHandler->db()->database()))
|
||||
return false;
|
||||
|
||||
m_fltService = new FilterManagement::Initialization;
|
||||
if (!m_fltService->initialize(m_ddsHandler->ddsConnector(), m_dbHandler->db()->database()))
|
||||
return false;
|
||||
|
||||
m_mrkService = new MarkerManagement::Initialization;
|
||||
if (!m_mrkService->initialize(m_ddsHandler->ddsConnector(), m_dbHandler->db()->database()))
|
||||
return false;
|
||||
|
||||
m_evlService = new Evaluations::Initialization;
|
||||
if (!m_evlService->initialize(m_ddsHandler->ddsConnector(), m_dbHandler->db()->database()) ||
|
||||
!m_evlService->loadFromDatabase())
|
||||
return false;
|
||||
|
||||
if (!loadFromDatabase())
|
||||
return false;
|
||||
|
||||
if (!m_almService->loadFromDatabase())
|
||||
return false;
|
||||
|
||||
if (!m_fltService->loadFromDatabase())
|
||||
return false;
|
||||
|
||||
if (!m_mrkService->loadFromDatabase())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainHandler::loadFromDatabase()
|
||||
{
|
||||
if (!m_webSocketEventServer || !m_webSocketEventServer->listen(Settings::getWebSocketServerPortRange(1)))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not initialize WebSocket Event server";
|
||||
return false;
|
||||
}
|
||||
m_ddsHandler->addPortToPacemaker(m_webSocketEventServer->listenPort(), Core::PortType::WebSocketServer);
|
||||
|
||||
if (!m_handlerEerEvent || !m_handlerEerEvent->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not initialize EquipmentErrorRegistration handler";
|
||||
return false;
|
||||
}
|
||||
if (!m_dynPartData || !m_dynPartData->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not initialize Participant Data handler";
|
||||
return false;
|
||||
}
|
||||
if (!m_handlerPartEvent || !m_handlerPartEvent->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not initialize Participant Event handler";
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "loadFromDatabase successfully finished";
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainHandler::addEventIdToRemove(qint64 id)
|
||||
{
|
||||
m_keysToRemove[time(nullptr)].push_back(id);
|
||||
}
|
||||
|
||||
void MainHandler::onRemoveKeys()
|
||||
{
|
||||
auto dts = m_ddsHandler->dts();
|
||||
qint64 toRemove = time(nullptr) - 10;
|
||||
auto it = m_keysToRemove.begin();
|
||||
while (it != m_keysToRemove.end() && it.key() < toRemove)
|
||||
{
|
||||
const auto &cont = it.value();
|
||||
for (const auto id : cont)
|
||||
dts->removeEventByKey(id);
|
||||
it = m_keysToRemove.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // ExerciseEventManagement
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* MainHandler for RecordingManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ExerciseEventManagement/eem_db.h>
|
||||
#include "dds_handler.h"
|
||||
#include "logger.h"
|
||||
#include <ngldb/db_service_handler.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
class Initialization;
|
||||
}
|
||||
namespace MarkerManagement
|
||||
{
|
||||
class Initialization;
|
||||
}
|
||||
namespace FilterManagement
|
||||
{
|
||||
class Initialization;
|
||||
}
|
||||
namespace Evaluations
|
||||
{
|
||||
class Initialization;
|
||||
}
|
||||
class QTimer;
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
using DbHandler = NGLDB::DbServiceHandler<DatabaseInterface>;
|
||||
class HandlerDynamicParticipantData;
|
||||
class HandlerParticipantEvent;
|
||||
class HandlerEquipmentErrorRegistration;
|
||||
class WebSocketAvs;
|
||||
class WebSocketEventServer;
|
||||
|
||||
class MainHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainHandler();
|
||||
~MainHandler();
|
||||
|
||||
bool init(int domainId, int exerciseId);
|
||||
void addEventIdToRemove(qint64 id);
|
||||
|
||||
private:
|
||||
bool initInternal(int domainId, int exerciseId);
|
||||
void onRemoveKeys();
|
||||
bool loadFromDatabase();
|
||||
|
||||
std::shared_ptr<DdsHandler> m_ddsHandler;
|
||||
std::shared_ptr<DbHandler> m_dbHandler;
|
||||
std::shared_ptr<HandlerDynamicParticipantData> m_dynPartData;
|
||||
std::shared_ptr<HandlerParticipantEvent> m_handlerPartEvent;
|
||||
std::shared_ptr<HandlerEquipmentErrorRegistration> m_handlerEerEvent;
|
||||
std::shared_ptr<WebSocketAvs> m_webSocketAvs;
|
||||
std::shared_ptr<WebSocketEventServer> m_webSocketEventServer;
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_avmDtc;
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
|
||||
|
||||
AlarmManagement::Initialization *m_almService;
|
||||
FilterManagement::Initialization *m_fltService;
|
||||
MarkerManagement::Initialization *m_mrkService;
|
||||
Evaluations::Initialization *m_evlService;
|
||||
|
||||
QTimer *m_removeTimer;
|
||||
QMap<qint64, QVector<qint64>> m_keysToRemove;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
} // namespace ExerciseEventManagement
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Settings for ExerciseEventManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
#include <QPoint>
|
||||
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
#include <LtsUtils/LtsUtilsCore/lts_portrange.h>
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
class NGLSettingsClass : public NGL::Settings
|
||||
{
|
||||
public:
|
||||
NGLSettingsClass()
|
||||
: NGL::Settings(s_iniFile.isEmpty() ? NGL::findProjectConfigFile() : s_iniFile)
|
||||
{}
|
||||
static void setIniFile(const QString &fn)
|
||||
{
|
||||
s_iniFile = fn;
|
||||
}
|
||||
static QString s_iniFile;
|
||||
};
|
||||
QString NGLSettingsClass::s_iniFile;
|
||||
Q_GLOBAL_STATIC(NGLSettingsClass, s)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
NGL::Settings *Settings::settings()
|
||||
{
|
||||
return s();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Settings::setIniFile(const QString &ini)
|
||||
{
|
||||
NGLSettingsClass::setIniFile(ini);
|
||||
}
|
||||
|
||||
QString Settings::getWebSocketUrl()
|
||||
{
|
||||
QString url = settings()->settings()->value(QStringLiteral("AVS_SERVER/url"), QStringLiteral("ws://EXCAVS01:7020")).toString();
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
int Settings::getCleanupTimeout()
|
||||
{
|
||||
int timeout = settings()->settings()->value(QStringLiteral("EEM/cleanupTimeout"), 600000).toInt();
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
QPair<quint16, quint16> Settings::getWebSocketServerPortRange(int typeId)
|
||||
{
|
||||
return LtsUtils::fromQPoint(settings()->settings()->value(QString(QStringLiteral("EEM/webSocketServerPortRange/%1")).arg(typeId), QPoint()).toPoint());
|
||||
}
|
||||
|
||||
} // namespace ExerciseEventManagement
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Settings for ExerciseEventManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QString>
|
||||
#include <QPair>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class Settings;
|
||||
}
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
namespace Settings
|
||||
{
|
||||
NGL::Settings *settings();
|
||||
void setIniFile(const QString &ini);
|
||||
QString getWebSocketUrl();
|
||||
int getCleanupTimeout();
|
||||
QPair<quint16, quint16> getWebSocketServerPortRange(int typeId);
|
||||
}
|
||||
|
||||
} // namespace ExerciseEventManagement
|
||||
+716
@@ -0,0 +1,716 @@
|
||||
/**
|
||||
* WebSocket connection to AVS to retrieve AVS events
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-02-06
|
||||
*/
|
||||
|
||||
|
||||
#include "web_socket_avs.h"
|
||||
#include "web_socket_server.h"
|
||||
#include "main_handler.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <ExerciseEventManagement/eem_db.h>
|
||||
|
||||
#include <QTimer>
|
||||
#include <QWebSocket>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
|
||||
ProjectDataManagement::EventType avsEventTypeToPdmEventType(int avsEventType)
|
||||
{
|
||||
ProjectDataManagement::EventType eventType;
|
||||
switch(avsEventType)
|
||||
{
|
||||
case 305: //MVS
|
||||
case 301: // CAMERA_AUDIO
|
||||
case 302: // CAMERA_VIDEO
|
||||
eventType = ProjectDataManagement::EventType::CameraVideo;
|
||||
break;
|
||||
case 303: // RADIO_CNR
|
||||
eventType = ProjectDataManagement::EventType::RadioCnr;
|
||||
break;
|
||||
case 304: // RADIO_TVC
|
||||
eventType = ProjectDataManagement::EventType::RadioTvc;
|
||||
break;
|
||||
default:
|
||||
eventType = ProjectDataManagement::EventType::Unknown;
|
||||
break;
|
||||
}
|
||||
return eventType;
|
||||
}
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
WebSocketAvs::WebSocketAvs(MainHandler *mainHandler,
|
||||
const std::shared_ptr<DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<DbHandler> &db,
|
||||
const std::shared_ptr<WebSocketEventServer> &eventServer,
|
||||
const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
int exerciseId,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_ddsHandler(ddsHandler)
|
||||
, m_dbHandler(db)
|
||||
, m_eventServer(eventServer)
|
||||
, m_avmDtc(avmDtc)
|
||||
, m_ismDtc(ismDtc)
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_wsSocket(nullptr)
|
||||
, m_wsReconnectTimer(new QTimer(this))
|
||||
, m_cleanupTimer(new QTimer(this))
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_lastUpdate(0)
|
||||
, m_bWebSocketDisconnectedWarnedOnce(false)
|
||||
, m_logger(getLogger("WebSocketAvs"))
|
||||
{
|
||||
connect(m_wsReconnectTimer, &QTimer::timeout,
|
||||
this, &WebSocketAvs::openWebSocket);
|
||||
|
||||
connect(m_cleanupTimer, &QTimer::timeout,
|
||||
this, &WebSocketAvs::onCleanUpDbInternal);
|
||||
|
||||
//if there is a positive time start it
|
||||
//if not: don't do it!
|
||||
int cleanupTimeout = Settings::getCleanupTimeout();
|
||||
INFO_LOG(m_logger) << "cleanup Timer Interval: " << cleanupTimeout;
|
||||
if (cleanupTimeout > 0)
|
||||
{
|
||||
m_cleanupTimer->setInterval(cleanupTimeout);
|
||||
m_cleanupTimer->start();
|
||||
INFO_LOG(m_logger) << "Started cleanup Timer with Interval: " << cleanupTimeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WebSocketAvs::~WebSocketAvs()
|
||||
{
|
||||
}
|
||||
|
||||
void WebSocketAvs::init()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "WebSocketAvs::init";
|
||||
m_wsReconnectTimer->start(1000);
|
||||
//onCleanUpDbInternal();
|
||||
}
|
||||
|
||||
void WebSocketAvs::setWsUrl(const QString &url)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Url: " << url;
|
||||
m_wsUrl = url;
|
||||
}
|
||||
|
||||
AvsData WebSocketAvs::jsonObjectToAvsData(const QJsonObject &obj)
|
||||
{
|
||||
AvsData data;
|
||||
data.id = 0;
|
||||
data.eventTime = obj[QStringLiteral("eventTime")].toDouble();
|
||||
data.endTime = obj[QStringLiteral("endTime")].toDouble();
|
||||
data.streamName = obj[QStringLiteral("streamName")].toString();
|
||||
|
||||
int avsEventType = obj[QStringLiteral("eventType")].toInt();
|
||||
ProjectDataManagement::EventType eventType;
|
||||
switch(avsEventType)
|
||||
{
|
||||
case 301: // CAMERA_AUDIO
|
||||
case 302: // CAMERA_VIDEO
|
||||
eventType = ProjectDataManagement::EventType::CameraVideo;
|
||||
break;
|
||||
case 303: // RADIO_CNR
|
||||
eventType = ProjectDataManagement::EventType::RadioCnr;
|
||||
break;
|
||||
case 304: // RADIO_TVC
|
||||
eventType = ProjectDataManagement::EventType::RadioTvc;
|
||||
break;
|
||||
default:
|
||||
eventType = ProjectDataManagement::EventType::Unknown;
|
||||
ERROR_LOG(m_logger) << "Unknown avsEventType: " << avsEventType;
|
||||
break;
|
||||
}
|
||||
data.eventType = eventType.underlying();
|
||||
|
||||
int mountingPointId = 0;
|
||||
if (m_avmDtc->mountingPointForStreamName(data.streamName, mountingPointId))
|
||||
{
|
||||
int mainStructureElementId = 0;
|
||||
if (m_ismDtc->getBuildingId(mountingPointId, mainStructureElementId))
|
||||
data.mainStructureElementId = mainStructureElementId;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
Database::EemEvent WebSocketAvs::avsDataToEemEvent(const AvsData &data)
|
||||
{
|
||||
Database::EemEvent eemEvent;
|
||||
eemEvent.id = data.id;
|
||||
eemEvent.eventTypeId = data.eventType.underlying();
|
||||
eemEvent.sampleTime = data.eventTime;
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("streamName")] = data.streamName;
|
||||
if (data.endTime > 0)
|
||||
{
|
||||
qint64 duration = data.endTime - data.eventTime;
|
||||
obj[QStringLiteral("duration")] = duration;
|
||||
}
|
||||
obj[QStringLiteral("endTime")] = data.endTime;
|
||||
obj[QStringLiteral("MainStructureElementId")] = data.mainStructureElementId;
|
||||
eemEvent.properties = QString::fromUtf8(QJsonDocument(obj).toJson());
|
||||
|
||||
return eemEvent;
|
||||
}
|
||||
|
||||
ExerciseEventManagement::Event WebSocketAvs::avsDataToEvent(const AvsData &data)
|
||||
{
|
||||
ExerciseEventManagement::Event event;
|
||||
event.id(data.id);
|
||||
event.sampleTime(data.eventTime);
|
||||
event.eventTypeId(data.eventType);
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("streamName")] = data.streamName;
|
||||
if (data.endTime > 0)
|
||||
{
|
||||
qint64 duration = data.endTime - data.eventTime;
|
||||
obj[QStringLiteral("duration")] = duration;
|
||||
}
|
||||
obj[QStringLiteral("endTime")] = data.endTime;
|
||||
obj[QStringLiteral("MainStructureElementId")] = data.mainStructureElementId;
|
||||
event.properties(QJsonDocument(obj).toJson(QJsonDocument::Compact).toStdString());
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
void WebSocketAvs::onTextMessageReceived(const QString &message)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Got message from AVS control process: " << message;
|
||||
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(message.toUtf8()));
|
||||
const QJsonObject obj = doc.object();
|
||||
AvsData data = jsonObjectToAvsData(obj);
|
||||
|
||||
bool lastRangeClosed = obj[QStringLiteral("lastRangeClosed")].toBool();
|
||||
handleAvsData(data, lastRangeClosed);
|
||||
}
|
||||
|
||||
void WebSocketAvs::handleAvsData(const AvsData &data, const bool &lastRangeClosed)
|
||||
{
|
||||
QString streamName = data.streamName;
|
||||
|
||||
DEBUG_LOG(m_logger) << "handleAvsData for stream: " << streamName;
|
||||
|
||||
auto it = m_avsDataMap.find(streamName);
|
||||
|
||||
// existing stream ..........................................................
|
||||
if (it != m_avsDataMap.end())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "handleAvsData for stream 1: " << streamName;
|
||||
AvsData &avsData = m_avsDataMap[streamName];
|
||||
if ( (avsData.endTime == -1) && (data.endTime == -1))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "kein Publish (avsData.endTime == -1) && (data.endTime == -1)";
|
||||
return;
|
||||
}
|
||||
if ( (data.endTime == -1) && (data.eventType == ProjectDataManagement::EventType::RadioCnr))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "kein Publish (avsData.endTime == -1) && RadioCnr";
|
||||
return;
|
||||
}
|
||||
|
||||
if (avsData.eventTime != data.eventTime) // new range -> close old range
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "handleAvsData for stream 2: " << streamName;
|
||||
if (avsData.eventTime == -1) // missing end time -> set artificial end time
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Missing end time for stream: " << streamName << " -> setting artificial end time: " << avsData.eventTime + 1000;
|
||||
avsData.eventTime = avsData.eventTime + 1000;
|
||||
publishData(streamName);
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "handleAvsData for stream remove: " << streamName;
|
||||
m_avsDataMap.remove(streamName);
|
||||
}
|
||||
else // update range
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "handleAvsData update range publish" << streamName;
|
||||
|
||||
avsData.endTime = data.endTime;
|
||||
publishData(streamName);
|
||||
// if (lastRangeClosed)
|
||||
// m_avsDataMap.remove(streamName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// new range ................................................................
|
||||
DEBUG_LOG(m_logger) << "m_avsDataMap.insert(streamName";
|
||||
m_avsDataMap.insert(streamName, data);
|
||||
AvsData &avsData = m_avsDataMap[streamName];
|
||||
if (!lastRangeClosed)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "!lastRangeClosed";
|
||||
avsData.endTime = -1;
|
||||
}
|
||||
else if (avsData.endTime == -1) // range is closed but end time is missing
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "avsData.endTime == -1";
|
||||
avsData.endTime = avsData.eventTime + 1000; // -> set artificial end time
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "publishData";
|
||||
avsData.id = publishData(streamName);
|
||||
// if (lastRangeClosed)
|
||||
// m_avsDataMap.remove(streamName);
|
||||
|
||||
// // new stream ...............................................................
|
||||
// if (it == m_avsDataMap.end())
|
||||
// {
|
||||
// DEBUG_LOG(m_logger) << "received event on new stream: " << streamName;
|
||||
// AvsData avsData = data;
|
||||
// if (!lastRangeClosed) // waiting for end time
|
||||
// avsData.endTime = -1;
|
||||
// else if (avsData.endTime == -1) // missing end time -> set artificial end time
|
||||
// avsData.endTime = avsData.eventTime + 1000;
|
||||
// m_avsDataMap.insert(streamName, avsData);
|
||||
// m_avsDataMap[streamName].id = publishData(streamName);
|
||||
// if (lastRangeClosed) // event is over -> data not needed anymore
|
||||
// {
|
||||
// m_avsDataMap.remove(streamName);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// // ..........................................................................
|
||||
|
||||
// AvsData &avsData = m_avsDataMap[streamName]; // working on reference
|
||||
|
||||
// if (avsData.eventTime != data.eventTime) // same stream, different time -> new event received
|
||||
// {
|
||||
// DEBUG_LOG(m_logger) << "new event on stream: " << streamName;
|
||||
|
||||
// // close old event ........................................................
|
||||
// if (avsData.endTime == -1) // last event on the same stream was not closed
|
||||
// {
|
||||
// WARNING_LOG(m_logger) << "Missing end time for stream: " << streamName << ". Setting artificial end time.";
|
||||
// avsData.endTime = avsData.eventTime + 1000;
|
||||
// publishData(streamName);
|
||||
// }
|
||||
// // ........................................................................
|
||||
|
||||
// avsData = data;
|
||||
// avsData.id = 0;
|
||||
// m_avsDataMap[streamName].id = publishData(streamName);
|
||||
// if (lastRangeClosed) // event is over -> data not needed anymore
|
||||
// {
|
||||
// m_avsDataMap.remove(streamName);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// else // same event
|
||||
// {
|
||||
// avsData.endTime = data.endTime;
|
||||
// DEBUG_LOG(m_logger) << "received new end time: " << data.endTime << " for stream: " << streamName;
|
||||
// if (lastRangeClosed)
|
||||
// {
|
||||
// publishData(streamName);
|
||||
// m_avsDataMap.remove(streamName); // event is over -> data not needed anymore
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
int WebSocketAvs::publishData(const QString &streamName)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "WebSocketAvs::publishData";
|
||||
if (streamName.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Ignoring empty stream name";
|
||||
return 0;
|
||||
}
|
||||
|
||||
AvsData data = m_avsDataMap.value(streamName);
|
||||
Database::EemEvent dbData = avsDataToEemEvent(data);
|
||||
ExerciseEventManagement::Event ddsEvent = avsDataToEvent(data);
|
||||
qint64 endTime = data.endTime;
|
||||
|
||||
bool isAlreadyInDb = false;
|
||||
auto cb = [this, dbData, &isAlreadyInDb, streamName, endTime] (const Database::EemEvent &ev)
|
||||
{
|
||||
// endTime and streamName aus DB Event (ev) Properties lesen!
|
||||
const QJsonDocument evDoc = QJsonDocument::fromJson(ev.properties.toUtf8());
|
||||
const QJsonObject evObj = evDoc.object();
|
||||
|
||||
const qint64 evEndTime = evObj[(QStringLiteral("end_time"))].toInt();
|
||||
const QString streamNameDb = evObj[QStringLiteral("streamName")].toString();
|
||||
|
||||
if ((ev.sampleTime == dbData.sampleTime && ev.eventTypeId == dbData.eventTypeId) ||
|
||||
(evEndTime > 0 && endTime == -1 ))
|
||||
{
|
||||
if (streamName == streamNameDb)
|
||||
isAlreadyInDb = true;
|
||||
}
|
||||
};
|
||||
if (!m_dbHandler->db()->selectBySampleTime(cb, dbData.sampleTime))
|
||||
{
|
||||
if (isAlreadyInDb)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Ignoring existing event at " << dbData.sampleTime;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// write to database
|
||||
if (dbData.id > 0)
|
||||
{
|
||||
if (!m_dbHandler->db()->update(dbData))
|
||||
ERROR_LOG(m_logger) << "Error while updating dbData with id : " << data.id;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_dbHandler->db()->insert(dbData))
|
||||
ERROR_LOG(m_logger) << "Error while inserting avsData in db: streamName: " << data.streamName;
|
||||
ddsEvent.id(dbData.id);
|
||||
}
|
||||
|
||||
// publish data
|
||||
INFO_LOG(m_logger) << "Publish data for stream: " << streamName << " and database id=" << dbData.id;
|
||||
m_eventServer->sendEvent(Database::toJson(dbData));
|
||||
m_ddsHandler->dts()->publish(ddsEvent);
|
||||
m_mainHandler->addEventIdToRemove(dbData.id); // take data from dds-bus after 10s, we need just to make sure the recording service got it
|
||||
|
||||
return dbData.id;
|
||||
}
|
||||
|
||||
|
||||
void WebSocketAvs::openWebSocket()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "openWebSocket";
|
||||
closeWebSocket();
|
||||
m_wsSocket = new QWebSocket;
|
||||
connect(m_wsSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error),
|
||||
this, &WebSocketAvs::onWebSocketError);
|
||||
connect(m_wsSocket, &QWebSocket::connected,
|
||||
this, &WebSocketAvs::onWebSocketConnected);
|
||||
connect(m_wsSocket, &QWebSocket::disconnected,
|
||||
this, &WebSocketAvs::onWebSocketDisconnected);
|
||||
connect(m_wsSocket, &QWebSocket::textMessageReceived,
|
||||
this, &WebSocketAvs::onTextMessageReceived);
|
||||
|
||||
m_wsSocket->open(QUrl::fromEncoded(m_wsUrl.toLocal8Bit()));
|
||||
}
|
||||
|
||||
void WebSocketAvs::closeWebSocket()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "closeWebSocket";
|
||||
if (m_wsSocket)
|
||||
{
|
||||
m_wsSocket->disconnect(this);
|
||||
m_wsSocket->close();
|
||||
m_wsSocket->deleteLater();
|
||||
m_wsSocket = nullptr;
|
||||
}
|
||||
m_wsReconnectTimer->stop();
|
||||
}
|
||||
|
||||
void WebSocketAvs::onWebSocketError(QAbstractSocket::SocketError error)
|
||||
{
|
||||
if (!m_wsSocket)
|
||||
return;
|
||||
WARNING_LOG(m_logger) << "Error connecting to " << m_wsSocket->peerAddress().toString() << ": " << error;
|
||||
closeWebSocket();
|
||||
m_wsReconnectTimer->start(1000);
|
||||
}
|
||||
|
||||
void WebSocketAvs::onWebSocketConnected()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "connected to via websockets";
|
||||
m_wsReconnectTimer->stop();
|
||||
m_bWebSocketDisconnectedWarnedOnce = false;
|
||||
|
||||
QTimer::singleShot(300, this, &WebSocketAvs::onSendExerciseId);
|
||||
}
|
||||
|
||||
void WebSocketAvs::onWebSocketDisconnected()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "WebSocketAvs::onWebSocketDisconnected()";
|
||||
if (!m_bWebSocketDisconnectedWarnedOnce)
|
||||
{
|
||||
m_bWebSocketDisconnectedWarnedOnce = true;
|
||||
WARNING_LOG(m_logger) << "Websocket to " << m_wsUrl << " closed - trying to reconnect in 1 sec";
|
||||
}
|
||||
|
||||
closeWebSocket();
|
||||
m_wsReconnectTimer->start(1000);
|
||||
}
|
||||
|
||||
void WebSocketAvs::onSendExerciseId()
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Send exerciseId: ";
|
||||
|
||||
QJsonObject obj;
|
||||
|
||||
obj[QStringLiteral("exerciseId")] = QJsonValue(m_exerciseId);
|
||||
|
||||
QString jsonStr = QString::fromUtf8(QJsonDocument(obj).toJson());
|
||||
m_wsSocket->sendTextMessage(jsonStr);
|
||||
}
|
||||
|
||||
void WebSocketAvs::onCleanUpDbInternal()
|
||||
{
|
||||
m_cleanupTimer->stop();
|
||||
|
||||
const auto allDataMap = getAllAvsData();
|
||||
const auto dbData = getAllInternalDbData();
|
||||
//qCritical() << " START CLEANUP with " << allDataMap.keys().size() << " keys";
|
||||
m_avmDtc->waitForHistoricalDataStreamName(1500);
|
||||
m_ismDtc->waitForHistoricalDataMainStructureElement(1500);
|
||||
// qCritical() << "CHECK STREAMNAME " << m_avmDtc->streamNames().size();
|
||||
for (const auto &stream : allDataMap.keys())
|
||||
{
|
||||
QVector<AvsData> externalData = allDataMap.value(stream);
|
||||
|
||||
|
||||
//This is the fixed map ... there shouldn't be multiple entries!
|
||||
QMap<quint64, AvsData> ntpRangeSortExternal;
|
||||
for (const auto &eavItem : externalData)
|
||||
{
|
||||
ntpRangeSortExternal.insert(eavItem.eventTime, eavItem);
|
||||
}
|
||||
|
||||
|
||||
QMultiMap<quint64, AvsData> ntpRangeSortLocal;
|
||||
for (const auto &avItem : dbData.value(stream))
|
||||
{
|
||||
ntpRangeSortLocal.insert(avItem.eventTime, avItem);
|
||||
}
|
||||
DEBUG_LOG(m_logger) <<" Start with key: '" << stream << "' external = " << externalData.size() << " internal: " << ntpRangeSortLocal.size();
|
||||
QVector<qint64> itemsToRemoveFromInternal;
|
||||
QMap<qint64, AvsData> collection;
|
||||
QVector<AvsData> toAdd;
|
||||
QVector<AvsData> toIgnore;
|
||||
QVector<AvsData> toUpdate;
|
||||
|
||||
|
||||
for (const auto &eItem : ntpRangeSortExternal)
|
||||
{
|
||||
QList<AvsData> list = ntpRangeSortLocal.values(eItem.eventTime);
|
||||
if (list.isEmpty())
|
||||
{
|
||||
//there is no external item so add
|
||||
if (!collection.contains(eItem.eventTime))
|
||||
{
|
||||
AvsData add = eItem;
|
||||
bool checkMsi = eItem.eventType == ProjectDataManagement::EventType::CameraVideo;
|
||||
|
||||
int mountingPointId = 0;
|
||||
if (checkMsi && m_avmDtc->mountingPointForStreamName(eItem.streamName, mountingPointId))
|
||||
{
|
||||
//FATAL_LOG(m_logger) << "FOUND MPI ";
|
||||
|
||||
int mainStructureElementId = 0;
|
||||
if (m_ismDtc->getBuildingId(mountingPointId, mainStructureElementId))
|
||||
add.mainStructureElementId = mainStructureElementId;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "need to add: " << add.eventType << " st: " << add.streamName << " mpi:" << add.mainStructureElementId;
|
||||
toAdd.append(add);
|
||||
collection.insert(add.eventTime, add);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for ( auto item : list)
|
||||
{
|
||||
bool checkMsi = eItem.eventType == ProjectDataManagement::EventType::CameraVideo;
|
||||
|
||||
if (item.endTime == eItem.endTime )
|
||||
{
|
||||
|
||||
//FINF MSE ID!
|
||||
int mountingPointId = 0;
|
||||
int mainStructureElementId = 0;
|
||||
|
||||
if (checkMsi && m_avmDtc->mountingPointForStreamName(item.streamName, mountingPointId))
|
||||
{
|
||||
//qCritical() << "FOUND mpi" << mountingPointId << " for Streamname: " << item.streamName;
|
||||
m_ismDtc->getBuildingId(mountingPointId, mainStructureElementId);
|
||||
//qCritical() << "FOUND msi" << mainStructureElementId;
|
||||
}
|
||||
if(item.mainStructureElementId == 0 && mainStructureElementId > 0)
|
||||
{
|
||||
item.mainStructureElementId = mainStructureElementId;
|
||||
toUpdate.append(item);
|
||||
}
|
||||
else
|
||||
toIgnore.append(item);
|
||||
collection.insert(item.eventTime, item);
|
||||
continue;
|
||||
}else // if (eItem.endTime != item.endTime) is always true
|
||||
{
|
||||
item.endTime = eItem.endTime;
|
||||
//item.eventType = lItem.eventType;
|
||||
int mountingPointId = 0;
|
||||
if (checkMsi && m_avmDtc->mountingPointForStreamName(item.streamName, mountingPointId))
|
||||
{
|
||||
int mainStructureElementId = 0;
|
||||
if (m_ismDtc->getBuildingId(mountingPointId, mainStructureElementId))
|
||||
{
|
||||
item.mainStructureElementId = mainStructureElementId;
|
||||
}
|
||||
}
|
||||
toUpdate.append(item);
|
||||
collection.insert(item.eventTime, item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (const AvsData &oldEntry : qAsConst(ntpRangeSortLocal))
|
||||
{
|
||||
const auto &item = collection.value(oldEntry.eventTime);
|
||||
|
||||
if (item.id <= 0 )
|
||||
itemsToRemoveFromInternal.append(oldEntry.id);
|
||||
}
|
||||
//now remove old entries
|
||||
|
||||
|
||||
//REMOVE DATA
|
||||
for( const auto &del: itemsToRemoveFromInternal)
|
||||
{
|
||||
// FATAL_LOG(m_logger) << "need to remove " << del;
|
||||
m_dbHandler->db()->removeEemEvent(del);
|
||||
}
|
||||
|
||||
|
||||
for( const auto &update: toUpdate)
|
||||
{
|
||||
//UPDATE DATA
|
||||
Database::EemEvent dbDataUpdate = avsDataToEemEvent(update);
|
||||
m_dbHandler->db()->update(dbDataUpdate);
|
||||
}
|
||||
for( const auto &add: toAdd)
|
||||
{
|
||||
//ADD
|
||||
Database::EemEvent dbDataAdd = avsDataToEemEvent(add);
|
||||
dbDataAdd.id = 0;
|
||||
m_dbHandler->db()->insert(dbDataAdd);
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "DONE Sync wite remote DB "<< stream << " to Ignore" << toIgnore.size()<< " to Add" << toAdd.size() << " to Update:" << toUpdate.size()<< " to remove:" << itemsToRemoveFromInternal.size();
|
||||
}
|
||||
m_cleanupTimer->start();
|
||||
m_lastUpdate = QDateTime::currentMSecsSinceEpoch()-2*60*1000;
|
||||
DEBUG_LOG(m_logger) << "DONE Sync wite remote DB next check starts at: " << QDateTime::fromMSecsSinceEpoch(m_lastUpdate).toString();
|
||||
}
|
||||
|
||||
QMap<QString, QVector<AvsData> > WebSocketAvs::getAllAvsData()
|
||||
{
|
||||
|
||||
//select all Data from AVS avm_timeline events
|
||||
// order by stream
|
||||
QMultiMap<QString, AvsData> ret;
|
||||
QMap<QString, QVector<AvsData> > retu;
|
||||
|
||||
//QString tableNameCameraEvents = (QLatin1String("avm") + QLatin1String(".avs_camera_events")); // todo get shema name
|
||||
|
||||
QString stmt(QLatin1String("SELECT id, time_start_msec, time_end_msec, stream_name, event_type, last_update FROM ") + QLatin1String("avm.avs_camera_events") +
|
||||
QLatin1String(" WHERE context_id = :context"));
|
||||
if (m_lastUpdate > 0)
|
||||
stmt += QLatin1String(" and time_start_msec > ") + QString::number(m_lastUpdate);
|
||||
DEBUG_LOG(m_logger) << "START Sync read remote DB at " << QDateTime::fromMSecsSinceEpoch(m_lastUpdate).toString();
|
||||
NSqlQuery q(m_dbHandler->db()->database());
|
||||
if (!q.prepare(stmt))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not prepare statement" << stmt << q.lastError().text() << q.lastError().databaseText();
|
||||
return retu;
|
||||
} // if
|
||||
q.setForwardOnly(true);
|
||||
QString val = QStringLiteral("ex_") + QString::number(m_exerciseId);
|
||||
q.bindValue(QLatin1String(":context"),val);
|
||||
|
||||
// qWarning() << "frist try statement fallback" << stmt ;
|
||||
|
||||
|
||||
if (!q.exec())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Could not execute" << stmt << q.lastError().text() << q.lastError().databaseText();
|
||||
return retu;
|
||||
} // if
|
||||
|
||||
//qWarning() << "frist try FOUND" << q.size() ;
|
||||
|
||||
AvsData item;
|
||||
int j =0;
|
||||
while(q.next())
|
||||
{
|
||||
int i = 0;
|
||||
item.id = q.value(i++).toInt();
|
||||
|
||||
item.eventTime = q.value(i++).toDouble();
|
||||
item.endTime = q.value(i++).toDouble();
|
||||
item.streamName = q.value(i++).toString().trimmed();
|
||||
item.eventType = avsEventTypeToPdmEventType(q.value(i++).toInt());
|
||||
ret.insert(item.streamName, item);
|
||||
j++;
|
||||
} // while
|
||||
|
||||
for (const auto &stream: ret.uniqueKeys())
|
||||
{
|
||||
retu.insert(stream, ret.values(stream).toVector());
|
||||
}
|
||||
// qCritical() << "DONE reading external db " << j;
|
||||
|
||||
return retu;
|
||||
|
||||
}
|
||||
|
||||
QMap<QString, QVector<AvsData>> WebSocketAvs::getAllInternalDbData()
|
||||
{
|
||||
//get all local db data
|
||||
QMap<QString, QVector<AvsData> > retu;
|
||||
|
||||
QMultiMap<QString, AvsData> ret;
|
||||
QVector<Database::EemEvent> dataVec;
|
||||
//qCritical() << "START reading internal db ";
|
||||
|
||||
m_dbHandler->db()->selectByEventTypeId(dataVec, ProjectDataManagement::EventType::CameraVideo);
|
||||
m_dbHandler->db()->selectByEventTypeId(dataVec, ProjectDataManagement::EventType::RadioCnr);
|
||||
m_dbHandler->db()->selectByEventTypeId(dataVec, ProjectDataManagement::EventType::RadioTvc);
|
||||
|
||||
// m_dbHandler->db()->select(dataVec);
|
||||
//qCritical() << "END select reading internal db ";
|
||||
DEBUG_LOG(m_logger) << "START Sync read local DB at " << QDateTime::fromMSecsSinceEpoch(m_lastUpdate).toString();
|
||||
int j = 0;
|
||||
for (const auto &dataI : qAsConst(dataVec))
|
||||
{
|
||||
if (m_lastUpdate > 0 && dataI.sampleTime < m_lastUpdate)
|
||||
continue;
|
||||
QJsonDocument job = QJsonDocument::fromJson(dataI.properties.toUtf8());
|
||||
if(!job.isObject())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "ERROR Parsing Json";
|
||||
}
|
||||
|
||||
QJsonObject obj = job.object();
|
||||
|
||||
AvsData data;
|
||||
data.id = dataI.id;
|
||||
data.eventTime = dataI.sampleTime;
|
||||
data.endTime = obj.value(QStringLiteral("endTime")).toDouble();
|
||||
data.eventType = dataI.eventTypeId;
|
||||
data.mainStructureElementId =obj.value(QStringLiteral("MainStructureElementId")).toDouble();
|
||||
data.streamName =obj.value(QStringLiteral("streamName")).toString();
|
||||
|
||||
ret.insert(data.streamName, data);
|
||||
j++;
|
||||
//ok add to map
|
||||
}
|
||||
|
||||
for (const auto &stream: ret.uniqueKeys())
|
||||
{
|
||||
retu.insert(stream, ret.values(stream).toVector());
|
||||
}
|
||||
// qCritical() << "DONE reading internal db" << j;
|
||||
return retu;
|
||||
}
|
||||
|
||||
} // namespace ExerciseEventManagement
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* WebSocket connection to AVS to retrieve AVS events
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-02-06
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractSocket>
|
||||
#include <QTimer>
|
||||
#include <QVector>
|
||||
#include <QSharedPointer>
|
||||
#include "logger.h"
|
||||
|
||||
#include "dds_handler.h"
|
||||
#include "eem_db.h"
|
||||
#include <ngldb/db_service_handler.h>
|
||||
|
||||
#include <ExerciseEventManagement/eem.hpp>
|
||||
|
||||
#include <ProjectDataManagement/pdm_enums.hpp>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
|
||||
class QWebSocket;
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
class MainHandler;
|
||||
class WebSocketEventServer;
|
||||
|
||||
using DbHandler = NGLDB::DbServiceHandler<DatabaseInterface>;
|
||||
struct AvsData
|
||||
{
|
||||
int id;
|
||||
qint64 eventTime;
|
||||
qint64 endTime;
|
||||
ProjectDataManagement::EventType eventType;
|
||||
QString streamName;
|
||||
int mainStructureElementId;
|
||||
QSharedPointer<QTimer> timer; // no plain ptr here since AvsData is copied
|
||||
AvsData()
|
||||
: id(0)
|
||||
, eventTime(0)
|
||||
, endTime(-1)
|
||||
, eventType(ProjectDataManagement::EventType::Unknown)
|
||||
, mainStructureElementId(0)
|
||||
, timer(new QTimer)
|
||||
{
|
||||
timer->setSingleShot(true);
|
||||
timer->setInterval(3000);
|
||||
}
|
||||
};
|
||||
|
||||
class WebSocketAvs : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
WebSocketAvs(MainHandler *mainHandler,
|
||||
const std::shared_ptr<DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<DbHandler> &db,
|
||||
const std::shared_ptr<WebSocketEventServer> &eventServer,
|
||||
const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
int exerciseId,
|
||||
QObject *parent = nullptr);
|
||||
~WebSocketAvs();
|
||||
|
||||
void setWsUrl(const QString &url);
|
||||
void init();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onTextMessageReceived(const QString &message);
|
||||
void handleAvsData(const AvsData &data, const bool &lastRangeClosed);
|
||||
int publishData(const QString &streamName);
|
||||
void openWebSocket();
|
||||
void closeWebSocket();
|
||||
void onWebSocketError(QAbstractSocket::SocketError error);
|
||||
void onWebSocketConnected();
|
||||
void onWebSocketDisconnected();
|
||||
void onSendExerciseId();
|
||||
|
||||
void onCleanUpDbInternal();
|
||||
QMap<QString, QVector<AvsData>> getAllAvsData();
|
||||
QMap<QString, QVector<AvsData>> getAllInternalDbData();
|
||||
|
||||
private:
|
||||
AvsData jsonObjectToAvsData(const QJsonObject &obj);
|
||||
Database::EemEvent avsDataToEemEvent(const AvsData &data);
|
||||
ExerciseEventManagement::Event avsDataToEvent(const AvsData &data);
|
||||
|
||||
private:
|
||||
std::shared_ptr<DdsHandler> m_ddsHandler; ///< Pointer to DDS handler
|
||||
std::shared_ptr<DbHandler> m_dbHandler;
|
||||
std::shared_ptr<WebSocketEventServer> m_eventServer;
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_avmDtc;
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
MainHandler *m_mainHandler;
|
||||
QWebSocket *m_wsSocket;
|
||||
QTimer *m_wsReconnectTimer;
|
||||
QTimer *m_cleanupTimer;
|
||||
QString m_wsUrl;
|
||||
QMap<QString, AvsData> m_avsDataMap;
|
||||
int m_exerciseId;
|
||||
qint64 m_lastUpdate;
|
||||
bool m_bWebSocketDisconnectedWarnedOnce;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
} // namespace ExerciseEventManagement
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* WebSocketServer to publish Events
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-02-06
|
||||
*/
|
||||
|
||||
|
||||
#include "web_socket_server.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QSqlError>
|
||||
#include <QTimer>
|
||||
#include <QUrlQuery>
|
||||
#include <QWebSocket>
|
||||
#include <QWebSocketServer>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
WebSocketEventServer::WebSocketEventServer(const QSqlDatabase &db, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_wsServer(nullptr)
|
||||
, m_cleanupTimer(new QTimer(this))
|
||||
, m_db(db)
|
||||
, m_logger(getLogger("WebSocketEventServer"))
|
||||
{
|
||||
m_cleanupTimer->setInterval(10000); // clear every 10s
|
||||
connect(m_cleanupTimer, &QTimer::timeout, this, &WebSocketEventServer::onCleanupLiveHistory);
|
||||
}
|
||||
|
||||
WebSocketEventServer::~WebSocketEventServer()
|
||||
{
|
||||
for (auto s : qAsConst(m_liveSockets))
|
||||
{
|
||||
s->disconnect(this);
|
||||
s->close();
|
||||
}
|
||||
qDeleteAll(m_liveSockets);
|
||||
}
|
||||
|
||||
bool WebSocketEventServer::listen(const QPair<quint16, quint16> &portRange)
|
||||
{
|
||||
for (quint16 currentPort = portRange.first; currentPort <= portRange.second; ++currentPort)
|
||||
{
|
||||
if (listen(currentPort))
|
||||
return true;
|
||||
}
|
||||
|
||||
return listen(0);
|
||||
}
|
||||
|
||||
bool WebSocketEventServer::listen(quint16 port)
|
||||
{
|
||||
if (m_wsServer && m_wsServer->isListening())
|
||||
return true;
|
||||
|
||||
m_cleanupTimer->start();
|
||||
|
||||
delete m_wsServer;
|
||||
m_wsServer = new QWebSocketServer(QStringLiteral("EEM-Events"), QWebSocketServer::NonSecureMode, this);
|
||||
|
||||
connect(m_wsServer, &QWebSocketServer::newConnection,
|
||||
this, &WebSocketEventServer::onNewConnection);
|
||||
|
||||
bool bRet = m_wsServer->listen(QHostAddress::Any, port);
|
||||
|
||||
if (bRet)
|
||||
NOTICE_LOG(m_logger) << "Listening on port " << listenPort();
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
quint16 WebSocketEventServer::listenPort() const
|
||||
{
|
||||
return m_wsServer ? m_wsServer->serverPort() : 0;
|
||||
}
|
||||
|
||||
void WebSocketEventServer::sendEvent(const QJsonObject &obj)
|
||||
{
|
||||
const QJsonDocument doc(obj);
|
||||
const QString msg = QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
|
||||
for (QWebSocket *ws : qAsConst(m_liveSockets))
|
||||
ws->sendTextMessage(msg);
|
||||
m_liveHistory[time(nullptr)].push_back(msg);
|
||||
}
|
||||
|
||||
|
||||
void WebSocketEventServer::onNewConnection()
|
||||
{
|
||||
QWebSocket *ws = m_wsServer->nextPendingConnection();
|
||||
if (!ws)
|
||||
return;
|
||||
DEBUG_LOG(m_logger) << "New incoming connection from "
|
||||
<< ws->peerAddress().toString() << ":"
|
||||
<< ws->peerPort() << ", "
|
||||
<< ws->requestUrl().toString();
|
||||
const QUrl requestUrl = ws->requestUrl();
|
||||
const QString requestPath = requestUrl.path();
|
||||
if (requestPath == QStringLiteral("/live"))
|
||||
{
|
||||
connect(ws, &QWebSocket::disconnected,
|
||||
this, &WebSocketEventServer::onSocketDisconnected);
|
||||
for (const auto &historyVec : qAsConst(m_liveHistory))
|
||||
{
|
||||
for (const auto &msg : historyVec)
|
||||
ws->sendTextMessage(msg);
|
||||
}
|
||||
m_liveSockets += ws;
|
||||
}
|
||||
else if (requestPath.startsWith(QLatin1String("/request")))
|
||||
historyDataRequested(m_db, ws, requestUrl);
|
||||
else
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Unknown request path: '" << requestPath << "' - closing";
|
||||
ws->close();
|
||||
ws->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketEventServer::onSocketDisconnected()
|
||||
{
|
||||
QWebSocket *ws = qobject_cast<QWebSocket *>(sender());
|
||||
if (!ws)
|
||||
return;
|
||||
DEBUG_LOG(m_logger) << "Disconnected from "
|
||||
<< ws->peerAddress().toString() << ":"
|
||||
<< ws->peerPort() << ", "
|
||||
<< ws->requestUrl().toString();
|
||||
ws->deleteLater();
|
||||
m_liveSockets -= ws;
|
||||
}
|
||||
|
||||
void WebSocketEventServer::onCleanupLiveHistory()
|
||||
{
|
||||
qint64 tNow = time(nullptr) - 120; // 2min
|
||||
auto it = m_liveHistory.begin();
|
||||
while (it != m_liveHistory.end() && it.key() < tNow)
|
||||
it = m_liveHistory.erase(it);
|
||||
}
|
||||
|
||||
void WebSocketEventServer::historyDataRequested(const QSqlDatabase &db, QWebSocket *ws, const QUrl &requestUrl)
|
||||
{
|
||||
const QUrlQuery query(requestUrl);
|
||||
const int requestId = query.queryItemValue(QStringLiteral("requestId")).toInt();
|
||||
const qint64 from = query.queryItemValue(QStringLiteral("from")).toLongLong();
|
||||
const qint64 to = query.queryItemValue(QStringLiteral("to")).toLongLong();
|
||||
if (requestId == 0 || from <= 0 || to <= 0 || from > to)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Unknown request: '" << requestUrl.toString() << "' - closing, "
|
||||
<< requestId << ", " << from << ", to " << to;
|
||||
ws->sendTextMessage(QStringLiteral("{}"));
|
||||
ws->close();
|
||||
ws->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QString stmt(QLatin1String(" SELECT id, event_type_id, participant_id, party_id, equipment_number, properties, sample_time, position_x, position_y, position_z"
|
||||
" FROM eem_event WHERE sample_time > ") + QString::number(from) +
|
||||
QLatin1String(" AND sample_time <= ") + QString::number(to));
|
||||
// add event type filter to query if preset
|
||||
if (query.hasQueryItem(QStringLiteral("eventTypeId")))
|
||||
{
|
||||
const QString ids = query.queryItemValue(QStringLiteral("eventTypeId"));
|
||||
// split/unsplit to make sure only integers are there
|
||||
const QVector<QStringRef> idVec = ids.splitRef(QLatin1Char(','));
|
||||
QStringList eventList;
|
||||
eventList.reserve(idVec.size());
|
||||
for (const auto &id : idVec)
|
||||
{
|
||||
int i = id.toInt();
|
||||
if (i == 0)
|
||||
continue;
|
||||
eventList += QString::number(i);
|
||||
}
|
||||
const QString eventStr = eventList.join(QLatin1Char(','));
|
||||
stmt += QStringLiteral(" AND event_type_id IN (") + eventStr + QLatin1Char(')');
|
||||
}
|
||||
|
||||
// add Json properties filter to query if present
|
||||
if (query.hasQueryItem(QStringLiteral("filter")))
|
||||
{
|
||||
const QString filterString = query.queryItemValue(QStringLiteral("filter"));
|
||||
DEBUG_LOG(m_logger) << "filter string: " << filterString;
|
||||
const QJsonObject obj(QJsonDocument::fromJson(filterString.toUtf8()).object());
|
||||
if (obj.keys().size() == 1)
|
||||
{
|
||||
const QJsonValue val = obj.value(obj.keys().constFirst());
|
||||
if (val.isObject())
|
||||
stmt += QStringLiteral(" AND properties @> '") + filterString + QLatin1Char('\'');
|
||||
else if (val.isArray())
|
||||
{
|
||||
// currently we only support int arrays
|
||||
const QJsonArray arr(val.toArray());
|
||||
QStringList sl;
|
||||
sl.reserve(arr.size());
|
||||
for (const auto &ele : arr)
|
||||
sl += QString::number(ele.toInt());
|
||||
if (sl.size() > 0)
|
||||
stmt += QStringLiteral(" AND CAST (properties ->> '%1' AS int) IN (").arg(obj.keys().constFirst()) +
|
||||
sl.join(QLatin1Char(',')) + QLatin1Char(')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add a limit for max query rows
|
||||
if (query.hasQueryItem(QStringLiteral("limit")))
|
||||
{
|
||||
const QString limitString = query.queryItemValue(QStringLiteral("limit"));
|
||||
DEBUG_LOG(m_logger) << "limiting query to " << limitString << " events";
|
||||
stmt += QStringLiteral(" LIMIT ") + limitString;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "stmt: " << stmt;
|
||||
|
||||
NSqlQuery q(db);
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while selecting event-data: " << stmt << ", " << q.lastError().databaseText();
|
||||
ws->sendTextMessage(QStringLiteral("{}"));
|
||||
ws->close();
|
||||
ws->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonArray events;
|
||||
Database::EemEvent data;
|
||||
while (q.next())
|
||||
{
|
||||
int i = 0;
|
||||
data.id = q.value(i++).toInt();
|
||||
data.eventTypeId = static_cast<ProjectDataManagement::EventType_def::type>(q.value(i++).toInt());
|
||||
data.participantId = q.value(i++).toInt();
|
||||
data.partyId = q.value(i++).toInt();
|
||||
data.equipmentNumber = q.value(i++).toInt();
|
||||
data.properties = q.value(i++).toString();
|
||||
data.sampleTime = q.value(i++).toLongLong();
|
||||
double pos_lon = q.value(i++).toDouble();
|
||||
double pos_lat = q.value(i++).toDouble();
|
||||
double pos_z = q.value(i++).toDouble();
|
||||
data.position = LtsUtils::QPoint3D(pos_lon, pos_lat, pos_z);
|
||||
|
||||
events.append(Database::toJson(data));
|
||||
if (events.size() > 100)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Sending an answer with " << events.size() << " events for query " << stmt;
|
||||
const QJsonDocument doc(events);
|
||||
ws->sendTextMessage(QString::fromUtf8(doc.toJson(QJsonDocument::Compact)));
|
||||
events = QJsonArray();
|
||||
}
|
||||
}
|
||||
if (!events.isEmpty())
|
||||
{
|
||||
INFO_LOG(m_logger) << "Sending an answer with " << events.size() << " events for query " << stmt;
|
||||
const QJsonDocument doc(events);
|
||||
ws->sendTextMessage(QString::fromUtf8(doc.toJson(QJsonDocument::Compact)));
|
||||
}
|
||||
|
||||
// finished
|
||||
ws->sendTextMessage(QStringLiteral("{}"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* WebSocketServer to publish Events
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-02-06
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
#include <QSqlDatabase>
|
||||
#include <QVector>
|
||||
#include <ExerciseEventManagement/eem_db_structs.h>
|
||||
#include "logger.h"
|
||||
|
||||
class QTimer;
|
||||
class QUrl;
|
||||
class QWebSocket;
|
||||
class QWebSocketServer;
|
||||
namespace ExerciseEventManagement
|
||||
{
|
||||
class WebSocketEventServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
WebSocketEventServer(const QSqlDatabase &db, QObject *parent = nullptr);
|
||||
~WebSocketEventServer();
|
||||
|
||||
bool listen(const QPair<quint16, quint16> &portRange);
|
||||
bool listen(quint16 port);
|
||||
quint16 listenPort() const;
|
||||
|
||||
void sendEvent(const QJsonObject &obj);
|
||||
private:
|
||||
void onNewConnection();
|
||||
void onSocketDisconnected();
|
||||
void onCleanupLiveHistory();
|
||||
void historyDataRequested(const QSqlDatabase &db, QWebSocket *ws, const QUrl &requestUrl);
|
||||
private:
|
||||
QSet<QWebSocket *> m_liveSockets;
|
||||
QMap<qint64, QVector<QString>> m_liveHistory;
|
||||
QWebSocketServer *m_wsServer;
|
||||
QTimer *m_cleanupTimer;
|
||||
QSqlDatabase m_db;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace ExerciseEventManagement
|
||||
Reference in new issue
Block a user