mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-24 15:26:48 -06:00
491 lines
18 KiB
C++
491 lines
18 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 "RicHoloLensRestClient.h"
|
|
|
|
#include "cvfBase.h"
|
|
#include "cvfTrace.h"
|
|
|
|
#include <QNetworkRequest>
|
|
#include <QSslConfiguration>
|
|
#include <QDateTime>
|
|
|
|
// For getting time stamps for round-trip timing
|
|
#if defined (__linux__)
|
|
#include <sys/time.h>
|
|
#include <ctime>
|
|
#endif
|
|
|
|
|
|
#ifndef QT_NO_OPENSSL
|
|
// Uncomment to enable experimental SSL support
|
|
// The experimental support must be revised before shipping
|
|
#define EXPERIMENTAL_SSL_SUPPORT
|
|
#endif
|
|
|
|
|
|
//==================================================================================================
|
|
//
|
|
//
|
|
//
|
|
//==================================================================================================
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RicHoloLensRestClient::RicHoloLensRestClient(QString serverUrl, QString sessionName, RicHoloLensRestResponseHandler* responseHandler)
|
|
: m_serverUrl(serverUrl),
|
|
m_sessionName(sessionName),
|
|
m_responseHandler(responseHandler),
|
|
m_dbgDisableCertificateVerification(false)
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::clearResponseHandler()
|
|
{
|
|
m_responseHandler = nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::dbgDisableCertificateVerification()
|
|
{
|
|
m_dbgDisableCertificateVerification = true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::createSession(const QByteArray& sessionPinCode)
|
|
{
|
|
const QString url = m_serverUrl + "/sessions/create/" + m_sessionName;
|
|
cvf::Trace::show("createSession: POST on url: %s", url.toLatin1().constData());
|
|
|
|
QNetworkRequest request(url);
|
|
//request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded"));
|
|
request.setRawHeader("PinCode", sessionPinCode);
|
|
|
|
|
|
#ifdef EXPERIMENTAL_SSL_SUPPORT
|
|
// NOTE !!!
|
|
// Apparently something like this is currently needed in order to get SSL/HTTPS going
|
|
// Still, can't quite figure it out since it appears to be sufficient to do this on the first request
|
|
// This will have to be investigated further, SP 20180924
|
|
QSslConfiguration sslConf = request.sslConfiguration();
|
|
|
|
// Needed this one to be able to connect to sharing server
|
|
sslConf.setProtocol(QSsl::AnyProtocol);
|
|
|
|
if (m_dbgDisableCertificateVerification)
|
|
{
|
|
sslConf.setPeerVerifyMode(QSslSocket::VerifyNone);
|
|
}
|
|
|
|
request.setSslConfiguration(sslConf);
|
|
#endif
|
|
|
|
QNetworkReply* reply = m_accessManager.post(request, QByteArray());
|
|
connect(reply, SIGNAL(finished()), SLOT(slotCreateSessionFinished()));
|
|
|
|
#ifdef EXPERIMENTAL_SSL_SUPPORT
|
|
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), SLOT(slotSslErrors(const QList<QSslError>&)));
|
|
#endif
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::slotCreateSessionFinished()
|
|
{
|
|
QNetworkReply* reply = dynamic_cast<QNetworkReply*>(sender());
|
|
if (!reply)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (detectAndHandleErrorReply("createSession", reply))
|
|
{
|
|
reply->deleteLater();
|
|
|
|
m_responseHandler->handleFailedCreateSession();
|
|
|
|
return;
|
|
}
|
|
|
|
const QByteArray serverData = reply->readAll();
|
|
//cvf::Trace::show(" serverResponse: %s", serverData.constData());
|
|
|
|
// Currently we get the bearer token back in the response wholesale
|
|
// The format we get is typically: "Bearer <the token>"
|
|
// For example: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
|
|
// Presumably the format of the response will change, but for now just strip away the starting "Bearer " string and consider the rest as the actual token
|
|
m_bearerToken = serverData;
|
|
m_bearerToken.replace("Bearer ", "");
|
|
|
|
reply->deleteLater();
|
|
|
|
cvf::Trace::show("createSession OK");
|
|
if (m_responseHandler)
|
|
{
|
|
m_responseHandler->handleSuccessfulCreateSession();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::deleteSession()
|
|
{
|
|
const QString url = m_serverUrl + "/sessions/delete/" + m_sessionName;
|
|
cvf::Trace::show("deleteSession: DELETE on url: %s", url.toLatin1().constData());
|
|
|
|
QNetworkRequest request(url);
|
|
//request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded"));
|
|
addBearerAuthenticationHeaderToRequest(&request);
|
|
|
|
QNetworkReply* reply = m_accessManager.deleteResource(request);
|
|
connect(reply, SIGNAL(finished()), SLOT(slotDeleteSessionFinished()));
|
|
|
|
#ifdef EXPERIMENTAL_SSL_SUPPORT
|
|
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), SLOT(slotSslErrors(const QList<QSslError>&)));
|
|
#endif
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::slotDeleteSessionFinished()
|
|
{
|
|
QNetworkReply* reply = dynamic_cast<QNetworkReply*>(sender());
|
|
if (!reply)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (detectAndHandleErrorReply("deleteSession", reply))
|
|
{
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
reply->deleteLater();
|
|
|
|
cvf::Trace::show("deleteSession OK");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::sendMetaData(int metaDataSequenceNumber, const QString& jsonMetaDataString)
|
|
{
|
|
const QString url = m_serverUrl + "/sessions/" + m_sessionName + "/metadata";
|
|
cvf::Trace::show("sendMetaData (metaDataSequenceNumber=%d): POST on url: %s", metaDataSequenceNumber, url.toLatin1().constData());
|
|
|
|
const qint64 sendStartTimeStamp_ms = getCurrentTimeStamp_ms();
|
|
|
|
QNetworkRequest request(url);
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
|
|
addBearerAuthenticationHeaderToRequest(&request);
|
|
|
|
const QByteArray jsonByteArr = jsonMetaDataString.toLatin1();
|
|
|
|
QNetworkReply* reply = m_accessManager.post(request, jsonByteArr);
|
|
reply->setProperty("holo_metaDataSequenceNumber", QVariant(metaDataSequenceNumber));
|
|
reply->setProperty("holo_sendStartTimeStamp_ms", QVariant(sendStartTimeStamp_ms));
|
|
|
|
connect(reply, SIGNAL(finished()), SLOT(slotSendMetaDataFinished()));
|
|
|
|
#ifdef EXPERIMENTAL_SSL_SUPPORT
|
|
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), SLOT(slotSslErrors(const QList<QSslError>&)));
|
|
#endif
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::slotSendMetaDataFinished()
|
|
{
|
|
QNetworkReply* reply = dynamic_cast<QNetworkReply*>(sender());
|
|
if (!reply)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (detectAndHandleErrorReply("sendMetaData", reply))
|
|
{
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
int metaDataSequenceNumber = -1;
|
|
{
|
|
QVariant var = reply->property("holo_metaDataSequenceNumber");
|
|
if (var.type() == QVariant::Int)
|
|
{
|
|
metaDataSequenceNumber = var.toInt();
|
|
}
|
|
}
|
|
|
|
double elapsedTime_s = -1;
|
|
{
|
|
QVariant var = reply->property("holo_sendStartTimeStamp_ms");
|
|
if (var.type() == QVariant::LongLong)
|
|
{
|
|
const qint64 startTimeStamp_ms = var.toLongLong();
|
|
elapsedTime_s = (getCurrentTimeStamp_ms() - startTimeStamp_ms)/1000.0;
|
|
}
|
|
}
|
|
|
|
const QByteArray serverData = reply->readAll();
|
|
//cvf::Trace::show(" serverResponse: %s", serverData.constData());
|
|
|
|
reply->deleteLater();
|
|
|
|
cvf::Trace::show("sendMetaData (metaDataSequenceNumber=%d) OK, elapsedTime=%.2fs", metaDataSequenceNumber, elapsedTime_s);
|
|
if (m_responseHandler)
|
|
{
|
|
m_responseHandler->handleSuccessfulSendMetaData(metaDataSequenceNumber, serverData);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::sendBinaryData(const QByteArray& binaryDataArr)
|
|
{
|
|
const QString url = m_serverUrl + "/sessions/" + m_sessionName + "/data";
|
|
cvf::Trace::show("sendBinaryData: POST on url: %s", url.toLatin1().constData());
|
|
|
|
const qint64 sendStartTimeStamp_ms = getCurrentTimeStamp_ms();
|
|
|
|
QNetworkRequest request(url);
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
|
addBearerAuthenticationHeaderToRequest(&request);
|
|
|
|
QNetworkReply* reply = m_accessManager.post(request, binaryDataArr);
|
|
reply->setProperty("holo_sendStartTimeStamp_ms", QVariant(sendStartTimeStamp_ms));
|
|
|
|
connect(reply, SIGNAL(finished()), SLOT(slotSendBinaryDataFinished()));
|
|
|
|
// Debugging!
|
|
connect(reply, SIGNAL(uploadProgress(qint64, qint64)), SLOT(slotDbgUploadProgress(qint64, qint64)));
|
|
|
|
#ifdef EXPERIMENTAL_SSL_SUPPORT
|
|
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), SLOT(slotSslErrors(const QList<QSslError>&)));
|
|
#endif
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::slotSendBinaryDataFinished()
|
|
{
|
|
QNetworkReply* reply = dynamic_cast<QNetworkReply*>(sender());
|
|
if (!reply)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (detectAndHandleErrorReply("sendBinaryData", reply))
|
|
{
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
double elapsedTime_s = -1;
|
|
{
|
|
QVariant var = reply->property("holo_sendStartTimeStamp_ms");
|
|
if (var.type() == QVariant::LongLong)
|
|
{
|
|
const qint64 startTimeStamp_ms = var.toLongLong();
|
|
elapsedTime_s = (getCurrentTimeStamp_ms() - startTimeStamp_ms)/1000.0;
|
|
}
|
|
}
|
|
|
|
reply->deleteLater();
|
|
|
|
cvf::Trace::show("sendBinaryData OK, elapsedTime=%.2fs", elapsedTime_s);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::slotDbgUploadProgress(qint64 bytesSent, qint64 bytesTotal)
|
|
{
|
|
static int sl_lastPct = -1;
|
|
int pct = 0;
|
|
if (bytesTotal > 0)
|
|
{
|
|
pct = static_cast<int>(100*(bytesSent/static_cast<double>(bytesTotal)));
|
|
}
|
|
|
|
if (pct % 10 == 0 && pct != sl_lastPct)
|
|
{
|
|
double elapsedTime_s = -1;
|
|
QNetworkReply* reply = dynamic_cast<QNetworkReply*>(sender());
|
|
if (reply)
|
|
{
|
|
QVariant var = reply->property("holo_sendStartTimeStamp_ms");
|
|
if (var.type() == QVariant::LongLong)
|
|
{
|
|
const qint64 startTimeStamp_ms = var.toLongLong();
|
|
elapsedTime_s = (getCurrentTimeStamp_ms() - startTimeStamp_ms)/1000.0;
|
|
}
|
|
}
|
|
|
|
cvf::Trace::show("Sending progress: %3d%%, %.2f/%.2fMB (elapsedTime=%.2fs)", pct, bytesSent/(1024.0*1024.0), bytesTotal/(1024.0*1024.0), elapsedTime_s);
|
|
sl_lastPct = pct;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::slotSslErrors(const QList<QSslError>& errors)
|
|
{
|
|
#ifdef EXPERIMENTAL_SSL_SUPPORT
|
|
cvf::Trace::show("RicHoloLensRestClient::slotSslErrors()");
|
|
for (int i = 0; i < errors.size(); i++)
|
|
{
|
|
cvf::Trace::show(" %s", errors[i].errorString().toLatin1().constData());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicHoloLensRestClient::addBearerAuthenticationHeaderToRequest(QNetworkRequest* request) const
|
|
{
|
|
CVF_ASSERT(request);
|
|
|
|
request->setRawHeader("Authorization", "Bearer " + m_bearerToken);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RicHoloLensRestClient::detectAndHandleErrorReply(QString operationName, QNetworkReply* reply)
|
|
{
|
|
CVF_ASSERT(reply);
|
|
|
|
const QNetworkReply::NetworkError nwErrCode = reply->error();
|
|
const int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
|
if (nwErrCode == QNetworkReply::NoError && httpStatusCode == 200)
|
|
{
|
|
// No error detected
|
|
return false;
|
|
}
|
|
|
|
QString mainErrMsg = operationName + " FAILED";
|
|
if (nwErrCode != QNetworkReply::NoError)
|
|
{
|
|
const QString nwErrCodeAsString = networkErrorCodeAsString(nwErrCode);
|
|
const QString errText = reply->errorString();
|
|
mainErrMsg += QString(" [nwErr='%1'(%2) httpStatus=%3]: %4").arg(nwErrCodeAsString).arg(nwErrCode).arg(httpStatusCode).arg(errText);
|
|
}
|
|
else
|
|
{
|
|
mainErrMsg += QString(" [httpStatus=%1]").arg(httpStatusCode);
|
|
}
|
|
|
|
cvf::Trace::show(mainErrMsg.toLatin1().constData());
|
|
|
|
reply->errorString();
|
|
|
|
const QString url = reply->url().toString();
|
|
cvf::Trace::show(" url: %s", url.toLatin1().constData());
|
|
|
|
const QByteArray serverData = reply->readAll();
|
|
cvf::Trace::show(" serverResponse: %s", serverData.constData());
|
|
|
|
if (m_responseHandler)
|
|
{
|
|
m_responseHandler->handleError(mainErrMsg, url, serverData);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RicHoloLensRestClient::networkErrorCodeAsString(QNetworkReply::NetworkError nwErr)
|
|
{
|
|
switch (nwErr)
|
|
{
|
|
case QNetworkReply::NoError: return "NoError";
|
|
|
|
case QNetworkReply::ConnectionRefusedError: return "ConnectionRefusedError";
|
|
case QNetworkReply::RemoteHostClosedError: return "RemoteHostClosedError";
|
|
case QNetworkReply::HostNotFoundError: return "HostNotFoundError";
|
|
case QNetworkReply::TimeoutError: return "TimeoutError";
|
|
case QNetworkReply::OperationCanceledError: return "OperationCanceledError";
|
|
case QNetworkReply::SslHandshakeFailedError: return "SslHandshakeFailedError";
|
|
//case QNetworkReply::TemporaryNetworkFailureError: return "TemporaryNetworkFailureError";
|
|
case QNetworkReply::UnknownNetworkError: return "UnknownNetworkError";
|
|
|
|
case QNetworkReply::ProxyConnectionRefusedError: return "ProxyConnectionRefusedError";
|
|
case QNetworkReply::ProxyConnectionClosedError: return "ProxyConnectionClosedError";
|
|
case QNetworkReply::ProxyNotFoundError: return "ProxyNotFoundError";
|
|
case QNetworkReply::ProxyTimeoutError: return "ProxyTimeoutError";
|
|
case QNetworkReply::ProxyAuthenticationRequiredError: return "ProxyAuthenticationRequiredError";
|
|
case QNetworkReply::UnknownProxyError: return "UnknownProxyError";
|
|
|
|
case QNetworkReply::ContentAccessDenied: return "ContentAccessDenied";
|
|
case QNetworkReply::ContentOperationNotPermittedError: return "ContentOperationNotPermittedError";
|
|
case QNetworkReply::ContentNotFoundError: return "ContentNotFoundError";
|
|
case QNetworkReply::AuthenticationRequiredError: return "AuthenticationRequiredError";
|
|
case QNetworkReply::ContentReSendError: return "ContentReSendError";
|
|
case QNetworkReply::UnknownContentError: return "UnknownContentError";
|
|
|
|
case QNetworkReply::ProtocolUnknownError: return "ProtocolUnknownError";
|
|
case QNetworkReply::ProtocolInvalidOperationError: return "ProtocolInvalidOperationError";
|
|
case QNetworkReply::ProtocolFailure: return "ProtocolFailure";
|
|
};
|
|
|
|
return "UnknownErrorCode";
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
qint64 RicHoloLensRestClient::getCurrentTimeStamp_ms()
|
|
{
|
|
#if QT_VERSION >= 0x040700
|
|
const qint64 timeStamp_ms = QDateTime::currentMSecsSinceEpoch();
|
|
return timeStamp_ms;
|
|
#elif defined(__linux__)
|
|
struct timespec ts;
|
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
|
|
{
|
|
return static_cast<qint64>(ts.tv_sec*1000 + ts.tv_nsec/1000000);
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|