]> Git Repo - VerusCoin.git/blob - src/asyncrpcoperation.cpp
Merge commit '51e448641d6cbcd582afa22cd8475f8c3086dad7' as 'src/snark'
[VerusCoin.git] / src / asyncrpcoperation.cpp
1 // Copyright (c) 2016 The Zcash developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "asyncrpcoperation.h"
6
7 #include <boost/uuid/uuid.hpp>
8 #include <boost/uuid/uuid_generators.hpp>
9 #include <boost/uuid/uuid_io.hpp>
10
11 #include <string>
12 #include <ctime>
13 #include <chrono>
14
15 using namespace std;
16
17 static boost::uuids::random_generator uuidgen;
18
19 std::map<OperationStatus, std::string> OperationStatusMap = {
20     {OperationStatus::READY, "queued"},
21     {OperationStatus::EXECUTING, "executing"},
22     {OperationStatus::CANCELLED, "cancelled"},
23     {OperationStatus::FAILED, "failed"},
24     {OperationStatus::SUCCESS, "success"}
25 };
26
27 /**
28  * Every operation instance should have a globally unique id
29  */
30 AsyncRPCOperation::AsyncRPCOperation() : error_code_(0), error_message_() {
31     // Set a unique reference for each operation
32     boost::uuids::uuid uuid = uuidgen();
33     id_ = "opid-" + boost::uuids::to_string(uuid);
34     creation_time_ = (int64_t)time(NULL);
35     set_state(OperationStatus::READY);
36 }
37
38 AsyncRPCOperation::AsyncRPCOperation(const AsyncRPCOperation& o) :
39         id_(o.id_), creation_time_(o.creation_time_), state_(o.state_.load()),
40         start_time_(o.start_time_), end_time_(o.end_time_),
41         error_code_(o.error_code_), error_message_(o.error_message_),
42         result_(o.result_)
43 {
44 }
45
46 AsyncRPCOperation& AsyncRPCOperation::operator=( const AsyncRPCOperation& other ) {
47     this->id_ = other.id_;
48     this->creation_time_ = other.creation_time_;
49     this->state_.store(other.state_.load());
50     this->start_time_ = other.start_time_;
51     this->end_time_ = other.end_time_;
52     this->error_code_ = other.error_code_;
53     this->error_message_ = other.error_message_;
54     this->result_ = other.result_;
55     return *this;
56 }
57
58
59 AsyncRPCOperation::~AsyncRPCOperation() {
60 }
61
62 /**
63  * Override this cancel() method if you can interrupt main() when executing.
64  */
65 void AsyncRPCOperation::cancel() {
66     if (isReady()) {
67         set_state(OperationStatus::CANCELLED);
68     }
69 }
70
71 /**
72  * Start timing the execution run of the code you're interested in
73  */
74 void AsyncRPCOperation::start_execution_clock() {
75     std::lock_guard<std::mutex> guard(lock_);
76     start_time_ = std::chrono::system_clock::now();
77 }
78
79 /**
80  * Stop timing the execution run
81  */
82 void AsyncRPCOperation::stop_execution_clock() {
83     std::lock_guard<std::mutex> guard(lock_);
84     end_time_ = std::chrono::system_clock::now();
85 }
86
87 /**
88  * Implement this virtual method in any subclass.  This is just an example implementation.
89  */
90 void AsyncRPCOperation::main() {
91     if (isCancelled()) {
92         return;
93     }
94     
95     set_state(OperationStatus::EXECUTING);
96
97     start_execution_clock();
98
99     // Do some work here..
100
101     stop_execution_clock();
102
103     // If there was an error, you might set it like this:
104     /*
105     setErrorCode(123);
106     setErrorMessage("Murphy's law");
107     setState(OperationStatus::FAILED);
108     */
109
110     // Otherwise, if the operation was a success:
111     UniValue v(UniValue::VSTR, "We have a result!");
112     set_result(v);
113     set_state(OperationStatus::SUCCESS);
114 }
115
116 /**
117  * Return the error of the completed operation as a UniValue object.
118  * If there is no error, return null UniValue.
119  */
120 UniValue AsyncRPCOperation::getError() const {
121     if (!isFailed()) {
122         return NullUniValue;
123     }
124
125     std::lock_guard<std::mutex> guard(lock_);
126     UniValue error(UniValue::VOBJ);
127     error.push_back(Pair("code", this->error_code_));
128     error.push_back(Pair("message", this->error_message_));
129     return error;
130 }
131
132 /**
133  * Return the result of the completed operation as a UniValue object.
134  * If the operation did not succeed, return null UniValue.
135  */
136 UniValue AsyncRPCOperation::getResult() const {
137     if (!isSuccess()) {
138         return NullUniValue;
139     }
140
141     std::lock_guard<std::mutex> guard(lock_);
142     return this->result_;
143 }
144
145
146 /**
147  * Returns a status UniValue object.
148  * If the operation has failed, it will include an error object.
149  * If the operation has succeeded, it will include the result value.
150  * If the operation was cancelled, there will be no error object or result value.
151  */
152 UniValue AsyncRPCOperation::getStatus() const {
153     OperationStatus status = this->getState();
154     UniValue obj(UniValue::VOBJ);
155     obj.push_back(Pair("id", this->id_));
156     obj.push_back(Pair("status", OperationStatusMap[status]));
157     obj.push_back(Pair("creation_time", this->creation_time_));
158     // TODO: Issue #1354: There may be other useful metadata to return to the user.
159     UniValue err = this->getError();
160     if (!err.isNull()) {
161         obj.push_back(Pair("error", err.get_obj()));
162     }
163     UniValue result = this->getResult();
164     if (!result.isNull()) {
165         obj.push_back(Pair("result", result));
166
167         // Include execution time for successful operation
168         std::chrono::duration<double> elapsed_seconds = end_time_ - start_time_;
169         obj.push_back(Pair("execution_secs", elapsed_seconds.count()));
170
171     }
172     return obj;
173 }
174
175 /**
176  * Return the operation state in human readable form.
177  */
178 std::string AsyncRPCOperation::getStateAsString() const {
179     OperationStatus status = this->getState();
180     return OperationStatusMap[status];
181 }
This page took 0.032834 seconds and 4 git commands to generate.