]> nmode's Git Repositories - signal-cli/commitdiff
Switch to jsonrpsee
authorAsamK <asamk@gmx.de>
Thu, 10 Aug 2023 22:21:38 +0000 (00:21 +0200)
committerAsamK <asamk@gmx.de>
Thu, 10 Aug 2023 22:36:22 +0000 (00:36 +0200)
Fixes #1275

client/Cargo.lock
client/Cargo.toml
client/src/cli.rs
client/src/jsonrpc.rs
client/src/main.rs
client/src/tcp.rs [deleted file]
client/src/transports/ipc.rs [new file with mode: 0644]
client/src/transports/mod.rs [new file with mode: 0644]
client/src/transports/stream_codec.rs [new file with mode: 0644]
client/src/transports/tcp.rs [new file with mode: 0644]

index aed17e7f7f83fca038fdb0c7fb5f951d4b5bc692..45764a2224c94bfcc954ee55526b42cb37fb8a59 100644 (file)
@@ -17,15 +17,6 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
-[[package]]
-name = "aho-corasick"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b8f9420f797f2d9e935edf629310eb938a0d839f984e25327f3c7eed22300c"
-dependencies = [
- "memchr",
-]
-
 [[package]]
 name = "anstream"
 version = "0.3.2"
@@ -81,6 +72,26 @@ version = "1.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
 
+[[package]]
+name = "async-lock"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
+dependencies = [
+ "event-listener",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.1.0"
@@ -102,6 +113,21 @@ dependencies = [
  "rustc-demangle",
 ]
 
+[[package]]
+name = "base64"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
+
+[[package]]
+name = "beef"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -115,14 +141,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
 
 [[package]]
-name = "bstr"
-version = "1.6.0"
+name = "bumpalo"
+version = "3.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
-dependencies = [
- "memchr",
- "serde",
-]
+checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
 
 [[package]]
 name = "bytes"
@@ -195,23 +217,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
 
 [[package]]
-name = "convert_case"
-version = "0.4.0"
+name = "core-foundation"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
 
 [[package]]
-name = "derive_more"
-version = "0.99.17"
+name = "core-foundation-sys"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
-dependencies = [
- "convert_case",
- "proc-macro2",
- "quote",
- "rustc_version",
- "syn 1.0.109",
-]
+checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "errno"
@@ -235,31 +260,16 @@ dependencies = [
 ]
 
 [[package]]
-name = "fnv"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
-
-[[package]]
-name = "futures"
-version = "0.1.31"
+name = "event-listener"
+version = "2.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
+checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
 
 [[package]]
-name = "futures"
-version = "0.3.28"
+name = "fnv"
+version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
-dependencies = [
- "futures-channel",
- "futures-core",
- "futures-executor",
- "futures-io",
- "futures-sink",
- "futures-task",
- "futures-util",
-]
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
 name = "futures-channel"
@@ -268,7 +278,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
 dependencies = [
  "futures-core",
- "futures-sink",
 ]
 
 [[package]]
@@ -277,24 +286,6 @@ version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
 
-[[package]]
-name = "futures-executor"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
-dependencies = [
- "futures-core",
- "futures-task",
- "futures-util",
- "num_cpus",
-]
-
-[[package]]
-name = "futures-io"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
-
 [[package]]
 name = "futures-macro"
 version = "0.3.28"
@@ -318,36 +309,27 @@ version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
 
+[[package]]
+name = "futures-timer"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
+
 [[package]]
 name = "futures-util"
 version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
 dependencies = [
- "futures 0.1.31",
- "futures-channel",
  "futures-core",
- "futures-io",
  "futures-macro",
  "futures-sink",
  "futures-task",
- "memchr",
  "pin-project-lite",
  "pin-utils",
  "slab",
 ]
 
-[[package]]
-name = "getrandom"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.9.0+wasi-snapshot-preview1",
-]
-
 [[package]]
 name = "gimli"
 version = "0.27.3"
@@ -355,18 +337,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
 
 [[package]]
-name = "globset"
-version = "0.4.13"
+name = "h2"
+version = "0.3.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d"
+checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049"
 dependencies = [
- "aho-corasick",
- "bstr",
+ "bytes",
  "fnv",
- "log",
- "regex",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap 1.9.3",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
 ]
 
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+
 [[package]]
 name = "heck"
 version = "0.4.1"
@@ -380,12 +380,97 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
 
 [[package]]
