diff --git a/src/cpp/lib/NotificationList.h b/src/cpp/lib/NotificationList.h index a3b2edcf1..e343218bb 100644 --- a/src/cpp/lib/NotificationList.h +++ b/src/cpp/lib/NotificationList.h @@ -45,6 +45,7 @@ public: void printErrors(); std::string getErrorsHtml(); std::string getErrorsHtmlNewFormat(); + std::vector getErrorsArray(); void sendErrorsAsEmail(std::string rawHtml = ""); diff --git a/src/cpp/model/gradido/Transaction.cpp b/src/cpp/model/gradido/Transaction.cpp index 5fb937688..0bbaf0ec1 100644 --- a/src/cpp/model/gradido/Transaction.cpp +++ b/src/cpp/model/gradido/Transaction.cpp @@ -10,8 +10,10 @@ #include "../../controller/HederaRequest.h" #include "../lib/DataTypeConverter.h" +#include "../lib/Profiler.h" #include "../hedera/Transaction.h" +#include "../hedera/TransactionId.h" #include "../../tasks/HederaTask.h" @@ -413,7 +415,8 @@ namespace model { transaction->sign(user); // dirty hack because gn crashes if its get transactions out of order mPairedTransaction = transaction; - Poco::Thread::sleep(1000); + // removed because now using only one hedera node + //Poco::Thread::sleep(1000); } else { addError(new Error(function_name, "Error creating outbound transaction")); @@ -533,11 +536,11 @@ namespace model { || TRANSACTION_VALID_MISSING_PARAM == result || TRANSCATION_VALID_INVALID_PUBKEY == result || TRANSACTION_VALID_INVALID_SIGN == result) { addError(new ParamError(function_name, "code error", TransactionValidationToString(result))); - sendErrorsAsEmail(); + //sendErrorsAsEmail(); } else if (mTransactionBody->isGroupMemberUpdate()) { addError(new ParamError(function_name, "validation return: ", TransactionValidationToString(result))); - sendErrorsAsEmail(); + //sendErrorsAsEmail(); } else { @@ -572,7 +575,7 @@ namespace model { error_name = t->gettext_str("Unknown Error"); error_description = t->gettext_str("Admin gets an E-Mail"); addError(new ParamError(function_name, "unknown error", TransactionValidationToString(result))); - sendErrorsAsEmail(); + //sendErrorsAsEmail(); } auto pt = PendingTasksManager::getInstance(); @@ -642,7 +645,7 @@ namespace model { consensus_submit_message.setMessage(json_message); } else { - sendErrorsAsEmail(); + //sendErrorsAsEmail(); return -7; } @@ -657,6 +660,7 @@ namespace model { auto hedera_transaction_body = hedera_operator_account->createTransactionBody(); hedera_transaction_body->setConsensusSubmitMessage(consensus_submit_message); model::hedera::Transaction hedera_transaction; + hedera_transaction.sign(crypto_key->getKeyPair(), std::move(hedera_transaction_body)); HederaRequest hedera_request; @@ -666,7 +670,7 @@ namespace model { { addError(new Error(function_name, "error send transaction to hedera")); getErrors(&hedera_request); - sendErrorsAsEmail(); + //sendErrorsAsEmail(); return -2; } else { @@ -686,10 +690,19 @@ namespace model { // simply assume if transaction was sended to hedera without error, it was also accepted from gradido node // TODO: later check, but now I haven't any way to communicate with the gradido node mTransactionBody->getTransactionBase()->transactionAccepted(getUser()); + auto transaction_model = getModel(); + transaction_model->setFinished(Poco::DateTime()); + Poco::JSON::Object::Ptr result = new Poco::JSON::Object; + model::hedera::TransactionId transaction_id(hedera_task->getTransactionId()); + result->set("state", "success"); + result->set("transactionId", transaction_id.convertToJSON()); + + transaction_model->setResultJson(result); + Profiler timer; + transaction_model->updateFinishedAndResult(); + printf("time for update 2 fields in db: %s\n", timer.string().data()); + // trigger community server update in 5 seconds - Poco::DateTime now; - std::string now_string = Poco::DateTimeFormatter::format(now, "%f.%m.%Y %H:%M:%S"); - //printf("[%s] trigger community server update in 5 second, now: %s\n", function_name, now_string.data()); CronManager::getInstance()->scheduleUpdateRun(Poco::Timespan(5, 0)); return 1; } @@ -700,7 +713,7 @@ namespace model { else { addError(new ParamError(function_name, "hedera crypto key not found for paying for consensus submit message! NetworkType: ", network_type)); - sendErrorsAsEmail(); + //sendErrorsAsEmail(); return -3; } } @@ -709,7 +722,7 @@ namespace model { addError(new Error(function_name, "hedera topic id or operator account not found!")); addError(new ParamError(function_name, "topic id: ", topic_id->getModel()->toString())); addError(new ParamError(function_name, "network type: ", network_type)); - sendErrorsAsEmail(); + //sendErrorsAsEmail(); return -4; } return 0; @@ -795,11 +808,17 @@ namespace model { //printf("[SendTransactionTask::run] result: %d\n", result); // delete because of error if (-1 == result) { - mTransaction->deleteFromDB(); + //mTransaction->deleteFromDB(); + Poco::JSON::Object::Ptr errors = new Poco::JSON::Object; + errors->set("errors", mTransaction->getErrorsArray()); + errors->set("state", "error"); + auto model = mTransaction->getModel(); + model->setResultJson(errors); + model->updateFinishedAndResult(); } // delete because succeed, maybe change later if (1 == result) { - mTransaction->deleteFromDB(); + //mTransaction->deleteFromDB(); } return 0; } diff --git a/src/cpp/model/hedera/TransactionId.cpp b/src/cpp/model/hedera/TransactionId.cpp new file mode 100644 index 000000000..df6606af1 --- /dev/null +++ b/src/cpp/model/hedera/TransactionId.cpp @@ -0,0 +1,47 @@ +#include "TransactionId.h" + +#include "../../lib/DataTypeConverter.h" + +namespace model { + namespace hedera { + TransactionId::TransactionId() + : shard(0), realm(0), num(0) + { + + } + + TransactionId::TransactionId(const proto::TransactionID& transaction) + { + auto account_id = transaction.accountid(); + shard = account_id.shardnum(); + realm = account_id.realmnum(); + num = account_id.accountnum(); + mTransactionValidStart = DataTypeConverter::convertFromProtoTimestamp(transaction.transactionvalidstart()); + + } + + TransactionId::TransactionId(int shard, int realm, int num, Poco::Timestamp transactionValidStart) + : shard(shard), realm(realm), num(num), mTransactionValidStart(transactionValidStart) + { + + } + + TransactionId::~TransactionId() + { + + } + + Poco::JSON::Object::Ptr TransactionId::convertToJSON() + { + Poco::JSON::Object::Ptr result = new Poco::JSON::Object; + result->set("transactionValidStart", mTransactionValidStart); + Poco::JSON::Object accountId; + accountId.set("shard", shard); + accountId.set("realm", realm); + accountId.set("num", num); + result->set("accountId", accountId); + return result; + } + + } +} \ No newline at end of file diff --git a/src/cpp/model/hedera/TransactionId.h b/src/cpp/model/hedera/TransactionId.h new file mode 100644 index 000000000..dcc877271 --- /dev/null +++ b/src/cpp/model/hedera/TransactionId.h @@ -0,0 +1,44 @@ +#ifndef _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_ID_H +#define _GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_ID_H + +/*! +* @author: Dario Rekowski +* +* @date: 02.09.20 +* +* @brief: class for composing hedera transaction +* +*/ + +#include "../../proto/hedera/BasicTypes.pb.h" + +#include "Poco/JSON/Object.h" + +namespace model { + namespace hedera { + class TransactionId + { + public: + TransactionId(); + TransactionId(const proto::TransactionID& transaction); + TransactionId(int shard, int realm, int num, Poco::Timestamp transactionValidStart); + ~TransactionId(); + + Poco::JSON::Object::Ptr convertToJSON(); + + protected: + Poco::Timestamp mTransactionValidStart; + union { + struct { + int shard; + int realm; + int num; + }; + int val[3]; + }; + }; + } +} + + +#endif //_GRADIDO_LOGIN_SERVER_MODEL_HEDERA_TRANSACTION_ID_H \ No newline at end of file diff --git a/src/cpp/model/table/PendingTask.cpp b/src/cpp/model/table/PendingTask.cpp index bce0bb7f6..72fe10a21 100644 --- a/src/cpp/model/table/PendingTask.cpp +++ b/src/cpp/model/table/PendingTask.cpp @@ -1,5 +1,6 @@ #include "PendingTask.h" +#include "Poco/JSON/Parser.h" //#include using namespace Poco::Data::Keywords; @@ -37,6 +38,36 @@ namespace model mRequest.assignRaw((const unsigned char*)serializedProto.data(), serializedProto.size()); } + void PendingTask::setResultJson(Poco::JSON::Object::Ptr result) + { + UNIQUE_LOCK; + std::stringstream ss; + result->stringify(ss); + mResultJsonString = ss.str(); + } + + Poco::JSON::Object::Ptr PendingTask::getResultJson() const + { + std::string temp; + { + SHARED_LOCK; + temp = mResultJsonString; + } + Poco::JSON::Parser parser; + Poco::Dynamic::Var result; + try + { + result = parser.parse(temp); + } + catch (Poco::JSON::JSONException& jsone) + { + return nullptr; + } + + return result.extract(); + + } + bool PendingTask::updateRequest() { Poco::ScopedLock _poco_lock(mWorkMutex); @@ -63,6 +94,34 @@ namespace model return 0; } + bool PendingTask::updateFinishedAndResult() + { + Poco::ScopedLock _poco_lock(mWorkMutex); + SHARED_LOCK; + if (!mID) { + return 0; + } + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + + Poco::Data::Statement update(session); + + update << "UPDATE " << getTableName() << " SET finished = ?, result_json = ? where id = ?;", + use(mFinished), use(mResultJsonString), use(mID); + + try { + return 1 == update.execute(); + } + catch (Poco::Exception& ex) { + addError(new ParamError(getTableName(), "[updateFinishedAndResult] mysql error by update", ex.displayText().data())); + addError(new ParamError(getTableName(), "data set: \n", toString().data())); + } + //printf("data valid: %s\n", toString().data()); + return 0; + } + + + std::string PendingTask::toString() { std::stringstream ss; diff --git a/src/cpp/model/table/PendingTask.h b/src/cpp/model/table/PendingTask.h index 8d94ad7dc..4fa84a73b 100644 --- a/src/cpp/model/table/PendingTask.h +++ b/src/cpp/model/table/PendingTask.h @@ -41,10 +41,13 @@ namespace model { //! \brief update table row with current request bool updateRequest(); + bool updateFinishedAndResult(); + inline int getUserId() const { SHARED_LOCK; return mUserId; } inline int getHederaId() const { SHARED_LOCK; return mHederaId; } inline const std::vector& getRequest() const { SHARED_LOCK; return mRequest.content(); } inline std::string getRequestCopy() const { SHARED_LOCK; return std::string((const char*)mRequest.content().data(), mRequest.content().size()); } + Poco::JSON::Object::Ptr getResultJson() const; inline Poco::DateTime getCreated() const { SHARED_LOCK; return mCreated; } inline TaskType getTaskType() const { SHARED_LOCK; return (TaskType)mTaskTypeId; } inline const char* getTaskTypeString() const { SHARED_LOCK; return typeToString((TaskType)mTaskTypeId); } @@ -54,6 +57,8 @@ namespace model { inline void setUserId(int userId) { UNIQUE_LOCK; mUserId = userId; } inline void setHederaId(int hederaId) { UNIQUE_LOCK; mHederaId = hederaId; } void setRequest(const std::string& serializedProto); + inline void setFinished(Poco::DateTime date) { UNIQUE_LOCK; mFinished = date; } + void setResultJson(Poco::JSON::Object::Ptr result); inline void setTaskType(TaskType type) { UNIQUE_LOCK; mTaskTypeId = type; } inline void setChildPendingTaskId(int childPendingTaskId) {UNIQUE_LOCK; mChildPendingTaskId = childPendingTaskId;} inline void setParentPendingTaskId(int parentPendingTaskId) { UNIQUE_LOCK; mParentPendingTaskId = parentPendingTaskId; }