diff options
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | database.cpp | 91 | ||||
| -rw-r--r-- | database.h | 40 | ||||
| -rw-r--r-- | server_main.cpp | 94 | ||||
| m--------- | vendor/stduuid | 0 |
6 files changed, 16 insertions, 215 deletions
| diff --git a/.gitmodules b/.gitmodules index de49c9f..2f929e3 100644 --- a/.gitmodules +++ b/.gitmodules | |||
| @@ -10,6 +10,3 @@ | |||
| 10 | [submodule "vendor/base64"] | 10 | [submodule "vendor/base64"] |
| 11 | path = vendor/base64 | 11 | path = vendor/base64 |
| 12 | url = https://github.com/tobiaslocker/base64 | 12 | url = https://github.com/tobiaslocker/base64 |
| 13 | [submodule "vendor/stduuid"] | ||
| 14 | path = vendor/stduuid | ||
| 15 | url = https://github.com/mariusbancila/stduuid | ||
| diff --git a/CMakeLists.txt b/CMakeLists.txt index b1a7b38..82e9d64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -16,7 +16,6 @@ include_directories( | |||
| 16 | vendor/hkutil | 16 | vendor/hkutil |
| 17 | vendor/asio/asio/include | 17 | vendor/asio/asio/include |
| 18 | vendor/base64/include | 18 | vendor/base64/include |
| 19 | vendor/stduuid | ||
| 20 | ${tesseract_INCLUDE_DIRS} | 19 | ${tesseract_INCLUDE_DIRS} |
| 21 | ${lept_INCLUDE_DIRS} | 20 | ${lept_INCLUDE_DIRS} |
| 22 | ${GraphicsMagick_INCLUDE_DIRS} | 21 | ${GraphicsMagick_INCLUDE_DIRS} |
| @@ -52,7 +51,7 @@ target_link_libraries( | |||
| 52 | wizard | 51 | wizard |
| 53 | ) | 52 | ) |
| 54 | 53 | ||
| 55 | add_executable(wizard_server database.cpp server_main.cpp) | 54 | add_executable(wizard_server server_main.cpp) |
| 56 | set_property(TARGET wizard_server PROPERTY CXX_STANDARD 17) | 55 | set_property(TARGET wizard_server PROPERTY CXX_STANDARD 17) |
| 57 | set_property(TARGET wizard_server PROPERTY CXX_STANDARD_REQUIRED ON) | 56 | set_property(TARGET wizard_server PROPERTY CXX_STANDARD_REQUIRED ON) |
| 58 | target_link_libraries( | 57 | target_link_libraries( |
| diff --git a/database.cpp b/database.cpp deleted file mode 100644 index 037579b..0000000 --- a/database.cpp +++ /dev/null | |||
| @@ -1,91 +0,0 @@ | |||
| 1 | #include "database.h" | ||
| 2 | |||
| 3 | #include <include/uuid.h> | ||
| 4 | |||
| 5 | #include <stdexcept> | ||
| 6 | |||
| 7 | std::string database::create(std::mt19937& rng) { | ||
| 8 | std::lock_guard state_guard(mutex_); | ||
| 9 | |||
| 10 | std::string token = uuids::to_string(uuids::uuid_random_generator{rng}()); | ||
| 11 | requests_[token] = request{}; | ||
| 12 | |||
| 13 | return token; | ||
| 14 | } | ||
| 15 | |||
| 16 | void database::subscribe(const std::string& token, | ||
| 17 | subscribe_callback_type callback) { | ||
| 18 | std::lock_guard state_guard(mutex_); | ||
| 19 | |||
| 20 | if (!requests_.count(token)) { | ||
| 21 | throw std::invalid_argument("Could not find request."); | ||
| 22 | } | ||
| 23 | |||
| 24 | request& req = requests_[token]; | ||
| 25 | size_t nextId = req.subscribers.size(); | ||
| 26 | req.subscribers.push_back(callback); | ||
| 27 | } | ||
| 28 | |||
| 29 | void database::post(const std::string& token, const std::string& msg) { | ||
| 30 | std::lock_guard state_guard(mutex_); | ||
| 31 | |||
| 32 | if (!requests_.count(token)) { | ||
| 33 | throw std::invalid_argument("Could not find request."); | ||
| 34 | } | ||
| 35 | |||
| 36 | request& req = requests_.at(token); | ||
| 37 | |||
| 38 | for (std::optional<subscribe_callback_type>& callback : req.subscribers) { | ||
| 39 | if (callback) { | ||
| 40 | try { | ||
| 41 | (*callback)(msg); | ||
| 42 | } catch (const std::exception& ex) { | ||
| 43 | callback = std::nullopt; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | void database::setResult(const std::string& token, const std::string& result) { | ||
| 50 | std::lock_guard state_guard(mutex_); | ||
| 51 | |||
| 52 | if (!requests_.count(token)) { | ||
| 53 | throw std::invalid_argument("Could not find request."); | ||
| 54 | } | ||
| 55 | |||
| 56 | request& req = requests_[token]; | ||
| 57 | req.result = result; | ||
| 58 | } | ||
| 59 | |||
| 60 | const std::string& database::getResult(const std::string& token) { | ||
| 61 | std::lock_guard state_guard(mutex_); | ||
| 62 | |||
| 63 | if (!requests_.count(token)) { | ||
| 64 | throw std::invalid_argument("Could not find request."); | ||
| 65 | } | ||
| 66 | |||
| 67 | const request& req = requests_.at(token); | ||
| 68 | return req.result; | ||
| 69 | } | ||
| 70 | |||
| 71 | void database::mark_done(const std::string& token) { | ||
| 72 | std::lock_guard state_guard(mutex_); | ||
| 73 | |||
| 74 | if (!requests_.count(token)) { | ||
| 75 | throw std::invalid_argument("Could not find request."); | ||
| 76 | } | ||
| 77 | |||
| 78 | request& req = requests_[token]; | ||
| 79 | req.done = true; | ||
| 80 | } | ||
| 81 | |||
| 82 | bool database::is_done(const std::string& token) { | ||
| 83 | std::lock_guard state_guard(mutex_); | ||
| 84 | |||
| 85 | if (!requests_.count(token)) { | ||
| 86 | throw std::invalid_argument("Could not find request."); | ||
| 87 | } | ||
| 88 | |||
| 89 | const request& req = requests_.at(token); | ||
| 90 | return req.done; | ||
| 91 | } | ||
| diff --git a/database.h b/database.h deleted file mode 100644 index d8d9b67..0000000 --- a/database.h +++ /dev/null | |||
| @@ -1,40 +0,0 @@ | |||
| 1 | #ifndef DATABASE_H_0A27B356 | ||
| 2 | #define DATABASE_H_0A27B356 | ||
| 3 | |||
| 4 | #include <functional> | ||
| 5 | #include <map> | ||
| 6 | #include <mutex> | ||
| 7 | #include <optional> | ||
| 8 | #include <random> | ||
| 9 | #include <string> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | class database { | ||
| 13 | public: | ||
| 14 | // Feel free to throw an exception if the subscriber should be killed. | ||
| 15 | using subscribe_callback_type = std::function<void(const std::string&)>; | ||
| 16 | |||
| 17 | std::string create(std::mt19937& rng); | ||
| 18 | |||
| 19 | void subscribe(const std::string& token, subscribe_callback_type callback); | ||
| 20 | void post(const std::string& token, const std::string& msg); | ||
| 21 | |||
| 22 | void setResult(const std::string& token, const std::string& result); | ||
| 23 | const std::string& getResult(const std::string& token); | ||
| 24 | |||
| 25 | void mark_done(const std::string& token); | ||
| 26 | bool is_done(const std::string& token); | ||
| 27 | |||
| 28 | private: | ||
| 29 | struct request { | ||
| 30 | std::vector<std::optional<subscribe_callback_type>> subscribers; | ||
| 31 | std::string result; | ||
| 32 | bool done = false; | ||
| 33 | }; | ||
| 34 | |||
| 35 | std::mutex mutex_; | ||
| 36 | |||
| 37 | std::map<std::string, request> requests_; | ||
| 38 | }; | ||
| 39 | |||
| 40 | #endif /* end of include guard: DATABASE_H_0A27B356 */ | ||
| diff --git a/server_main.cpp b/server_main.cpp index 145f8a2..00a4e7a 100644 --- a/server_main.cpp +++ b/server_main.cpp | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include <websocketpp/server.hpp> | 12 | #include <websocketpp/server.hpp> |
| 13 | 13 | ||
| 14 | #include "cardset.h" | 14 | #include "cardset.h" |
| 15 | #include "database.h" | ||
| 16 | #include "imagestore.h" | 15 | #include "imagestore.h" |
| 17 | #include "wizard.h" | 16 | #include "wizard.h" |
| 18 | 17 | ||
| @@ -67,8 +66,6 @@ class server { | |||
| 67 | std::string cmd = msgJson["cmd"]; | 66 | std::string cmd = msgJson["cmd"]; |
| 68 | if (cmd == "generate") { | 67 | if (cmd == "generate") { |
| 69 | cmd_generate(connection, msgJson["text"]); | 68 | cmd_generate(connection, msgJson["text"]); |
| 70 | } else if (cmd == "check") { | ||
| 71 | cmd_check(connection, msgJson["token"]); | ||
| 72 | } else { | 69 | } else { |
| 73 | std::string response = R"( | 70 | std::string response = R"( |
| 74 | { | 71 | { |
| @@ -84,71 +81,11 @@ class server { | |||
| 84 | } | 81 | } |
| 85 | 82 | ||
| 86 | void cmd_generate(websocketpp::connection_hdl connection, std::string text) { | 83 | void cmd_generate(websocketpp::connection_hdl connection, std::string text) { |
| 87 | std::string token; | 84 | asio::post(std::bind(&server::generate_thread, this, connection, text)); |
| 88 | |||
| 89 | { | ||
| 90 | std::lock_guard rng_guard(rng_mutex_); | ||
| 91 | token = database_.create(rng_); | ||
| 92 | } | ||
| 93 | |||
| 94 | nlohmann::json tokenMsg; | ||
| 95 | tokenMsg["type"] = "token"; | ||
| 96 | tokenMsg["token"] = token; | ||
| 97 | socket_.send(connection, tokenMsg.dump(), | ||
| 98 | websocketpp::frame::opcode::value::TEXT); | ||
| 99 | |||
| 100 | database_.subscribe(token, [this, connection](const std::string& msg) { | ||
| 101 | socket_.send(connection, msg, websocketpp::frame::opcode::value::TEXT); | ||
| 102 | }); | ||
| 103 | |||
| 104 | asio::post(std::bind(&server::generate_thread, this, token, text)); | ||
| 105 | } | 85 | } |
| 106 | 86 | ||
| 107 | void cmd_check(websocketpp::connection_hdl connection, std::string token) { | 87 | void generate_thread(websocketpp::connection_hdl connection, |
| 108 | bool failed = false; | 88 | std::string text) { |
| 109 | |||
| 110 | try { | ||
| 111 | database_.subscribe(token, [this, connection](const std::string& msg) { | ||
| 112 | socket_.send(connection, msg, websocketpp::frame::opcode::value::TEXT); | ||
| 113 | }); | ||
| 114 | |||
| 115 | if (!database_.is_done(token)) { | ||
| 116 | return; | ||
| 117 | } | ||
| 118 | |||
| 119 | std::string result = database_.getResult(token); | ||
| 120 | nlohmann::json resultMsg; | ||
| 121 | if (result.empty()) { | ||
| 122 | resultMsg["type"] = "error"; | ||
| 123 | resultMsg["msg"] = "Unknown error occurred."; | ||
| 124 | } else { | ||
| 125 | resultMsg["type"] = "result"; | ||
| 126 | resultMsg["image"] = database_.getResult(token); | ||
| 127 | resultMsg["msg"] = "Success!"; | ||
| 128 | } | ||
| 129 | |||
| 130 | socket_.send(connection, resultMsg.dump(), | ||
| 131 | websocketpp::frame::opcode::value::TEXT); | ||
| 132 | } catch (const std::exception& ex) { | ||
| 133 | failed = true; | ||
| 134 | } | ||
| 135 | |||
| 136 | if (failed) { | ||
| 137 | try { | ||
| 138 | socket_.send(connection, R"( | ||
| 139 | { | ||
| 140 | "type": "error", | ||
| 141 | "msg": "Error retrieving request." | ||
| 142 | })", | ||
| 143 | websocketpp::frame::opcode::value::TEXT); | ||
| 144 | } catch (const std::exception& ex) { | ||
| 145 | // Well, okay | ||
| 146 | std::cout << ex.what() << std::endl; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | void generate_thread(std::string token, std::string text) { | ||
| 152 | std::unique_ptr<wizard> generator; | 89 | std::unique_ptr<wizard> generator; |
| 153 | 90 | ||
| 154 | { | 91 | { |
| @@ -157,13 +94,15 @@ class server { | |||
| 157 | } | 94 | } |
| 158 | 95 | ||
| 159 | try { | 96 | try { |
| 160 | generator->set_status_callback([this, token](const std::string& status) { | 97 | generator->set_status_callback( |
| 161 | nlohmann::json msg; | 98 | [this, connection](const std::string& status) { |
| 162 | msg["type"] = "status"; | 99 | nlohmann::json msg; |
| 163 | msg["msg"] = status; | 100 | msg["type"] = "status"; |
| 101 | msg["msg"] = status; | ||
| 164 | 102 | ||
| 165 | database_.post(token, msg.dump()); | 103 | socket_.send(connection, msg.dump(), |
| 166 | }); | 104 | websocketpp::frame::opcode::value::TEXT); |
| 105 | }); | ||
| 167 | 106 | ||
| 168 | Magick::Image resultImage = generator->run(); | 107 | Magick::Image resultImage = generator->run(); |
| 169 | Magick::Blob resultBlob; | 108 | Magick::Blob resultBlob; |
| @@ -173,24 +112,22 @@ class server { | |||
| 173 | resultBlob.length()); | 112 | resultBlob.length()); |
| 174 | std::string resultEncoded = base64::to_base64(resultBytes); | 113 | std::string resultEncoded = base64::to_base64(resultBytes); |
| 175 | 114 | ||
| 176 | database_.setResult(token, resultEncoded); | ||
| 177 | |||
| 178 | nlohmann::json resultMsg; | 115 | nlohmann::json resultMsg; |
| 179 | resultMsg["type"] = "result"; | 116 | resultMsg["type"] = "result"; |
| 180 | resultMsg["image"] = resultEncoded; | 117 | resultMsg["image"] = resultEncoded; |
| 181 | resultMsg["msg"] = "Success!"; | 118 | resultMsg["msg"] = "Success!"; |
| 182 | 119 | ||
| 183 | database_.post(token, resultMsg.dump()); | 120 | socket_.send(connection, resultMsg.dump(), |
| 121 | websocketpp::frame::opcode::value::TEXT); | ||
| 184 | } catch (const std::exception& ex) { | 122 | } catch (const std::exception& ex) { |
| 185 | nlohmann::json response; | 123 | nlohmann::json response; |
| 186 | response["type"] = "error"; | 124 | response["type"] = "error"; |
| 187 | response["msg"] = | 125 | response["msg"] = |
| 188 | std::string("Error generating card (") + ex.what() + ")"; | 126 | std::string("Error generating card (") + ex.what() + ")"; |
| 189 | 127 | ||
| 190 | database_.post(token, response.dump()); | 128 | socket_.send(connection, response.dump(), |
| 129 | websocketpp::frame::opcode::value::TEXT); | ||
| 191 | } | 130 | } |
| 192 | |||
| 193 | database_.mark_done(token); | ||
| 194 | } | 131 | } |
| 195 | 132 | ||
| 196 | void cleanup_thread() { | 133 | void cleanup_thread() { |
| @@ -207,7 +144,6 @@ class server { | |||
| 207 | std::mt19937& rng_; | 144 | std::mt19937& rng_; |
| 208 | 145 | ||
| 209 | socket_type socket_; | 146 | socket_type socket_; |
| 210 | database database_; | ||
| 211 | }; | 147 | }; |
| 212 | 148 | ||
| 213 | } // namespace | 149 | } // namespace |
| diff --git a/vendor/stduuid b/vendor/stduuid deleted file mode 160000 | |||
| Subproject 3afe7193facd5d674de709fccc44d5055e144d7 | |||
