MessagePack RPC フレームワークの設計案

プロトコルにMessagePackを、IO戦略にmp::iothreadsを使ったRPCフレームワークの設計案。RPCのメソッドと、それに対応するコールバック関数の関連づけをリンク時に行う。google-gflagsと同じ戦略。
プロトコルは以下の3種類:

Request
[true, メソッドID, 引数, リクエストID] 型は[true, 8bit整数, 何か, 32bit整数]のtuple。典型的には引数はtuple。
Response
[false, 返り値, エラー, リクエストID] 型は[false, 何か, 何か, 32bit整数]のtuple。返り値とエラーのどちらかはnilにする。
Notification
[true, メソッドID, 引数, nil] 型は[true, 8bit整数, 何か, nil]のtuple。

非同期プロトコルで、リクエストの順番通りにレスポンスを返さなくても良い。その代わりレスポンスには「どのリクエストに対するレスポンスか」を示すID(リクエストID)を含める。Notificationはレスポンスを受け取らないリクエスト。
このプロトコルJSON-RPC とほぼ同じ。JSON-RPC では 連想配列を使っているところを tuple にしている。tuple の方が速い。MessagePackでは要素が16個までのtupleはオーバーヘッドが1バイトしかないので濫用して良い。

#include <mp/rpc.h>
#include <msgpack.hpp>

// これは実装済み@MessagePack
namespace protocol {
    using msgpack::define;
    using namespace msgpack::type;

    struct Get : define< tuple<raw_ref, std::vector<raw_ref, raw_ref>> > {
        raw_ref&     path()   { return get<0>(); }
        std::vector& header() { return get<1>(); }
    };

    struct Post : define< tuple<raw_ref, std::vector<raw_ref, raw_ref>, raw_ref> > {
        raw_ref&     path()   { return get<0>(); }
        std::vector& header() { return get<1>(); }
        raw_ref&     body()   { return get<2>(); }
    };
}


// これはただのクラス
class Server {
public:
    Server();
    void Get (protocol::Get&  request, mp::rpc::responder* res, std::auto_ptr<mp::zone>& objlife);
    void Post(protocol::Post& request, mp::rpc::responder* res, std::auto_ptr<mp::zone>& objlife);
};


// これは案
MP_RPC_PROTOCOL(1, protocol::Get,  Server, &Server::Get);
MP_RPC_PROTOCOL(2, protocol::Post, Server, &server::Post);

int main(int argc, char* argv[])
{
    // mainはこれだけ
    google::ParseCommandLineFlags(&argc, &argv, true);
    mp::rpc::run();
    return 0;
}


// あとはServerクラスを実装する

Server::Server() { }    // ここで初期化処理

void Server::Get (protocol::Get&  request, mp::rpc::responder* res, std::auto_ptr<mp::zone>& objlife)
{
    std::string body("foobar");
    res->result(body);
}

void Server::Post(protocol::Post& request, mp::rpc::responder* res, std::auto_ptr<mp::zone>& objlife)
{
    // RPC呼び出し
    protocol::Post param;
    mp::rpc::get_node("127.0.0.1:9000")->call(1, param, objlife,
            mp::bind(&Server::PostResponse, _1, _2));  // クロージャはbindで
}