C++
JSON
library
picojson
JSON-RPC-2.0

picojson で JSON-RPC-2.0 を扱う C++ のライブラリー実装

More than 1 year has passed since last update.


概要

picojson を使い JSON-RPC 2.0 を扱う C++ のライブラリー実装をやっつけたので紹介したい。


特徴


  • 依存ライブラリー



  • std=c++1z

  • 用途と機能



    • JSON-RPC 2.0 を扱う


      • request を picojson::value で受けて response ( result or error )を picojson::value で返すファンクター群を boost::signals2::signalstd::string のメソッド名との unordered_map でマッピング・管理する picojson ベースの JSON-RPC 2.0 サーバー server_type ( HTTP 機能は無し )

      • request をお手軽に生成する make_requestmake_request_with_uuidv4

      • request から id, method, params を取得しつつエラーがあれば例外を投げたり、例外から error の response を返す機能

      • result の response をお手軽に生成する make_responsemeke_response_from_request

      • etc.






実装


使い方

基本的な使い方は次の様な手順を想定しています:



  1. server_type のオブジェクト s を生成


  2. s.connectserver_type::method_functor_type な JSON-RPC のメソッドを接続


    • 必要に応じて第3引数に shared_ptr オブジェクトを投げてメソッドの接続の自動管理( track_foreign )を行う(多くの場合にコネクターの手動管理よりもお勧め)



  3. HTTP などで受け取った JSON 文字列の JSON-RPC 2.0 のリクエストを picojson::value にして soperator() へ放り投げる


  4. s に放り投げて返って来た picojson::value ( result or error )を HTTP などで返す


example

#include <usagi/json/picojson/rpc/jsonrpc20.hxx>


#include <memory>

auto main() -> int
{
using namespace usagi::json::picojson;
using namespace usagi::json::picojson::rpc::jsonrpc20;

server_type s;

// 野生のλ
auto fa = []( const value_type& request ){ return value_type( request.get< double >() * 2.0 ); };

// s に存在しないメソッド aaa を uuidv4 の id 付きで呼ぶ
std::cout << "trial-1: " << s( make_request_with_uuidv4( "aaa", value_type( 1.23 ) ) ) << '\n';

// s に fa をメソッド名 aaa として接続しコネクター ca を取得
auto ca = s.connect( "aaa", fa );

// s に存在するメソッド aaa を呼ぶ(期待される型の引数を伴う)
std::cout << "trial-2: " << s( make_request_with_uuidv4( "aaa", value_type( 1.23 ) ) ) << '\n';
// s に存在するメソッド aaa を呼ぶ(期待されない型の引数を伴う)
std::cout << "trial-3: " << s( make_request_with_uuidv4( "aaa", value_type( "1.23" ) ) ) << '\n';

// s に接続した fa をコネクター ca から切断
ca.disconnect();

// 有効なスロットが存在しないメソッド aaa を呼ぶ
std::cout << "trial-4: " << s( make_request_with_uuidv4( "aaa", value_type( 1.23 ) ) ) << '\n';

// shared_ptr の functor
auto fb = std::make_shared< server_type::method_functor_type >( []( const auto& ) { return value_type(); } );

// s に存在しないメソッド bbb を id なし( = null )で呼ぶ
std::cout << "trial-5: " << s( make_request( "bbb", value_type( 1.23 ) ) ) << '\n';

// s に fb の中身の functor を fb をトラッキングさせつつ接続しコネクター cb を取得
auto cb = s.connect( "bbb", *fb, fb );

// s に存在するメソッド bbb を呼ぶ
std::cout << "trial-6: " << s( make_request( "bbb" ) ) << '\n';

// s のメソッド bbb に接続した fb の中身の functor との接続をトラッキングする fb を無効化する(同時に接続が自動的に切断される)
fb.reset();

// (自動的に切断され)有効なスロットが存在しないメソッド bbb を呼ぶ
std::cout << "trial-7: " << s( make_request( "bbb" ) ) << '\n';
}


example の動作結果

trial-1: {"error":{"code":-32601,"data":null,"message":"Method not found"},"id":"7b474b5e-6df1-4200-8ba0-74508f8e6206","jsonrpc":"2.0"}

trial-2: {"id":"869650e4-0869-4304-ace6-27862ff5817b","jsonrpc":"2.0","result":2.46}
trial-3: {"error":{"code":-32603,"data":null,"message":"Internal error ( \"type mismatch! call is<type>() before get<type>()\" && is<double>() ) "},"id":"2d1e3204-493a-4edc-88b2-73b341546e1c","jsonrpc":"2.0"}
trial-4: {"error":{"code":-32601,"data":null,"message":"Method not found ( sigal is empty. ) "},"id":"4c102ebc-23a7-466a-9f4c-b9fcc1c727a5","jsonrpc":"2.0"}
trial-5: {"error":{"code":-32601,"data":null,"message":"Method not found"},"id":null,"jsonrpc":"2.0"}
trial-6: {"id":null,"jsonrpc":"2.0","result":null}
trial-7: {"error":{"code":-32601,"data":null,"message":"Method not found ( sigal is empty. ) "},"id":null,"jsonrpc":"2.0"}


cmake 経由で example を試す場合

git clone git@github.com:usagi/usagi.git

cd usagi
mkdir build
cd build
cmake .. -G Ninja -DEXAMPLES=1
ninja jsonrpc20
./jsonrpc20