CppWAMP
C++11 client library for the WAMP protocol
Registrations

Call Slots

A slot is a callable target that is called in response to a signal (the signal being the call invocation in this case). The term slot, borrowed from Qt's signals and slots, is used to distinguish a call handler from an asynchronous operation handler.

A callable target can be:

  • a free function,
  • a bound member function (using std::bind),
  • a function object,
  • a lambda function, etc.

A call slot represents an RPC handler that does not have any expectations on the invocation payload arguments. If necessary, the payload arguments must be checked during runtime, in the body of the call handler.

wamp::Session::enroll expects a call slot with the following signature:

where:

The following table summarizes the different types of call slots that can be used with the library:

Slot Type Wrapper Function Slot Signature
Simple Call Slot wamp::simpleRpc<TResult, TArgs...> TResult function(TArgs...)
Simple Coroutine Call Slot wamp::simpleCoroRpc<TResult, TArgs...> TResult function(TArgs..., Yield)
Unpacked Call Slot wamp::unpackedRpc<TArgs...> Outcome function(Invocation, TArgs...)
Unpacked Coroutine Call Slot wamp::unpackedCoroRpc<TArgs...> Outcome function(Invocation, TArgs..., Yield)

where Yield represents the type boost::asio::yield_context.

Simple Call Slots

A simple call slot represents an RPC handler that expects one or more payload arguments having specific, static types. The wamp::simpleRpc function can be used when registering such call slots. It takes a simple call slot, and converts it into a regular call slot that can be passed to wamp::Session::enroll.

wamp::simpleRpc expects a call slot with the following signature:

TResult function(TArgs...)

where

  • TResult is a static return type that will be automatically converted to a single wamp::Result payload argument and then returned as a wamp::Outcome. This return type may be void if the RPC is not expected to return a value.
  • TArgs... matches the template parameter pack that was passed to wamp::simpleRpc.

Examples of simple call slots are:

void setSpeed(float speed) { ... }
// ^ ^
// TResult TArgs
int purchase(std::string item, int cost, int qty) { ... }
//^ ^ ^ ^
// \ \----------|---------/
// TResult TArgs

The above slots can be registered as follows:

session->enroll(Procedure("setSpeed"),
simpleRpc<void, float>(&setSpeed),
handler);
session->enroll(Procedure("purchase"),
simpleRpc<int, std::string, int, int>(&purchase),
handler);

where handler is the asynchronous handler (or coroutine yield context) for the enroll operation itself.

Whenever a wamp::Session dispatches an RPC invocation to the above slots, it automatically unpacks the invocation payload positional arguments, and passes them to the slot's argument list. If Session cannot convert the invocation payload arguments to their target types, it automatically sends an ERROR reply back to the router.

Simple Coroutine Call Slots

A simple coroutine call slot is like a regular simple call slot, except that it is executed within the context of a coroutine. This is useful for RPC handlers that need to perform asynchronous operations themselves. The wamp::simpleCoroRpc function can be used when registering such call slots. It takes a simple coroutine call slot, and converts it into a regular call slot that can be passed to wamp::Session::enroll.

wamp::simpleCoroRpc expects a call slot with the following signature:

TResult function(TArgs..., boost::asio::yield_context)

where

  • TResult is a static return type that will be automatically converted to a single wamp::Result payload argument and then returned as a wamp::Outcome. This return type may be void if the RPC is not expected to return a value.
  • TArgs... matches the template parameter pack that was passed to wamp::simpleCoroRpc.
  • boost::asio::yield_context represents the RPC's coroutine context.

Examples of simple coroutine call slots are:

using Yield = boost::asio::yield_context;
void setSpeed(float speed, Yield yield) { ... }
// ^ ^
// TResult TArgs
int purchase(std::string item, int cost, int qty, Yield yield) { ... }
//^ ^ ^ ^
// \ \----------|---------/
// TResult TArgs

