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