引自 规范,JSONRPC“与传输层无关, 相关概念可在同一进程内、套接字、HTTP 或多种消息传递环境中使用”。
为体现这种传输无关性,jsonrpc 库使用 jsonrpc-connection 类的对象,
表示与远程 JSON 端点的连接(有关 Emacs 对象系统的详情,
see EIEIO in EIEIO)。
在现代面向对象术语中,该类是“抽象类”,即:一个可用的连接对象,
其实际类始终是 jsonrpc-connection 的子类。
尽管如此,我们仍可以围绕 jsonrpc-connection 类定义两套独立的 API:
在这种场景下,一个基于 JSONRPC 的新应用会选择 jsonrpc-connection 的一个具体子类,
该子类为端点间交换的 JSONRPC 消息提供传输层支持。
应用通过 make-instance 创建该子类的对象。
为发起与远程端点的通信,应用会将该对象传入
jsonrpc-notify、jsonrpc-request 或
jsonrpc-async-request 等函数。
为处理通常异步到达的、由远程发起的通信,
make-instance 初始化时应设置
:request-dispatcher 与 :notification-dispatcher
这两个 EIEIO 关键字参数。二者均为接收三个参数的函数:
连接对象、远程调用的 JSONRPC 方法名符号、以及 JSONRPC params 对象。
作为 :request-dispatcher 传入的函数,
负责处理远程端点的请求——这类请求期望本地端点(即你正在构建的应用)给出回复。
在该函数内部,你可以正常返回(普通返回)或非本地返回(抛出错误)。
两种退出方式都会通过传输层向远程端点的请求发送回复。
普通返回表示成功响应,返回值必须是可序列化为 JSON 的 Lisp 对象(see 解析和生成 JSON 值)。
该结果会作为 JSONRPC result 对象发送给服务端。
通过调用 jsonrpc-error 实现的非本地返回,
会向服务端发送错误响应。附带的 JSONRPC error 对象的详细信息,
由传入 jsonrpc-error 的参数填充。
由其他类型意外错误触发的非本地返回,同样会发送错误响应
(除非你已设置 debug-on-error,此时会调用 Lisp 调试器,see 发生错误时进入调试器)。
可以使用 jsonrpc 库构建基于“类 JSONRPC”传输协议的应用。
这类协议与 JSONRPC 相似但不完全相同,例如 DAP(调试适配器协议)。
这类协议同样定义请求、响应与通知消息,但格式与 JSONRPC 略有差异。
泛化函数 jsonrpc-convert-to-endpoint 与 jsonrpc-convert-from-endpoint
可用于定制 JSONRPC 内部表示与端点所接受格式之间的转换(see 泛型函数)。
在这种场景下,jsonrpc-connection 被继承以实现不同的底层传输策略
(有关子类化的详情,参见 Inheritance)。
应用构建接口的使用者可实例化该具体类(通过 make-instance 函数),
并使用该策略连接到 JSONRPC 端点。
内置的传输层实现可参见 基于进程的 JSONRPC 连接。
该 API 包含必选与可选部分。
为允许使用者发起 JSONRPC 通信(通知或请求)或回复端点请求,
新的传输层实现必须为新子类提供 jsonrpc-connection-send 泛化函数的特化版本(see 泛型函数)。
该泛化函数会由 jsonrpc-request、jsonrpc-notify 等原语自动调用。
该特化版本应确保参数列表中描述的消息,通过新传输层用于与端点通信的底层通信机制(即 “线路(wire)”)发送。
该 “线路(wire)” 可以是网络套接字、串行接口、HTTP 连接等。
同样,为处理三类远程通信(请求、通知、对本地请求的响应),
传输层实现应在 “线路(wire)” 上检测到可构造 JSONRPC(或类 JSONRPC)消息的数据后,
从 Elisp 中调用 jsonrpc-connection-receive 函数。
最后(可选),如果相关概念适用于该传输层,
jsonrpc-connection 子类应对 jsonrpc-shutdown 与
jsonrpc-running-p 泛化函数添加特化实现。
jsonrpc-shutdown 的特化版本应确保释放用于在线路上监听消息的系统资源
(例如进程、定时器等)。
jsonrpc-running-p 的特化版本应判断这些资源是否仍处于活跃状态,
或已(通过 jsonrpc-shutdown 或其他方式)释放。