The above slots can be registered as follows:

session->enroll(Procedure("setSpeed"),
simpleCoroRpc<void, float>(&setSpeed),
handler);
session->enroll(Procedure("purchase"),
simpleCoroRpc<int, std::string, int, int>(&purchase),
handler);

where handler is the asynchronous handler (or coroutine yield context) for the enroll operation itself.

Whenever a wamp::Session dispatches an RPC invocation to the above slots, it spawns a new coroutine to be executed on wamp::Session::userIosvc(). It then automatically unpacks the invocation payload positional arguments, and passes them to the slot's argument list. If Session cannot convert the invocation payload arguments to their target types, it automatically sends an ERROR reply back to the router.

Unpacked Call Slots

An unpacked call slot represents an RPC handler that expects one or more payload arguments having specific, static types. The wamp::unpackedRpc function can be used when registering such call slots. It takes an unpacked call slot, and converts it into a regular call slot that can be passed to wamp::Session::enroll.

wamp::unpackedRpc expects a call slot with the following signature:

wamp::Outcome function(wamp::Invocation, TArgs...)

where

  • wamp::Outcome contains a wamp::Result or a wamp::Error object to be sent back to the caller,
  • wamp::Invocation is an object containing information and payload arguments related to the RPC invocation, and,
  • TArgs... matches the template parameter pack that was passed to wamp::unpackedRpc.
Note
Unpacked call slots differ from simple call slots in the following ways:
  • Unpacked call slots are passed a wamp::Invocation object, which contains metadata on the call invocation itself. It also allows the slot to manually send a YIELD message back to the caller in a separate asynchronous task.
  • Unpacked call slots are expected to return a wamp::Outcome object. This allows such slots to return wamp::deferment, which indicates to the library that the callee will manually send (or has already sent) a YIELD message back to the caller.

Examples of unpacked call slots are:

Outcome setSpeed(Invocation inv, float speed) { ... }
// ^
// TArgs
Outcome purchase(Invocation inv, std::string item, int cost, int qty) { ... }
// ^ ^ ^
// \----------|---------/
// TArgs

The above slots can be registered as follows:

session->enroll(Procedure("setSpeed"),
unpackedRpc<float>(&setSpeed),
handler);
session->enroll(Procedure("purchase"),
unpackedRpc<std::string, int, int>(&purchase),
handler);

where handler is the asynchronous handler (or coroutine yield context) for the enroll operation itself.

Whenever a wamp::Session dispatches an RPC invocation to the above slots, it automatically unpacks the invocation payload positional arguments, and passes them to the slot's argument list. If Session cannot convert the invocation payload arguments to their target types, it automatically sends an ERROR reply back to the router.

Unpacked Coroutine Call Slots

An unpacked coroutine call slot is like an unpacked call slot, except that the slot is executed within the context of a coroutine. The wamp::unpackedCoroRpc function can be used when registering such call slots.

wamp::unpackedCoroRpc expects a call slot with the following signature:

wamp::Outcome function(wamp::Invocation, TArgs..., boost::asio::yield_context)

where

  • wamp::Outcome contains a wamp::Result or a wamp::Error object to be sent back to the caller,
  • wamp::Invocation is an object containing information and payload arguments related to the RPC invocation, and,
  • TArgs... matches the template parameter pack that was passed to wamp::unpackedRpc.
  • boost::asio::yield_context represents the RPC's coroutine context.

RPC Outcomes

RPC call slots are required to return a wamp::Outcome object. Outcome is a discriminated union (i.e. variant) that can contain either:

  • a wamp::Result object, which contains positional/keyword return arguments,
  • a wamp::Error object, which contains an error URI and other error-related information, or,
  • none of the above, which means that the outcome is deferred.

Result Outcomes

An RPC call slot can send a result back to the caller by returning a wamp::Result object:

Outcome add(Invocation, int a, int b)
{
return Result().withArgs(a + b);
}

