mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-14 01:13:52 -06:00
415 lines
16 KiB
C++
415 lines
16 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2018- Equinor ASA
|
|
//
|
|
// ResInsight is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
|
// for more details.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "RicHoloLensSession.h"
|
|
#include "RicHoloLensSessionObserver.h"
|
|
|
|
#include "RiaLogging.h"
|
|
#include "RiaPreferences.h"
|
|
|
|
#include "VdeArrayDataPacket.h"
|
|
#include "VdeFileExporter.h"
|
|
#include "VdePacketDirectory.h"
|
|
#include "VdeVizDataExtractor.h"
|
|
|
|
#include "cvfAssert.h"
|
|
#include "cvfTimer.h"
|
|
|
|
#include <QDir>
|
|
|
|
#include <algorithm>
|
|
|
|
//==================================================================================================
|
|
//
|
|
//
|
|
//
|
|
//==================================================================================================
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RicHoloLensSession::RicHoloLensSession()
|
|
: m_isSessionValid( false )
|
|
, m_lastExtractionMetaDataSequenceNumber( -1 )
|
|
, m_sessionObserver( nullptr )
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RicHoloLensSession::~RicHoloLensSession()
|
|
{
|
|
destroySession();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RicHoloLensSession* RicHoloLensSession::createSession( const QString& serverUrl,
|
|
const QString& sessionName,
|
|
const QByteArray& sessionPinCode,
|
|
RicHoloLensSessionObserver* sessionObserver )
|
|
{
|
|
RicHoloLensSession* newSession = new RicHoloLensSession;
|
|
|
|
newSession->m_restClient = new RicHoloLensRestClient( serverUrl, sessionName, newSession );
|
|
|
|
if ( RiaApplication::instance()->preferences()->holoLensDisableCertificateVerification() )
|
|
{
|
|
RiaLogging::warning( "HoloLens: Disabling certificate verification for HTTPS connections" );
|
|
newSession->m_restClient->dbgDisableCertificateVerification();
|
|
}
|
|
|
|
newSession->m_restClient->createSession( sessionPinCode );
|
|
|
|
newSession->m_sessionObserver = sessionObserver;
|
|
|
|
const QString dbgExportFolder = RiaApplication::instance()->preferences()->holoLensExportFolder();
|
|
if ( !dbgExportFolder.isEmpty() )
|
|
{
|
|
newSession->m_dbgFileExportDestinationFolder = dbgExportFolder;
|
|
RiaLogging::info( QString( "HoloLens: Debug file export will be written to folder: %1" ).arg( dbgExportFolder ) );
|
|
}
|
|
|
|
return newSession;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RicHoloLensSession* RicHoloLensSession::createDummyFileBackedSession()
|
|
{
|
|
RicHoloLensSession* newSession = new RicHoloLensSession;
|
|
|
|
newSession->m_isSessionValid = true;
|
|
|
|
newSession->m_dbgFileExportDestinationFolder = RiaApplication::instance()->preferences()->holoLensExportFolder();
|
|
|
|
return newSession;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensSession::destroySession()
|
|
{
|
|
if ( m_restClient )
|
|
{
|
|
if ( m_isSessionValid )
|
|
{
|
|
m_restClient->deleteSession();
|
|
}
|
|
|
|
m_restClient->clearResponseHandler();
|
|
m_restClient->deleteLater();
|
|
m_restClient = nullptr;
|
|
}
|
|
|
|
m_isSessionValid = false;
|
|
|
|
m_lastExtractionMetaDataSequenceNumber = -1;
|
|
m_lastExtractionAllReferencedPacketIdsArr.clear();
|
|
m_packetDirectory.clear();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RicHoloLensSession::isSessionValid() const
|
|
{
|
|
return m_isSessionValid;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensSession::updateSessionDataFromView( const RimGridView& activeView )
|
|
{
|
|
RiaLogging::info( "HoloLens: Updating visualization data" );
|
|
|
|
// Grab the current max ID as an easy way to detect if new IDs have been added for debugging purposes
|
|
const int dbgMaxAssignedIdBeforeExtraction = m_cachingIdFactory.lastAssignedId();
|
|
|
|
// Note that we pass the caching ID factory on the constructor which will try and detect data payloads that
|
|
// are equal, and will then "recycle" the array IDs for these
|
|
VdeVizDataExtractor extractor( activeView, &m_cachingIdFactory );
|
|
|
|
QString modelMetaJsonStr;
|
|
std::vector<int> allReferencedPacketIds;
|
|
extractor.extractViewContents( &modelMetaJsonStr, &allReferencedPacketIds, &m_packetDirectory );
|
|
|
|
// Note!
|
|
// The packet directory should now contain all the packets that are being actively referenced.
|
|
// We now prune out any packets that are no longer being referenced. This means we do no caching of actual packet
|
|
// data over time and that we assume that the server will ask for data packets/arrays right after having received updated meta data
|
|
m_packetDirectory.pruneUnreferencedPackets( allReferencedPacketIds );
|
|
|
|
m_lastExtractionMetaDataSequenceNumber++;
|
|
m_lastExtractionAllReferencedPacketIdsArr = allReferencedPacketIds;
|
|
|
|
if ( m_restClient )
|
|
{
|
|
RiaLogging::info( QString( "HoloLens: Sending updated meta data to sharing server (sequenceNumber=%1)" )
|
|
.arg( m_lastExtractionMetaDataSequenceNumber ) );
|
|
m_restClient->sendMetaData( m_lastExtractionMetaDataSequenceNumber, modelMetaJsonStr );
|
|
}
|
|
|
|
// Debug export to file
|
|
if ( !m_dbgFileExportDestinationFolder.isEmpty() )
|
|
{
|
|
const QDir outputDir( m_dbgFileExportDestinationFolder );
|
|
const QString absOutputFolder = outputDir.absolutePath();
|
|
|
|
if ( !outputDir.mkpath( "." ) )
|
|
{
|
|
RiaLogging::error(
|
|
QString( "HoloLens: Could not create debug file export folder: %1" ).arg( absOutputFolder ) );
|
|
return;
|
|
}
|
|
|
|
// For debugging, write only the new packets to file
|
|
// Determine which packets are new by comparing the IDs to the max known ID before extraction
|
|
std::vector<int> packetIdsToWrite;
|
|
for ( int packetId : allReferencedPacketIds )
|
|
{
|
|
if ( packetId > dbgMaxAssignedIdBeforeExtraction )
|
|
{
|
|
packetIdsToWrite.push_back( packetId );
|
|
}
|
|
}
|
|
|
|
// This will write all packets seen in this extraction to file
|
|
// packetIdsToWrite = allReferencedPacketIds;
|
|
|
|
RiaLogging::info( QString( "HoloLens: Doing debug export of data (%1 packets) to folder: %2" )
|
|
.arg( packetIdsToWrite.size() )
|
|
.arg( absOutputFolder ) );
|
|
VdeFileExporter fileExporter( absOutputFolder );
|
|
if ( !fileExporter.exportToFile( modelMetaJsonStr, m_packetDirectory, packetIdsToWrite ) )
|
|
{
|
|
RiaLogging::error( "HoloLens: Error exporting debug data to folder" );
|
|
}
|
|
|
|
RiaLogging::info( "HoloLens: Done exporting debug data" );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensSession::handleSuccessfulCreateSession()
|
|
{
|
|
RiaLogging::info( "HoloLens: Session successfully created" );
|
|
m_isSessionValid = true;
|
|
|
|
notifyObserver( RicHoloLensSessionObserver::CreateSessionSucceeded );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensSession::handleFailedCreateSession()
|
|
{
|
|
RiaLogging::error( "HoloLens: Failed to create session" );
|
|
m_isSessionValid = false;
|
|
|
|
notifyObserver( RicHoloLensSessionObserver::CreateSessionFailed );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Handle the server response we receive after sending new meta data
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensSession::handleSuccessfulSendMetaData( int metaDataSequenceNumber,
|
|
const QByteArray& jsonServerResponseString )
|
|
{
|
|
cvf::Timer tim;
|
|
|
|
RiaLogging::info(
|
|
QString( "HoloLens: Processing server response (meta data sequenceNumber=%1)" ).arg( metaDataSequenceNumber ) );
|
|
|
|
if ( m_lastExtractionMetaDataSequenceNumber != metaDataSequenceNumber )
|
|
{
|
|
RiaLogging::warning(
|
|
QString( "HoloLens: Ignoring server response, the meta data sequenceNumber(%1) has been superseded" )
|
|
.arg( metaDataSequenceNumber ) );
|
|
return;
|
|
}
|
|
|
|
std::vector<int> arrayIdsToSend;
|
|
|
|
// cvf::Trace::show("Raw JSON response from server: '%s'", jsonServerResponseString.data());
|
|
QByteArray trimmedServerResponseString = jsonServerResponseString.trimmed();
|
|
if ( trimmedServerResponseString.size() > 0 )
|
|
{
|
|
if ( !parseJsonIntegerArray( trimmedServerResponseString, &arrayIdsToSend ) )
|
|
{
|
|
RiaLogging::error(
|
|
"HoloLens: Error parsing array server response with array Ids, no data will be sent to server" );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// An empty server response means we should send all array referenced by the last sent meta data
|
|
if ( m_lastExtractionAllReferencedPacketIdsArr.size() > 0 )
|
|
{
|
|
arrayIdsToSend = m_lastExtractionAllReferencedPacketIdsArr;
|
|
RiaLogging::info( "HoloLens: Empty server response, sending all arrays referenced by last meta data" );
|
|
}
|
|
}
|
|
|
|
if ( arrayIdsToSend.size() == 0 )
|
|
{
|
|
RiaLogging::info( "HoloLens: Nothing to do, no data requested by server" );
|
|
return;
|
|
}
|
|
|
|
RiaLogging::info( QString( "HoloLens: Start sending data to server, %1 data arrays have been requested" )
|
|
.arg( arrayIdsToSend.size() ) );
|
|
|
|
size_t totalBytesSent = 0;
|
|
size_t totalNumArraysSent = 0;
|
|
|
|
const bool sendAsIndividualPackets = false;
|
|
|
|
// Sending data packets one by one
|
|
if ( sendAsIndividualPackets )
|
|
{
|
|
for ( size_t i = 0; i < arrayIdsToSend.size(); i++ )
|
|
{
|
|
const int arrayId = arrayIdsToSend[i];
|
|
const VdeArrayDataPacket* packet = m_packetDirectory.lookupPacket( arrayId );
|
|
if ( !packet )
|
|
{
|
|
RiaLogging::warning(
|
|
QString( "HoloLens: Could not get the requested data from cache, array id: %1 " ).arg( arrayId ) );
|
|
continue;
|
|
}
|
|
|
|
QByteArray packetByteArr( packet->fullPacketRawPtr(), static_cast<int>( packet->fullPacketSize() ) );
|
|
|
|
RiaLogging::info( QString( "HoloLens: sending array id: %1, %2KB (%3 bytes)" )
|
|
.arg( arrayId )
|
|
.arg( packetByteArr.size() / 1024.0, 0, 'f', 2 )
|
|
.arg( packetByteArr.size() ) );
|
|
|
|
m_restClient->sendBinaryData( packetByteArr, "arrId" + QByteArray::number( arrayId ) );
|
|
|
|
totalNumArraysSent++;
|
|
totalBytesSent += packetByteArr.size();
|
|
}
|
|
}
|
|
// Sending all requested arrays/packets in one combined packet
|
|
else
|
|
{
|
|
QByteArray combinedPacketArr;
|
|
if ( !m_packetDirectory.getPacketsAsCombinedBuffer( arrayIdsToSend, &combinedPacketArr ) )
|
|
{
|
|
RiaLogging::warning( "HoloLens: Error gathering the requested arrays, no data will be sent" );
|
|
return;
|
|
}
|
|
|
|
totalNumArraysSent = arrayIdsToSend.size();
|
|
totalBytesSent = combinedPacketArr.size();
|
|
|
|
RiaLogging::info( QString( "HoloLens: Sending data to server (%1 arrays combined), %2KB (%3 bytes)" )
|
|
.arg( totalNumArraysSent )
|
|
.arg( totalBytesSent / 1024.0, 0, 'f', 2 )
|
|
.arg( totalBytesSent ) );
|
|
|
|
m_restClient->sendBinaryData( combinedPacketArr, "metaSeqNum" + QByteArray::number( metaDataSequenceNumber ) );
|
|
}
|
|
|
|
const double totalMb = totalBytesSent / ( 1024.0 * 1024.0 );
|
|
RiaLogging::info( QString( "HoloLens: Finished sending data to server, %1 arrays, total %2MB (%3 bytes) in %4ms" )
|
|
.arg( totalNumArraysSent )
|
|
.arg( totalMb, 0, 'f', 2 )
|
|
.arg( totalBytesSent )
|
|
.arg( static_cast<int>( tim.time() * 1000 ) ) );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RicHoloLensSession::parseJsonIntegerArray( const QByteArray& jsonString, std::vector<int>* integerArr )
|
|
{
|
|
// cvf::Trace::show("jsonString: '%s'", jsonString.data());
|
|
|
|
const int openBraceIdx = jsonString.indexOf( '[' );
|
|
const int closeBraceIdx = jsonString.lastIndexOf( ']' );
|
|
if ( openBraceIdx < 0 || closeBraceIdx < 0 )
|
|
{
|
|
RiaLogging::debug( "Error parsing JSON array, could not find opening or closing braces" );
|
|
return false;
|
|
}
|
|
|
|
if ( closeBraceIdx <= openBraceIdx )
|
|
{
|
|
RiaLogging::debug( "Error parsing JSON array, wrong placement of braces" );
|
|
return false;
|
|
}
|
|
|
|
QByteArray arrayContents = jsonString.mid( openBraceIdx + 1, closeBraceIdx - openBraceIdx - 1 ).trimmed();
|
|
// cvf::Trace::show("arrayContents: '%s'", arrayContents.data());
|
|
|
|
QList<QByteArray> stringList = arrayContents.split( ',' );
|
|
for ( const QByteArray& entry : stringList )
|
|
{
|
|
bool convertOk = false;
|
|
const int intVal = entry.toInt( &convertOk );
|
|
if ( convertOk )
|
|
{
|
|
integerArr->push_back( intVal );
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensSession::handleError( const QString& errMsg, const QString& url, const QString& serverData )
|
|
{
|
|
QString fullMsg = "HoloLens communication error: " + errMsg;
|
|
|
|
if ( !serverData.isEmpty() )
|
|
{
|
|
fullMsg += "\n serverMsg: " + serverData;
|
|
}
|
|
|
|
fullMsg += "\n url: " + url;
|
|
|
|
RiaLogging::error( fullMsg );
|
|
|
|
// It is probably not correct to always consider an error a state change, but for now
|
|
notifyObserver( RicHoloLensSessionObserver::GeneralError );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensSession::notifyObserver( RicHoloLensSessionObserver::Notification notification )
|
|
{
|
|
if ( m_sessionObserver )
|
|
{
|
|
m_sessionObserver->handleSessionNotification( this, notification );
|
|
}
|
|
}
|