/** * Digital Voice Modem - Host Software * GPLv2 Open Source. Use is subject to license terms. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * @package DVM / Host Software * */ /* * Copyright (C) 2023 by Bryan Biedenkapp N2PLL * * Permission is hereby granted, free of charge, to any person or organization * obtaining a copy of the software and accompanying documentation covered by * this license (the “Software”) to use, reproduce, display, distribute, execute, * and transmit the Software, and to prepare derivative works of the Software, and * to permit third-parties to whom the Software is furnished to do so, all subject * to the following: * * The copyright notices in the Software and this entire statement, including the * above license grant, this restriction and the following disclaimer, must be included * in all copies of the Software, in whole or in part, and all derivative works of the * Software, unless such copies or derivative works are solely in the form of * machine-executable object code generated by a source language processor. * * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE * DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #if !defined(__REST_HTTP__HTTP_CLIENT_H__) #define __REST_HTTP__HTTP_CLIENT_H__ #include "Defines.h" #include "network/rest/http/Connection.h" #include "network/rest/http/ConnectionManager.h" #include "network/rest/http/HTTPRequestHandler.h" #include "Thread.h" #include #include #include #include #include #include #include namespace network { namespace rest { namespace http { // --------------------------------------------------------------------------- // Class Declaration // This class implements top-level routines of the HTTP client. // --------------------------------------------------------------------------- template class ConnectionImpl = Connection> class HTTPClient : private Thread { public: /// Initializes a new instance of the HTTPClient class. explicit HTTPClient(const std::string& address, uint16_t port) : m_address(address), m_port(port), m_connection(nullptr), m_ioContext(), m_connectionManager(), m_socket(m_ioContext), m_requestHandler() { /* stub */ } /// Initializes a copy instance of the HTTPClient class. HTTPClient(const HTTPClient&) = delete; /// HTTPClient& operator=(const HTTPClient&) = delete; /// Helper to set the HTTP request handlers. template void setHandler(Handler&& handler) { m_requestHandler = RequestHandlerType(std::forward(handler)); } /// Send HTTP request to HTTP server. void request(HTTPPayload& request) { asio::post(m_ioContext, [this, request]() { std::lock_guard guard(m_lock); { write(request); } }); } /// Opens connection to the network. bool open() { return run(); } /// Closes connection to the network. void close() { if (m_connection != nullptr) { m_connection->stop(); } wait(); } private: /// virtual void entry() { asio::ip::tcp::resolver resolver(m_ioContext); auto endpoints = resolver.resolve(m_address, std::to_string(m_port)); connect(endpoints); // the entry() call will block until all asynchronous operations // have finished m_ioContext.run(); } /// Perform an asynchronous connect operation. void connect(asio::ip::basic_resolver_results& endpoints) { asio::async_connect(m_socket, endpoints, [this](asio::error_code ec, asio::ip::tcp::endpoint) { if (!ec) { m_connection = std::make_shared(std::move(m_socket), m_connectionManager, m_requestHandler, false, true); m_connection->start(); } }); } /// Perform an asynchronous write operation. void write(HTTPPayload request) { asio::async_write(m_socket, request.toBuffers(), [=](asio::error_code ec, std::size_t) { if (!ec) { // initiate graceful connection closure asio::error_code ignored_ec; m_socket.shutdown(asio::ip::tcp::socket::shutdown_both, ignored_ec); } if (ec != asio::error::operation_aborted) { m_socket.close(); } }); } std::string m_address; uint16_t m_port; typedef ConnectionImpl ConnectionType; typedef std::shared_ptr ConnectionTypePtr; ConnectionTypePtr m_connection; asio::io_context m_ioContext; ConnectionManager m_connectionManager; asio::ip::tcp::socket m_socket; RequestHandlerType m_requestHandler; std::mutex m_lock; }; } // namespace http } // namespace rest } // namespace network #endif // __REST_HTTP__HTTP_CLIENT_H__