-name = "instant"
-version = "0.1.12"
+name = "http"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
 dependencies = [
- "cfg-if",
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
+dependencies = [
+ "bytes",
+ "http",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
+
+[[package]]
+name = "httpdate"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
+
+[[package]]
+name = "hyper"
+version = "0.14.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2 0.4.9",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97"
+dependencies = [
+ "futures-util",
+ "http",
+ "hyper",
+ "log",
+ "rustls",
+ "rustls-native-certs",
+ "tokio",
+ "tokio-rustls",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.0",
 ]
 
 [[package]]
@@ -406,7 +491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
 dependencies = [
  "hermit-abi",
- "rustix 0.38.7",
+ "rustix 0.38.8",
  "windows-sys",
 ]
 
@@ -417,66 +502,76 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
 
 [[package]]
-name = "jsonrpc-client-transports"
-version = "18.0.0"
-source = "git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params#8a68f95e202943fd338fd0c14da08c2dc8f6e6a6"
+name = "js-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
 dependencies = [
- "derive_more",
- "futures 0.3.28",
- "jsonrpc-core 18.0.0 (git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params)",
- "jsonrpc-pubsub",
- "jsonrpc-server-utils 18.0.0 (git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params)",
- "log",
- "parity-tokio-ipc",
- "serde",
- "serde_json",
- "tokio",
+ "wasm-bindgen",
 ]
 
 [[package]]
-name = "jsonrpc-core"
-version = "18.0.0"
+name = "jsonrpsee"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb"
+checksum = "e5f3783308bddc49d0218307f66a09330c106fbd792c58bac5c8dc294fdd0f98"
 dependencies = [
- "futures 0.3.28",
- "futures-executor",
- "futures-util",
- "log",
- "serde",
- "serde_derive",
- "serde_json",
+ "jsonrpsee-core",
+ "jsonrpsee-http-client",
+ "jsonrpsee-proc-macros",
+ "jsonrpsee-types",
+ "tracing",
 ]
 
 [[package]]
-name = "jsonrpc-core"
-version = "18.0.0"
-source = "git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params#8a68f95e202943fd338fd0c14da08c2dc8f6e6a6"
+name = "jsonrpsee-core"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aaa4c4d5fb801dcc316d81f76422db259809037a86b3194ae538dd026b05ed7"
 dependencies = [
- "futures 0.3.28",
- "futures-executor",
+ "anyhow",
+ "async-lock",
+ "async-trait",
+ "beef",
+ "futures-timer",
  "futures-util",
- "log",
+ "hyper",
+ "jsonrpsee-types",
+ "rustc-hash",
  "serde",
- "serde_derive",
  "serde_json",
+ "thiserror",
+ "tokio",
+ "tokio-stream",
+ "tracing",
 ]
 
 [[package]]
-name = "jsonrpc-core-client"
-version = "18.0.0"
+name = "jsonrpsee-http-client"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0"
+checksum = "aa7165efcbfbc951d180162ff28fe91b657ed81925e37a35e4a396ce12109f96"
 dependencies = [
- "futures 0.3.28",
- "jsonrpc-client-transports",
+ "async-trait",
+ "hyper",
+ "hyper-rustls",
+ "jsonrpsee-core",
+ "jsonrpsee-types",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "tokio",
+ "tower",
+ "tracing",
 ]
 
 [[package]]
-name = "jsonrpc-derive"
-version = "18.0.0"
-source = "git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params#8a68f95e202943fd338fd0c14da08c2dc8f6e6a6"
+name = "jsonrpsee-proc-macros"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21dc12b1d4f16a86e8c522823c4fab219c88c03eb7c924ec0501a64bf12e058b"
 dependencies = [
+ "heck",
  "proc-macro-crate",
  "proc-macro2",
  "quote",
@@ -484,60 +579,19 @@ dependencies = [
 ]
 
 [[package]]
-name = "jsonrpc-pubsub"
-version = "18.0.0"
-source = "git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params#8a68f95e202943fd338fd0c14da08c2dc8f6e6a6"
-dependencies = [
- "futures 0.3.28",
- "jsonrpc-core 18.0.0 (git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params)",
- "lazy_static",
- "log",
- "parking_lot",
- "rand",
- "serde",
-]
-
-[[package]]
-name = "jsonrpc-server-utils"
-version = "18.0.0"
+name = "jsonrpsee-types"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4"
+checksum = "00aa7cc87bc42e04e26c8ac3e7186142f7fd2949c763d9b6a7e64a69672d8fb2"
 dependencies = [
- "bytes",
- "futures 0.3.28",
- "globset",
- "jsonrpc-core 18.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static",
- "log",
- "tokio",
- "tokio-stream",
- "tokio-util",
- "unicase",
-]
-
-[[package]]
-name = "jsonrpc-server-utils"
-version = "18.0.0"
-source = "git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params#8a68f95e202943fd338fd0c14da08c2dc8f6e6a6"
-dependencies = [
- "bytes",
- "futures 0.3.28",
- "globset",
- "jsonrpc-core 18.0.0 (git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params)",
- "lazy_static",
- "log",
- "tokio",
- "tokio-stream",
- "tokio-util",
- "unicase",
+ "anyhow",
+ "beef",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "tracing",
 ]
 
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
 [[package]]
 name = "libc"
 version = "0.2.147"
@@ -556,16 +610,6 @@ version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
 
-[[package]]
-name = "lock_api"
-version = "0.4.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
-dependencies = [
- "autocfg",
- "scopeguard",
-]
-
 [[package]]
 name = "log"
 version = "0.4.19"
@@ -594,7 +638,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
 dependencies = [
  "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
  "windows-sys",
 ]
 
@@ -624,42 +668,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
 [[package]]
-name = "parity-tokio-ipc"
-version = "0.9.0"
+name = "openssl-probe"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6"
-dependencies = [
- "futures 0.3.28",
- "libc",
- "log",
- "rand",
- "tokio",
- "winapi",
-]
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 [[package]]
-name = "parking_lot"
-version = "0.11.2"
+name = "pin-project"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
+checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
 dependencies = [
- "instant",
- "lock_api",
- "parking_lot_core",
+ "pin-project-internal",
 ]
 
 [[package]]
-name = "parking_lot_core"
-version = "0.8.6"
+name = "pin-project-internal"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
+checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
 dependencies = [
- "cfg-if",
- "instant",
- "libc",
- "redox_syscall",
- "smallvec",
- "winapi",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
 ]
 
 [[package]]
@@ -674,19 +705,14 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
-[[package]]
-name = "ppv-lite86"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
 [[package]]
 name = "proc-macro-crate"
-version = "0.1.5"
+version = "1.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
+checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
 dependencies = [
- "toml",
+ "once_cell",
+ "toml_edit",
 ]
 
 [[package]]
@@ -708,144 +734,150 @@ dependencies = [
 ]
 
 [[package]]
-name = "rand"
-version = "0.7.3"
+name = "ring"
+version = "0.16.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
 dependencies = [
- "getrandom",
+ "cc",
  "libc",
- "rand_chacha",
- "rand_core",
- "rand_hc",
+ "once_cell",
+ "spin",
+ "untrusted",
+ "web-sys",
+ "winapi",
 ]
 
 [[package]]
-name = "rand_chacha"
-version = "0.2.2"
+name = "rustc-demangle"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustix"
+version = "0.37.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
 dependencies = [
- "ppv-lite86",
- "rand_core",
+ "bitflags 1.3.2",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys 0.3.8",
+ "windows-sys",
 ]
 
 [[package]]
-name = "rand_core"
-version = "0.5.1"
+name = "rustix"
+version = "0.38.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
 dependencies = [
- "getrandom",
+ "bitflags 2.3.3",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.5",
+ "windows-sys",
 ]
 
 [[package]]
-name = "rand_hc"
-version = "0.2.0"
+name = "rustls"
+version = "0.21.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb"
 dependencies = [
- "rand_core",
+ "log",
+ "ring",
+ "rustls-webpki",
+ "sct",
 ]
 
 [[package]]
-name = "redox_syscall"
-version = "0.2.16"
+name = "rustls-native-certs"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
 dependencies = [
- "bitflags 1.3.2",
+ "openssl-probe",
+ "rustls-pemfile",
+ "schannel",
+ "security-framework",
 ]
 
 [[package]]
-name = "regex"
-version = "1.9.3"
+name = "rustls-pemfile"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a"
+checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
 dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
+ "base64",
 ]
 
 [[package]]
-name = "regex-automata"
-version = "0.3.6"
+name = "rustls-webpki"
+version = "0.101.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
+checksum = "261e9e0888cba427c3316e6322805653c9425240b6fd96cee7cb671ab70ab8d0"
 dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
+ "ring",
+ "untrusted",
 ]
 
 [[package]]
-name = "regex-syntax"
-version = "0.7.4"
+name = "ryu"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
+checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
 
 [[package]]
-name = "rustc-demangle"
-version = "0.1.23"
+name = "schannel"
+version = "0.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
+dependencies = [
+ "windows-sys",
+]
 
 [[package]]
-name = "rustc_version"
-version = "0.4.0"
+name = "sct"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
 dependencies = [
- "semver",
+ "ring",
+ "untrusted",
 ]
 
 [[package]]
-name = "rustix"
-version = "0.37.23"
+name = "security-framework"
+version = "2.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
+checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
 dependencies = [
  "bitflags 1.3.2",
- "errno",
- "io-lifetimes",
+ "core-foundation",
+ "core-foundation-sys",
  "libc",
- "linux-raw-sys 0.3.8",
- "windows-sys",
+ "security-framework-sys",
 ]
 
 [[package]]
-name = "rustix"
-version = "0.38.7"
+name = "security-framework-sys"
+version = "2.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399"
+checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
 dependencies = [
- "bitflags 2.3.3",
- "errno",
+ "core-foundation-sys",
  "libc",
- "linux-raw-sys 0.4.5",
- "windows-sys",
 ]
 
-[[package]]
-name = "ryu"
-version = "1.0.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
-
-[[package]]
-name = "scopeguard"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
-
-[[package]]
-name = "semver"
-version = "1.0.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
-
 [[package]]
 name = "serde"
 version = "1.0.183"
@@ -882,16 +914,16 @@ name = "signal-cli-client"
 version = "0.0.1"
 dependencies = [
  "anyhow",
+ "bytes",
  "clap",
- "jsonrpc-client-transports",
- "jsonrpc-core 18.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core-client",
- "jsonrpc-derive",
- "jsonrpc-server-utils 18.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures-util",
+ "jsonrpsee",
  "log",
  "serde",
  "serde_json",
+ "thiserror",
  "tokio",
+ "tokio-util",
 ]
 
 [[package]]
@@ -904,10 +936,14 @@ dependencies = [
 ]
 
 [[package]]
-name = "smallvec"
-version = "1.11.0"
+name = "socket2"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
+checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
+dependencies = [
+ "libc",
+ "winapi",
+]
 
 [[package]]
 name = "socket2"
@@ -919,6 +955,12 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "spin"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+
 [[package]]
 name = "strsim"
 version = "0.10.0"
@@ -957,6 +999,26 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "thiserror"
+version = "1.0.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
 [[package]]
 name = "tokio"
 version = "1.30.0"
@@ -969,7 +1031,7 @@ dependencies = [
  "mio",
  "num_cpus",
  "pin-project-lite",
- "socket2",
+ "socket2 0.5.3",
  "tokio-macros",
  "windows-sys",
 ]
@@ -985,6 +1047,16 @@ dependencies = [
  "syn 2.0.28",
 ]
 
+[[package]]
+name = "tokio-rustls"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
 [[package]]
 name = "tokio-stream"
 version = "0.1.14"
@@ -998,42 +1070,113 @@ dependencies = [
 
 [[package]]
 name = "tokio-util"
-version = "0.6.10"
+version = "0.7.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507"
+checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
 dependencies = [
  "bytes",
  "futures-core",
  "futures-sink",
- "log",
  "pin-project-lite",
  "tokio",
+ "tracing",
 ]
 
 [[package]]
-name = "toml"
-version = "0.5.11"
+name = "toml_datetime"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+
+[[package]]
+name = "toml_edit"
+version = "0.19.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
 dependencies = [
- "serde",
+ "indexmap 2.0.0",
+ "toml_datetime",
+ "winnow",
 ]
 
 [[package]]
-name = "unicase"
-version = "2.6.0"
+name = "tower"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
 dependencies = [
- "version_check",
+ "futures-core",
+ "futures-util",
+ "pin-project",
+ "pin-project-lite",
+ "tower-layer",
+ "tower-service",
+ "tracing",
 ]
 
+[[package]]
+name = "tower-layer"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
+
+[[package]]
+name = "tower-service"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
+
+[[package]]
+name = "tracing"
+version = "0.1.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
+dependencies = [
+ "cfg-if",
+ "log",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
+
 [[package]]
 name = "unicode-ident"
 version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
 
+[[package]]
+name = "untrusted"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
+
 [[package]]
 name = "utf8parse"
 version = "0.2.1"
@@ -1041,22 +1184,83 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
 
 [[package]]
-name = "version_check"
-version = "0.9.4"
+name = "want"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
 
 [[package]]
 name = "wasi"
-version = "0.9.0+wasi-snapshot-preview1"
+version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
+name = "wasm-bindgen"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+
+[[package]]
+name = "web-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
 
 [[package]]
 name = "winapi"
@@ -1145,3 +1349,12 @@ name = "windows_x86_64_msvc"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+
+[[package]]
+name = "winnow"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19f495880723d0999eb3500a9064d8dbcf836460b24c17df80ea7b5794053aac"
+dependencies = [
+ "memchr",
+]
index 9e3cd4dfd31548d47a8d54ee9680caf1528b49ca..fb77b86c117815ade98da8a480fa30b08a51b23b 100644 (file)
@@ -8,18 +8,16 @@ edition = "2021"
 [dependencies]
 anyhow = "1"
 clap = { version = "4", features = ["cargo", "derive", "wrap_help"] }
-jsonrpc-core = "18"
-jsonrpc-core-client = "18"
-jsonrpc-client-transports = { version = "18", default-features = false, features = [
-    "ipc",
-] }
-jsonrpc-derive = "18"
-jsonrpc-server-utils = "18"
 log = "0.4"
 serde = "1"
 serde_json = "1"
-tokio = { version = "1", features = ["rt", "macros", "net"] }
-
-[patch.crates-io]
-jsonrpc-client-transports = { git = "https://github.com/AsamK/jsonrpc", branch = "client_subscribe_named_params" }
-jsonrpc-derive = { git = "https://github.com/AsamK/jsonrpc", branch = "client_subscribe_named_params" }
+tokio = { version = "1", features = ["rt", "macros", "net", "rt-multi-thread"] }
+jsonrpsee = { version = "0.19.0", features = [
+    "macros",
+    "async-client",
+    "http-client",
+] }
+bytes = "1"
+tokio-util = "0.7"
+futures-util = "0.3"
+thiserror = "1"
index ca80929017b31558083407009926afea4b928ec9..6a8dd3613dedaad0cb8f571884b37548700f32a0 100644 (file)
@@ -10,13 +10,17 @@ pub struct Cli {
     pub account: Option<String>,
 
     /// TCP host and port of signal-cli daemon
-    #[arg(long)]
+    #[arg(long, conflicts_with = "json_rpc_http")]
     pub json_rpc_tcp: Option<Option<SocketAddr>>,
 
     /// UNIX socket address and port of signal-cli daemon
-    #[arg(long)]
+    #[arg(long, conflicts_with = "json_rpc_tcp")]
     pub json_rpc_socket: Option<Option<OsString>>,
 
+    /// HTTP URL of signal-cli daemon
+    #[arg(long, conflicts_with = "json_rpc_socket")]
+    pub json_rpc_http: Option<Option<String>>,
+
     #[arg(value_enum, long, default_value_t = OutputTypes::Json)]
     pub output: OutputTypes,
 
index 51e41c198b68fa2eee10e6f65ea2e34d24a88bc4..cd2573053218abbdd27a194baa8d42cf77cc8bd3 100644 (file)
@@ -1,49 +1,59 @@
 use std::path::Path;
 
-use jsonrpc_client_transports::{transports::ipc, RpcError};
-use jsonrpc_core::serde::Deserialize;
-use jsonrpc_derive::rpc;
+use jsonrpsee::async_client::ClientBuilder;
+use jsonrpsee::core::client::SubscriptionClientT;
+use jsonrpsee::core::Error;
+use jsonrpsee::http_client::HttpClientBuilder;
+use jsonrpsee::proc_macros::rpc;
+use serde::Deserialize;
+use serde_json::Value;
 use tokio::net::ToSocketAddrs;
 
-pub type SignalCliClient = gen_client::Client;
-
-#[rpc(client, params = "named")]
+#[rpc(client)]
 pub trait Rpc {
-    #[rpc(name = "addDevice", params = "named")]
-    fn add_device(&self, account: Option<String>, uri: String) -> Result<Value>;
+    #[method(name = "addDevice", param_kind = map)]
+    async fn add_device(
+        &self,
+        account: Option<String>,
+        uri: String,
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "block", params = "named")]
+    #[method(name = "block", param_kind = map)]
     fn block(
         &self,
         account: Option<String>,
         recipients: Vec<String>,
         #[allow(non_snake_case)] groupIds: Vec<String>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "deleteLocalAccountData", params = "named")]
+    #[method(name = "deleteLocalAccountData", param_kind = map)]
     fn delete_local_account_data(
         &self,
         account: Option<String>,
         #[allow(non_snake_case)] ignoreRegistered: Option<bool>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "getUserStatus", params = "named")]
-    fn get_user_status(&self, account: Option<String>, recipients: Vec<String>) -> Result<Value>;
+    #[method(name = "getUserStatus", param_kind = map)]
+    fn get_user_status(
+        &self,
+        account: Option<String>,
+        recipients: Vec<String>,
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "joinGroup", params = "named")]
-    fn join_group(&self, account: Option<String>, uri: String) -> Result<Value>;
+    #[method(name = "joinGroup", param_kind = map)]
+    fn join_group(&self, account: Option<String>, uri: String) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "finishLink", params = "named")]
+    #[method(name = "finishLink", param_kind = map)]
     fn finish_link(
         &self,
         #[allow(non_snake_case)] deviceLinkUri: String,
         #[allow(non_snake_case)] deviceName: String,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "listAccounts", params = "named")]
-    fn list_accounts(&self) -> Result<Value>;
+    #[method(name = "listAccounts", param_kind = map)]
+    fn list_accounts(&self) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "listContacts", params = "named")]
+    #[method(name = "listContacts", param_kind = map)]
     fn list_contacts(
         &self,
         account: Option<String>,
@@ -51,60 +61,64 @@ pub trait Rpc {
         #[allow(non_snake_case)] allRecipients: bool,
         blocked: Option<bool>,
         name: Option<String>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "listDevices", params = "named")]
-    fn list_devices(&self, account: Option<String>) -> Result<Value>;
+    #[method(name = "listDevices", param_kind = map)]
+    fn list_devices(&self, account: Option<String>) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "listGroups", params = "named")]
+    #[method(name = "listGroups", param_kind = map)]
     fn list_groups(
         &self,
         account: Option<String>,
         #[allow(non_snake_case)] groupIds: Vec<String>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "listIdentities", params = "named")]
-    fn list_identities(&self, account: Option<String>, number: Option<String>) -> Result<Value>;
+    #[method(name = "listIdentities", param_kind = map)]
+    fn list_identities(
+        &self,
+        account: Option<String>,
+        number: Option<String>,
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "listStickerPacks", params = "named")]
-    fn list_sticker_packs(&self, account: Option<String>) -> Result<Value>;
+    #[method(name = "listStickerPacks", param_kind = map)]
+    fn list_sticker_packs(&self, account: Option<String>) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "quitGroup", params = "named")]
+    #[method(name = "quitGroup", param_kind = map)]
     fn quit_group(
         &self,
         account: Option<String>,
         #[allow(non_snake_case)] groupId: String,
         delete: bool,
         admins: Vec<String>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "register", params = "named")]
