LoginSignup
1

More than 5 years have passed since last update.

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

Posted at

概要

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1