colnod-connector/src/colnod/colnodapi.cpp
Filip Bucek 9f9ae6243c WIP: ColnodAPI::downloadData ( solving memory leaks )
Problem with ASSERT: "dataCount < 5" in file /Users/fbucek/Documents/Spaceti/acs/colnod-connector/src/colnod/colnodapi.cpp, line 80
2019-12-04 16:30:59 +01:00

382 lines
12 KiB
C++

#include "colnodapi.h"
#include <utility>
Q_LOGGING_CATEGORY(colnod, "colnod.api");
ColnodAPI::ColnodAPI(serversdk::RequestManager* reqMan, const bool &dryMode, QString userName, QString password)
:mReqMan(reqMan), mUserName(std::move(userName)), mPassword(std::move(password)), mDryMode(dryMode)
{
// -----------------------------------
mReqMan->setIgnoreSsl(true);
// -----------------------------------
}
/**
* @brief Downloads new data from Colnod -> emits downloadDataFinished signal
* @param time
*
* @return signal with nullptr when something went wrong
* @return signal with data when valid data returned
*/
void ColnodAPI::downloadData(const qint64 &time)
{
// Have to get Login
auto login = requestLogin();
Q_ASSERT(login);
connect(login.get(), &serversdk::Request::finished, this, [=](){
// Get login token
if (login->status() != 200) {
emit downloadDataFinished(nullptr);
return;
}
AuthToken token;
auto responseData = login->responseData();
if (responseData.isEmpty()) {
qCWarning(colnod) << "empty response data when logging in";
emit downloadDataFinished(nullptr);
return;
}
token.fromJson(responseData);
authToken = token.id();
if (authToken.isEmpty()) {
qCCritical(colnod) << "Token uuid is empty";
emit downloadDataFinished(nullptr);
return;
}
// NOTE: why?
// auto errorHandler = [=](const std::shared_ptr<serversdk::Request>& request){
// if (!checkRequest(request)) {
// qWarning(colnod) << "ERROR during calling" << request->url() << ", request unsuccessful";
// mValid = false;
// emit downloadDataFinished(nullptr); // TODO: think about it, will the other if passed?
// }
// else if (!checkResponse(request->responseData())) {
// qWarning(colnod) << "Data from" << request->url() << "are invalid";
// mValid = false;
// }
// };
// if I have all data emit downloadDataFinished
connect(this, &ColnodAPI::partOfDataReady, this, &ColnodAPI::areDataReady);
Timestamp timestamp;
timestamp.setTimestamp(time);
auto data = std::make_shared<Data>();
int dataCount = 0;
auto checkData = [&dataCount, &data, this]() {
qDebug() << "check data" << dataCount;
if (dataCount > 5) {
qCCritical(colnod) << "check data cannnot be higher then 4";
}
Q_ASSERT(dataCount < 5);
if (dataCount == 4)
emit downloadDataFinished(data);
};
auto tokensRequest = getTokensUpdated(timestamp);
// connect(tokensRequest.get(), &serversdk::Request::finished, errorHandler);
connect(tokensRequest.get(), &serversdk::Request::finished, [=, &dataCount](){
qDebug(colnod) << "tokens finished";
if (!saveUpdatedTokens(data, tokensRequest->responseData())) {
emit downloadDataFinished(nullptr);
return;
}
++dataCount;
checkData();
//saveUpdatedTokens(data, tokensRequest->responseData());
//emit partOfDataReady(data);
});
auto deletedTokensRequest = getTokensDeleted(timestamp);
// connect(deletedTokensRequest.get(), &serversdk::Request::finished, errorHandler);
connect(deletedTokensRequest.get(), &serversdk::Request::finished, [=, &dataCount](){
qDebug(colnod) << "tokens finished";
if (!saveDeletedTokens(data, deletedTokensRequest->responseData())) {
emit downloadDataFinished(nullptr);
return;
}
++dataCount;
checkData();
//emit partOfDataReady(data);
});
auto subjectsRequest = getSubjectsUpdated(timestamp);
// connect(subjectsRequest.get(), &serversdk::Request::finished, errorHandler);
connect(subjectsRequest.get(), &serversdk::Request::finished, [=, &dataCount](){
qDebug(colnod) << "tokens finished";
if (!saveUpdatedSubjects(data, subjectsRequest->responseData())) {
emit downloadDataFinished(nullptr);
return;
}
++dataCount;
checkData();
});
auto deletedSubjectsRequest = getSubjectsDeleted(timestamp);
// connect(deletedSubjectsRequest.get(), &serversdk::Request::finished, errorHandler);
connect(deletedSubjectsRequest.get(), &serversdk::Request::finished, [=, &dataCount](){
qDebug(colnod) << "tokens finished";
saveDeletedSubjects(data, deletedSubjectsRequest->responseData());
++dataCount;
checkData();
// emit partOfDataReady(data);
});
});
}
void ColnodAPI::processData(const std::shared_ptr<Data> &data)
{
for (const auto &token : data->updatedTokens) {
qInfo(colnod).noquote() << Message::massageTemplate("Updating", "token", "colnod", token->name());
}
for (const auto &id : data->deletedTokens) {
qInfo(colnod).noquote() << Message::massageTemplate("Deleting", "token", "colnod", id);
}
if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty()) {
qInfo(colnod) << dash;
}
qInfo(colnod) << tab << "-> DATA PROCESSED TO COLNOD:";
qInfo(colnod) << tab << tab << data->updatedTokens.size() << "TOKENS UPDATED";
qInfo(colnod) << tab << tab << data->deletedTokens.size() << "TOKENS DELETED";
qInfo(colnod) << dash;
connect(this, &ColnodAPI::partOfDataProcessFinished, this, &ColnodAPI::isDataProcessFinished);
if ( !data->updatedTokens.isEmpty() && !mDryMode) {
setTokens(data->updatedTokens);
} else {
emit partOfDataProcessFinished();
}
if ( !data->deletedTokens.isEmpty() && !mDryMode) {
deleteTokens(data->deletedTokens);
} else {
emit partOfDataProcessFinished();
}
}
std::shared_ptr<serversdk::Request> ColnodAPI::requestLogin()
{
Q_ASSERT(mReqMan);
LoginResp login;
login.setUsername(userName());
// password
QString encodedPassword = QCryptographicHash::hash(
password().toLocal8Bit(), // -> bytearray
QCryptographicHash::Sha512 // SHA 512
).toHex().toUpper();
login.setPassword(encodedPassword);
auto loginRequest = composeRequest("/AaaManager/authSession", login.jsonData());
loginRequest->setUserName(login.username());
loginRequest->setPassword(login.password());
mReqMan->processRequest(loginRequest);
return loginRequest;
}
std::shared_ptr<serversdk::Request> ColnodAPI::getTokensUpdated(const Timestamp &time)
{
auto request = composeRequest("/TokenManager/getTokensUpdated", time.jsonData());
request->setUserName(authToken);
mReqMan->processRequest(request);
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::getTokensDeleted(const Timestamp &time)
{
auto request = composeRequest("/TokenManager/getTokensDeleted", time.jsonData());
request->setUserName(authToken);
mReqMan->processRequest(request);
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::getSubjectsUpdated(const Timestamp &time)
{
auto request = composeRequest("/SubjectManager/getSubjectsUpdated", time.jsonData());
request->setUserName(authToken);
mReqMan->processRequest(request);
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::getSubjectsDeleted(const Timestamp &time)
{
auto request = composeRequest("/SubjectManager/getSubjectsDeleted", time.jsonData());
request->setUserName(authToken);
mReqMan->processRequest(request);
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::setTokens(const QHash<QString, std::shared_ptr<Token>> &tokens)
{
auto request = composeRequest("/TokenManager/setTokens", Token::tokensToColnodJson(tokens));
request->setUserName(authToken);
mReqMan->processRequest(request);
connect(request.get(), &serversdk::Request::finished, [=](){
if (!checkRequest(request)) {
qCritical(colnod) << "ERROR during calling /TokenManager/setTokens, request unsuccessful. EXIT";
emit error();
}
if (checkResponse(request->responseData())) {
emit partOfDataProcessFinished();
}
else {
qWarning(colnod) << "Tokens wasn't updated";
mValid = false;
emit partOfDataProcessFinished();
}
});
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::deleteTokens(const QList<QString> &ids)
{
auto request = composeRequest("/TokenManager/deleteTokens", Token::idsToJSON(ids));
request->setUserName(authToken);
mReqMan->processRequest(request);
connect(request.get(), &serversdk::Request::finished, [=](){
if (!checkRequest(request)) {
qCritical(colnod) << "ERROR during calling /TokenManager/deleteTokens, request unsuccessful. EXIT";
emit error();
}
if (checkResponse(request->responseData())) {
emit partOfDataProcessFinished();
}
else {
qWarning(colnod) << "Tokens wasn't deleted";
mValid = false;
emit partOfDataProcessFinished();
}
});
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::composeRequest(const QString &endpoint, const QByteArray &data)
{
QString url = mHost + endpoint;
return std::make_shared<serversdk::Request>("POST", url, data);
}
bool ColnodAPI::checkRequest(const std::shared_ptr<serversdk::Request> &request)
{
return request->status() == 200;
}
bool ColnodAPI::isValid()
{
return mValid;
}
QString ColnodAPI::password() const
{
return mPassword;
}
void ColnodAPI::setPassword(const QString &password)
{
mPassword = password;
}
qint64 ColnodAPI::lastSync() const
{
return mLastSync.timestamp();
}
void ColnodAPI::setlastSync(const qint64 &lastSync)
{
mLastSync.setTimestamp(lastSync);
}
QString ColnodAPI::userName() const
{
return mUserName;
}
void ColnodAPI::setUserName(const QString &userName)
{
mUserName = userName;
}
void ColnodAPI::areDataReady(const std::shared_ptr<Data> &data)
{
if (++amountData == 4) {
qInfo(colnod) << tab << "-> COLNOD DATA:";
qInfo(colnod) << tab << tab << data->updatedTokens.size() << "TOKENS WERE ADDED/UPDATED";
qInfo(colnod) << tab << tab << data->deletedTokens.size() << "TOKENS DELETED";
qInfo(colnod) << tab << tab << data->updatedSubjects.size() << "SUBJECTS WERE ADDED/UPDATED";
qInfo(colnod) << tab << tab << data->deletedSubjects.size() << "SUBJECTS DELETED";
qInfo(colnod) << dash;
amountData = 0;
emit downloadDataFinished(data);
}
}
void ColnodAPI::isDataProcessFinished()
{
if (++amountProccessesFinished == 2) {
emit dataProcessFinished();
}
}
bool ColnodAPI::saveUpdatedTokens(const std::shared_ptr<Data>& data, const QByteArray &responseData)
{
Q_ASSERT(data);
return data->loadTokensFromJson(responseData);
}
bool ColnodAPI::saveDeletedTokens(const std::shared_ptr<Data>& data, const QByteArray &responseData)
{
Q_ASSERT(data);
if (responseData.isEmpty())
return false;
QJsonDocument doc = QJsonDocument::fromJson(responseData);
QJsonArray items = doc.object()["items"].toArray();
for (QJsonValueRef item : items) {
data->deletedTokens.append(item.toString());
}
return true;
}
bool ColnodAPI::saveUpdatedSubjects(const std::shared_ptr<Data>& data, const QByteArray &responseData)
{
Q_ASSERT(data);
return data->loadSubjectsFormJson(responseData);
}
bool ColnodAPI::saveDeletedSubjects(const std::shared_ptr<Data>& data, const QByteArray &responseData)
{
Q_ASSERT(data);
if (responseData.isEmpty())
return false;
QJsonDocument doc = QJsonDocument::fromJson(responseData);
QJsonArray items = doc.object()["items"].toArray();
for (QJsonValueRef item : items) {
data->deletedSubjects.append(item.toString());
}
return true;
}
void ColnodAPI::newData()
{
mData = std::make_shared<Data>();
}
bool ColnodAPI::checkResponse(const QByteArray &responseData)
{
QJsonDocument doc = QJsonDocument::fromJson(responseData);
return doc.object().contains("items");
}