+    #[method(name = "register", param_kind = map)]
     fn register(
         &self,
         account: Option<String>,
         voice: bool,
         captcha: Option<String>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "removeContact", params = "named")]
+    #[method(name = "removeContact", param_kind = map)]
     fn remove_contact(
         &self,
         account: Option<String>,
         recipient: String,
         forget: bool,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "removeDevice", params = "named")]
+    #[method(name = "removeDevice", param_kind = map)]
     fn remove_device(
         &self,
         account: Option<String>,
         #[allow(non_snake_case)] deviceId: u32,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "removePin", params = "named")]
-    fn remove_pin(&self, account: Option<String>) -> Result<Value>;
+    #[method(name = "removePin", param_kind = map)]
+    fn remove_pin(&self, account: Option<String>) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "remoteDelete", params = "named")]
+    #[method(name = "remoteDelete", param_kind = map)]
     fn remote_delete(
         &self,
         account: Option<String>,
@@ -112,9 +126,9 @@ pub trait Rpc {
         recipients: Vec<String>,
         #[allow(non_snake_case)] groupIds: Vec<String>,
         #[allow(non_snake_case)] noteToSelf: bool,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "send", params = "named")]
+    #[method(name = "send", param_kind = map)]
     fn send(
         &self,
         account: Option<String>,
@@ -132,21 +146,21 @@ pub trait Rpc {
         sticker: Option<String>,
         #[allow(non_snake_case)] storyTimestamp: Option<u64>,
         #[allow(non_snake_case)] storyAuthor: Option<String>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "sendContacts", params = "named")]
-    fn send_contacts(&self, account: Option<String>) -> Result<Value>;
+    #[method(name = "sendContacts", param_kind = map)]
+    fn send_contacts(&self, account: Option<String>) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "sendPaymentNotification", params = "named")]
+    #[method(name = "sendPaymentNotification", param_kind = map)]
     fn send_payment_notification(
         &self,
         account: Option<String>,
         recipient: String,
         receipt: String,
         note: String,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "sendReaction", params = "named")]
+    #[method(name = "sendReaction", param_kind = map)]
     fn send_reaction(
         &self,
         account: Option<String>,
@@ -158,75 +172,75 @@ pub trait Rpc {
         #[allow(non_snake_case)] targetTimestamp: u64,
         remove: bool,
         story: bool,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "sendReceipt", params = "named")]
+    #[method(name = "sendReceipt", param_kind = map)]
     fn send_receipt(
         &self,
         account: Option<String>,
         recipient: String,
         #[allow(non_snake_case)] targetTimestamps: Vec<u64>,
         r#type: String,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "sendSyncRequest", params = "named")]
-    fn send_sync_request(&self, account: Option<String>) -> Result<Value>;
+    #[method(name = "sendSyncRequest", param_kind = map)]
+    fn send_sync_request(&self, account: Option<String>) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "sendTyping", params = "named")]
+    #[method(name = "sendTyping", param_kind = map)]
     fn send_typing(
         &self,
         account: Option<String>,
         recipients: Vec<String>,
         #[allow(non_snake_case)] groupIds: Vec<String>,
         stop: bool,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "setPin", params = "named")]
