/* * This file is part of OpenTTD. * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . */ /** * @file http.h Shared functions for implementations of HTTP requests. */ #ifndef NETWORK_CORE_HTTP_SHARED_H #define NETWORK_CORE_HTTP_SHARED_H #include "http.h" #include #include #include /** Converts a HTTPCallback to a Thread-Safe variant. */ class HTTPThreadSafeCallback { private: /** Entries on the queue for later handling. */ class Callback { public: Callback(UniqueBuffer data) : data(std::move(data)), failure(false) {} Callback() : data({}), failure(true) {} UniqueBuffer data; bool failure; }; public: /** * Similar to HTTPCallback::OnFailure, but thread-safe. */ void OnFailure() { std::lock_guard lock(this->mutex); this->queue.emplace_back(); } /** * Similar to HTTPCallback::OnReceiveData, but thread-safe. */ void OnReceiveData(UniqueBuffer data) { std::lock_guard lock(this->mutex); this->queue.emplace_back(std::move(data)); } /** * Process everything on the queue. * * Should be called from the Game Thread. */ void HandleQueue() { this->cancelled = callback->IsCancelled(); std::lock_guard lock(this->mutex); for (auto &item : this->queue) { if (item.failure) { this->callback->OnFailure(); } else { this->callback->OnReceiveData(std::move(item.data)); } } this->queue.clear(); this->queue_cv.notify_all(); } /** * Wait till the queue is dequeued, or a condition is met. * @param condition Condition functor. */ template void WaitTillEmptyOrCondition(T condition) { std::unique_lock lock(this->mutex); while (!(queue.empty() || condition())) { this->queue_cv.wait(lock); } } /** * Check if the queue is empty. */ bool IsQueueEmpty() { std::lock_guard lock(this->mutex); return this->queue.empty(); } /** * Clear everything in the queue. * * Should be called from the Game Thread. */ void ClearQueue() { std::lock_guard lock(this->mutex); this->queue.clear(); this->queue_cv.notify_all(); } HTTPThreadSafeCallback(HTTPCallback *callback) : callback(callback) {} ~HTTPThreadSafeCallback() { std::lock_guard lock(this->mutex); queue.clear(); queue_cv.notify_all(); } std::atomic cancelled = false; private: HTTPCallback *callback; ///< The callback to send data back on. std::mutex mutex; ///< Mutex to protect the queue. std::vector queue; ///< Queue of data to send back. std::condition_variable queue_cv; ///< Condition variable to wait for the queue to be empty. }; #endif /* NETWORK_CORE_HTTP_SHARED_H */