#ifndef LIBREPOMGR_CLIENT_SESSION_H #define LIBREPOMGR_CLIENT_SESSION_H #include "../global.h" #include "../webapi/typedefs.h" #include #include #include #include #include #include #include #include namespace LibRepoMgr { struct ServiceSetup; namespace WebClient { struct LIBREPOMGR_EXPORT HttpClientError : std::runtime_error { explicit HttpClientError(); explicit HttpClientError(const char *context, boost::beast::error_code errorCode); operator bool() const; const char *const context; const boost::beast::error_code errorCode; }; inline HttpClientError::HttpClientError() : std::runtime_error(std::string()) , context(nullptr) , errorCode(boost::beast::error_code()) { } inline LibRepoMgr::WebClient::HttpClientError::operator bool() const { return errorCode ? true : false; } using Response = WebAPI::Response; using FileResponse = boost::beast::http::response_parser; using StringResponse = boost::beast::http::response_parser; using MultiResponse = std::variant; using Request = boost::beast::http::request; struct ChunkProcessing; class LIBREPOMGR_EXPORT Session : public std::enable_shared_from_this { public: using Handler = std::function; using ChunkHandler = std::function; template explicit Session(boost::asio::io_context &ioContext, const Handler &handler = Handler()); template explicit Session(boost::asio::io_context &ioContext, Handler &&handler = Handler()); template explicit Session(boost::asio::io_context &ioContext, boost::asio::ssl::context &sslContext, const Handler &handler = Handler()); template explicit Session(boost::asio::io_context &ioContext, boost::asio::ssl::context &sslContext, Handler &&handler); void setChunkHandler(ChunkHandler &&handler); void run(const char *host, const char *port, boost::beast::http::verb verb, const char *target, std::optional bodyLimit = std::nullopt, unsigned int version = 11); private: using RawSocket = boost::asio::ip::tcp::socket; using SslStream = boost::asio::ssl::stream; struct ChunkProcessing { boost::beast::http::chunk_extensions chunkExtensions; std::string currentChunk; std::function onChunkHeader; std::function onChunkBody; Session::ChunkHandler handler; }; RawSocket &socket(); void resolved(boost::beast::error_code ec, boost::asio::ip::tcp::resolver::results_type results); void connected(boost::beast::error_code ec); void handshakeDone(boost::beast::error_code ec); void sendRequest(); void requested(boost::beast::error_code ec, std::size_t bytesTransferred); void onChunkHeader(std::uint64_t chunkSize, boost::beast::string_view extensions, boost::beast::error_code &ec); std::size_t onChunkBody(std::uint64_t bytesLeftInThisChunk, boost::beast::string_view chunkBodyData, boost::beast::error_code &ec); void chunkReceived(boost::beast::error_code ec, std::size_t bytesTransferred); bool continueReadingChunks(); void received(boost::beast::error_code ec, std::size_t bytesTransferred); void closed(boost::beast::error_code ec); public: Request request; MultiResponse response; std::string destinationFilePath; private: boost::asio::ip::tcp::resolver m_resolver; std::variant m_stream; boost::beast::flat_buffer m_buffer; std::unique_ptr m_chunkProcessing; Handler m_handler; }; template inline Session::Session(boost::asio::io_context &ioContext, const Handler &handler) : response(ResponseType{}) , m_resolver(ioContext) , m_stream(RawSocket{ ioContext }) , m_handler(handler) { } template inline Session::Session(boost::asio::io_context &ioContext, Handler &&handler) : response(ResponseType{}) , m_resolver(ioContext) , m_stream(RawSocket{ ioContext }) , m_handler(std::move(handler)) { } template inline Session::Session(boost::asio::io_context &ioContext, boost::asio::ssl::context &sslContext, const Handler &handler) : response(ResponseType{}) , m_resolver(ioContext) , m_stream(SslStream{ ioContext, sslContext }) , m_handler(handler) { } template inline Session::Session(boost::asio::io_context &ioContext, boost::asio::ssl::context &sslContext, Handler &&handler) : response(ResponseType{}) , m_resolver(ioContext) , m_stream(SslStream{ ioContext, sslContext }) , m_handler(std::move(handler)) { } LIBREPOMGR_EXPORT std::variant> runSessionFromUrl(boost::asio::io_context &ioContext, boost::asio::ssl::context &sslContext, std::string_view url, Session::Handler &&handler, std::string &&destinationPath = std::string(), std::string_view userName = std::string_view(), std::string_view password = std::string_view(), boost::beast::http::verb verb = boost::beast::http::verb::get, std::optional bodyLimit = std::nullopt, Session::ChunkHandler &&chunkHandler = Session::ChunkHandler()); } // namespace WebClient } // namespace LibRepoMgr #endif // LIBREPOMGR_CLIENT_SESSION_H