aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/deps/rpclib/include/rpc/client.h
blob: 624607641bba4992ec73f9ff70e85d03776add80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#pragma once

#include <future>
#include <memory>

#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 <typename... Args>
    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 <typename... Args>
    std::future<RPCLIB_MSGPACK::object_handle> 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 <typename... Args>
    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<RPCLIB_MSGPACK::object_handle>;

    enum class request_type { call = 0, notification = 2 };

    void wait_conn();
    void post(std::shared_ptr<RPCLIB_MSGPACK::sbuffer> buffer, int idx,
              std::string const& func_name,
              std::shared_ptr<rsp_promise> 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"