2018-10-22 04:09:52 -05:00
/////////////////////////////////////////////////////////////////////////////////
//
2019-01-09 08:21:38 -06:00
// Copyright (C) 2018- Equinor ASA
2018-10-22 04:09:52 -05:00
//
// 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"
2018-12-18 15:08:57 -06:00
# include "RicHoloLensSessionObserver.h"
2018-10-22 04:09:52 -05:00
2018-10-22 04:45:33 -05:00
# include "RiaLogging.h"
2018-10-25 08:34:21 -05:00
# include "RiaPreferences.h"
2018-10-22 04:45:33 -05:00
2018-10-25 08:34:21 -05:00
# include "VdeVizDataExtractor.h"
# include "VdeFileExporter.h"
# include "VdePacketDirectory.h"
# include "VdeArrayDataPacket.h"
# include "cvfAssert.h"
2018-12-19 05:31:44 -06:00
# include "cvfTimer.h"
2018-10-25 08:34:21 -05:00
# include <QDir>
2018-12-19 05:31:44 -06:00
# include <algorithm>
2018-10-25 08:34:21 -05:00
//==================================================================================================
//
//
//
//==================================================================================================
2018-10-22 04:45:33 -05:00
2018-10-22 04:09:52 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RicHoloLensSession : : RicHoloLensSession ( )
2018-10-25 08:34:21 -05:00
: m_isSessionValid ( false ) ,
m_lastExtractionMetaDataSequenceNumber ( - 1 ) ,
2019-01-15 06:23:12 -06:00
m_sessionObserver ( nullptr )
2018-10-22 04:09:52 -05:00
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2018-10-25 08:34:21 -05:00
RicHoloLensSession : : ~ RicHoloLensSession ( )
2018-10-22 04:09:52 -05:00
{
2018-10-25 08:34:21 -05:00
destroySession ( ) ;
}
2018-10-22 04:09:52 -05:00
2018-10-25 08:34:21 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2018-12-18 15:08:57 -06:00
RicHoloLensSession * RicHoloLensSession : : createSession ( const QString & serverUrl , const QString & sessionName , const QByteArray & sessionPinCode , RicHoloLensSessionObserver * sessionObserver )
2018-10-25 08:34:21 -05:00
{
RicHoloLensSession * newSession = new RicHoloLensSession ;
newSession - > m_restClient = new RicHoloLensRestClient ( serverUrl , sessionName , newSession ) ;
2019-01-15 06:23:12 -06:00
if ( RiaApplication : : instance ( ) - > preferences ( ) - > holoLensDisableCertificateVerification ( ) )
{
RiaLogging : : warning ( " HoloLens: Disabling certificate verification for HTTPS connections " ) ;
newSession - > m_restClient - > dbgDisableCertificateVerification ( ) ;
}
2018-12-18 15:08:57 -06:00
newSession - > m_restClient - > createSession ( sessionPinCode ) ;
newSession - > m_sessionObserver = sessionObserver ;
2018-10-25 08:34:21 -05:00
2019-01-15 06:23:12 -06:00
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 ) ) ;
}
2018-10-25 08:34:21 -05:00
return newSession ;
2018-10-22 04:09:52 -05:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2018-10-25 08:34:21 -05:00
RicHoloLensSession * RicHoloLensSession : : createDummyFileBackedSession ( )
2018-10-22 04:09:52 -05:00
{
2018-10-25 08:34:21 -05:00
RicHoloLensSession * newSession = new RicHoloLensSession ;
2018-10-22 04:09:52 -05:00
2018-10-25 08:34:21 -05:00
newSession - > m_isSessionValid = true ;
2018-10-22 04:45:33 -05:00
2019-01-15 06:23:12 -06:00
newSession - > m_dbgFileExportDestinationFolder = RiaApplication : : instance ( ) - > preferences ( ) - > holoLensExportFolder ( ) ;
2018-10-22 04:45:33 -05:00
2018-10-25 08:34:21 -05:00
return newSession ;
2018-10-22 04:09:52 -05:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2018-10-25 08:34:21 -05:00
void RicHoloLensSession : : destroySession ( )
2018-10-22 04:09:52 -05:00
{
2018-10-25 08:34:21 -05:00
if ( m_restClient )
2018-10-22 04:09:52 -05:00
{
2018-10-25 08:34:21 -05:00
if ( m_isSessionValid )
{
m_restClient - > deleteSession ( ) ;
}
m_restClient - > clearResponseHandler ( ) ;
m_restClient - > deleteLater ( ) ;
m_restClient = nullptr ;
2018-10-22 04:09:52 -05:00
}
2018-10-25 08:34:21 -05:00
m_isSessionValid = false ;
2018-10-22 04:09:52 -05:00
2018-10-25 08:34:21 -05:00
m_lastExtractionMetaDataSequenceNumber = - 1 ;
m_lastExtractionAllReferencedPacketIdsArr . clear ( ) ;
m_packetDirectory . clear ( ) ;
2018-10-22 04:09:52 -05:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicHoloLensSession : : isSessionValid ( ) const
{
return m_isSessionValid ;
}
2018-10-22 05:00:02 -05:00
//--------------------------------------------------------------------------------------------------
2018-10-25 08:34:21 -05:00
///
2018-10-22 05:00:02 -05:00
//--------------------------------------------------------------------------------------------------
2018-10-25 08:34:21 -05:00
void RicHoloLensSession : : updateSessionDataFromView ( const RimGridView & activeView )
2018-10-22 05:00:02 -05:00
{
2018-10-25 08:34:21 -05:00
RiaLogging : : info ( " HoloLens: Updating visualization data " ) ;
2018-12-19 05:31:44 -06:00
// 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 ( ) ;
2018-10-25 08:34:21 -05:00
2018-12-19 05:31:44 -06:00
// 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 ) ;
2018-12-18 15:08:57 -06:00
QString modelMetaJsonStr ;
std : : vector < int > allReferencedPacketIds ;
2018-10-25 08:34:21 -05:00
extractor . extractViewContents ( & modelMetaJsonStr , & allReferencedPacketIds , & m_packetDirectory ) ;
2018-12-19 05:31:44 -06:00
// 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 ) ;
2018-10-25 08:34:21 -05:00
m_lastExtractionMetaDataSequenceNumber + + ;
m_lastExtractionAllReferencedPacketIdsArr = allReferencedPacketIds ;
2018-12-18 15:08:57 -06:00
2018-10-25 08:34:21 -05:00
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 ) ;
}
2018-12-18 15:08:57 -06:00
2018-10-25 08:34:21 -05:00
// Debug export to file
2019-01-15 06:23:12 -06:00
if ( ! m_dbgFileExportDestinationFolder . isEmpty ( ) )
2018-10-25 08:34:21 -05:00
{
2019-01-15 06:23:12 -06:00
const QDir outputDir ( m_dbgFileExportDestinationFolder ) ;
2018-10-25 08:34:21 -05:00
const QString absOutputFolder = outputDir . absolutePath ( ) ;
if ( ! outputDir . mkpath ( " . " ) )
{
RiaLogging : : error ( QString ( " HoloLens: Could not create debug file export folder: %1 " ) . arg ( absOutputFolder ) ) ;
return ;
}
2018-12-19 05:31:44 -06:00
// 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 ) ) ;
2018-10-25 08:34:21 -05:00
VdeFileExporter fileExporter ( absOutputFolder ) ;
2018-12-19 05:31:44 -06:00
if ( ! fileExporter . exportToFile ( modelMetaJsonStr , m_packetDirectory , packetIdsToWrite ) )
2018-10-25 08:34:21 -05:00
{
RiaLogging : : error ( " HoloLens: Error exporting debug data to folder " ) ;
}
RiaLogging : : info ( " HoloLens: Done exporting debug data " ) ;
}
2018-10-22 05:00:02 -05:00
}
2018-10-22 04:09:52 -05:00
//--------------------------------------------------------------------------------------------------
2018-10-25 08:34:21 -05:00
///
2018-10-22 04:09:52 -05:00
//--------------------------------------------------------------------------------------------------
2018-10-25 08:34:21 -05:00
void RicHoloLensSession : : handleSuccessfulCreateSession ( )
2018-10-22 04:45:33 -05:00
{
2018-10-25 08:34:21 -05:00
RiaLogging : : info ( " HoloLens: Session successfully created " ) ;
m_isSessionValid = true ;
2018-12-18 15:08:57 -06:00
notifyObserver ( RicHoloLensSessionObserver : : CreateSessionSucceeded ) ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensSession : : handleFailedCreateSession ( )
{
RiaLogging : : error ( " HoloLens: Failed to create session " ) ;
m_isSessionValid = false ;
notifyObserver ( RicHoloLensSessionObserver : : CreateSessionFailed ) ;
2018-10-22 04:45:33 -05:00
}
2018-10-22 04:09:52 -05:00
//--------------------------------------------------------------------------------------------------
2018-10-25 08:34:21 -05:00
/// Handle the server response we receive after sending new meta data
2018-10-22 04:09:52 -05:00
//--------------------------------------------------------------------------------------------------
2018-12-19 05:31:44 -06:00
void RicHoloLensSession : : handleSuccessfulSendMetaData ( int metaDataSequenceNumber , const QByteArray & jsonServerResponseString )
2018-10-22 04:09:52 -05:00
{
2018-12-19 05:31:44 -06:00
cvf : : Timer tim ;
RiaLogging : : info ( QString ( " HoloLens: Processing server response (meta data sequenceNumber=%1) " ) . arg ( metaDataSequenceNumber ) ) ;
2018-10-25 08:34:21 -05:00
if ( m_lastExtractionMetaDataSequenceNumber ! = metaDataSequenceNumber )
{
2018-12-19 05:31:44 -06:00
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 " ) ;
2018-10-25 08:34:21 -05:00
return ;
}
2018-10-22 04:45:33 -05:00
2018-12-19 05:31:44 -06:00
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 ( ) ) ) ;
2019-01-17 02:37:35 -06:00
m_restClient - > sendBinaryData ( packetByteArr , " arrId " + QByteArray : : number ( arrayId ) ) ;
2018-12-19 05:31:44 -06:00
totalNumArraysSent + + ;
totalBytesSent + = packetByteArr . size ( ) ;
}
}
// Sending all requested arrays/packets in one combined packet
else
2018-10-25 08:34:21 -05:00
{
QByteArray combinedPacketArr ;
2018-12-19 05:31:44 -06:00
if ( ! m_packetDirectory . getPacketsAsCombinedBuffer ( arrayIdsToSend , & combinedPacketArr ) )
2018-10-25 08:34:21 -05:00
{
2018-12-19 05:31:44 -06:00
RiaLogging : : warning ( " HoloLens: Error gathering the requested arrays, no data will be sent " ) ;
2018-10-25 08:34:21 -05:00
return ;
}
2018-10-22 04:45:33 -05:00
2018-12-19 05:31:44 -06:00
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 ) ) ;
2018-10-25 08:34:21 -05:00
2019-01-17 02:37:35 -06:00
m_restClient - > sendBinaryData ( combinedPacketArr , " metaSeqNum " + QByteArray : : number ( metaDataSequenceNumber ) ) ;
2018-10-25 08:34:21 -05:00
}
2018-12-19 05:31:44 -06:00
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 ;
2018-10-22 04:09:52 -05:00
}
2018-10-22 04:45:33 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2018-10-25 08:34:21 -05:00
void RicHoloLensSession : : handleError ( const QString & errMsg , const QString & url , const QString & serverData )
2018-10-22 04:45:33 -05:00
{
2018-10-25 08:34:21 -05:00
QString fullMsg = " HoloLens communication error: " + errMsg ;
if ( ! serverData . isEmpty ( ) )
{
fullMsg + = " \n serverMsg: " + serverData ;
}
2018-10-22 04:45:33 -05:00
2018-10-25 08:34:21 -05:00
fullMsg + = " \n url: " + url ;
2018-10-22 04:45:33 -05:00
2018-10-25 08:34:21 -05:00
RiaLogging : : error ( fullMsg ) ;
2018-12-18 15:08:57 -06:00
// 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 ) ;
}
2018-10-22 04:45:33 -05:00
}
2018-10-25 08:34:21 -05:00