Commit c27e8eef authored by Karel Slaný's avatar Karel Slaný

Pulled changes in shared code.

parent 34473ed6
......@@ -26,7 +26,7 @@
#include "src/datovka_shared/log/log.h"
#include "src/datovka_shared/records_management/conversion.h"
QList<qint64> createIdList(const QStringList &strList, bool *ok)
QList<qint64> RecMgmt::createIdList(const QStringList &strList, bool *ok)
{
QList<qint64> idList;
bool iOk = false;
......
......@@ -26,11 +26,15 @@
#include <QList>
#include <QStringList>
/*!
* @brief Convert list of strings into list of qint64.
*
* @param[in] strList String list.
* @param[out] ok Set to true if all entries are successfully converted.
* @return List if qint64.
*/
QList<qint64> createIdList(const QStringList &strList, bool *ok);
namespace RecMgmt {
/*!
* @brief Convert list of strings into list of qint64.
*
* @param[in] strList String list.
* @param[out] ok Set to true if all entries are successfully converted.
* @return List if qint64.
*/
QList<qint64> createIdList(const QStringList &strList, bool *ok);
}
......@@ -30,13 +30,13 @@
#include "src/datovka_shared/records_management/io/records_management_connection.h"
/* Must be set to false for production releases. */
const bool RecordsManagementConnection::ignoreSslErrorsDflt = false;
const bool RecMgmt::Connection::ignoreSslErrorsDflt = false;
/*!
* @brief Converts service identifier onto service name.
*/
static
const QString &serviceName(enum RecordsManagementConnection::ServiceId srvcId)
const QString &serviceName(enum RecMgmt::Connection::ServiceId srvcId)
{
static const QString SrvServiceInfo(QStringLiteral("service_info"));
static const QString SrvUploadHierarchy(QStringLiteral("upload_hierarchy"));
......@@ -45,16 +45,16 @@ const QString &serviceName(enum RecordsManagementConnection::ServiceId srvcId)
static const QString InvalidService;
switch (srvcId) {
case RecordsManagementConnection::SRVC_SERVICE_INFO:
case RecMgmt::Connection::SRVC_SERVICE_INFO:
return SrvServiceInfo;
break;
case RecordsManagementConnection::SRVC_UPLOAD_HIERARCHY:
case RecMgmt::Connection::SRVC_UPLOAD_HIERARCHY:
return SrvUploadHierarchy;
break;
case RecordsManagementConnection::SRVC_UPLOAD_FILE:
case RecMgmt::Connection::SRVC_UPLOAD_FILE:
return SrvUploadFile;
break;
case RecordsManagementConnection::SRVC_STORED_FILES:
case RecMgmt::Connection::SRVC_STORED_FILES:
return SrvStoredFiles;
break;
default:
......@@ -68,8 +68,7 @@ const QString &serviceName(enum RecordsManagementConnection::ServiceId srvcId)
* @brief Create URL from base URL and from service identifier.
*/
static
QUrl constructUrl(QString baseUrl,
enum RecordsManagementConnection::ServiceId srvcId)
QUrl constructUrl(QString baseUrl, enum RecMgmt::Connection::ServiceId srvcId)
{
const QString &srvcName(serviceName(srvcId));
......@@ -83,7 +82,7 @@ QUrl constructUrl(QString baseUrl,
return QUrl(baseUrl + srvcName);
}
RecordsManagementConnection::RecordsManagementConnection(bool ignoreSslErrors,
RecMgmt::Connection::Connection(bool ignoreSslErrors,
QObject *parent)
: QObject(parent),
m_baseUrlStr(),
......@@ -97,14 +96,14 @@ RecordsManagementConnection::RecordsManagementConnection(bool ignoreSslErrors,
this, SLOT(handleSslErrors(QNetworkReply *, const QList<QSslError>)));
}
void RecordsManagementConnection::setConnection(const QString &baseUrl,
void RecMgmt::Connection::setConnection(const QString &baseUrl,
const QString &token)
{
m_baseUrlStr = baseUrl;
m_tokenStr = token;
}
bool RecordsManagementConnection::communicate(enum ServiceId srvcId,
bool RecMgmt::Connection::communicate(enum ServiceId srvcId,
const QByteArray &requestData, QByteArray &replyData, QObject *cbObj)
{
debugFuncCall();
......@@ -125,7 +124,7 @@ bool RecordsManagementConnection::communicate(enum ServiceId srvcId,
cbObj, SLOT(onUploadProgress(qint64, qint64)));
}
bool retVal = waitReplyFinished(reply, m_timeOut);
bool retVal = waitReplyFinished(reply, m_timeOut, cbObj);
if (cbObj != Q_NULLPTR) {
cbObj->disconnect(SIGNAL(callAbort()), reply, SLOT(abort()));
......@@ -180,7 +179,7 @@ bool readAndAddCert(const QByteArray &certData, QSsl::EncodingFormat fmt)
return true;
}
bool RecordsManagementConnection::addTrustedCertificate(const QString &filePath)
bool RecMgmt::Connection::addTrustedCertificate(const QString &filePath)
{
QByteArray certData;
......@@ -218,7 +217,7 @@ bool RecordsManagementConnection::addTrustedCertificate(const QString &filePath)
return false;
}
void RecordsManagementConnection::handleSslErrors(QNetworkReply *reply,
void RecMgmt::Connection::handleSslErrors(QNetworkReply *reply,
const QList<QSslError> &errors)
{
Q_UNUSED(reply);
......@@ -246,8 +245,7 @@ void RecordsManagementConnection::handleSslErrors(QNetworkReply *reply,
}
}
QNetworkRequest RecordsManagementConnection::createRequest(
enum ServiceId srvcId) const
QNetworkRequest RecMgmt::Connection::createRequest(enum ServiceId srvcId) const
{
debugFuncCall();
......@@ -265,8 +263,8 @@ QNetworkRequest RecordsManagementConnection::createRequest(
return request;
}
QNetworkReply *RecordsManagementConnection::sendRequest(
const QNetworkRequest &request, const QByteArray &data)
QNetworkReply *RecMgmt::Connection::sendRequest(const QNetworkRequest &request,
const QByteArray &data)
{
debugFuncCall();
......@@ -297,8 +295,8 @@ QNetworkReply *RecordsManagementConnection::sendRequest(
return reply;
}
bool RecordsManagementConnection::waitReplyFinished(QNetworkReply *reply,
unsigned int timeOut)
bool RecMgmt::Connection::waitReplyFinished(QNetworkReply *reply,
unsigned int timeOut, QObject *cbObj)
{
if (Q_UNLIKELY(reply == Q_NULLPTR)) {
Q_ASSERT(0);
......@@ -309,26 +307,46 @@ bool RecordsManagementConnection::waitReplyFinished(QNetworkReply *reply,
QTimer timer;
timer.setSingleShot(true);
QEventLoop eventLoop;
if (cbObj != Q_NULLPTR) {
connect(&timer, SIGNAL(timeout()), cbObj, SLOT(onTimeout()));
}
connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
timer.start(timeOut);
eventLoop.exec();
if (timer.isActive()) {
do {
timer.start(timeOut);
eventLoop.exec();
/*
* Repeat if a callback object is present and while
* communication has not been stopped.
* Exit if no callback object is specified.
*/
} while ((cbObj != Q_NULLPTR) && reply->isRunning());
if (cbObj != Q_NULLPTR) {
timer.disconnect(SIGNAL(timeout()), cbObj, SLOT(onTimeout()));
}
timer.disconnect(SIGNAL(timeout()), &eventLoop, SLOT(quit()));
reply->disconnect(SIGNAL(finished()), &eventLoop, SLOT(quit()));
if (reply->isFinished()) {
timer.stop();
return true;
} else {
/* Timeout expired. */
disconnect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
logErrorNL("%s",
"Connection timed out. Check your internet connection.");
reply->abort();
}
return false;
/*
* The value QNetworkReply::OperationCanceledError means cancelled via
* abort() or close().
*/
return reply->error() == QNetworkReply::NoError;
}
bool RecordsManagementConnection::processReply(QNetworkReply *reply,
bool RecMgmt::Connection::processReply(QNetworkReply *reply,
QByteArray &replyData)
{
debugFuncCall();
......
......@@ -30,131 +30,183 @@
#include <QObject>
#include <QString>
/*!
* @brief Encapsulates connection to records management service.
*/
class RecordsManagementConnection : public QObject {
Q_OBJECT
public:
/*!
* @brief Records management service identifiers.
*/
enum ServiceId {
SRVC_SERVICE_INFO,
SRVC_UPLOAD_HIERARCHY,
SRVC_UPLOAD_FILE,
SRVC_STORED_FILES
};
/*!
* @brief Use for controlling of global behaviour on SSL errors.
*/
static
const bool ignoreSslErrorsDflt;
/*!
* @brief Constructor.
*/
explicit RecordsManagementConnection(bool ignoreSslErrors = false,
QObject *parent = Q_NULLPTR);
/*!
* @brief Set connection data.
*
* @param[in] baseUrl Service base URL.
* @param[in] token Authentication token.
*/
void setConnection(const QString &baseUrl, const QString &token);
/*!
* @brief Send request and wait for reply.
*
* @note The callback object must be able to emit the signal
* 'callAbort()' which will abort the network communication.
* The callback object must be define the slots
* 'onDownloadProgress(qint64, qint64)' and
* 'onUploadProgress(qint64, qint64)' which should handle
* the corresponding network reply signals.
*
* @param[in] srvcId Srvice identifier.
* @param[in] requestData Data to be sent.
* @param[out] replyData Data from the reply.
* @param[in,out] cbObj Callback object to be connected to the internal
* network reply object.
*/
bool communicate(enum ServiceId srvcId, const QByteArray &requestData,
QByteArray &replyData, QObject *cbObj = Q_NULLPTR);
/*!
* @brief Add certificate to certificate store.
*
* @param[in] filePath Path to certificate file.
* @return True on success.
*/
static
bool addTrustedCertificate(const QString &filePath);
namespace RecMgmt {
signals:
#if 0
/*!
* @brief Emitted when some error during communication occurs.
* @brief An connection timeout handler prototype.
*
* @param[in] message Message string containing error description.
* @note There is a problem in Qt with multiple inheritance from
* QObject classes. E.g. we cannot use this class to directly derive
* dialogues from it. This class serves as an illustration how a
* progress handler (callback) object could look like. See
* https://stackoverflow.com/a/2998374 on pure virtual slots
* https://stackoverflow.com/a/8578921 on QObject multiple inheritance
*/
void connectionError(const QString &message);
private slots:
void handleSslErrors(QNetworkReply *reply,
const QList<QSslError> &errors);
private:
/*!
* @brief Create network request.
*
* @param[in] srvcId Srvice identifier.
* @return Created network request.
*/
QNetworkRequest createRequest(enum ServiceId srvcId) const;
/*!
* @brief Send request.
*
* @param[in] request Network request.
* @param[in] data Data to be sent along with the request.
* @return Null pointer on failure.
*/
QNetworkReply *sendRequest(const QNetworkRequest &request,
const QByteArray &data);
/*!
* @brief Blocks until all data are sent and received or until timed out.
*
* @note The reply is aborted when it times out. In this case the reply
* is not deleted.
*
* @param[in,out] reply Communication context.
* @param[in] timeOut Communication timeout.
* @return True if all data have been received,
* false if communication timed out.
*/
static
bool waitReplyFinished(QNetworkReply *reply, unsigned int timeOut);
class ProgressHandler : protected QObject {
Q_OBJECT
signals:
/*!
* @brief When this signal is emitted then the network
* communication is directly aborted.
*/
void callAbort(void);
public slots:
/*!
* @brief This slot is connected to the network reply object and
* handles the ingoing communication.
*/
void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
/*!
* @brief This slot is connected to the network reply object and
* handles the outgoing communication.
*/
void onUploadProgress(qint64 bytesSent, qint64 bytesTotal);
/*!
* @brief This slot is connected to the internal timer object
* and should watch the progress of the data transfer. It
* should be able to emit the callAbort() signal.
*/
void onTimeout(void);
};
#endif
/*!
* @brief Process reply data.
*
* @param[in,out] reply Obtained reply.
* @param[out] replyData Obtained reply data.
* @return True on success, false on error.
* @brief Encapsulates connection to records management service.
*/
static
bool processReply(QNetworkReply *reply, QByteArray &replyData);
QString m_baseUrlStr; /*!< Service base URL. */
QString m_tokenStr; /*!< Authentication token. */
QString m_agentName; /*!< Usually the application name. */
class Connection : public QObject {
Q_OBJECT
public:
/*!
* @brief Records management service identifiers.
*/
enum ServiceId {
SRVC_SERVICE_INFO,
SRVC_UPLOAD_HIERARCHY,
SRVC_UPLOAD_FILE,
SRVC_STORED_FILES
};
/*!
* @brief Use for controlling of global behaviour on SSL errors.
*/
static
const bool ignoreSslErrorsDflt;
/*!
* @brief Constructor.
*/
explicit Connection(bool ignoreSslErrors = false,
QObject *parent = Q_NULLPTR);
/*!
* @brief Set connection data.
*
* @param[in] baseUrl Service base URL.
* @param[in] token Authentication token.
*/
void setConnection(const QString &baseUrl, const QString &token);
/*!
* @brief Send request and wait for reply.
*
* @note The callback object must be able to emit the signal
* 'callAbort()' which will abort the network communication.
* The callback object must be define the slots
* 'onDownloadProgress(qint64, qint64)' and
* 'onUploadProgress(qint64, qint64)' which should handle
* the corresponding network reply signals.
*
* @param[in] srvcId Srvice identifier.
* @param[in] requestData Data to be sent.
* @param[out] replyData Data from the reply.
* @param[in,out] cbObj Callback object to be connected to the
* internal network reply object.
*/
bool communicate(enum ServiceId srvcId,
const QByteArray &requestData, QByteArray &replyData,
QObject *cbObj = Q_NULLPTR);
/*!
* @brief Add certificate to certificate store.
*
* @param[in] filePath Path to certificate file.
* @return True on success.
*/
static
bool addTrustedCertificate(const QString &filePath);
signals:
/*!
* @brief Emitted when some error during communication occurs.
*
* @param[in] message Message string containing error description.
*/
void connectionError(const QString &message);
private slots:
void handleSslErrors(QNetworkReply *reply,
const QList<QSslError> &errors);
private:
/*!
* @brief Create network request.
*
* @param[in] srvcId Service identifier.
* @return Created network request.
*/
QNetworkRequest createRequest(enum ServiceId srvcId) const;
/*!
* @brief Send request.
*
* @param[in] request Network request.
* @param[in] data Data to be sent along with the request.
* @return Null pointer on failure.
*/
QNetworkReply *sendRequest(const QNetworkRequest &request,
const QByteArray &data);
/*!
* @brief Blocks until all data are sent and received or until
* timed out.
*
* @note The reply is aborted when it times out and no callback
* object is specified. In this case the reply is not deleted.
*
* @param[in,out] reply Communication context.
* @param[in] timeOut Communication timeout.
* @param[in,out] cbObj Callback object to be connected to the
* internal timer object.
* @return True if all data have been received,
* false if communication timed out.
*/
static
bool waitReplyFinished(QNetworkReply *reply,
unsigned int timeOut, QObject *cbObj);
/*!
* @brief Process reply data.
*
* @param[in,out] reply Obtained reply.
* @param[out] replyData Obtained reply data.
* @return True on success, false on error.
*/
static
bool processReply(QNetworkReply *reply, QByteArray &replyData);
QString m_baseUrlStr; /*!< Service base URL. */
QString m_tokenStr; /*!< Authentication token. */
QString m_agentName; /*!< Usually the application name. */
unsigned int m_timeOut; /*!< Communication timeout. */
bool m_ignoreSslErrors; /*!< True if SSL errors should be ignored. */
QNetworkAccessManager m_nam; /*!< Network access manager. */
};
unsigned int m_timeOut; /*!< Communication timeout. */
bool m_ignoreSslErrors; /*!< True if SSL errors should be ignored. */
QNetworkAccessManager m_nam; /*!< Network access manager. */
};
}
......@@ -41,35 +41,35 @@ static const QString strAlreadyPresent("ALREADY_PRESENT");
static const QString strLimitExceeded("LIMIT_EXCEEDED");
static const QString strUnspecified("UNSPECIFIED");
ErrorEntry::ErrorEntry(void)
RecMgmt::ErrorEntry::ErrorEntry(void)
: m_code(ERR_NO_ERROR),
m_description()
{
}
ErrorEntry::ErrorEntry(enum Code code, const QString &description)
RecMgmt::ErrorEntry::ErrorEntry(enum Code code, const QString &description)
: m_code(code),
m_description(description)
{
}
ErrorEntry::ErrorEntry(const ErrorEntry &ee)
: m_code(ee.m_code),
m_description(ee.m_description)
RecMgmt::ErrorEntry::ErrorEntry(const ErrorEntry &other)
: m_code(other.m_code),
m_description(other.m_description)
{
}
enum ErrorEntry::Code ErrorEntry::code(void) const
enum RecMgmt::ErrorEntry::Code RecMgmt::ErrorEntry::code(void) const
{
return m_code;
}
const QString &ErrorEntry::description(void) const
const QString &RecMgmt::ErrorEntry::description(void) const
{
return m_description;
}
bool ErrorEntry::fromJsonVal(const QJsonValue *jsonVal)
bool RecMgmt::ErrorEntry::fromJsonVal(const QJsonValue *jsonVal)
{
if (jsonVal == Q_NULLPTR) {
Q_ASSERT(0);
......@@ -107,7 +107,7 @@ bool ErrorEntry::fromJsonVal(const QJsonValue *jsonVal)
return true;
}
bool ErrorEntry::toJsonVal(QJsonValue *jsonVal) const
bool RecMgmt::ErrorEntry::toJsonVal(QJsonValue *jsonVal) const
{
if (jsonVal == Q_NULLPTR) {
Q_ASSERT(0);
......@@ -126,7 +126,7 @@ bool ErrorEntry::toJsonVal(QJsonValue *jsonVal) const
return true;
}
QString ErrorEntry::trVerbose(void) const
QString RecMgmt::ErrorEntry::trVerbose(void) const
{
QString retStr(codeToString(m_code) + QLatin1String(" ("));
QString explanation;
......@@ -166,7 +166,7 @@ QString ErrorEntry::trVerbose(void) const
return retStr;
}
const QString &ErrorEntry::codeToString(enum Code code)
const QString &RecMgmt::ErrorEntry::codeToString(enum Code code)
{
switch (code) {
case ERR_NO_ERROR:
......@@ -201,18 +201,19 @@ const QString &ErrorEntry::codeToString(enum Code code)
}
}
enum ErrorEntry::Code ErrorEntry::stringToCode(const QString &str, bool *ok)
enum RecMgmt::ErrorEntry::Code RecMgmt::ErrorEntry::stringToCode(
const QString &str, bool *ok)
{
if (str == strNoError) {
if (ok != Q_NULLPTR) {
*ok = true;
}
return ErrorEntry::ERR_NO_ERROR;
return ERR_NO_ERROR;
} else if (str == strMalformedRequest) {
if (ok != Q_NULLPTR) {
*ok = true;
}
return ErrorEntry::ERR_MALFORMED_REQUEST;
return ERR_MALFORMED_REQUEST;
} else if (str == strMissingIdentifier) {
if (ok != Q_NULLPTR) {
*ok = true;
......@@ -227,26 +228,26 @@ enum ErrorEntry::Code ErrorEntry::stringToCode(const QString &str, bool *ok)
if (ok != Q_NULLPTR) {
*ok = true;
}
return ErrorEntry::ERR_UNSUPPORTED_FILE_FORMAT;
return ERR_UNSUPPORTED_FILE_FORMAT;
} else if (str == strAlreadyPresent) {
if (ok != Q_NULLPTR) {
*ok = true;
}
return ErrorEntry::ERR_ALREADY_PRESENT;
return ERR_ALREADY_PRESENT;
} else if (str == strLimitExceeded) {
if (ok != Q_NULLPTR) {
*ok = true;
}
return ErrorEntry::ERR_LIMIT_EXCEEDED;
return ERR_LIMIT_EXCEEDED;
} else if (str == strUnspecified) {
if (ok != Q_NULLPTR) {
*ok = true;
}
return ErrorEntry::ERR_UNSPECIFIED;
return ERR_UNSPECIFIED;
} else {
if (ok != Q_NULLPTR) {
*ok = false;
}
return ErrorEntry::ERR_UNSPECIFIED;
return ERR_UNSPECIFIED;
}
}
......@@ -28,109 +28,113 @@
class QJsonValue; /* Forward declaration. */
/*!
* @brief Encapsulates any error entry.
*/
class ErrorEntry {
Q_DECLARE_TR_FUNCTIONS(ErrorEntry)
namespace RecMgmt {
public:
/*!
* @brief Error codes.
* @brief Encapsulates any error entry.
*/
enum Code {
ERR_NO_ERROR, /*!< Just for convenience. */
ERR_MALFORMED_REQUEST, /*!< JSON request was corrupt. */
ERR_MISSING_IDENTIFIER, /*!< JSON request provided no identifier. */
ERR_WRONG_IDENTIFIER, /*!< Wrong identifier provided in JSON request. */
ERR_UNSUPPORTED_FILE_FORMAT, /*!< Uploaded file format not supported. */
ERR_ALREADY_PRESENT, /*!< File is already present. */
ERR_LIMIT_EXCEEDED, /*!< Too many identifiers in a single request. */
ERR_UNSPECIFIED /*!< Unspecified error. */
class ErrorEntry {
Q_DECLARE_TR_FUNCTIONS(ErrorEntry)
public:
/*!
* @brief Error codes.
*/
enum Code {
ERR_NO_ERROR, /*!< Just for convenience. */
ERR_MALFORMED_REQUEST, /*!< JSON request was corrupt. */
ERR_MISSING_IDENTIFIER, /*!< JSON request provided no identifier. */
ERR_WRONG_IDENTIFIER, /*!< Wrong identifier provided in JSON request. */
ERR_UNSUPPORTED_FILE_FORMAT, /*!< Uploaded file format not supported. */
ERR_ALREADY_PRESENT, /*!< File is already present. */
ERR_LIMIT_EXCEEDED, /*!< Too many identifiers in a single request. */
ERR_UNSPECIFIED /*!< Unspecified error. */
};
/*!
* @brief Constructor. Constructs a no-error entry.
*/
ErrorEntry(void);