-    fn set_pin(&self, account: Option<String>, pin: String) -> Result<Value>;
+    #[method(name = "setPin", param_kind = map)]
+    fn set_pin(&self, account: Option<String>, pin: String) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "submitRateLimitChallenge", params = "named")]
+    #[method(name = "submitRateLimitChallenge", param_kind = map)]
     fn submit_rate_limit_challenge(
         &self,
         account: Option<String>,
         challenge: String,
         captcha: String,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "startLink", params = "named")]
-    fn start_link(&self, account: Option<String>) -> Result<JsonLink>;
+    #[method(name = "startLink", param_kind = map)]
+    fn start_link(&self, account: Option<String>) -> Result<JsonLink, ErrorObjectOwned>;
 
-    #[rpc(name = "trust", params = "named")]
+    #[method(name = "trust", param_kind = map)]
     fn trust(
         &self,
         account: Option<String>,
         recipient: String,
         #[allow(non_snake_case)] trustAllKnownKeys: bool,
         #[allow(non_snake_case)] verifiedSafetyNumber: Option<String>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "unblock", params = "named")]
+    #[method(name = "unblock", param_kind = map)]
     fn unblock(
         &self,
         account: Option<String>,
         recipients: Vec<String>,
         #[allow(non_snake_case)] groupIds: Vec<String>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "unregister", params = "named")]
+    #[method(name = "unregister", param_kind = map)]
     fn unregister(
         &self,
         account: Option<String>,
         #[allow(non_snake_case)] deleteAccount: bool,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "updateAccount", params = "named")]
+    #[method(name = "updateAccount", param_kind = map)]
     fn update_account(
         &self,
         account: Option<String>,
         #[allow(non_snake_case)] deviceName: Option<String>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "updateConfiguration", params = "named")]
+    #[method(name = "updateConfiguration", param_kind = map)]
     fn update_configuration(
         &self,
         account: Option<String>,
@@ -234,18 +248,18 @@ pub trait Rpc {
         #[allow(non_snake_case)] unidentifiedDeliveryIndicators: Option<bool>,
         #[allow(non_snake_case)] typingIndicators: Option<bool>,
         #[allow(non_snake_case)] linkPreviews: Option<bool>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "updateContact", params = "named")]
+    #[method(name = "updateContact", param_kind = map)]
     fn update_contact(
         &self,
         account: Option<String>,
         recipient: String,
         name: Option<String>,
         expiration: Option<u32>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "updateGroup", params = "named")]
+    #[method(name = "updateGroup", param_kind = map)]
     fn update_group(
         &self,
         account: Option<String>,
@@ -265,9 +279,9 @@ pub trait Rpc {
         #[allow(non_snake_case)] setPermissionEditDetails: Option<String>,
         #[allow(non_snake_case)] setPermissionSendMessages: Option<String>,
         expiration: Option<u32>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "updateProfile", params = "named")]
+    #[method(name = "updateProfile", param_kind = map)]
     fn update_profile(
         &self,
         account: Option<String>,
@@ -278,32 +292,33 @@ pub trait Rpc {
         #[allow(non_snake_case)] mobileCoinAddress: Option<String>,
         avatar: Option<String>,
         #[allow(non_snake_case)] removeAvatar: bool,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "uploadStickerPack", params = "named")]
-    fn upload_sticker_pack(&self, account: Option<String>, path: String) -> Result<Value>;
+    #[method(name = "uploadStickerPack", param_kind = map)]
+    fn upload_sticker_pack(
+        &self,
+        account: Option<String>,
+        path: String,
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[rpc(name = "verify", params = "named")]
+    #[method(name = "verify", param_kind = map)]
     fn verify(
         &self,
         account: Option<String>,
         #[allow(non_snake_case)] verificationCode: String,
         pin: Option<String>,
-    ) -> Result<Value>;
+    ) -> Result<Value, ErrorObjectOwned>;
 
-    #[pubsub(
-        subscription = "receive",
-        subscribe,
-        name = "subscribeReceive",
-        params = "named"
+    #[subscription(
+        name = "subscribeReceive" => "receive",
+        unsubscribe = "unsubscribeReceive",
+        item = Value,
+        param_kind = map
     )]
-    fn subscribe_receive(&self, _: Self::Metadata, _: Subscriber<Value>, account: Option<String>);
+    async fn subscribe_receive(&self, account: Option<String>) -> SubscriptionResult;
 
-    #[pubsub(subscription = "receive", unsubscribe, name = "unsubscribeReceive")]
-    fn unsubscribe_receive(&self, _: Option<Self::Metadata>, _: SubscriptionId) -> Result<bool>;
-
-    #[rpc(name = "version")]
-    fn version(&self) -> Result<Value>;
+    #[method(name = "version")]
+    fn version(&self) -> Result<Value, ErrorObjectOwned>;
 }
 
 #[derive(Deserialize)]
@@ -312,10 +327,20 @@ pub struct JsonLink {
     pub device_link_uri: String,
 }
 
-pub async fn connect_tcp(tcp: impl ToSocketAddrs) -> Result<SignalCliClient, RpcError> {
-    super::tcp::connect::<_, SignalCliClient>(tcp).await
+pub async fn connect_tcp(tcp: impl ToSocketAddrs) -> Result<impl SubscriptionClientT, Error> {
+    let (sender, receiver) = super::transports::tcp::connect(tcp).await?;
+
+    Ok(ClientBuilder::default().build_with_tokio(sender, receiver))
+}
+
+pub async fn connect_unix(
+    socket_path: impl AsRef<Path>,
+) -> Result<impl SubscriptionClientT, Error> {
+    let (sender, receiver) = super::transports::ipc::connect(socket_path).await?;
+
+    Ok(ClientBuilder::default().build_with_tokio(sender, receiver))
 }
 
-pub async fn connect_unix(socket_path: impl AsRef<Path>) -> Result<SignalCliClient, RpcError> {
-    ipc::connect::<_, SignalCliClient>(socket_path).await
+pub async fn connect_http(uri: &str) -> Result<impl SubscriptionClientT, Error> {
+    HttpClientBuilder::default().build(uri)
 }
index ea9cb9c83c1087a6b8d0553d945f9c9acefec87a..f4ab67f93afc3b7b332d279f1d665a6e0a2992ea 100644 (file)
@@ -1,40 +1,53 @@
-use clap::Parser;
-use jsonrpc_client_transports::{RpcError, TypedSubscriptionStream};
-use jsonrpc_core::{futures_util::StreamExt, Value};
 use std::{path::PathBuf, time::Duration};
+
+use clap::Parser;
+use cli::Cli;
+use jsonrpsee::core::client::{Subscription, SubscriptionClientT};
+use jsonrpsee::core::Error as RpcError;
+use serde_json::Value;
 use tokio::{select, time::sleep};
 
 use crate::cli::{GroupPermission, LinkState};
+use crate::jsonrpc::RpcClient;
 
 mod cli;
-#[allow(clippy::too_many_arguments)]
+#[allow(non_snake_case, clippy::too_many_arguments)]
 mod jsonrpc;
-mod tcp;
+mod transports;
 
 const DEFAULT_TCP: &str = "127.0.0.1:7583";
 const DEFAULT_SOCKET_SUFFIX: &str = "signal-cli/socket";
+const DEFAULT_HTTP: &str = "http://localhost:8080/api/v1/rpc";
 
 #[tokio::main]
 async fn main() -> Result<(), anyhow::Error> {
     let cli = cli::Cli::parse();
 
-    let client = connect(&cli)
-        .await
-        .map_err(|e| anyhow::anyhow!("Failed to connect to socket: {e}"))?;
+    let result = connect(cli).await;
+
+    match result {
+        Ok(Value::Null) => {}
+        Ok(v) => println!("{v}"),
+        Err(e) => return Err(anyhow::anyhow!("JSON-RPC command failed: {e:?}")),
+    }
+    Ok(())
+}
 
-    let result = match cli.command {
+async fn handle_command(
+    cli: Cli,
+    client: impl SubscriptionClientT + Sync,
+) -> Result<Value, RpcError> {
+    match cli.command {
         cli::CliCommands::Receive { timeout } => {
-            let mut stream = client
-                .subscribe_receive(cli.account)
-                .map_err(|e| anyhow::anyhow!("JSON-RPC command failed: {:?}", e))?;
+            let mut stream = client.subscribe_receive(cli.account).await?;
 
             {
                 while let Some(v) = stream_next(timeout, &mut stream).await {
-                    let v = v.map_err(|e| anyhow::anyhow!("JSON-RPC command failed: {:?}", e))?;
+                    let v = v?;
                     println!("{v}");
                 }
             }
-            return Ok(());
+            Ok(Value::Null)
         }
         cli::CliCommands::AddDevice { uri } => client.add_device(cli.account, uri).await,
         cli::CliCommands::Block {
@@ -54,7 +67,7 @@ async fn main() -> Result<(), anyhow::Error> {
             let url = client
                 .start_link(cli.account)
                 .await
-                .map_err(|e| anyhow::anyhow!("JSON-RPC command startLink failed: {e:?}",))?
+                .map_err(|e| RpcError::Custom(format!("JSON-RPC command startLink failed: {e:?}")))?
                 .device_link_uri;
             println!("{}", url);
             client.finish_link(url, name).await
@@ -349,18 +362,28 @@ async fn main() -> Result<(), anyhow::Error> {
             pin,
         } => client.verify(cli.account, verification_code, pin).await,
         cli::CliCommands::Version => client.version().await,
-    };
-
-    result
-        .map(|v| println!("{v}"))
-        .map_err(|e| anyhow::anyhow!("JSON-RPC command failed: {e:?}",))?;
-    Ok(())
+    }
 }
 
-async fn connect(cli: &cli::Cli) -> Result<jsonrpc::SignalCliClient, RpcError> {
-    if let Some(tcp) = cli.json_rpc_tcp {
+async fn connect(cli: Cli) -> Result<Value, RpcError> {
+    if let Some(http) = &cli.json_rpc_http {
+        let uri = if let Some(uri) = http {
+            uri
+        } else {
+            DEFAULT_HTTP
+        };
+        let client = jsonrpc::connect_http(uri)
+            .await
+            .map_err(|e| RpcError::Custom(format!("Failed to connect to socket: {e}")))?;
+
+        handle_command(cli, client).await
+    } else if let Some(tcp) = cli.json_rpc_tcp {
         let socket_addr = tcp.unwrap_or_else(|| DEFAULT_TCP.parse().unwrap());
-        jsonrpc::connect_tcp(socket_addr).await
+        let client = jsonrpc::connect_tcp(socket_addr)
+            .await
+            .map_err(|e| RpcError::Custom(format!("Failed to connect to socket: {e}")))?;
+
+        handle_command(cli, client).await
     } else {
         let socket_path = cli
             .json_rpc_socket
@@ -374,13 +397,17 @@ async fn connect(cli: &cli::Cli) -> Result<jsonrpc::SignalCliClient, RpcError> {
                 })
             })
             .unwrap_or_else(|| ("/run".to_owned() + DEFAULT_SOCKET_SUFFIX).into());
-        jsonrpc::connect_unix(socket_path).await
+        let client = jsonrpc::connect_unix(socket_path)
+            .await
+            .map_err(|e| RpcError::Custom(format!("Failed to connect to socket: {e}")))?;
+
+        handle_command(cli, client).await
     }
 }
 
 async fn stream_next(
     timeout: f64,
-    stream: &mut TypedSubscriptionStream<Value>,
+    stream: &mut Subscription<Value>,
 ) -> Option<Result<Value, RpcError>> {
     if timeout < 0.0 {
         stream.next().await
diff --git a/client/src/tcp.rs b/client/src/tcp.rs
deleted file mode 100644 (file)
index 5365038..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-use jsonrpc_client_transports::{transports::duplex, RpcChannel, RpcError};
-use jsonrpc_core::futures_util::{SinkExt, StreamExt, TryStreamExt};
-use jsonrpc_server_utils::{codecs::StreamCodec, tokio_util::codec::Decoder};
-use tokio::net::{TcpStream, ToSocketAddrs};
-
-/// Connect to a JSON-RPC TCP server.
-pub async fn connect<S: ToSocketAddrs, Client: From<RpcChannel>>(
-    socket: S,
-) -> Result<Client, RpcError> {
-    let connection = TcpStream::connect(socket)
-        .await
-        .map_err(|e| RpcError::Other(Box::new(e)))?;
-    let (sink, stream) = StreamCodec::stream_incoming().framed(connection).split();
-    let sink = sink.sink_map_err(|e| RpcError::Other(Box::new(e)));
-    let stream = stream.map_err(|e| log::error!("TCP stream error: {}", e));
-
-    let (client, sender) = duplex(
-        Box::pin(sink),
-        Box::pin(
-            stream
-                .take_while(|x| std::future::ready(x.is_ok()))
-                .map(|x| x.expect("Stream is closed upon first error.")),
-        ),
-    );
-
-    tokio::spawn(client);
-
-    Ok(sender.into())
-}
diff --git a/client/src/transports/ipc.rs b/client/src/transports/ipc.rs
new file mode 100644 (file)
index 0000000..497955e
--- /dev/null
@@ -0,0 +1,23 @@
+use std::path::Path;
+
+use futures_util::stream::StreamExt;
+use jsonrpsee::core::client::{TransportReceiverT, TransportSenderT};
+use jsonrpsee::core::Error;
+use tokio::net::UnixStream;
+use tokio_util::codec::Decoder;
+
+use super::stream_codec::StreamCodec;
+use super::{Receiver, Sender};
+
+/// Connect to a JSON-RPC Unix Socket server.
+pub async fn connect(
+    socket: impl AsRef<Path>,
+) -> Result<(impl TransportSenderT + Send, impl TransportReceiverT + Send), Error> {
+    let connection = UnixStream::connect(socket).await?;
+    let (sink, stream) = StreamCodec::stream_incoming().framed(connection).split();
+
+    let sender = Sender { inner: sink };
+    let receiver = Receiver { inner: stream };
+
+    Ok((sender, receiver))
+}
diff --git a/client/src/transports/mod.rs b/client/src/transports/mod.rs
new file mode 100644 (file)
index 0000000..04f4390
--- /dev/null
@@ -0,0 +1,64 @@
+use futures_util::{stream::StreamExt, Sink, SinkExt, Stream};
+use jsonrpsee::core::{
+    async_trait,
+    client::{ReceivedMessage, TransportReceiverT, TransportSenderT},
+};
+use thiserror::Error;
+
+pub mod ipc;
+mod stream_codec;
+pub mod tcp;
+
+#[derive(Debug, Error)]
+enum Errors {
+    #[error("Other: {0}")]
+    Other(String),
+    #[error("Closed")]
+    Closed,
+}
+
+struct Sender<T: Send + Sink<String>> {
+    inner: T,
+}
+
+#[async_trait]
+impl<T: Send + Sink<String, Error = impl std::error::Error> + Unpin + 'static> TransportSenderT
+    for Sender<T>
+{
+    type Error = Errors;
+
+    async fn send(&mut self, body: String) -> Result<(), Self::Error> {
+        self.inner
+            .send(body)
+            .await
+            .map_err(|e| Errors::Other(format!("{:?}", e)))?;
+        Ok(())
+    }
+
+    async fn close(&mut self) -> Result<(), Self::Error> {
+        self.inner
+            .close()
+            .await
+            .map_err(|e| Errors::Other(format!("{:?}", e)))?;
+        Ok(())
+    }
+}
+
+struct Receiver<T: Send + Stream> {
+    inner: T,
+}
+
+#[async_trait]
+impl<T: Send + Stream<Item = Result<String, std::io::Error>> + Unpin + 'static> TransportReceiverT
+    for Receiver<T>
+{
+    type Error = Errors;
+
+    async fn receive(&mut self) -> Result<ReceivedMessage, Self::Error> {
+        match self.inner.next().await {
+            None => Err(Errors::Closed),
+            Some(Ok(msg)) => Ok(ReceivedMessage::Text(msg)),
+            Some(Err(e)) => Err(Errors::Other(format!("{:?}", e))),
+        }
+    }
+}
diff --git a/client/src/transports/stream_codec.rs b/client/src/transports/stream_codec.rs
new file mode 100644 (file)
index 0000000..6f77306
--- /dev/null
@@ -0,0 +1,61 @@
+use bytes::BytesMut;
+use std::{io, str};
+use tokio_util::codec::{Decoder, Encoder};
+
+type Separator = u8;
+
+/// Stream codec for streaming protocols (ipc, tcp)
+#[derive(Debug, Default)]
+pub struct StreamCodec {
+    incoming_separator: Separator,
+    outgoing_separator: Separator,
+}
+
+impl StreamCodec {
+    /// Default codec with streaming input data. Input can be both enveloped and not.
+    pub fn stream_incoming() -> Self {
+        StreamCodec::new(b'\n', b'\n')
+    }
+
+    /// New custom stream codec
+    pub fn new(incoming_separator: Separator, outgoing_separator: Separator) -> Self {
+        StreamCodec {
+            incoming_separator,
+            outgoing_separator,
+        }
+    }
+}
+
+impl Decoder for StreamCodec {
+    type Item = String;
+    type Error = io::Error;
+
+    fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<Self::Item>> {
+        if let Some(i) = buf
+            .as_ref()
+            .iter()
+            .position(|&b| b == self.incoming_separator)
+        {
+            let line = buf.split_to(i);
+            let _ = buf.split_to(1);
+
+            match str::from_utf8(line.as_ref()) {
+                Ok(s) => Ok(Some(s.to_string())),
+                Err(_) => Err(io::Error::new(io::ErrorKind::Other, "invalid UTF-8")),
+            }
+        } else {
+            Ok(None)
+        }
+    }
+}
+
+impl Encoder<String> for StreamCodec {
+    type Error = io::Error;
+
+    fn encode(&mut self, msg: String, buf: &mut BytesMut) -> io::Result<()> {
+        let mut payload = msg.into_bytes();
+        payload.push(self.outgoing_separator);
+        buf.extend_from_slice(&payload);
+        Ok(())
+    }
+}
diff --git a/client/src/transports/tcp.rs b/client/src/transports/tcp.rs
new file mode 100644 (file)
index 0000000..8d7a27d
--- /dev/null
@@ -0,0 +1,21 @@
+use futures_util::stream::StreamExt;
+use jsonrpsee::core::client::{TransportReceiverT, TransportSenderT};
+use jsonrpsee::core::Error;
+use tokio::net::{TcpStream, ToSocketAddrs};
+use tokio_util::codec::Decoder;
+
+use super::stream_codec::StreamCodec;
+use super::{Receiver, Sender};
+
+/// Connect to a JSON-RPC TCP server.
+pub async fn connect(
+    socket: impl ToSocketAddrs,
+) -> Result<(impl TransportSenderT + Send, impl TransportReceiverT + Send), Error> {
+    let connection = TcpStream::connect(socket).await?;
+    let (sink, stream) = StreamCodec::stream_incoming().framed(connection).split();
+
+    let sender = Sender { inner: sink };
+    let receiver = Receiver { inner: stream };
+
+    Ok((sender, receiver))
+}