仕様を引用すると、JSONRPCは「同一プロセス内、ソケット経由、HTTP経由、あるいは多種多様なメッセージパッシング環境において概念を利用できるという点で、トランスポートに依存しない」とされています。
このアグノスティシズムをモデル化するため、jsonrpc ライブラリでは jsonrpc-connection クラスのオブジェクトを使用しています。これはリモートの JSON
エンドポイントへの接続を表すものです(Emacs のオブジェクトシステムの詳細については、EIEIO
の EIEIO
を参照してください)。現代的なオブジェクト指向の用語で言えば、このクラスは「抽象」クラスであり、つまり、有用な接続オブジェクトの実際のクラスは常に
jsonrpc-connection のサブクラスとなります。それでも、jsonrpc-connection クラスを中心に2つの異なるAPIを定義することが可能です:
このシナリオでは、JSONRPCベースの新規アプリケーション候補が、エンドポイント間でやり取りされるJSONRPCメッセージのトランスポートを提供するjsonrpc-connectionの具体的なサブクラスを選択します。
本アプリケーションは、make-instanceを用いて当該サブクラスのオブジェクトを生成します。リモートエンドポイントへの接続を開始するため、本アプリケーションはこのオブジェクトをjsonrpc-notify、jsonrpc-request、またはjsonrpc-async-requestなどの関数に渡します。
一般的に非同期で届くリモートからのコンタクトを処理する場合、make-instance
のインスタンス化によって :request-dispatcher および :notification-dispatcher の EIEIO
キーワード引数を初期化する必要があります。これらはいずれも、接続オブジェクト、リモートで呼び出された JSONRPC メソッド名を示すシンボル、および
JSONRPC params オブジェクトという 3 つの引数を取る関数です。
:request-dispatcher
として渡された関数は、リモートエンドポイントからのリクエストを処理する役割を担っており、このリクエストではローカルエンドポイント(この場合は開発中のアプリケーション)からの応答が期待されます。この関数内では、ローカルに返す(通常の
return)か、ローカル以外に返す(エラーをスローする)かのいずれかが可能です。リクエストディスパッチャからのいずれの終了においても、リモートエンドポイントのリクエストに対する応答がトランスポート経由で送信されます。
通常のリターンは成功レスポンスを決定し、戻り値はJSONとしてシリアライズ可能なLispオブジェクトである必要があります(JSON値のパースと生成を参照)。結果はJSONRPC result オブジェクトとしてサーバーに転送されます。関数 jsonrpc-error
を呼び出すことで得られる非ローカルリターンは、エラーレスポンスをサーバーに送信します。その他のあらゆる種類の予期しないエラーによってトリガーされた非ローカルリターンも、レスポンスの送信を引き起こします。デバッガが呼び出されることはありません(debug-on-error
を設定している場合は例外で、その場合はLispデバッガが呼び出される可能性があります。エラー発生時のデバッガ起動を参照してください)。
付随するJSONRPC error
オブジェクトの詳細は、(予期しないエラーが発生した場合は)自動的に、(明示的な呼び出しの場合は)jsonrpc-error に渡された内容で埋められます。
例外的に、:code を 32000 に、:data を任意の JSON オブジェクトに設定する jsonrpc-error への明示的な呼び出しは、「エラーなし」という意味を持ち、result が :data
に設定された状態でリモートエンドポイントへの通常のレスポンスをトリガーします。これは、アプリケーションがユーザーの終了などの非ローカルな終了を無害なものとして扱いたい場合に有用です。
jsonrpc ライブラリを使用して、「準
JSONRPC」と表現できるトランスポートプロトコルに基づくアプリケーションを構築することが可能です。これらは、DAP (Debug Adapter Protocol)
のように、JSONRPC
に似てはいますが、完全に同一ではありません。これらのプロトコルでもリクエスト、レスポンス、通知メッセージが定義されていますが、その形式は JSONRPC
とは完全には一致しません。汎用関数 jsonrpc-convert-to-endpoint および
jsonrpc-convert-from-endpoint は、JSONRPC
の内部表現と、エンドポイントが受け付ける形式との間の変換用にカスタマイズできます(汎用関数 を参照)。
このシナリオでは、jsonrpc-connection
をサブクラス化することで、異なる基盤となるトランスポート戦略を実装します(サブクラス化の詳細については、継承を参照してください)。アプリケーション構築インターフェースの利用者は、その後(make-instance 関数を用いて)この具象クラスのオブジェクトをインスタンス化し、その戦略を用いて
JSONRPC エンドポイントに接続できます。組み込みのトランスポート実装については、プロセスベースの JSONRPC
接続を参照してください。
このAPIには必須部分と任意部分があります。
ユーザーがJSONRPCコンタクト(通知またはリクエスト)を開始したり、エンドポイントへのリクエストに応答したりできるように、新しいトランスポート実装では、jsonrpc-connection-send
汎用関数に新しいサブクラス向けの特化を付与する必要があります(汎用関数を参照)。この汎用関数は、jsonrpc-request や jsonrpc-notify
などのプリミティブによって自動的に呼び出されます。この特化により、引数リストで記述されたメッセージが、新しいトランスポートがエンドポイントと通信する際に使用する基盤となる通信メカニズム(いわゆる「ワイヤ」)を通じて確実に送信されるようにする必要があります。この「ワイヤ」は、ネットワークソケット、シリアルインターフェース、HTTP接続などが考えられます。
同様に、3種類のリモートコンタクト(リクエスト、通知、およびローカルリクエストへの応答)を処理するため、トランスポートの実装では、JSONRPC(または準JSONRPC)メッセージの作成に利用可能な「ワイヤ」上のデータを検知した後、Elispから関数
jsonrpc-connection-receive が呼び出されるように構成する必要があります。
最後に、任意として、jsonrpc-connection
サブクラスは、これらの概念がトランスポートに適用される場合、jsonrpc-shutdown および
jsonrpc-running-p ジェネリック関数に特化を追加すべきである。jsonrpc-shutdown
の特化は、回線上でメッセージを待ち受けるために使用されるあらゆるシステムリソース(例:プロセス、タイマーなど)の解放を確実に行うべきである。jsonrpc-running-p の特化は、これらのリソースが依然として有効であるか、あるいは(jsonrpc-shutdown 経由またはその他の方法で)既に解放されているかを示すべきである。