Code structure

In the src directory, two files called pub.cpp and sub.cpp contain implementations of the ipc_lib.h header file. In order for these to transmit data between the two actors, a proxy needs to be running. The cx_proxy found in /usr/local/bin/ after correct installation of xMsg is all you need for this example.

The two files, pub.cpp and sub.cpp, contain calls to the header file in their main functions that create the respective xMsg actors. To build these files follow the build instructions in the README. GCC 4.9+ and CMake 3.1+ is required to build. After running the CMake file, start cx_proxy and the pub / sub executables that were made after building the project.

When running, these two actors should be sending / receiving a simple “Hello World” message. To demonstrate the advantages of xMsg, try killing one of the actors and then restarting it. The actor should immediately reconnect and continue working.

Expanding on the example

The example contains a publisher that executes the run() method from the IpcProducer class in the header. The while loop is then terminated and in the pub.cpp class an example of the overloaded operator << is used to demonstrate how to write to the publisher’s message field. This can be used to send different types of data to the subscriber. After using the << operator, the method sendMsg() is called to send the message.

Using what has been given in this simple ‘Hello World!’ example, the two example classes can be expanded out to meet the needs of the user. The basic method calls to send data and write data to send can be found in the pub.cpp class, and the basic methods to start a receiver can be found in the sub.cpp class. To alter how the data is handled when received, the UserCallback in the header file can be changed.

Actors

In order to send and receive data, an actor for publishers and subscribers needs to be created:

Creating producer actor:

xmsg::xMsg producer = xmsg::xMsg("publisher");

Creating consumer actor:

xmsg::xMsg consumer = xmsg::xMsg("subscriber");

These actor names will be used for all of the examples following.

Proxy

A proxy needs to exist in order for the messages to be sent between publisher and subscribers. After installation of xMsg, cx_proxy should be installed inside the local bin directory:

On Mac OSX:

/usr/local/bin/cx_proxy

A proxy actor can also be crafted if it needs to perform specific actions.

Creating connections

After creating these actor objects, the connections need to be created for each actor. This is done with:

Connection for the actor:

xmsg::ProxyConnection connection = ACTOR.connect(xmsg::util::to_host_addr("localhost"));

Messages

In order to send a message, the topic needs to be created first to send a message with. To make a topic you can use:

auto topic = xmsg::Topic::build(domain, subject, type);

Where the three parameters are strings specifying the domain, subject, and type respectively. To then build the message you call:

xmsg::Message message = xmsg::make_message(topic, data);

Topic is the object created above and data is the data being send in the message.

To receive messages, the subscriber needs to subscribe to a topic, specify a connection, and specify a user callback. To specify these three requirements, the subscriber can call:

auto sub = consumer.subscribe(topic, std::move(connection), user_callback);

Where user_callback is an object containing the instructions of what to do with the received message.

User Callback

A user defined callback method needs to be created in order for the xMsg subscriber to receive and process the data from the message. To read the data from the message, the subscriber needs to parse the data from the serialized message. To do this, the subscriber can call:

auto value = xmsg::parse_message<std::string>(msg);

Where msg is the received message.

Payloads

To create a payload for xMsg, first create the object with:

xmsg::proto::Payload payload;

After creating the object, you can begin to add items to the object to store. Payload has a method called add_item(), which adds a new item to the payload and returns a pointer to the new item. Making a call similar to this would give you a pointer to the item:

xmsg::proto::Payload_Item* item = payload.add_item();

Now item is a pointer to a newly added item to the payload. Using this pointer, you can set the item name and the data for the item. The data is a pointer inside item accessible with mutable_data().

Items from payloads can be named and given data. To set the name of a payload item:

item->set_name("test");

In order to set the data for a payload item, use:

item->mutable_data()->CopyFrom(data);

To read a Payload from a message, first create a buffer object with the data from the message:

const std::vector<std::uint8_t>& buffer = msg.data();

Then take the buffer object created, and use xmsg::proto::Payload’s ParseFromArray:

payload.ParseFromArray(buffer.data(), buffer.size());

To send a payload, you first need to serialize the payload before you can create a message containing it. To serialize the payload, you first want to create a buffer object:

auto buffer = std::vector<std::uint8_t>(payload.ByteSize());

Then you need to serialize the payload:

payload.SerializeToArray(buffer.data(), buffer.size());

Then return the buffer. After creating the buffer containing a serialized payload, you can begin to craft the message. Create a method receiving a topic and the payload to return the signature of an xMsg message:

xmsg::Message payload_message(const xmsg::Topic& topic,
                              const xmsg::proto::Payload& payload)
{
    // serialize_payload just creates a buffer object, serializes the payload
    // to an array, and returns the buffer, which can be seen above
    auto buffer = serialize_payload(payload);
    return {topic, xmsg::mimetype::xmsg_data, std::move(buffer)};
}

After creating this method, you can call it to create the message conatining the payload:

message = payload_message(topic, payload);

Under the directory xMsgMultPayloads, there is an example of a producer subscriber model with the producer sending a payload containing multiple payload items and the subscriber receiving the payload and printing out the names of each item.

Arrays

When arrays are sent, you cannot call parse_message on the message because it is not a primitive. Here is a quick snippet of code to read an array of ints from a message:

auto data2 = xmsg::parse_message<xmsg::proto::Data>(msg);
auto rep2 = data2.flsint64a();
std::int64_t values[3];
std::copy(rep2.begin(), rep2.end(), values);
for (int val : values) {
    std::cout << val << std::endl;
}