#include #include #include #include #include #include #include #include #include #include #include struct Credentail { int cert_; }; struct Download { enum class ConnectionType { Telnet, Ssh }; std::string url_; Credentail credentail_; int maxMbps_; bool cache_; ConnectionType type_; }; struct Upload { enum class ConnectionType { Telnet, Ssh }; std::string url_; Credentail credentail_; int maxMbps_; int size_; ConnectionType type_; }; struct RemoveFromCache { std::string url_; }; struct ClearCache { }; struct Image { std::vector bitmap_; }; class Server { public: enum class ErrorCode { Ok, WrongUrl, CanNotConnect, WrongCredential, MaximumSizeExceeded, MissingImage, }; using CallbackType = void (*)(ErrorCode, Image); void handle(const Download& request, CallbackType callback) { if (const auto it = findImage(request.url_); it != std::cend(cache_)) { callback(ErrorCode::Ok, it->first); return; } Image img; const auto ec = download(request, img); if (ec == ErrorCode::Ok) { if (request.cache_) { cache_.emplace_back(img, request.url_); } } callback(ec, img); } void handle(const Upload& request, CallbackType callback) const { if (request.size_ > 100) { callback(ErrorCode::MaximumSizeExceeded, Image{}); return; } Image img; callback(upload(request, img), img); } void handle(const RemoveFromCache& request, CallbackType callback) { if (const auto it = findImage(request.url_); it != std::cend(cache_)) { cache_.erase(it); callback(ErrorCode::Ok, Image{}); return; } callback(ErrorCode::MissingImage, Image{}); } void handle(const ClearCache& request, CallbackType callback) { cache_.clear(); callback(ErrorCode::Ok, Image{}); } private: std::vector>::const_iterator findImage(const std::string& url) const { return std::find_if(cbegin(cache_), cend(cache_), [url](const auto& pair) { const auto& [image, this_url] = pair; return this_url == url; }); } ErrorCode download(const Download& request, Image& image) const { if (request.type_ == Download::ConnectionType::Ssh && request.credentail_.cert_ != 123) { return ErrorCode::WrongCredential; } if (request.type_ == Download::ConnectionType::Telnet && request.credentail_.cert_ != 231) { return ErrorCode::CanNotConnect; } // Simulate some other error if (request.maxMbps_ % 2) { return ErrorCode::WrongUrl; } image.bitmap_ = {97, 98, 99, 100, 101, 102}; return ErrorCode::Ok; } ErrorCode upload(const Upload& request, const Image& image) const { if (request.type_ == Upload::ConnectionType::Ssh && request.credentail_.cert_ != 1234) { return ErrorCode::WrongCredential; } if (request.type_ == Upload::ConnectionType::Telnet && request.credentail_.cert_ != 5432) { return ErrorCode::CanNotConnect; } // Simulate some other error if (!request.maxMbps_ % 2) { return ErrorCode::WrongUrl; } return ErrorCode::Ok; } std::vector> cache_; }; class RequestHandler { public: using RequestType = std::variant; void start(Server* server) { std::thread(&RequestHandler::run, this, server).detach(); } void stop() { stop_ = true; cv_.notify_one(); } void pushRequest(const RequestType& request, Server::CallbackType callback) { { std::lock_guard lock(m_); requests_.emplace(request, callback); } cv_.notify_one(); } private: using QueueType = std::pair; void run(Server* server) { while (!stop_) { const auto res = waitForRequest(); if (!res) { return; } const auto [request, callback] = *res; switch (request.index()) { case 0: server->handle(std::get(request), callback); break; case 1: server->handle(std::get(request), callback); break; case 2: server->handle(std::get(request), callback); break; case 3: server->handle(std::get(request), callback); break; } } } std::optional waitForRequest() { std::unique_lock lk(m_); cv_.wait(lk, [&]() { return !requests_.empty() || stop_; }); if (stop_) { return std::nullopt; } auto pair = requests_.front(); requests_.pop(); return pair; } std::mutex m_; std::condition_variable cv_; std::atomic stop_{false}; std::queue requests_; }; int main() { Server server; RequestHandler handler; handler.start(&server); handler.pushRequest(Download{"sth.png", 123, 100, true, Download::ConnectionType::Ssh}, [](Server::ErrorCode ec, Image image) { if (ec == Server::ErrorCode::Ok) { for (auto el : image.bitmap_) { std::cout << el << ' '; } std::cout << '\n'; } else { std::cout << "FAILED!\n"; } }); std::this_thread::sleep_for(std::chrono::milliseconds(10)); handler.stop(); }