]>
Commit | Line | Data |
---|---|---|
fc72c078 S |
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 | ||
6 | #ifndef ASYNCRPCOPERATION_H | |
7 | #define ASYNCRPCOPERATION_H | |
8 | ||
9 | #include <string> | |
10 | #include <atomic> | |
11 | #include <map> | |
12 | #include <chrono> | |
e2574666 S |
13 | #include <memory> |
14 | #include <thread> | |
15 | #include <utility> | |
16 | #include <future> | |
fc72c078 | 17 | |
2cc6bab2 | 18 | #include <univalue.h> |
fc72c078 S |
19 | |
20 | using namespace std; | |
fc72c078 S |
21 | |
22 | /** | |
3b54bf58 | 23 | * AsyncRPCOperation objects are submitted to the AsyncRPCQueue for processing. |
fc72c078 | 24 | * |
3b54bf58 | 25 | * To subclass AsyncRPCOperation, implement the main() method. |
fc72c078 | 26 | * Update the operation status as work is underway and completes. |
3b54bf58 | 27 | * If main() can be interrupted, inmplement the cancel() method. |
fc72c078 S |
28 | */ |
29 | ||
30 | typedef std::string AsyncRPCOperationId; | |
31 | ||
32 | typedef enum class operationStateEnum { | |
33 | READY = 0, | |
34 | EXECUTING, | |
35 | CANCELLED, | |
36 | FAILED, | |
37 | SUCCESS | |
38 | } OperationStatus; | |
39 | ||
40 | class AsyncRPCOperation { | |
41 | public: | |
42 | AsyncRPCOperation(); | |
fc72c078 S |
43 | virtual ~AsyncRPCOperation(); |
44 | ||
3b54bf58 | 45 | // You must implement this method in your subclass. |
fc72c078 S |
46 | virtual void main(); |
47 | ||
3b54bf58 | 48 | // Override this method if you can interrupt execution of main() in your subclass. |
fc72c078 S |
49 | void cancel(); |
50 | ||
51 | // Getters and setters | |
52 | ||
53 | OperationStatus getState() const { | |
3b54bf58 | 54 | return state_.load(); |
fc72c078 S |
55 | } |
56 | ||
57 | AsyncRPCOperationId getId() const { | |
3b54bf58 | 58 | return id_; |
fc72c078 S |
59 | } |
60 | ||
61 | int64_t getCreationTime() const { | |
3b54bf58 | 62 | return creation_time_; |
fc72c078 S |
63 | } |
64 | ||
8aa7937d | 65 | // Override this method to add data to the default status object. |
0d37ae3a | 66 | virtual UniValue getStatus() const; |
fc72c078 | 67 | |
0d37ae3a | 68 | UniValue getError() const; |
fc72c078 | 69 | |
0d37ae3a | 70 | UniValue getResult() const; |
c72a4272 S |
71 | |
72 | std::string getStateAsString() const; | |
fc72c078 S |
73 | |
74 | int getErrorCode() const { | |
e2574666 | 75 | std::lock_guard<std::mutex> guard(lock_); |
3b54bf58 | 76 | return error_code_; |
fc72c078 S |
77 | } |
78 | ||
79 | std::string getErrorMessage() const { | |
e2574666 | 80 | std::lock_guard<std::mutex> guard(lock_); |
3b54bf58 | 81 | return error_message_; |
fc72c078 S |
82 | } |
83 | ||
84 | bool isCancelled() const { | |
61ea2aba | 85 | return OperationStatus::CANCELLED == getState(); |
fc72c078 S |
86 | } |
87 | ||
88 | bool isExecuting() const { | |
61ea2aba | 89 | return OperationStatus::EXECUTING == getState(); |
fc72c078 S |
90 | } |
91 | ||
92 | bool isReady() const { | |
61ea2aba | 93 | return OperationStatus::READY == getState(); |
fc72c078 S |
94 | } |
95 | ||
96 | bool isFailed() const { | |
61ea2aba | 97 | return OperationStatus::FAILED == getState(); |
fc72c078 S |
98 | } |
99 | ||
100 | bool isSuccess() const { | |
61ea2aba | 101 | return OperationStatus::SUCCESS == getState(); |
fc72c078 S |
102 | } |
103 | ||
104 | protected: | |
61ea2aba S |
105 | // The state_ is atomic because only it can be mutated externally. |
106 | // For example, the user initiates a shut down of the application, which closes | |
107 | // the AsyncRPCQueue, which in turn invokes cancel() on all operations. | |
108 | // The member variables below are protected rather than private in order to | |
109 | // allow subclasses of AsyncRPCOperation the ability to access and update | |
110 | // internal state. Currently, all operations are executed in a single-thread | |
111 | // by a single worker. | |
e2574666 | 112 | mutable std::mutex lock_; // lock on this when read/writing non-atomics |
0d37ae3a | 113 | UniValue result_; |
3b54bf58 S |
114 | int error_code_; |
115 | std::string error_message_; | |
116 | std::atomic<OperationStatus> state_; | |
117 | std::chrono::time_point<std::chrono::system_clock> start_time_, end_time_; | |
fc72c078 | 118 | |
3b54bf58 S |
119 | void start_execution_clock(); |
120 | void stop_execution_clock(); | |
fc72c078 | 121 | |
3b54bf58 S |
122 | void set_state(OperationStatus state) { |
123 | this->state_.store(state); | |
fc72c078 S |
124 | } |
125 | ||
3b54bf58 | 126 | void set_error_code(int errorCode) { |
e2574666 | 127 | std::lock_guard<std::mutex> guard(lock_); |
3b54bf58 | 128 | this->error_code_ = errorCode; |
fc72c078 S |
129 | } |
130 | ||
3b54bf58 | 131 | void set_error_message(std::string errorMessage) { |
e2574666 | 132 | std::lock_guard<std::mutex> guard(lock_); |
3b54bf58 | 133 | this->error_message_ = errorMessage; |
fc72c078 S |
134 | } |
135 | ||
0d37ae3a | 136 | void set_result(UniValue v) { |
e2574666 | 137 | std::lock_guard<std::mutex> guard(lock_); |
3b54bf58 | 138 | this->result_ = v; |
fc72c078 S |
139 | } |
140 | ||
141 | private: | |
3b54bf58 S |
142 | |
143 | // Derived classes should write their own copy constructor and assignment operators | |
144 | AsyncRPCOperation(const AsyncRPCOperation& orig); | |
145 | AsyncRPCOperation& operator=( const AsyncRPCOperation& other ); | |
fc72c078 | 146 | |
e2574666 | 147 | // Initialized in the operation constructor, never to be modified again. |
3b54bf58 S |
148 | AsyncRPCOperationId id_; |
149 | int64_t creation_time_; | |
fc72c078 S |
150 | }; |
151 | ||
152 | #endif /* ASYNCRPCOPERATION_H */ | |
153 |