You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OpenTTD-patches/src/network/core/http_shared.h

133 lines
3.2 KiB
C++

/*
* 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 <http://www.gnu.org/licenses/>.
*/
/**
* @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 <condition_variable>
#include <mutex>
#include <vector>
/** Converts a HTTPCallback to a Thread-Safe variant. */
class HTTPThreadSafeCallback {
private:
/** Entries on the queue for later handling. */
class Callback {
public:
Callback(UniqueBuffer<char> data) : data(std::move(data)), failure(false) {}
Callback() : data({}), failure(true) {}
UniqueBuffer<char> data;
bool failure;
};
public:
/**
* Similar to HTTPCallback::OnFailure, but thread-safe.
*/
void OnFailure()
{
std::lock_guard<std::mutex> lock(this->mutex);
this->queue.emplace_back();
}
/**
* Similar to HTTPCallback::OnReceiveData, but thread-safe.
*/
void OnReceiveData(UniqueBuffer<char> data)
{
std::lock_guard<std::mutex> 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<std::mutex> 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 <typename T>
void WaitTillEmptyOrCondition(T condition)
{
std::unique_lock<std::mutex> lock(this->mutex);
while (!(queue.empty() || condition())) {
this->queue_cv.wait(lock);
}
}
/**
* Check if the queue is empty.
*/
bool IsQueueEmpty()
{
std::lock_guard<std::mutex> lock(this->mutex);
return this->queue.empty();
}
/**
* Clear everything in the queue.
*
* Should be called from the Game Thread.
*/
void ClearQueue()
{
std::lock_guard<std::mutex> lock(this->mutex);
this->queue.clear();
this->queue_cv.notify_all();
}
HTTPThreadSafeCallback(HTTPCallback *callback) : callback(callback) {}
~HTTPThreadSafeCallback()
{
std::lock_guard<std::mutex> lock(this->mutex);
queue.clear();
queue_cv.notify_all();
}
std::atomic<bool> cancelled = false;
private:
HTTPCallback *callback; ///< The callback to send data back on.
std::mutex mutex; ///< Mutex to protect the queue.
std::vector<Callback> 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 */