Clients#

Simple Example#

A msgpack_rpc::clients::Client object can be created using msgpack_rpc::clients::ClientBuilder. After creating a client, msgpack_rpc::clients::Client::call() function can be used to call a method.

Example of a Simple Client#
#include <cassert>
#include <iostream>

#include "msgpack_rpc/clients/client.h"
#include "msgpack_rpc/clients/client_builder.h"

int main() {
    // Create a client.
    msgpack_rpc::clients::Client client =
        msgpack_rpc::clients::ClientBuilder()
            // Specify the URI of the server to connect to.
            .connect_to("tcp://localhost:7136")
            // build() creates a client and starts processing of the client.
            .build();

    // Call a method in the server.
    // Specify the result type in the template parameter.
    const int result = client.call<int>("add", 2, 3);
    std::cout << "Result: " << result << std::endl;  // NOLINT
    assert(result == 5);

    // Stop the client by destructing the client.

    return 0;
}

More APIs#

An example with more APIs is shown below.

Example to use various APIs of clients#
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>

#include <lyra/lyra.hpp>

#include "msgpack_rpc/clients/call_future.h"
#include "msgpack_rpc/clients/client.h"
#include "msgpack_rpc/clients/client_builder.h"
#include "msgpack_rpc/clients/server_exception.h"
#include "msgpack_rpc/config/client_config.h"
#include "msgpack_rpc/config/config_parser.h"
#include "msgpack_rpc/logging/logger.h"

void parse_command_line_arguments(int argc, char** argv,
    std::string& config_file_path, std::string& config_name);

int main(int argc, char** argv) {
    std::string config_file_path;
    std::string config_name;
    parse_command_line_arguments(argc, argv, config_file_path, config_name);

    // Parse configuration.
    msgpack_rpc::config::ConfigParser parser;
    parser.parse(config_file_path);

    // Create a logger from a configuration.
    const std::shared_ptr<msgpack_rpc::logging::Logger> logger =
        msgpack_rpc::logging::Logger::create(
            parser.logging_config(config_name));

    // Create a client.
    msgpack_rpc::clients::Client client =
        // Optionally specify configurations of the client and a logger.
        msgpack_rpc::clients::ClientBuilder(
            parser.client_config(config_name), logger)

            /* ****************************************************************
             * Configure URIs of the server.
             ******************************************************************/
            // Specify the URI of the server to connect to.
            .connect_to("tcp://localhost:8246")
            // Several URIs can be specified by calling multiple times.
            .connect_to("tcp://localhost:8247")
            // Specify a TCP port.
            .connect_to_tcp("localhost", 8248)  // NOLINT(*-magic-numbers)

            // build() creates a client and starts processing of the client.
            .build();

    /* ************************************************************************
     * Synchronously call methods.
     **************************************************************************/
    // Synchronously call a method.
    {
        // Specify the result type in the template parameter.
        const int result = client.call<int>("add", 2, 3);
        MSGPACK_RPC_INFO(logger, "Result of add(2, 3): {}", result);
    }
    // Synchronously call a method without a result.
    {
        // Specify void as the result type.
        client.call<void>("print", "Test message.");
    }
    // Synchronously call a method which throws exceptions.
    {
        try {
            client.call<void>("throw");
            MSGPACK_RPC_CRITICAL(logger, "No exception was thrown.");
        } catch (const msgpack_rpc::clients::ServerException& exception) {
            MSGPACK_RPC_INFO(
                logger, "Correctly thrown exception: {}", exception.what());
        }
    }
    // Synchronously call a method which throws exceptions using objects.
    {
        try {
            client.call<void>("throw_int", 123);  // NOLINT(*-magic-numbers)
            MSGPACK_RPC_CRITICAL(logger, "No exception was thrown.");
        } catch (const msgpack_rpc::clients::ServerException& exception) {
            MSGPACK_RPC_INFO(
                logger, "Correctly thrown exception: {}", exception.what());
        }
    }

    /* ************************************************************************
     * Asynchronously call methods.
     **************************************************************************/
    // Asynchronously call a method.
    {
        // Specify the result type in the template parameter.
        msgpack_rpc::clients::CallFuture<int> future =
            client.async_call<int>("add", 2, 3);

        // Wait for a response with a timeout.
        // An exception with status code TIMEOUT will be thrown for the timeout.
        int result = future.get_result_within(std::chrono::seconds(1));

        // Wait for a response without specifying a timeout.
        // The timeout in the configuration is used.
        result = future.get_result();

        MSGPACK_RPC_INFO(logger, "Result of add(2, 3): {}", result);
    }
    // Asynchronously call a method without a result.
    {
        // Specify void as the result type.
        msgpack_rpc::clients::CallFuture<void> future =
            client.async_call<void>("print", "Test message.");

        // get_result, get_result_within functions can be called to check
        // whether the method execution has been completed as in std::future
        // class.
        future.get_result();
    }
    // Asynchronously call a method which throws exceptions.
    {
        try {
            // get_result and get_result_within functions throws the exception
            // in the server.
            client.async_call<void>("throw").get_result();
            MSGPACK_RPC_CRITICAL(logger, "No exception was thrown.");
        } catch (const msgpack_rpc::clients::ServerException& exception) {
            MSGPACK_RPC_INFO(
                logger, "Correctly thrown exception: {}", exception.what());
        }
    }

    /* ************************************************************************
     * Notifications.
     **************************************************************************/
    {
        // Send a notification.
        // ALl notifications are processed asynchronously because notifications
        // have no responses.
        client.notify("print", "Test message.");
        // Nothing is returned from clients even when the method in the server
        // is implemented with return values.
        client.notify("add", 2, 3);
        // No exception is thrown from clients even when the method in the
        // server is implemented to throw an exception.
        client.notify("throw");
    }

    client.call<void>("print", "Client finishes.");

    return 0;
}

