#pragma once #include #include #include "rpc/config.h" #include "rpc/detail/log.h" #include "rpc/detail/pimpl.h" #include "rpc/msgpack.hpp" namespace rpc { //! \brief Implements a client that connects to a msgpack-rpc server and is //! able to call functions synchronously or asynchronously. This is the main //! interfacing point for implementing client applications. //! //! Use this class to connect to msgpack-rpc servers and call their exposed //! functions. This class supports calling functions synchronously and //! asynchronously. When the client object is created, it initiates connecting //! to the given server asynchronically and disconnects when it is destroyed. class client { public: //! \brief Constructs a client. //! //! When a client is constructed, it initiates a connection //! asynchronically. This means that it will not block while the connection //! is established. However, when the first call is performed, it *might* //! block if the connection was not already established. //! //! \param addr The address of the server to connect to. This might be an //! IP address or a host name, too. //! \param port The port on the server to connect to. client(std::string const &addr, uint16_t port); //! \cond DOXYGEN_SKIP client(client const &) = delete; //! \endcond //! \brief Destructor. //! //! During destruction, the connection to the server is gracefully closed. //! This means that any outstanding reads and writes are completed first. ~client(); //! \brief Calls a function with the given name and arguments (if any). //! //! \param func_name The name of the function to call on the server. //! \param args A variable number of arguments to pass to the called //! function. //! //! \tparam Args The types of the arguments. Each type in this parameter //! pack have to be serializable by msgpack. //! //! \returns A RPCLIB_MSGPACK::object containing the result of the function (if //! any). To obtain a typed value, use the msgpack API. //! //! \throws rpc::rpc_error if the server responds with an error. template RPCLIB_MSGPACK::object_handle call(std::string const &func_name, Args... args); //! \brief Calls a function asynchronously with the given name and //! arguments. //! //! A call is performed asynchronously in the context of the client, i.e. //! this is not to be confused with parallel execution on the server. //! This function differs from `call` in that it does not wait for the //! result of the function. Instead, it returns a std::future that //! can be used to retrieve the result later. //! //! \param func_name The name of the function to call. //! \param args The arguments to pass to the function. //! //! \tparam Args The types of the arguments. //! //! \returns A std::future, possibly holding a future result //! (which is a RPCLIB_MSGPACK::object). template std::future async_call(std::string const &func_name, Args... args); //! \brief Sends a notification with the given name and arguments (if any). //! //! Notifications are a special kind of calls. They can be used to notify //! the server, while not expecting a response. In `rpclib` terminology, //! a notification is like an `async_call` without a return value. //! //! \param func_name The name of the notification to call. //! \param args The arguments to pass to the function. //! \tparam Args THe types of the arguments. //! //! \note This function returns immediately (possibly before the //! notification is written to the socket). template void send(std::string const &func_name, Args... args); //! \brief Returns the timeout setting of this client in milliseconds. //! //! The timeout is applied to synchronous calls. If the timeout expires //! without receiving a response from the server, rpc::timeout exceptio //! will be thrown. //! //! \note The timeout has no effect on async calls. For those, //! the preferred timeout mechanism remains using std::future. //! //! The default value for timeout is 5000ms (5 seconds). uint64_t get_timeout() const; //! \brief Sets the timeout for global calls. For more information, //! see client::get_timeout(). void set_timeout(uint64_t value); //! \brief Enum representing the connection states of the client. enum class connection_state { initial, connected, disconnected, reset }; //! \brief Returns the current connection state. connection_state get_connection_state() const; //! \brief Waits for the completion of all ongoing calls. void wait_all_responses(); private: //! \brief Type of a promise holding a future response. using rsp_promise = std::promise; enum class request_type { call = 0, notification = 2 }; void wait_conn(); void post(std::shared_ptr buffer, int idx, std::string const& func_name, std::shared_ptr p); void post(RPCLIB_MSGPACK::sbuffer *buffer); int get_next_call_idx(); RPCLIB_NORETURN void throw_timeout(std::string const& func_name); private: static constexpr double buffer_grow_factor = 1.8; RPCLIB_DECLARE_PIMPL() }; } #include "rpc/client.inl"