If only positional Variant arguments need to be returned, they can be returned directly via a braced initializer list:

Outcome add(Invocation, int a, int b)
{
return {a + b};
}

If an empty result needs to be returned, an empty initializer list can be used:

Outcome doSomething()
{
// Do something...
return {};
}

Error Outcomes

An RPC call slot can send an error back to the caller by returning a wamp::Error object:

Outcome divide(Invocation, int a, int b)
{
if (b == 0)
return Error("myapp.divide_by_zero");
else
return {a/b};
}

Instead of returning an Error object via the Outcome return parameter, a call slot can also throw an Error object as an exception. The library will catch such exceptions and will send a corresponding ERROR message back to the caller:

Outcome divide(Invocation, int a, int b)
{
if (b == 0)
throw Error("myapp.divide_by_zero");
return {a/b};
}
Note
Thrown exception types other than wamp::Error are not handled by the library, and will result in the exception being rethrown by boost::asio::io_service::run.

Deferred Outcomes

A deferred outcome means that the call slot does not return anything, and that measures will be taken by the callee to manually yield a Result or Error object back to the caller (via wamp::Invocation::yield). This can be useful when the call result can only be determined in a different asynchronous context.

Example:

Outcome Client::addPerson(Invocation inv, Object person)
{
// We need to issue another RPC to the database service before we can
// fulfill this RPC.
boost::asio::spawn(inv.executor(),
[this, inv](boost::asio::yield_context yield)
{
auto dbResult = session_->call( Rpc("db.add").withArgs(person),
yield );
// Manually send the result back to the caller
auto personId = dbResult[0].to<int>();
inv.yield({personId});
});
// We don't know the result yet as this point. Return a deferred outcome
// to indicate that we'll send the result manually in a different
// asynchronous context.
return deferment;
}

Scoped Registrations

A wamp::ScopedRegistration object can be used to limit a registration's lifetime to a particular scope. When a ScopedRegistration object is destroyed, it automatically unregisters the RPC. This helps in automating the lifetime management of RPC registrations using RAII techniques.

Here's an example illustrating how ScopedRegistration can be used to manage the lifetime of several registrations:

using namespace wamp;
class Service // One of several services using the same Session
{
public:
void start(Session::Ptr session)
{
// The session has already connected and joined when this is called.
auto r1 = session_->enroll(Procedure("sum"), &Service::sum,
yield).value();
auto r2 = session_->enroll(Procedure("prod"), &Service::prod,
yield).value();
// Store scoped registrations in private member
registrations_.push_back(r1);
registrations_.push_back(r2);
}
private:
static Outcome sum(Invocation inv)
{
float x = 0;
float y = 0;
inv.convertTo(x, y);
return {x + y};
}
static Outcome prod(Invocation inv)
{
float x = 0;
float y = 0;
inv.convertTo(x, y);
return {x * y};
}
// When the Service is destroyed, the stored elements will also be
// destroyed, performing automatic unregistration for each registered RPC.
std::vector<ScopedRegistration> registrations_;
};
wamp::Object
std::map< String, Variant > Object
Variant bound type for maps of variants.
Definition: variantdefs.hpp:52
wamp::Session::Ptr
std::shared_ptr< Session > Ptr
Shared pointer to a Session.
Definition: session.hpp:117
wamp::Procedure
Contains the procedure URI and other options contained within WAMP REGISTER messages.
Definition: peerdata.hpp:492
wamp::deferment
constexpr Deferment deferment
Convenient value of the wamp::Deferment tag type that can be passed to the wamp::Outcome constructor.
Definition: peerdata.hpp:703
wamp
Definition: anyhandler.hpp:36
wamp::Outcome
Contains the outcome of an RPC invocation.
Definition: peerdata.hpp:709
wamp::Invocation
Contains payload arguments and other options within WAMP INVOCATION messages.
Definition: peerdata.hpp:799