msgpack

IrrlichtにMsgPackRPCを仕込む
IrrlichtにMsgPackRPCを仕込む Oculusの通販ステータスが早くもProcessingに変わって届くのが楽しみな今日この頃。 レンダリングエンジンにはIrrlichtを選択したのであるが、 そのままだとシーンを構築するとか諸々の作業がC++直叩きになる。 これだとさすがに大変なのでMsgPackRPCでラップして外部のツールから 操作しようと構想しておったのだが始めてみると早速問題に突き当たった。 オブジェクトを生成してそのメソッドをコールするのにどうすればいいのか。 こういう場合だ。 IMesh *mesh=CreateMesh("miku.pmd"); mesh->SetPosition(0, 0, 5); MsgPackRPC経由だと以下のような感じか。 # pythonとかそういうの client=msgpac.rpc.client() mesh=client.call("CreateMesh", "miku.pmd") client.call("Mesh_SetPosition", mesh, 0, 0, 5) 1つめのCreateMeshはグローバル関数かシングルトン的オブジェクトのメソッド呼び出しになるので特に問題は無い。 2つめはSetPositionのthisとしてmeshを送ってやる必要がある。 ここでmsgpack的にはIMesh*をシリアライズ/デシリアライズすることが必要になる。 案1 ポインタを整数値としてキャストすればいいじゃない template <typename Stream> inline packer<Stream>& operator<< (packer<Stream>& o, IMesh *v) { // ポインタをintにキャスト o.pack((int)v); return o; } inline IMesh *v operator>> (object o, IMesh* v) { unsigned int p; o.convert(&p): // intをポインタにキャスト v=(IMesh*)p; return v; } さすがにワイルドすぎる。というかポインタが既に開放されている場合になすすべが無いので没

おれおれmsgpack-rpc-pythonを作る
おれおれmsgpack-rpc-pythonを作る MsgPackRPCのpythonバインディング(クライアント側)が必要になったのでmsgpack-rpc-pythonを使ってみたのだが、 GUI(pyqt)に載せて接続制御とエラーハンドリングを細やかに制御したいので俺俺で類似品を作ることにした。 tonado-msgpackと名付けて取り合えず作業開始。 https://github.com/ousttrue/tornado-msgpack msgpack-rpc-pythonのおかげでtornadoの存在を知ったのだがtornado.ioloopが見れば見るほどboost::asioっぽい。 ということで、c++で作成中のmsgpack-rpc-asioのpython版のような感じのAPIにしてみた。 以下の点を考慮している。 tornado.ioloopを隠さない tornado.ioloopをスレッドに乗せて回しっぱなしにする tornado.ioloopひとつで複数の接続を扱う dispatcherを乗せ換え易くする。 接続ステータスの変化をコールバックで受け取る 非同期リクエストのコールバックを早期にセットする TCP以外は考慮しない プロジェクト作成 tonado_msgpack/ setup.py sample/ sample.py tonado_msgpack setup.py from distutils.core import setup setup( name='tonado_msgpack', version='0.1', py_modules=['tonado_msgpack'], ) 作業開始 $ python setup.py develop --user sample/sample.py #!/usr/bin/env python import tornado_msgpack import tornado if __name__=="__main__": port=18080 # dispatcher dispatcher=tornado_msgpack.Dispatcher() def add(a, b): return a+b dispatcher.add_handler("add", add) # server server_loop=tornado.ioloop.IOLoop() def on_receive(msg, session): result=dispatcher.dispatch(msg) session.

msgpack-rpc-asioの関数登録と実行
msgpack-rpc-asioの関数登録と実行 msgpack-rpcのリクエストは、によると [type, msgid, method, params] という形式なのでmethod名をstd::stringとしてparamsをstd::tupleとして得られる。 これをサーバ側で如何に呼び出すかについて。 単純な実装だと以下のようにメソッド名をキーにして分岐することになる。 ```c++ int and(int, int); class dispatcher { void dispatch(int msgid, const std::string &method, const msgpack::object &params) { if(method==“add”){ // 引数展開 std::tuple t; params.convert(&t); // 関数実行 int result=add(std::get<0>(t), std::get<1>(t)); // 結果のパッキング // response [type, msgid, error, result] msgpack::sbuffer response; msgpack::packer<msgpack::sbuffer> pk(&response); pk.pack_array(4) pk.pack(1); pk.pack(msgid); pk.pack_nil(); pk.pack(result); // responseを送り返す } else{ throw “unknown func”; } } 引数展開、関数呼び出し、結果のパッキングと一連の操作を定型処理として括りだすと下記のように書ける。c++ // 2引数展開用 class dispatcher { // 実行 void dispatcher::dispatch(int msgid, const std::string &method, const msgpack::object &params) { if(method==“add”){ msgpack::sbuffer response=unpack_exec_pack(msgid, add, params);

可変長テンプレート引数
可変長テンプレート引数 引き続きmsgpack-rpc-asioを実装しているのだが、可変長テンプレート引数(valiadic template)を使うと関数登録のような場合にうまく書けることがわかった。 昨日は関数オブジェクトからstd::functionの型を得るのに下記のようにしていたのだけど、 ```c++ // ret template Ret helper0(Ret (F::*)(Rest…)); template Ret helper0(Ret (F::*)(Rest…) const); // 1 template A1 helper1(Ret (F::*)(A1, Rest…)); template A1 helper1(Ret (F::*)(A1, Rest…) const); // 2 template A2 helper2(Ret (F::*)(A1, A2, Rest…)); template A2 helper2(Ret (F::*)(A1, A2, Rest…) const); template void add_handler(F handler, const std::string &method) { typedef decltype(handler) functor; typedef decltype(helper0(&functor::operator())) R; typedef decltype(helper1(&functor::operator())) A1; typedef decltype(helper2(&functor::operator())) A2; // register function... std::function<R(A1, A2)> func(handler); } 次のように書けた。c++ template void add_handler(F handler, R(C::*)(A1, A2)const) { // register function… std::function func(handler); }

lambdaの引数の型を得たい
lambdaの引数の型を得たい msgpack-rpcの関数登録の都合上、 lambda関数から引数の型を得たい。 下記のような書き方をしたい。 ```c++ template void register_func(const std::stiring &func_name, R(*handler)(A1, A2)) { // 関数登録 } int main() { // errorになる register_func(“add”, [](int%20a,%20int%20b)->int{ return a+b; }); return 0; } ``` 上記の書き方では普通の関数ポインタを受けることはできるのだが、 std::functionとlambdaは受けられない。 std::functionを受けるには下記のようにすることでできた。 c++ template<typename R, typename A1, typename A2> void register_func(const std::string &func_name, std::function<R(A1, A2) handler) { // } 残り、lambdaを受けられる記述方法を知りたいのだがどうしたらよいものか。 下記のような手はうまくいかなかった・・・ c++ template<typename F, typename R, typename A1, typename A2> void add_handler(F handler, const std::string &method) { std::function<R(A1, A2)> f(handler); //add_handler }