Boost logo

Boost :

Subject: Re: [boost] Interest in Remote Procedure Call Library?
From: OvermindDL1 (overminddl1_at_[hidden])
Date: 2010-02-07 18:52:45


On Sun, Feb 7, 2010 at 1:08 PM, vicente.botet <vicente.botet_at_[hidden]> wrote:
> /* snip RPC stuff */

For note, I created an RPC system a while ago (of which I donated some
of the code to RakNet, but my version is still more complete). It
uses no macros, it handles overloads fine, and it was to be plugged
into any system as well (I had a networking interface, as well as an
interface into a little custom scripting language). It was used like
this:

// Some functions and member function to link in
void _myFunc(someClass *m1, anotherClass &m2, yetAnotherClass m3, int
i, float f, RPCInfo *rpc, std::string s)
{
    /* do stuff */
}

class myClass
{
    public:
    void _myMemberFunc(int i, float f);
    static RPCHandler::type_of_callback<myClass::_myMemberFunc>::type
myMemberFunc;
}

// You "register" it to the RPC system like this:
RPCHandler global_rpc;

auto myFunc = global_rpc.register(_myfunc, 0); // Either globally

void someFunctionSomewhere(RPCHandler &rpc)
{
    auto myLocalFunc = global_rpc.register(_myfunc1); // or locally

    // Registing a member function is the same way
    myClass::myMemberFunc =
global_rpc.register(myClass::_myMemberFunc, "theMemberFunc") // and
yes, the second parameter, the id, can be an int or string, whichever
is easier for your situation
}

To use it you can set flags in the RPC class as to how to route that
callback, whether it is local only, remote only, both, etc...
And to use it, you just call the returned object from the register
function as just any other function:

myFunc(m1,m2,m3,42,3.14,"Hello World");
If that need to be called on a remote system, then it will be
serialized up, sent out, and called remotely. If it is supposed to be
called locally, then it will just call it locally right then and
there.

myClass m;
myClass::myMemberFunc(m, 42, 3.14); // You would probably make a
wrapped around this though...

RPC calls can be registered at any time, and can be unregistered, and
with bind they can be bound to specific objects and so forth as well.
But the register call returns a specialized callback struct (that you
can stuff into a boost::function if you do not care about overloading,
or can be used as-is by the type_of_callback thing or auto).

I had talked about this on boost before, hinted at making it a
library, but no interest was expressed. I still have my code, it is
well tested and in the wild (through RakNet), so if anyone is
interested then I can clean it up and write documentation and submit
it.

The way it works though is just very heavy use of Boost.Fusion and
function traits and a few other things. In the RakNet version I
serialized things out to its bitstream, otherwise I use
Boost.Serialization (which can be overridden to use yet another thing
if you want, like I do for my scripting language version). But if a
parameter is by value, it just packages it up according to
Boost.Serialization (or whatever you use internally). If it is a
reference or pointer it still follows the same serialization pattern,
unless a few conditions are met. If it is a pointer or reference and
it is to an RPCInfo type, then it passes in information about the
call, like if it remote, local, and a few other things. In the RakNet
version I added another overload so if a class was passed by
pointer/reference and it was a subclass of NetworkIDObject, then
instead of serializing the object it just sends its network ID number
and looks up that same object on the remote system (perfect for *this
and any other passed in parameters). It is easy to add new overrides
too, and it threw a compile error in a specific spot if the thing
could not be serialized and/or did not match other things and various
other conditions as well, all compile-time.

But yes, if anyone wants the code, I can easily give it, just no
documentation and bit a messy, but it works quite well, no macros
needed, no needing to register types, etc...

And as you may notice, mine will silently drop return values, it is
asynchronous only, but functionality like futures or synchronized
calls could easily be added (although I would prefer async futures or
async callbacks personally).

And let me say, Boost.Fusion is so awesome!


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk