diff --git a/json_rpc/client.nim b/json_rpc/client.nim index dd88280..f432306 100644 --- a/json_rpc/client.nim +++ b/json_rpc/client.nim @@ -31,6 +31,8 @@ type awaiting*: Table[RequestId, Future[JsonString]] lastId: int onDisconnect*: proc() {.gcsafe, raises: [].} + onProcessMessage*: proc(client: RpcClient, line: string): + Result[bool, string] {.gcsafe, raises: [].} GetJsonRpcRequestHeaders* = proc(): seq[(string, string)] {.gcsafe, raises: [].} @@ -67,6 +69,12 @@ method close*(client: RpcClient): Future[void] {.base, gcsafe, async.} = doAssert(false, "`RpcClient.close` not implemented") proc processMessage*(client: RpcClient, line: string): Result[void, string] = + if client.onProcessMessage.isNil.not: + let fallBack = client.onProcessMessage(client, line).valueOr: + return err(error) + if not fallBack: + return ok() + # Note: this doesn't use any transport code so doesn't need to be # differentiated. try: diff --git a/tests/all.nim b/tests/all.nim index feebc94..696a09a 100644 --- a/tests/all.nim +++ b/tests/all.nim @@ -19,4 +19,5 @@ import testhook, test_jrpc_sys, test_router_rpc, - test_callsigs + test_callsigs, + test_client_hook diff --git a/tests/test_client_hook.nim b/tests/test_client_hook.nim new file mode 100644 index 0000000..6a97273 --- /dev/null +++ b/tests/test_client_hook.nim @@ -0,0 +1,76 @@ +# json-rpc +# Copyright (c) 2023 Status Research & Development GmbH +# Licensed under either of +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) +# * MIT license ([LICENSE-MIT](LICENSE-MIT)) +# at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +import + unittest2, + ../json_rpc/rpcclient, + ../json_rpc/rpcserver + +createRpcSigsFromNim(RpcClient): + proc get_Banana(id: int): int + +proc installHandlers(s: RpcServer) = + s.rpc("get_Banana") do(id: int) -> JsonString: + if id == 99: + return "123".JsonString + elif id == 100: + return "\"stop\"".JsonString + else: + return "\"error\"".JsonString + +type + Shadow = ref object + something: int + +proc setupClientHook(client: RpcClient): Shadow = + var shadow = Shadow(something: 0) + client.onProcessMessage = proc(client: RpcClient, line: string): + Result[bool, string] {.gcsafe, raises: [].} = + + try: + let m = JrpcConv.decode(line, JsonNode) + if m["result"].kind == JString: + if m["result"].str == "stop": + shadow.something = 123 + return ok(false) + else: + shadow.something = 77 + return err("not stop") + + return ok(true) + except CatchableError as exc: + return err(exc.msg) + shadow + +suite "test callsigs": + var server = newRpcHttpServer(["127.0.0.1:0"]) + server.installHandlers() + var client = newRpcHttpClient() + let shadow = client.setupClientHook() + + server.start() + waitFor client.connect("http://" & $server.localAddress()[0]) + + test "client onProcessMessage hook": + let res = waitFor client.get_Banana(99) + check res == 123 + check shadow.something == 0 + + expect JsonRpcError: + let res2 = waitFor client.get_Banana(123) + check res2 == 0 + check shadow.something == 77 + + expect InvalidResponse: + let res2 = waitFor client.get_Banana(100) + check res2 == 0 + check shadow.something == 123 + + waitFor server.stop() + waitFor server.closeWait()