PreVerify/lib/qtl/include/qtl_asio.hpp

398 lines
12 KiB
C++
Raw Permalink Normal View History

2024-09-09 19:18:28 +08:00
#ifndef _QTL_ASIO_H_
#define _QTL_ASIO_H_
#include "qtl_async.hpp"
#include <asio/version.hpp>
#define ASIO_STANDALONE
#if defined(_MSC_VER) && _WIN32_WINNT<0x0600
#define ASIO_ENABLE_CANCELIO 1
#endif
#if ASIO_VERSION < 101200
#include <asio/io_service.hpp>
#else
#include <asio/io_context.hpp>
#endif // ASIO_VERSION
#include <asio/strand.hpp>
#include <asio/ip/tcp.hpp>
#include <asio/async_result.hpp>
#include <asio/steady_timer.hpp>
#if ASIO_VERSION < 100000
#error The asio version required by QTL is at least 10.0
#endif
namespace qtl
{
namespace NS_ASIO = ::asio;
namespace asio
{
class service
{
public:
#if ASIO_VERSION < 101200
typedef NS_ASIO::io_service service_type;
#else
typedef NS_ASIO::io_context service_type;
#endif // ASIO_VERSION
service() NOEXCEPT { }
explicit service(int concurrency_hint) : _service(concurrency_hint) { }
void reset()
{
_service.reset();
}
void run()
{
_service.run();
}
void stop()
{
_service.stop();
}
service_type& context() NOEXCEPT { return _service; }
private:
class event_item : public qtl::event
{
public:
event_item(service& service, qtl::socket_type fd)
: _service(service), _strand(service.context()), _socket(service.context(), NS_ASIO::ip::tcp::v4(), fd), _timer(service.context()), _busying(false)
{
}
NS_ASIO::ip::tcp::socket& next_layer() { return _socket; }
public: // qtl::event
virtual void set_io_handler(int flags, long timeout, std::function<void(int)>&& handler) override
{
if (flags&qtl::event::ef_read)
{
#if ASIO_VERSION < 101200
_socket.async_read_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code& ec, size_t bytes_transferred) {
#else
_socket.async_wait(NS_ASIO::socket_base::wait_read, _strand.wrap([this, handler](const NS_ASIO::error_code& ec) {
#endif // ASIO_VERSION
if (!ec)
handler(qtl::event::ef_read);
else if (ec == NS_ASIO::error::make_error_code(NS_ASIO::error::operation_aborted))
handler(qtl::event::ef_timeout);
else
handler(qtl::event::ef_exception);
_busying = false;
_timer.cancel();
}));
_busying = true;
}
if (flags&qtl::event::ef_write)
{
#if ASIO_VERSION < 101200
_socket.async_write_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code& ec, size_t bytes_transferred) {
#else
_socket.async_wait(NS_ASIO::socket_base::wait_write, _strand.wrap([this, handler](const NS_ASIO::error_code& ec) {
#endif //ASIO_VERSION
if (!ec)
handler(qtl::event::ef_write);
else if (ec == NS_ASIO::error::make_error_code(NS_ASIO::error::operation_aborted))
handler(qtl::event::ef_timeout);
else
handler(qtl::event::ef_exception);
_timer.cancel();
_busying = false;
}));
_busying = true;
}
if (timeout > 0)
{
#if ASIO_VERSION < 101200
_timer.expires_from_now(std::chrono::seconds(timeout));
#else
_timer.expires_after(NS_ASIO::chrono::seconds(timeout));
#endif // ASIO_VERSION
_timer.async_wait(_strand.wrap([this, handler](NS_ASIO::error_code ec) {
if (!ec)
{
_socket.cancel(ec);
}
}));
}
}
virtual void remove() override
{
if (_busying) return;
#if ASIO_VERSION >= 101200 && (!defined(_WIN32) || _WIN32_WINNT >= 0x0603 )
_socket.release();
#endif //Windows 8.1
_service.remove(this);
}
virtual bool is_busying() override
{
return _busying;
}
private:
service& _service;
service_type::strand _strand;
NS_ASIO::ip::tcp::socket _socket;
NS_ASIO::steady_timer _timer;
bool _busying;
};
public:
template<typename Connection>
event_item* add(Connection* connection)
{
event_item* item = new event_item(*this, connection->socket());
std::lock_guard<std::mutex> lock(_mutex);
_events.push_back(std::unique_ptr<event_item>(item));
return item;
}
private:
service_type _service;
std::mutex _mutex;
std::vector<std::unique_ptr<event_item>> _events;
void remove(event_item* item)
{
std::lock_guard<std::mutex> lock(_mutex);
auto it = std::find_if(_events.begin(), _events.end(), [item](std::unique_ptr<event_item>& v) {
return item==v.get();
});
if (it != _events.end()) _events.erase(it);
}
};
#if ASIO_VERSION < 101200
template <typename Handler, typename Signature>
using async_init_type = NS_ASIO::detail::async_result_init<Handler, Signature>;
template <typename Handler, typename Signature>
inline typename NS_ASIO::handler_type<Handler, Signature>::type
get_async_handler(async_init_type<Handler, Signature>& init)
{
return init.handler;
}
#else
template <typename Handler, typename Signature>
using async_init_type = NS_ASIO::async_completion<Handler, Signature>;
template <typename Handler, typename Signature>
inline typename async_init_type<Handler, Signature>::completion_handler_type
get_async_handler(async_init_type<Handler, Signature>& init)
{
return init.completion_handler;
}
#endif // ASIO_VERSION
template<typename Connection, typename OpenHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(OpenHandler, void(typename Connection::exception_type))
async_open(service& service, Connection& db, OpenHandler&& handler, Args&&... args)
{
#if ASIO_VERSION < 101200
async_init_type<OpenHandler,
void(typename Connection::exception_type)> init(std::forward<OpenHandler>(handler));
#else
async_init_type<OpenHandler,
void(typename Connection::exception_type)> init(handler);
#endif
db.open(service, get_async_handler(init), std::forward<Args>(args)...);
return init.result.get();
}
template<typename Connection, typename CloseHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(CloseHandler, void())
async_close(Connection& db, CloseHandler&& handler, Args&&... args)
{
#if ASIO_VERSION < 101200
async_init_type<CloseHandler,
void()> init(std::forward<CloseHandler>(std::forward<CloseHandler>(handler)));
#else
async_init_type<CloseHandler,
void()> init(std::forward<CloseHandler>(handler));
#endif
db.close(get_async_handler(init), std::forward<Args>(args)...);
return init.result.get();
}
template<typename Connection, typename ExecuteHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
async_execute(Connection& db, ExecuteHandler&& handler, Args&&... args)
{
#if ASIO_VERSION < 101200
async_init_type<ExecuteHandler,
void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
#else
async_init_type<ExecuteHandler,
void(typename Connection::exception_type, uint64_t)> init(handler);
#endif
db.execute(get_async_handler(init), std::forward<Args>(args)...);
return init.result.get();
}
template<typename Connection, typename ExecuteHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
async_execute_direct(Connection& db, ExecuteHandler&& handler, Args&&... args)
{
#if ASIO_VERSION < 101200
async_init_type<ExecuteHandler,
void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
#else
async_init_type<ExecuteHandler,
void(typename Connection::exception_type, uint64_t)> init(handler);
#endif
db.execute_direct(get_async_handler(init), std::forward<Args>(args)...);
return init.result.get();
}
template<typename Connection, typename ExecuteHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
async_insert(Connection& db, ExecuteHandler&& handler, Args&&... args)
{
#if ASIO_VERSION < 101200
async_init_type<ExecuteHandler,
void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
#else
async_init_type<ExecuteHandler,
void(typename Connection::exception_type, uint64_t)> init(handler);
#endif
db.insert(get_async_handler(init), std::forward<Args>(args)...);
return init.result.get();
}
template<typename Connection, typename ExecuteHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
async_insert_direct(Connection& db, ExecuteHandler&& handler, Args&&... args)
{
#if ASIO_VERSION < 101200
async_init_type<ExecuteHandler,
void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
#else
async_init_type<ExecuteHandler,
void(typename Connection::exception_type, uint64_t)> init(handler);
#endif
db.insert_direct(get_async_handler(init), std::forward<Args>(args)...);
return init.result.get();
}
template<typename Connection, typename FinishHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query(Connection& db, FinishHandler&& handler, Args&&... args)
{
#if ASIO_VERSION < 101200
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
#else
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(handler);
#endif
db.query(std::forward<Args>(args)..., get_async_handler(init));
return init.result.get();
}
template<typename Connection, typename FinishHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query_explicit(Connection& db, FinishHandler&& handler, Args&&... args)
{
#if ASIO_VERSION < 101200
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
#else
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(handler);
#endif
db.query_explicit(std::forward<Args>(args)..., get_async_handler(init));
return init.result.get();
}
template<typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query_multi_with_params(Connection& db, A1&& a1, A2&& a2, FinishHandler&& handler, RowHandlers&&... row_handlers)
{
#if ASIO_VERSION < 101200
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
#else
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(handler);
#endif
db.query_multi_with_params(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
return init.result.get();
}
template<typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query_multi_with_params(Connection& db, A1&& a1, FinishHandler&& handler, RowHandlers&&... row_handlers)
{
#if ASIO_VERSION < 101200
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
#else
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(handler);
#endif
db.query_multi_with_params(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
return init.result.get();
}
template<typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query_multi(Connection& db, A1&& a1, A2&& a2, FinishHandler&& handler, RowHandlers&&... row_handlers)
{
#if ASIO_VERSION < 101200
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
#else
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(handler);
#endif
db.query_multi(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
return init.result.get();
}
template<typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query_multi(Connection& db, A1&& a1, FinishHandler&& handler, RowHandlers&&... row_handlers)
{
#if ASIO_VERSION < 101200
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
#else
async_init_type<FinishHandler,
void(typename Connection::exception_type)> init(handler);
#endif
db.query_multi(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
return init.result.get();
}
}
}
#endif //_QTL_ASIO_H_