/** * @RDE_HEADER@ * The DataManager class takes strucure element data from the HandlerStructureElement, * offers an interface to get and set structure data * $Id$ * $HeadURL$ * $Author$ * Created by Hannes Fritsche, SLSE, 2017-09-07 */ #include "bite_data_manager.h" #include "dds_handler.h" #include "WsBiteInterface/Messages/message_transmitter.h" #include #include #include #include #include #include namespace WarehouseGuez { namespace WsBiteInterface { using namespace JsonKeys; DataManager::DataManager(std::shared_ptr ddsHandler) : m_scmWebSocket(new QWebSocket) , m_ddsHandler(ddsHandler) , m_timer(new QTimer(this)) , m_logger(getLogger(QLatin1String("DataManager"))) { QUrl scmUrl(QStringLiteral("ws://%1:%2").arg(NGL::Connections::hostName(NGL::Connections::eConnection::SCM_WEBSOCKET)).arg(NGL::Connections::port(NGL::Connections::eConnection::SCM_WEBSOCKET))); connect(m_scmWebSocket, &QWebSocket::connected, this, &DataManager::onConnected); connect(m_scmWebSocket, &QWebSocket::disconnected, this, &DataManager::closed); m_scmWebSocket->open(scmUrl); // DTC TrainingAreaBase m_tabDtc = TrainingAreaBase::Interface::Dtc::create(m_ddsHandler->dds()); if (m_tabDtc == nullptr) { ERROR_LOG(m_logger) << "Could not create DTC TrainingAreaBase"; return; } #if 0 connectToTabWebSocket(8080, 42); #endif } DataManager::~DataManager() { for ( TabData data : m_tabWebSocketMap.values()) delete data.websocket; delete m_scmWebSocket; } void DataManager::onConnected() { DEBUG_LOG(m_logger) << "SCM websocket port connected"; connect(m_scmWebSocket, &QWebSocket::textMessageReceived, this, &DataManager::onTextMessageFromScm); connect(m_timer, &QTimer::timeout, this, &DataManager::onTimerTimeout); m_timer->setInterval(60000); m_timer->start(); onTimerTimeout(); } void DataManager::onTimerTimeout() { m_scmWebSocket->sendTextMessage(QStringLiteral("{\"type\":\"servicePortsInformationRequest\", \"uuid\": \"7777\"}")); } void DataManager::onTextMessageFromScm(const QString &message) { DEBUG_LOG(m_logger) << "onTextMessageFromScm from scm: " << message; const QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8()); const QJsonArray exercises = doc.object().value(DATA()).toArray(); for (const QJsonValue &valEx : exercises) { const QJsonObject &exercise = valEx.toObject(); const int exerciseId = exercise.value(EXERCISE_ID()).toInt(); DEBUG_LOG(m_logger) << "textMessageFromScm from scm - exerciseId " << exerciseId; const QJsonArray services = exercise.value(SERVICES()).toArray(); for (const QJsonValue &valSvc : services) { const QJsonObject &service = valSvc.toObject(); const QString svcName = service.value(NAME_ABBREVATION()).toString().toUpper(); DEBUG_LOG(m_logger) << "textMessageFromScm from scm - svcName " << svcName; if (svcName != QStringLiteral("TAB")) continue; DEBUG_LOG(m_logger) << "service TAB "; const QJsonArray ports = service.value(PORTS()).toArray(); for (const QJsonValue &valPort : ports) { const QJsonObject &port = valPort.toObject(); int typeId = port.value(TYPE_ID()).toInt(); if (typeId == static_cast(Core::CorePortType::WebSocketServer)) { int tabPort = port.value(NUMBER()).toInt(); DEBUG_LOG(m_logger) << "connect to TAB - port: " << tabPort; connectToTabWebSocket(tabPort, exerciseId); } } } } } void DataManager::onConnectedTab() { DEBUG_LOG(m_logger) << "TAB connected"; } void DataManager::connectToTabWebSocket(int port, int exerciseId) { if (m_tabWebSocketMap.contains(exerciseId)) { TabData tabData = m_tabWebSocketMap.value(exerciseId); // Websocket connection already exists? if (tabData.port == port) { INFO_LOG(m_logger) << "Connection to port " << port << " already exists."; return; } else { tabData.websocket->close(); delete tabData.websocket; m_tabWebSocketMap.remove(exerciseId); } } INFO_LOG(m_logger) << "New connection: exercise: " << exerciseId << ", port: " << port; const QUrl url(QStringLiteral("ws://%1:%2").arg(NGL::Connections::hostName(NGL::Connections::eConnection::SCM_WEBSOCKET)).arg(port)); QWebSocket *webSocketTab = new QWebSocket; connect(webSocketTab, &QWebSocket::connected, this, &DataManager::onConnectedTab); connect(webSocketTab, &QWebSocket::disconnected, this, &DataManager::closedTab); connect(webSocketTab, &QWebSocket::textMessageReceived, this, &DataManager::onTextMessageFromTab); DEBUG_LOG(m_logger) << "Trying to connect to TAB at " << url.toString(); webSocketTab->open(url); TabData data; data.exerciseId = exerciseId; data.port = port; data.websocket = webSocketTab; m_tabWebSocketMap.insert(exerciseId, data); } void DataManager::onClientDisconnect(Messages::MessageTransmitter *transmitter) { for (EquipData &ed : m_equipDataMap) { if (ed.transmitter == transmitter) { DEBUG_LOG(m_logger) << "removed dead transmitter"; ed.transmitter = nullptr; } } } void DataManager::onTextMessageFromTab(const QString &message) { INFO_LOG(m_logger) << "onTextMessageFromTab : " << message; const QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8()); if (doc.object().value(TYPE()) != BITE_DATA() && doc.object().value(TYPE()) != POSITION_DATA()) return; INFO_LOG(m_logger) << "TYPE: " << doc.object().value(TYPE()).toString(); QJsonObject data = doc.object().value(DATA()).toObject(); data.insert(LAST_UPDATE(), QDateTime::currentSecsSinceEpoch()); int equipNo = data.value(EQUIP_NO()).toInt(); INFO_LOG(m_logger) << "equipNo: " << equipNo; if (equipNo <= 0) return; if (doc.object().value(TYPE()) == BITE_DATA()) m_equipDataMap[equipNo].biteMessage = data; if (doc.object().value(TYPE()) == POSITION_DATA()) { m_equipDataMap[equipNo].lastPositionUpdate = data.value(LAST_POSITION_UPDATE()).toDouble(); INFO_LOG(m_logger) << "lastPosUpdate: " << m_equipDataMap[equipNo].lastPositionUpdate; } if (m_equipDataMap[equipNo].boxId >= 0) { Messages::MessageTransmitter* transmitter = m_equipDataMap[equipNo].transmitter; if (transmitter == nullptr) { ERROR_LOG(m_logger) << "transmitter for eqId " << equipNo << " no longer available"; return; } int &boxId = m_equipDataMap[equipNo].boxId; QJsonObject &biteData = m_equipDataMap[equipNo].biteMessage; biteData.insert(BOX(), boxId); biteData.insert(LAST_POSITION_UPDATE(), m_equipDataMap[equipNo].lastPositionUpdate); transmitter->addMessage(Messages::BiteDataMessage(biteData, m_equipDataMap[equipNo].uuid)); INFO_LOG(m_logger) << "Send Message with boxId: " << boxId << ", equipNo: " << equipNo; if (boxId == 0) boxId = -1; // only single request } } void DataManager::setEquipNoBoxId(int equipNo, int boxId, Messages::MessageTransmitter *transmitter, const QString &uuid) { INFO_LOG(m_logger) << "equipNo: " << equipNo << ", boxId = " << boxId; // erase abonnement, no further biteData telegrams if (equipNo == 0) { for ( int key : m_equipDataMap.keys()) { if (m_equipDataMap[key].boxId == boxId) { m_equipDataMap.remove(key); break; } } return; } auto &equipData = m_equipDataMap[equipNo]; // create new equipData if equipNo is not present yet equipData.equipNo = equipNo; equipData.boxId = boxId; equipData.transmitter = transmitter; equipData.uuid = uuid; // find biteMessage and send biteData telegram if not older than 1h if (!equipData.biteMessage.isEmpty()) { QJsonObject &data = equipData.biteMessage; qint64 lastUpdate = data.value(LAST_UPDATE()).toDouble(); if ( lastUpdate + 3600 > QDateTime::currentSecsSinceEpoch()) { data.insert(BOX(), boxId); data.insert(LAST_POSITION_UPDATE(), equipData.lastPositionUpdate); transmitter->addMessage(Messages::BiteDataMessage(data, equipData.uuid)); INFO_LOG(m_logger) << "Send Message with boxId: " << boxId << ", equipNo: " << equipNo; } } else { QJsonObject data; data.insert(EQUIP_NO(), equipNo); data.insert(BOX(), boxId); data.insert(LAST_UPDATE(), 0); data.insert(LAST_POSITION_UPDATE(), 0); data.insert(IS_LICENSED(), false); equipData.biteMessage = data; transmitter->addMessage(Messages::BiteDataMessage(data, equipData.uuid)); INFO_LOG(m_logger) << "Send Message with boxId: " << boxId << ", equipNo: " << equipNo << ", lastUpdate 0"; // send bite request QJsonObject biteData; biteData.insert(DATA(), data); biteData.insert(TYPE(), SEND_BITE_REQUEST()); biteData.insert(UUID_(), QUuid::createUuid().toString()); QString message = QString::fromStdString(QJsonDocument(biteData).toJson(QJsonDocument::Compact).toStdString()); INFO_LOG(m_logger) << "message: " << message; for (TabData dataTab : m_tabWebSocketMap) dataTab.websocket->sendTextMessage(message); } } } // namespace WsBiteInterface } // namespace WarehouseGuez