APIs of Clients#

class ClientBuilder#

Class of builders of clients.

Public Functions

inline ClientBuilder()#

Constructor.

This overload will use the default configurations for clients and loggers.

inline explicit ClientBuilder(config::ClientConfig client_config, const std::shared_ptr<logging::Logger> &logger = logging::Logger::create())#

Constructor.

Parameters:
  • client_config[in] Configuration of the client.

  • logger[in] Logger.

inline explicit ClientBuilder(const std::shared_ptr<logging::Logger> &logger)#

Constructor.

This overload will use the default configurations for clients.

Parameters:

logger[in] Logger.

inline Client build()#

Build a client.

Returns:

Client.

inline ClientBuilder &connect_to(addresses::URI uri)#

Add a URI to connect to.

Parameters:

uri[in] URI.

Returns:

This.

inline ClientBuilder &connect_to(std::string_view uri)#

Add a URI to connect to.

Parameters:

uri[in] URI.

Returns:

This.

inline ClientBuilder &connect_to_tcp(std::string_view host, std::uint16_t port_number)#

Add a TCP address to connect to.

Parameters:
  • host[in] Host name.

  • port_number[in] Port number.

Returns:

This.

class Client#

Class of clients.

Clients can be created using ClientBuilder.

Public Functions

inline explicit Client(std::shared_ptr<impl::IClientImpl> impl)#

Constructor.

Warning

Users should create clients using ClientBuilder instead of this constructor.

Parameters:

impl[in] Object of the internal implementation.

template<typename Result, typename ...Parameters>
inline CallFuture<std::decay_t<Result>> async_call(messages::MethodNameView method_name, const Parameters&... parameters)#

Asynchronously call a method.

Template Parameters:
  • Result – Type of the result.

  • Parameters – Types of parameters.

Parameters:
  • method_name[in] Name of the method.

  • parameters[in] Parameters.

Returns:

Future object to get the result of the RPC.

template<typename Result, typename ...Parameters>
inline std::decay_t<Result> call(messages::MethodNameView method_name, const Parameters&... parameters)#

Synchronously call a method.

Template Parameters:
  • Result – Type of the result.

  • Parameters – Types of parameters.

Parameters:
  • method_name[in] Name of the method.

  • parameters[in] Parameters.

Throws:
Returns:

Result of the RPC.

inline std::shared_ptr<executors::IExecutor> executor()#

Get the executor.

Note

This function is mainly for testing. So this function may be removed in the future.

Returns:

Executor.

template<typename ...Parameters>
inline void notify(messages::MethodNameView method_name, const Parameters&... parameters)#

Notify to a method.

Note

Notifications are always processed asynchronously because a notification doesn’t have a response.

Template Parameters:

Parameters – Types of parameters.

Parameters:
  • method_name[in] Name of the method.

  • parameters[in] Parameters.

inline void stop()#

Stop processing of this client.

Note

Destructing this client without call of this function will automatically stop this client internally.

template<typename Result>
class CallFuture#

Class of future object to wait for asynchronous RPCs.

Objects of this class are created by Client::async_call function.

Template Parameters:

Result – Type of the result.

Public Functions

inline explicit CallFuture(std::shared_ptr<impl::ICallFutureImpl> impl)#

Constructor.

Warning

Users should create objects of this class using Client::async_call function.

Parameters:

impl[in] Object of the internal implementation.

inline Result get_result()#

Get the result of RPC.

Note

This function will wait for the result if not received.

Throws:
Returns:

Result.

inline Result get_result_within(std::chrono::nanoseconds timeout)#

Get the result of RPC within a timeout.

Note

This function will wait for the result if not received, and throw an exception when no result can be received within the given timeout.

Parameters:

timeout[in] Timeout.

Throws:
Returns:

Result.

class ServerException : public MsgpackRPCException#

Class of exceptions specifying errors in servers.

Exceptions of this class can be thrown by Client::call, CallFuture::get_result, and CallFuture::get_result_within functions.

Public Functions

ServerException(const ServerException&) noexcept#

Copy constructor.

ServerException(msgpack::object object, std::shared_ptr<msgpack::zone> zone)#

Constructor.

Parameters:
  • object[in] Object in msgpack library specifying the error.

  • zone[in] Zone in msgpack library.

ServerException(ServerException&&) noexcept#

Move constructor.

~ServerException() noexcept override#

Destructor.

template<typename T>
inline T error_as() const#

Get the error.

Template Parameters:

T – Type.

Returns:

Error.

const msgpack::object &object() const noexcept#

Get the object in msgpack library.

Returns:

Object in msgpack library.

ServerException &operator=(const ServerException&) noexcept#

Copy assignment operator.

Returns:

This.

ServerException &operator=(ServerException&&) noexcept#

Move assignment operator.

Returns:

This.