colnod-connector/src/colnod/colnodapi.cpp
2019-12-09 15:34:29 +01:00

368 lines
13 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
*/
bool ColnodAPI::downloadData(const qint64 &time)
{
// Have to get Login
auto login = requestLogin();
Q_ASSERT(login);
if (login->networkReply() == nullptr) {
qCCritical(colnod) << "Not possible to create login request";
return false;
}
connect(login.get(), &serversdk::Request::finished, this, [=](){
// Get login token
if (login->status() != 200) {
emit downloadDataFinished(nullptr);
return false;
}
AuthToken token;
if (checkResponse(login->responseData())) {
qCWarning(colnod) << "empty response data when logging in";
emit downloadDataFinished(nullptr);
return false;
}
token.fromJson(login->responseData());
authToken = token.id();
if (authToken.isEmpty()) {
qCCritical(colnod) << "Token uuid is empty";
emit downloadDataFinished(nullptr);
return false;
}
auto data = std::make_shared<Data>();
Timestamp timestamp;
timestamp.setTimestamp(time);
auto checkData = [=]() {
int dataCount = data->incrementCounter();
if ( dataCount > 5) {
qCCritical(colnod) << "check data cannnot be higher then 4";
}
Q_ASSERT(dataCount < 5);
if (dataCount == 4) {
qInfo(colnod) << tab << "- src col:" << tab << "tokens [" << data->updatedTokens.size() << ":" << data->deletedTokens.size() <<
"] subjects [" << data->updatedSubjects.size() << ":" << data->deletedSubjects.size() << "] [ added/updated : deleted ]";
if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty() ||
!data->updatedSubjects.isEmpty() || !data->deletedSubjects.isEmpty()) {
qInfo(colnod) << dash;
}
for (auto token : data->updatedTokens) {
qInfo(colnod) << Message::massageTemplate("Download updated", "token", "colnod", token->name());
}
for (auto id : data->deletedTokens) {
qInfo(colnod) << Message::massageTemplate("Download deleted", "token", "colnod", id);
}
for (auto subject : data->updatedSubjects) {
qInfo(colnod) << Message::massageTemplate("Download updated", "subject", "colnod", subject->name());
}
for (auto id : data->deletedSubjects) {
qInfo(colnod) << Message::massageTemplate("Download deleted", "token", "colnod", id);
}
if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty() ||
!data->updatedSubjects.isEmpty() || !data->deletedSubjects.isEmpty()) {
qInfo(colnod) << dash;
}
emit downloadDataFinished(data);
}
};
auto tokensRequest = getTokensUpdated(timestamp);
connect(tokensRequest.get(), &serversdk::Request::finished, [=](){
if (!saveUpdatedTokens(data, tokensRequest->responseData())) {
emit downloadDataFinished(nullptr);
return;
}
checkData();
});
auto deletedTokensRequest = getTokensDeleted(timestamp);
connect(deletedTokensRequest.get(), &serversdk::Request::finished, [=](){
if (!saveDeletedTokens(data, deletedTokensRequest->responseData())) {
emit downloadDataFinished(nullptr);
return;
}
checkData();
});
auto subjectsRequest = getSubjectsUpdated(timestamp);
connect(subjectsRequest.get(), &serversdk::Request::finished, [=](){
if (!saveUpdatedSubjects(data, subjectsRequest->responseData())) {
emit downloadDataFinished(nullptr);
return;
}
checkData();
});
auto deletedSubjectsRequest = getSubjectsDeleted(timestamp);
connect(deletedSubjectsRequest.get(), &serversdk::Request::finished, [=](){
if (!saveDeletedSubjects(data, deletedSubjectsRequest->responseData())) {
emit downloadDataFinished(nullptr);
return;
}
checkData();
});
return true;
});
return true;
}
void ColnodAPI::processData(const std::shared_ptr<Data> &data)
{
qInfo(colnod) << tab << "- push col:" << tab << "tokens [" << data->updatedTokens.size() << ":" << data->deletedTokens.size() <<
"] [ added/updated : deleted ]";
connect(this, &ColnodAPI::partOfDataProcessFinished, this, &ColnodAPI::isDataProcessFinished);
if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty()) {
qInfo(colnod) << dash;
}
if ( !data->updatedTokens.isEmpty() && !mDryMode) {
setTokens(data->updatedTokens);
} else {
emit partOfDataProcessFinished();
}
if ( !data->deletedTokens.isEmpty() && !mDryMode) {
deleteTokens(data->deletedTokens);
} else {
emit partOfDataProcessFinished();
}
if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty()) {
qInfo(colnod) << dash;
}
}
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";
}
if (checkResponse(request->responseData())) {
for (const auto &token : tokens) {
qInfo(colnod).noquote() << Message::massageTemplate("Updated", "token", "colnod", token->name());
}
emit partOfDataProcessFinished();
}
else {
qWarning(colnod) << "Tokens wasn't updated";
mValid = false;
emit partOfDataProcessFinished(false);
}
});
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";
}
if (checkResponse(request->responseData())) {
for (const auto &id : ids) {
qInfo(colnod).noquote() << Message::massageTemplate("Deleted", "token", "colnod", id);
}
emit partOfDataProcessFinished();
}
else {
qWarning(colnod) << "Tokens wasn't deleted";
mValid = false;
emit partOfDataProcessFinished(false);
}
});
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;
}
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) {
// new
qInfo(colnod) << "- src colnod: tokens [" << data->updatedTokens.size() << ":" << data->deletedTokens.size() <<
"] subjects [" << data->updatedSubjects.size() << ":" << data->deletedSubjects.size() << "] [ added/updated : deleted ]";
//OLD
// 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(bool success)
{
if (!success) {
mSuccess = false;
}
if (++amountProccessesFinished == 2) {
emit dataProcessFinished(mSuccess);
}
}
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;
}
bool ColnodAPI::checkResponse(const QByteArray &responseData)
{
QJsonDocument doc = QJsonDocument::fromJson(responseData);
return doc.object().contains("items");
}