Example 1

This example shows the basic of creating remote interface and introduces some basic features below:

  • synchronous method
  • asynchronous method
  • const qualified method
  • putting remote interface into namespace
  • binding target object to remote interface
  • getting a remote interface pointer from session

Let's say we already have an audio_player class below and we want to make this class accessible remotely from a client application.

// audio_player.hpp
#ifndef EXAMPLE_AUDIO_PLAYER_HPP
#define EXAMPLE_AUDIO_PLAYER_HPP

class audio_player
{
public:
    void play(std::string const& song) { m_playing = true; }

    void stop() { m_playing = false; }

    int rewind(int position) { /*take long time to rewind...*/ return position; }

    bool is_playing() const { return m_playing; }

    std::string name() const { return "no name"; }

private:
    bool m_playing;
};

#endif

The first step is to create a remote interface definition file below. The signature of the method in remote_player must be compatible with the method signature in the audio_player class. We only make 4 methods accessible from remote site and the name method in audio_player remain private. The remote_player class is put into example namespace.

// remote_player.hpp
#ifndef EXAMPLE_REMOTE_PLAYER_HPP
#define EXAMPLE_REMOTE_PLAYER_HPP
#include <remote/idl.hpp>

namespace example  // put this class into a namespace
{

#define REMOTE_CLASS                                    \
REMOTE_CLASS_BEGIN(remote_player)                       \
    REMOTE_METHOD_M1(void, play, std::string const&)    \
    REMOTE_METHOD_M0(void, stop)                        \
    REMOTE_METHOD_C0(bool, is_playing)                  \
    REMOTE_ASYNC_M1(int, rewind, int)                   \
REMOTE_CLASS_END
#include <remote/idl/class.hpp>

}

#define REMOTE_REGISTER_CLASS example::remote_player
#include <remote/idl/register_class.hpp>

#endif

Then, create an implementation file for the remote interface.

// remote_player.cpp
#include <remote/bindings/text_serializer.hpp>
#define REMOTE_IMPLEMENT_CLASS example::remote_player
#include "remote_player.hpp"

The remote_player.hpp and remote_player.cpp files serve as the interface contract between client and server applications. Just like ordinary C++ class files, these files can be included and compiled with the server and client applications. Alternatively, the remote_player.cpp file can also be compiled into a static library and then link to the server and client applications.

After we have the remote interface class, creating server and client applications are simple.

// server.cpp
#include "audio_player.hpp"
#include "remote_player.hpp"
#include <remote/server.hpp>
#include <remote/make_tcp_binding.hpp>

int main()
{
    audio_player player;

    remote::server server;
    server.bind<example::remote_player>(&player, "nice player");
    server.start(remote::make_tcp_binding(8888));

    std::cin.get();
    return 0;
}

In the server application, we first create an instance of audio_player object that we want to provide access from client. Then create a remote::server object to host remote service. The next part is to bind the player object to the server as remote_player interface that is accessible from client. The binding is given a name "nice player" so that client can request this binding by name. Finally, we start the server so that it starts listening to tcp port 8888 and waiting for connection from client.

// client.cpp
#include "remote_player.hpp"
#include <remote/session.hpp>
#include <remote/make_tcp_binding.hpp>

int main()
{
    remote::session session;

    // start session and connect to server
    session.start(remote::make_tcp_binding("localhost", 8888));
    if(session.wait_for_ready() != remote::session::started)
        return -1;

    // get a remote_player pointer by name
    boost::shared_ptr<example::remote_player> player
        = session.get<example::remote_player>("nice player");

    // use the remote_player pointer
    player->play("nice song");
    player->stop();
    bool state = player->is_playing();

    // asynchronous call
    remote::future<int> f = player->rewind(10);

    // do more work here...

    int pos = f.get();  // will throw if there is exception

    return 0;
}

In the client application, we first create a remote::session object to connect to the server. Then start the session to connect to "localhost" address and port 8888 using tcp. Then, wait for the session to establish connection and ready for network operations.

When the session is started, we can query for the remote_player interface pointer using the get method and by providing the name of the object we want to get. Once we get the remote interface pointer, we can use the interface like a normal pointer to call the remote method.

In this example, you can see that the client application can also call a constant method and also call a method asynchronously using remote::future. This is just the basic of remote library. There is more advance features we haven't covered in this example.

Next Example