Compare commits
27 Commits
cd2cf3346f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
62282eacd5
|
|||
|
a5c975d113
|
|||
|
ef1faf5bd9
|
|||
|
d47f62cdbb
|
|||
|
a1e10f93ce
|
|||
|
2cf0b9abe4
|
|||
|
8b0f01e606
|
|||
|
beda8c151d
|
|||
|
84f7009ad2
|
|||
|
267b741ac4
|
|||
|
bffb41e8a1
|
|||
|
b5870e62fe
|
|||
|
f4d65a2c51
|
|||
|
912b69ef93
|
|||
|
2353c1648e
|
|||
|
e1f453fa8b
|
|||
|
4dff84f4e7
|
|||
|
4fc0359625
|
|||
|
8313209e0e
|
|||
|
91deddc1d2
|
|||
|
0d018d0869
|
|||
|
71adf67727
|
|||
|
b12b382d94
|
|||
|
812861640d
|
|||
|
bfd4c1346f
|
|||
|
bf183a0598
|
|||
|
fc570fa0bd
|
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[build]
|
||||||
|
rustflags = ["--cfg", "tokio_unstable"]
|
||||||
@@ -15,4 +15,16 @@ jobs:
|
|||||||
- name: Run clippy
|
- name: Run clippy
|
||||||
run: nix build .#clippy_${{ matrix.feature }}
|
run: nix build .#clippy_${{ matrix.feature }}
|
||||||
- name: Build & test
|
- name: Build & test
|
||||||
run: nix build .#${{ matrix.feature }}
|
run: nix build .#${{ matrix.feature }}
|
||||||
|
docs:
|
||||||
|
runs-on: nix
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Build docs
|
||||||
|
run: nix build .#doc.doc
|
||||||
|
- name: (Temporary) Upload docs
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: docs
|
||||||
|
path: ./result-doc
|
||||||
23
.gitea/workflows/publish.yaml
Normal file
23
.gitea/workflows/publish.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: Publish library
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
tags:
|
||||||
|
- v*
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: nix
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Publish to Gitea Cargo registry
|
||||||
|
run: nix develop -c cargo publish --token "Bearer ${{ secrets.GITHUB_TOKEN }}" --index sparse+https://git.colon-three.com/api/packages/kodi/cargo/
|
||||||
|
- name: Publish to crates.io
|
||||||
|
run: nix develop -c cargo publish --token ${{ secrets.CRATESIO_TOKEN }}
|
||||||
|
- name: Publish to Gitea Releases
|
||||||
|
uses: akkuman/gitea-release-action@v1
|
||||||
|
with:
|
||||||
|
draft: true
|
||||||
784
Cargo.lock
generated
784
Cargo.lock
generated
@@ -75,6 +75,96 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-stream"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
|
||||||
|
dependencies = [
|
||||||
|
"async-stream-impl",
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-stream-impl"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.80"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum"
|
||||||
|
version = "0.6.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"axum-core",
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"itoa",
|
||||||
|
"matchit",
|
||||||
|
"memchr",
|
||||||
|
"mime",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustversion",
|
||||||
|
"serde",
|
||||||
|
"sync_wrapper",
|
||||||
|
"tower",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-core"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"mime",
|
||||||
|
"rustversion",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.73"
|
version = "0.3.73"
|
||||||
@@ -96,6 +186,12 @@ version = "0.21.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -105,6 +201,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
@@ -130,9 +232,72 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "eagle"
|
name = "console-api"
|
||||||
version = "0.2.0"
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a257c22cd7e487dd4a13d413beabc512c5052f0bc048db0da6a84c3d8a6142fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"prost",
|
||||||
|
"prost-types",
|
||||||
|
"tonic",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "console-subscriber"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "31c4cc54bae66f7d9188996404abdf7fdfa23034ef8e43478c8810828abad758"
|
||||||
|
dependencies = [
|
||||||
|
"console-api",
|
||||||
|
"crossbeam-channel",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"futures-task",
|
||||||
|
"hdrhistogram",
|
||||||
|
"humantime",
|
||||||
|
"prost",
|
||||||
|
"prost-types",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thread_local",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
"tonic",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.5.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "eagle"
|
||||||
|
version = "0.3.0"
|
||||||
|
dependencies = [
|
||||||
|
"console-subscriber",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"log",
|
"log",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -141,9 +306,17 @@ dependencies = [
|
|||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
"syn",
|
"syn",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-test",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_filter"
|
name = "env_filter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -167,6 +340,67 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-channel"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-sink"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@@ -184,24 +418,179 @@ version = "0.29.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.3.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"indexmap 2.2.6",
|
||||||
|
"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.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hdrhistogram"
|
||||||
|
version = "7.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"byteorder",
|
||||||
|
"flate2",
|
||||||
|
"nom",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"itoa",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httparse"
|
||||||
|
version = "1.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.14.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
|
"itoa",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-timeout"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1"
|
||||||
|
dependencies = [
|
||||||
|
"hyper",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tokio-io-timeout",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown 0.14.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.0"
|
version = "1.70.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.155"
|
version = "0.2.155"
|
||||||
@@ -214,12 +603,39 @@ version = "0.4.21"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata 0.1.10",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchit"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mime"
|
||||||
|
version = "0.3.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
@@ -240,6 +656,25 @@ dependencies = [
|
|||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
@@ -259,12 +694,50 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "percent-encoding"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project"
|
||||||
|
version = "1.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-internal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-internal"
|
||||||
|
version = "1.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@@ -280,6 +753,38 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost"
|
||||||
|
version = "0.12.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"prost-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost-derive"
|
||||||
|
version = "0.12.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"itertools",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost-types"
|
||||||
|
version = "0.12.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0"
|
||||||
|
dependencies = [
|
||||||
|
"prost",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.36"
|
version = "1.0.36"
|
||||||
@@ -327,8 +832,17 @@ checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata",
|
"regex-automata 0.4.7",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax 0.6.29",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -339,9 +853,15 @@ checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@@ -355,7 +875,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
|
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bitflags",
|
"bitflags 2.5.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
@@ -366,6 +886,18 @@ version = "0.1.24"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.203"
|
version = "1.0.203"
|
||||||
@@ -386,6 +918,35 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.118"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.7"
|
version = "0.5.7"
|
||||||
@@ -407,6 +968,42 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sync_wrapper"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.61"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.61"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.38.0"
|
version = "1.38.0"
|
||||||
@@ -421,9 +1018,20 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
|
"tracing",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-io-timeout"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
@@ -435,6 +1043,155 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-stream"
|
||||||
|
version = "0.1.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-test"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7"
|
||||||
|
dependencies = [
|
||||||
|
"async-stream",
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-util"
|
||||||
|
version = "0.7.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tonic"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13"
|
||||||
|
dependencies = [
|
||||||
|
"async-stream",
|
||||||
|
"async-trait",
|
||||||
|
"axum",
|
||||||
|
"base64",
|
||||||
|
"bytes",
|
||||||
|
"h2",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"hyper-timeout",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project",
|
||||||
|
"prost",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
"tower",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower"
|
||||||
|
version = "0.4.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"pin-project",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rand",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"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.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-attributes",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-attributes"
|
||||||
|
version = "0.1.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"valuable",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.3.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||||
|
dependencies = [
|
||||||
|
"matchers",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
"sharded-slab",
|
||||||
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "try-lock"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
@@ -447,6 +1204,21 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "want"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
|
||||||
|
dependencies = [
|
||||||
|
"try-lock",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
|||||||
31
Cargo.toml
31
Cargo.toml
@@ -1,32 +1,35 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "eagle"
|
name = "eagle"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
description = "A simple library for creating RPC protocols."
|
||||||
|
repository = "https://git.colon-three.com/kodi/eagle"
|
||||||
|
authors = ["KodiCraft <kodi@kdcf.me>"]
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
publish = ["gitea"]
|
edition = "2021"
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["tcp", "log"]
|
default = ["tcp", "log"]
|
||||||
tcp = ["tokio/net"]
|
tcp = []
|
||||||
unix = ["tokio/net"]
|
unix = []
|
||||||
log = ["dep:log", "dep:env_logger"]
|
log = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "1.0.85"
|
proc-macro2 = "1.0.85"
|
||||||
quote = "1.0.36"
|
quote = "1.0.36"
|
||||||
rand = "0.8.5"
|
|
||||||
ron = "0.8.1"
|
|
||||||
serde = { version = "1.0.203", features = ["serde_derive"] }
|
|
||||||
syn = "2.0.66"
|
syn = "2.0.66"
|
||||||
tokio = { version = "1.38.0", features = ["sync", "io-util"] }
|
|
||||||
env_logger = { version = "0.11.3", optional = true }
|
|
||||||
log = { version = "0.4.21", optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
# tokio = { version = "1.38.0", features = ["sync", "io-util"] }
|
||||||
|
ron = "0.8.1"
|
||||||
|
serde = { version = "1.0.203", features = ["serde_derive"] }
|
||||||
|
rand = "0.8.5"
|
||||||
tokio = { version = "1.38.0", features = ["sync", "rt-multi-thread", "macros", "time", "io-util", "net"] }
|
tokio = { version = "1.38.0", features = ["sync", "rt-multi-thread", "macros", "time", "io-util", "net"] }
|
||||||
env_logger = "0.11.3"
|
tokio-test = "0.4.4"
|
||||||
log = "0.4.21"
|
env_logger = { version = "0.11.3" }
|
||||||
|
log = { version = "0.4.21" }
|
||||||
|
console-subscriber = "0.3.0"
|
||||||
|
thiserror = "1.0.61"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|||||||
85
README.md
85
README.md
@@ -1,58 +1,89 @@
|
|||||||
# Eagle
|
# Eagle
|
||||||
|
|
||||||
## Disclaimer
|
## Stability
|
||||||
|
|
||||||
Eagle is still in development and not currently usable. The current state is barely a proof of concept.
|
Eagle is still in early development. Performance is not ideal, the interface is likely to change and the documentation is not final. Basic functionality is fully implemented and works as expected.
|
||||||
|
|
||||||
## What is Eagle?
|
## What is Eagle?
|
||||||
|
|
||||||
Eagle is a library designed to make "full-stack" applications with Rust. It allows you to define a communication protocol
|
Eagle is a library which allows you to easily build an [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) protocol.
|
||||||
based on simple "questions" and "answers" which can be implemented as simple functions. From the perspective of the client
|
It uses a macro to generate the required communication code and makes adding new functions easy and quick. Eagle is designed to work specifically with [`tokio`](https://crates.io/crates/tokio) and uses [`serde`](https://crates.io/crates/serde) for formatting data.
|
||||||
(which sends "questions") the protocol is simply a set of async functions on a struct. From the perspective of the server
|
|
||||||
(which sends "answers") the protocol is a trait which it implements on any struct of its choice.
|
Please note that since `eagle` is a pure proc-macro library, you must manually add compatible versions of `tokio`, `serde`, `ron` and optionally `log` to your dependencies.
|
||||||
|
|
||||||
## Using Eagle
|
## Using Eagle
|
||||||
|
|
||||||
The way that `eagle` is designed to be used is inside a shared dependency between your "server" and your "client". Both of these should be in a workspace. Create a `shared` crate which both components should depend on. Inside this crate, you can
|
The way that `eagle` is designed to be used is inside a shared dependency between your "server" and your "client". Both of these should be in a workspace. Create a `shared` crate which both components should depend on, this crate should have `eagle` as a dependency. By default `eagle` uses TCP for communication, but you may disable default features and enable the `unix` feature on `eagle` to use unix sockets instead.
|
||||||
define your protocol as an enum:
|
|
||||||
|
|
||||||
```rs
|
Inside this crate, you can define your protocol as an enum:
|
||||||
|
|
||||||
|
```rust
|
||||||
use eagle::Protocol;
|
use eagle::Protocol;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ExampleStruct {
|
||||||
|
a: i32,
|
||||||
|
b: i32
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Protocol)]
|
#[derive(Protocol)]
|
||||||
pub enum TestProtocol {
|
pub enum Example {
|
||||||
Addition((i32, i32), i32),
|
Addition((i32, i32), i32),
|
||||||
SomeKindOfQuestion(String, i32)
|
StructuredDataAlsoWorks(ExampleStruct, ()),
|
||||||
|
SetState(i32, i32),
|
||||||
|
GetState((), i32)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In your server, you will be able to implement this protocol for any struct (and in the future register it for communication):
|
Each variant describes one of the functions that the client can call, the first field on a variant represents the arguments that the client can send and the second field represents the return value. In the example above, the `addition` function would take in two [`i32`]s and return another [`i32`]. Any data passed this way must implement [`Clone`] as well as [`serde::Serialize`] and [`serde::Deserialize`].
|
||||||
|
|
||||||
```rs
|
The [`Protocol`] macro will create a number of exports in your shared crate. You will be able to import them by name in your client and server.
|
||||||
use shared::TestProtocolServer;
|
|
||||||
|
|
||||||
pub struct Server;
|
Once your protocol is defined, you can implement it on your server. To do so, you must first implement a handler for your
|
||||||
impl TestProtocolServer for Server {
|
protocol. A handler must implement [`Clone`] as well as the `ServerHandler` trait for your protocol. For the above example:
|
||||||
fn addition(&mut self, a: i32, b: i32) -> i32 {
|
|
||||||
|
```rust
|
||||||
|
struct ExampleHandler {
|
||||||
|
state: i32
|
||||||
|
}
|
||||||
|
impl ExampleServerHandler for ExampleHandler {
|
||||||
|
async fn addition(&mut self, a: i32, b: i32) -> i32 {
|
||||||
a + b
|
a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
fn some_kind_of_question(&mut self, question: String) -> i32 {
|
async fn get_state(&mut self) -> i32 {
|
||||||
42
|
self.state
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_state(&mut self, state: i32) -> i32 {
|
||||||
|
self.state = state;
|
||||||
|
self.state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In your client, you can use an instance of the client struct to query the server:
|
Your handler can now be used by the server. You can easily bind your server to a socket with:
|
||||||
|
|
||||||
```rs
|
```rust
|
||||||
use shared::TestProtocolClient;
|
use shared::ExampleServer;
|
||||||
|
|
||||||
#[tokio::main]
|
let handler = ExampleHandler { state: 0 };
|
||||||
async fn main() {
|
let server_task = ExampleServer::bind(handler, "127.0.0.1:1234").await;
|
||||||
let client = TestProtocolClient::new();
|
// Or, if you're using the 'unix' feature...
|
||||||
assert_eq!(client.addition(2, 2).await, 4);
|
let server_task = ExampleServer::bind(handler, "/tmp/sock").await;
|
||||||
}
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that bind is an asynchronous function which should never return, you must put it in a separate task. Once bound, the server will await for connections and start responding to queries.
|
||||||
|
|
||||||
|
On the client, all you need to do is to use your protocol's `Client` to connect and you can start making requests.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use shared::ExampleClient;
|
||||||
|
|
||||||
|
let client = ExampleClient::connect("127.0.0.1:1234").await.unwrap();
|
||||||
|
assert_eq!(client.addition(5, 2), 7);
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|||||||
19
flake.nix
19
flake.nix
@@ -14,12 +14,29 @@
|
|||||||
naersk-lib = pkgs.callPackage naersk {};
|
naersk-lib = pkgs.callPackage naersk {};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
packages = {
|
packages = rec {
|
||||||
|
all = pkgs.stdenv.mkDerivation rec {
|
||||||
|
name = "all";
|
||||||
|
buildInputs = [
|
||||||
|
default
|
||||||
|
doc
|
||||||
|
unix
|
||||||
|
tcp
|
||||||
|
clippy_unix
|
||||||
|
clippy_tcp
|
||||||
|
];
|
||||||
|
};
|
||||||
default = naersk-lib.buildPackage {
|
default = naersk-lib.buildPackage {
|
||||||
src = ./.;
|
src = ./.;
|
||||||
doCheck = true;
|
doCheck = true;
|
||||||
mode = "test";
|
mode = "test";
|
||||||
};
|
};
|
||||||
|
doc = naersk-lib.buildPackage {
|
||||||
|
src = ./.;
|
||||||
|
doDoc = true;
|
||||||
|
mode = "test";
|
||||||
|
cargoDocOptions = x: x ++ ["--no-deps"];
|
||||||
|
};
|
||||||
unix = naersk-lib.buildPackage {
|
unix = naersk-lib.buildPackage {
|
||||||
src = ./.;
|
src = ./.;
|
||||||
doCheck = true;
|
doCheck = true;
|
||||||
|
|||||||
385
src/lib.rs
385
src/lib.rs
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Eagle - A library for easy communication in full-stack Rust applications
|
Eagle - A simple library for RPC in Rust
|
||||||
Copyright (c) 2024 KodiCraft
|
Copyright (c) 2024 KodiCraft
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
@@ -15,6 +15,133 @@ GNU Affero General Public License for more details.
|
|||||||
You should have received a copy of the GNU Affero General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//! # Eagle - A simple library for RPC in Rust
|
||||||
|
//!
|
||||||
|
//! <div class="warning">Eagle is still in early development. This documentation is subject to change and may not be entirely accurate.</div>
|
||||||
|
//!
|
||||||
|
//! Eagle is a library for building RPC protocols in Rust. It uses a macro
|
||||||
|
//! to transform your protocol definition into the necessary code to allow
|
||||||
|
//! communication between a server and a client.
|
||||||
|
//!
|
||||||
|
//! Eagle uses [`tokio`](https://tokio.rs) as its async runtime and
|
||||||
|
//! [`ron`](https://crates.io/crates/ron) for serialization.
|
||||||
|
//!
|
||||||
|
//! ## Usage
|
||||||
|
//! `eagle` is designed to be used to create your own protocol crate. We
|
||||||
|
//! recommend creating a new cargo workspace for your project with a shared
|
||||||
|
//! crate which will contain your protocol definition and individual crates
|
||||||
|
//! for the server and client.
|
||||||
|
//!
|
||||||
|
//! In your shared crate, you can define your protocol using the [`Protocol`]
|
||||||
|
//! derive macro. This will generate the necessary code for the server and
|
||||||
|
//! client to communicate.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use eagle::Protocol;
|
||||||
|
//!
|
||||||
|
//! #[derive(Protocol)]
|
||||||
|
//! pub enum Example {
|
||||||
|
//! Add((i32, i32), i32),
|
||||||
|
//! Length(String, usize),
|
||||||
|
//! /* ... */
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The [`Protocol`] derive macro will generate all the necessary code, including
|
||||||
|
//! your handler trait, your server struct, and your client struct.
|
||||||
|
//!
|
||||||
|
//! On your server, you will need to implement the handler trait. This trait
|
||||||
|
//! describes the functions that the client can request from the server.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! # use eagle::Protocol;
|
||||||
|
//! # #[derive(Protocol)]
|
||||||
|
//! # pub enum Example {
|
||||||
|
//! # Add((i32, i32), i32),
|
||||||
|
//! # Length(String, usize),
|
||||||
|
//! # /* ... */
|
||||||
|
//! # }
|
||||||
|
//! #
|
||||||
|
//! #[derive(Clone)]
|
||||||
|
//! pub struct Handler;
|
||||||
|
//! impl ExampleServerHandler for Handler {
|
||||||
|
//! async fn add(&mut self, a: i32, b: i32) -> i32 {
|
||||||
|
//! a + b
|
||||||
|
//! }
|
||||||
|
//! async fn length(&mut self, s: String) -> usize {
|
||||||
|
//! s.len()
|
||||||
|
//! }
|
||||||
|
//! /* ... */
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! To start the server, you simply need to use the generated server struct and
|
||||||
|
//! pass it your handler.
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! # use eagle::Protocol;
|
||||||
|
//! # #[derive(Protocol)]
|
||||||
|
//! # pub enum Example {
|
||||||
|
//! # Add((i32, i32), i32),
|
||||||
|
//! # Length(String, usize),
|
||||||
|
//! # /* ... */
|
||||||
|
//! # }
|
||||||
|
//! #
|
||||||
|
//! # #[derive(Clone)]
|
||||||
|
//! # pub struct Handler;
|
||||||
|
//! # impl ExampleServerHandler for Handler {
|
||||||
|
//! # async fn add(&mut self, a: i32, b: i32) -> i32 {
|
||||||
|
//! # a + b
|
||||||
|
//! # }
|
||||||
|
//! # async fn length(&mut self, s: String) -> usize {
|
||||||
|
//! # s.len()
|
||||||
|
//! # }
|
||||||
|
//! # }
|
||||||
|
//! #
|
||||||
|
//! # tokio_test::block_on(async {
|
||||||
|
//! let handler = Handler;
|
||||||
|
//! let address = "127.0.0.1:12345"; // Or, if using the 'unix' feature, "/tmp/eagle.sock"
|
||||||
|
//! let server = ExampleServer::bind(handler, address).await;
|
||||||
|
//! # });
|
||||||
|
//! ```
|
||||||
|
//! Once bound, the server will begin listening for incoming connections and
|
||||||
|
//! queries.
|
||||||
|
//!
|
||||||
|
//! On the client side, you can simply use the generated client struct to connect
|
||||||
|
//! to the server and begin sending queries.
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! # use eagle::Protocol;
|
||||||
|
//! # #[derive(Protocol)]
|
||||||
|
//! # pub enum Example {
|
||||||
|
//! # Add((i32, i32), i32),
|
||||||
|
//! # Length(String, usize),
|
||||||
|
//! # /* ... */
|
||||||
|
//! # }
|
||||||
|
//! #
|
||||||
|
//! # #[derive(Clone)]
|
||||||
|
//! # pub struct Handler;
|
||||||
|
//! # impl ExampleServerHandler for Handler {
|
||||||
|
//! # async fn add(&mut self, a: i32, b: i32) -> i32 {
|
||||||
|
//! # a + b
|
||||||
|
//! # }
|
||||||
|
//! # async fn length(&mut self, s: String) -> usize {
|
||||||
|
//! # s.len()
|
||||||
|
//! # }
|
||||||
|
//! # }
|
||||||
|
//! #
|
||||||
|
//! # tokio_test::block_on(async {
|
||||||
|
//! # let handler = Handler;
|
||||||
|
//! let address = "127.0.0.1:12345"; // Or, if using the 'unix' feature, "/tmp/eagle.sock"
|
||||||
|
//! # let server = ExampleServer::bind(handler, address).await;
|
||||||
|
//! # tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; // Wait for the server to start
|
||||||
|
//! let client = ExampleClient::connect(address).await.unwrap();
|
||||||
|
//! assert_eq!(client.add(2, 5).await.unwrap(), 7);
|
||||||
|
//! # });
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
#![warn(missing_docs)]
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{parse2, spanned::Spanned, DeriveInput, Field, Ident};
|
use syn::{parse2, spanned::Spanned, DeriveInput, Field, Ident};
|
||||||
@@ -26,6 +153,33 @@ compile_error!("You must enable either the 'tcp' or 'unix' feature");
|
|||||||
#[cfg(all(feature = "unix", not(unix)))]
|
#[cfg(all(feature = "unix", not(unix)))]
|
||||||
compile_error!("The 'unix' feature requires compiling for a unix target");
|
compile_error!("The 'unix' feature requires compiling for a unix target");
|
||||||
|
|
||||||
|
/// Generate all the necessary RPC code for a protocol from an enum describing it.
|
||||||
|
///
|
||||||
|
/// This macro will generate various enums and structs to enable communication
|
||||||
|
/// between a server and a client. The following items will be generated, where {}
|
||||||
|
/// is the name of the protocol enum:
|
||||||
|
/// - `{}ServerHandler` - A trait that the server must implement to handle queries
|
||||||
|
/// - `{}Server` - A struct that the server uses to communicate with clients
|
||||||
|
/// - `{}Client` - A struct that the client uses to communicate with a server
|
||||||
|
///
|
||||||
|
/// Each variant of the passed enum represents a query that the client can send to the
|
||||||
|
/// server. The first field of each variant is the question (serverbound), the second field
|
||||||
|
/// is the answer (clientbound). You may use tuples to represent sending multiple arguments and
|
||||||
|
/// you may use the unit type `()` to represent no arguments. Only data types which implement
|
||||||
|
/// [`Clone`], [`serde::Serialize`], and [`serde::Deserialize`] can be used.
|
||||||
|
///
|
||||||
|
/// For more information on how to use the generated code, see the [crate-level documentation](index.html).
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```rust
|
||||||
|
/// use eagle::Protocol;
|
||||||
|
///
|
||||||
|
/// #[derive(Protocol)]
|
||||||
|
/// pub enum Example {
|
||||||
|
/// Add((i32, i32), i32),
|
||||||
|
/// Length(String, usize),
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(Protocol)]
|
#[proc_macro_derive(Protocol)]
|
||||||
pub fn derive_protocol_derive(input: TokenStream) -> TokenStream {
|
pub fn derive_protocol_derive(input: TokenStream) -> TokenStream {
|
||||||
let expanded = derive_protocol(input.into());
|
let expanded = derive_protocol(input.into());
|
||||||
@@ -38,28 +192,28 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
// TODO: These logs should be filterable in some way
|
// TODO: These logs should be filterable in some way
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let debug = quote! { log::debug! };
|
let debug = quote! { ::log::debug! };
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let info = quote! { log::info! };
|
let info = quote! { ::log::info! };
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let warn = quote! { log::warn! };
|
let warn = quote! { ::log::warn! };
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let error = quote! { log::error! };
|
let error = quote! { ::log::error! };
|
||||||
#[cfg(not(feature = "log"))]
|
#[cfg(not(feature = "log"))]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let debug = quote! { eprintln! };
|
let debug = quote! { ::std::eprintln! };
|
||||||
#[cfg(not(feature = "log"))]
|
#[cfg(not(feature = "log"))]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let info = quote! { eprintln! };
|
let info = quote! { ::std::eprintln! };
|
||||||
#[cfg(not(feature = "log"))]
|
#[cfg(not(feature = "log"))]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let warn = quote! { eprintln! };
|
let warn = quote! { ::std::eprintln! };
|
||||||
#[cfg(not(feature = "log"))]
|
#[cfg(not(feature = "log"))]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let error = quote! { eprintln! };
|
let error = quote! { ::std::eprintln! };
|
||||||
|
|
||||||
// Must be on an enum
|
// Must be on an enum
|
||||||
let enum_ = match &input.data {
|
let enum_ = match &input.data {
|
||||||
@@ -77,7 +231,7 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
let query_enum_name = format_ident!("__{}Query", name);
|
let query_enum_name = format_ident!("__{}Query", name);
|
||||||
let queries_struct_name = format_ident!("__{}Queries", name);
|
let queries_struct_name = format_ident!("__{}Queries", name);
|
||||||
let client_connection_struct_name = format_ident!("__{}Connection", name);
|
let client_connection_struct_name = format_ident!("__{}Connection", name);
|
||||||
let server_trait_name = format_ident!("{}ServerTrait", name);
|
let server_trait_name = format_ident!("{}ServerHandler", name);
|
||||||
let server_connection_struct_name = format_ident!("{}Server", name);
|
let server_connection_struct_name = format_ident!("{}Server", name);
|
||||||
let client_struct_name = format_ident!("{}Client", name);
|
let client_struct_name = format_ident!("{}Client", name);
|
||||||
|
|
||||||
@@ -95,6 +249,29 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
let mut query_set_answer = Vec::new();
|
let mut query_set_answer = Vec::new();
|
||||||
let mut query_get_answer = Vec::new();
|
let mut query_get_answer = Vec::new();
|
||||||
|
|
||||||
|
// TODO: This should just be regular code!
|
||||||
|
let join_handle_guard_name = format_ident!("__{}JoinHandleGuard", name);
|
||||||
|
let join_handle_guard = quote! {
|
||||||
|
struct #join_handle_guard_name<T: ::std::fmt::Debug>(::tokio::task::JoinHandle<T>);
|
||||||
|
impl<T: ::std::fmt::Debug> From<::tokio::task::JoinHandle<T>> for #join_handle_guard_name<T> {
|
||||||
|
fn from(handle: ::tokio::task::JoinHandle<T>) -> Self {
|
||||||
|
#debug("Creating join handle guard for task {:?}", handle);
|
||||||
|
Self(handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl #join_handle_guard_name<()> {
|
||||||
|
pub fn abort(self) {
|
||||||
|
self.0.abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: ::std::fmt::Debug> Drop for #join_handle_guard_name<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
#debug("Dropping join handle guard for task {:?}", self.0);
|
||||||
|
self.0.abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for variant in &enum_.variants {
|
for variant in &enum_.variants {
|
||||||
// Every variant must have 2 fields
|
// Every variant must have 2 fields
|
||||||
// The first field is the question (serverbound), the second field is the answer (clientbound)
|
// The first field is the question (serverbound), the second field is the answer (clientbound)
|
||||||
@@ -139,8 +316,8 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
// There is a function that must be implemented to get the answer from the query enum
|
// There is a function that must be implemented to get the answer from the query enum
|
||||||
query_get_answer.push(quote! {
|
query_get_answer.push(quote! {
|
||||||
#query_enum_name::#var_name(_, answer) => match answer {
|
#query_enum_name::#var_name(_, answer) => match answer {
|
||||||
Some(answer) => Some(#answer_enum_name::#var_name(answer.clone())),
|
::std::option::Option::Some(answer) => ::std::option::Option::Some(#answer_enum_name::#var_name(answer.clone())),
|
||||||
None => None
|
::std::option::Option::None => ::std::option::Option::None
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// There is a function that the server uses to call the appropriate function when receiving a query
|
// There is a function that the server uses to call the appropriate function when receiving a query
|
||||||
@@ -153,7 +330,7 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
});
|
});
|
||||||
// The function that the server needs to implement
|
// The function that the server needs to implement
|
||||||
server_trait.push(quote! {
|
server_trait.push(quote! {
|
||||||
fn #var_name(&mut self, #question_args) -> impl std::future::Future<Output = #answer_type> + Send;
|
fn #var_name(&mut self, #question_args) -> impl ::std::future::Future<Output = #answer_type> + Send;
|
||||||
});
|
});
|
||||||
// The function that the client uses to communicate
|
// The function that the client uses to communicate
|
||||||
client_impl.push(quote! {
|
client_impl.push(quote! {
|
||||||
@@ -163,42 +340,44 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
let answer = self.recv_until(nonce).await?;
|
let answer = self.recv_until(nonce).await?;
|
||||||
match answer {
|
match answer {
|
||||||
#answer_enum_name::#var_name(answer) => Ok(answer),
|
#answer_enum_name::#var_name(answer) => Ok(answer),
|
||||||
_ => panic!("The answer for this query is not the correct type."),
|
_ => ::std::panic!("The answer for this query is not the correct type."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// The query enum is the same as the source enum, but the second field is always wrapped in a Option<>
|
// The query enum is the same as the source enum, but the second field is always wrapped in a Option<>
|
||||||
query_enum.push(quote! {
|
query_enum.push(quote! {
|
||||||
#var_name(#question_field, Option<#answer_type>)
|
#var_name(#question_field, ::std::option::Option<#answer_type>)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an error and result type for sending messages
|
// Create an error and result type for sending messages
|
||||||
let error_enum = quote! {
|
let error_enum = quote! {
|
||||||
#[derive(Debug)]
|
#[derive(::std::fmt::Debug, ::std::clone::Clone, ::thiserror::Error)]
|
||||||
#vis enum #error_enum_name {
|
#vis enum #error_enum_name {
|
||||||
SendError(tokio::sync::mpsc::error::SendError<(u64, #question_enum_name)>),
|
#[error("Failed to send query: {0}")]
|
||||||
|
SendError(::tokio::sync::mpsc::error::SendError<(u64, #question_enum_name)>),
|
||||||
|
#[error("Connection to sender thread closed")]
|
||||||
Closed,
|
Closed,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Create enums for the types of messages the server and client will use
|
// Create enums for the types of messages the server and client will use
|
||||||
|
|
||||||
let answer_enum = quote! {
|
let answer_enum = quote! {
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
|
#[derive(::serde::Serialize, ::serde::Deserialize, ::std::clone::Clone, ::std::fmt::Debug)]
|
||||||
#vis enum #answer_enum_name {
|
#vis enum #answer_enum_name {
|
||||||
#(#server_enum), *,
|
#(#server_enum), *,
|
||||||
Ready
|
Ready
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let question_enum = quote! {
|
let question_enum = quote! {
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
|
#[derive(::serde::Serialize, ::serde::Deserialize, ::std::clone::Clone, ::std::fmt::Debug)]
|
||||||
#vis enum #question_enum_name {
|
#vis enum #question_enum_name {
|
||||||
#(#client_enum), *
|
#(#client_enum), *
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Create an enum to represent the queries the client has sent
|
// Create an enum to represent the queries the client has sent
|
||||||
let query_enum = quote! {
|
let query_enum = quote! {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(::std::clone::Clone, ::std::fmt::Debug)]
|
||||||
#vis enum #query_enum_name {
|
#vis enum #query_enum_name {
|
||||||
#(#query_enum), *
|
#(#query_enum), *
|
||||||
}
|
}
|
||||||
@@ -208,7 +387,7 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
#(#query_set_answer)*
|
#(#query_set_answer)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn get_answer(&self) -> Option<#answer_enum_name> {
|
pub fn get_answer(&self) -> ::std::option::Option<#answer_enum_name> {
|
||||||
match self {
|
match self {
|
||||||
#(#query_get_answer)*
|
#(#query_get_answer)*
|
||||||
}
|
}
|
||||||
@@ -224,17 +403,17 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "tcp")]
|
#[cfg(feature = "tcp")]
|
||||||
let stream_type = quote! { tokio::net::TcpStream };
|
let stream_type = quote! { ::tokio::net::TcpStream };
|
||||||
#[cfg(feature = "tcp")]
|
#[cfg(feature = "tcp")]
|
||||||
let stream_addr_trait = quote! { tokio::net::ToSocketAddrs };
|
let stream_addr_trait = quote! { ::tokio::net::ToSocketAddrs };
|
||||||
#[cfg(feature = "tcp")]
|
#[cfg(feature = "tcp")]
|
||||||
let listener_type = quote! { tokio::net::TcpListener };
|
let listener_type = quote! { ::tokio::net::TcpListener };
|
||||||
#[cfg(feature = "unix")]
|
#[cfg(feature = "unix")]
|
||||||
let stream_type = quote! { tokio::net::UnixStream };
|
let stream_type = quote! { ::tokio::net::UnixStream };
|
||||||
#[cfg(feature = "unix")]
|
#[cfg(feature = "unix")]
|
||||||
let stream_addr_trait = quote! { std::convert::AsRef<std::path::Path> };
|
let stream_addr_trait = quote! { ::std::convert::AsRef<std::path::Path> };
|
||||||
#[cfg(feature = "unix")]
|
#[cfg(feature = "unix")]
|
||||||
let listener_type = quote! { tokio::net::UnixListener };
|
let listener_type = quote! { ::tokio::net::UnixListener };
|
||||||
|
|
||||||
// Create a trait which the server will have to implement
|
// Create a trait which the server will have to implement
|
||||||
let server_trait = quote! {
|
let server_trait = quote! {
|
||||||
@@ -254,40 +433,41 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
};
|
};
|
||||||
let sc_struct = quote! {
|
let sc_struct = quote! {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#vis struct #server_connection_struct_name<H: #server_trait_name + ::std::marker::Send + Clone + 'static> {
|
#vis struct #server_connection_struct_name<H: #server_trait_name + ::std::marker::Send + ::std::clone::Clone + 'static> {
|
||||||
handler: ::std::sync::Arc<tokio::sync::Mutex<H>>,
|
handler: ::std::sync::Arc<::tokio::sync::Mutex<H>>,
|
||||||
tasks: ::std::sync::Arc<tokio::sync::Mutex<Vec<tokio::task::JoinHandle<()>>>>,
|
tasks: ::std::sync::Arc<::tokio::sync::Mutex<::std::vec::Vec<#join_handle_guard_name<()>>>>,
|
||||||
}
|
}
|
||||||
impl<H: #server_trait_name + ::std::marker::Send + Clone + 'static> #server_connection_struct_name<H> {
|
impl<H: #server_trait_name + ::std::marker::Send + std::clone::Clone + 'static> #server_connection_struct_name<H> {
|
||||||
pub async fn bind<A: #stream_addr_trait + ::std::marker::Send + std::fmt::Display + 'static>(handler: H, addr: A) -> Self {
|
pub async fn bind<A: #stream_addr_trait + ::std::marker::Send + ::std::fmt::Display + 'static>(handler: H, addr: A) -> Self {
|
||||||
#info("Binding server to address {}", addr);
|
#info("Binding server to address {}", addr);
|
||||||
let handler = ::std::sync::Arc::new(tokio::sync::Mutex::new(handler));
|
let handler = ::std::sync::Arc::new(::tokio::sync::Mutex::new(handler));
|
||||||
let tasks = ::std::sync::Arc::new(tokio::sync::Mutex::new(Vec::new()));
|
let tasks = ::std::sync::Arc::new(::tokio::sync::Mutex::new(::std::vec::Vec::new()));
|
||||||
let sc = Self {
|
let sc = Self {
|
||||||
handler,
|
handler,
|
||||||
tasks,
|
tasks,
|
||||||
};
|
};
|
||||||
let sc_clone = sc.clone();
|
let sc_clone = sc.clone();
|
||||||
let acc_task = tokio::spawn(async move {
|
let acc_task = ::tokio::spawn(async move {
|
||||||
sc_clone.accept_connections(addr).await.expect("Failed to accept connections!");
|
sc_clone.accept_connections(addr).await.expect("Failed to accept connections!");
|
||||||
});
|
});
|
||||||
sc.tasks.lock().await.push(acc_task);
|
sc.tasks.lock().await.push(acc_task.into());
|
||||||
sc
|
sc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn accept_connections<A: #stream_addr_trait>(
|
pub async fn accept_connections<A: #stream_addr_trait>(
|
||||||
&self,
|
&self,
|
||||||
addr: A,
|
addr: A,
|
||||||
) -> Result<(), std::io::Error> {
|
) -> ::std::result::Result<(), ::std::io::Error> {
|
||||||
#listener_statement
|
#listener_statement
|
||||||
|
#info("Listening for clients on {:?}", listener.local_addr()?);
|
||||||
loop {
|
loop {
|
||||||
let (stream, _) = listener.accept().await?;
|
let (stream, _) = listener.accept().await?;
|
||||||
#info("Accepted connection from {}", stream.peer_addr()?);
|
#info("Accepted connection from {:?}", stream.peer_addr()?);
|
||||||
let self_clone = self.clone();
|
let self_clone = self.clone();
|
||||||
let run_task = tokio::spawn(async move {
|
let run_task = ::tokio::spawn(async move {
|
||||||
self_clone.run(stream).await;
|
self_clone.run(stream).await;
|
||||||
});
|
});
|
||||||
self.tasks.lock().await.push(run_task);
|
self.tasks.lock().await.push(run_task.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +478,7 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn send(&self, stream: &mut #stream_type, nonce: u64, answer: #answer_enum_name) {
|
async fn send(&self, stream: &mut #stream_type, nonce: u64, answer: #answer_enum_name) {
|
||||||
use tokio::io::AsyncWriteExt;
|
use ::tokio::io::AsyncWriteExt;
|
||||||
let serialized = ron::ser::to_string(&(nonce, answer)).expect("Failed to serialize response!");
|
let serialized = ron::ser::to_string(&(nonce, answer)).expect("Failed to serialize response!");
|
||||||
let len = serialized.len() as u32;
|
let len = serialized.len() as u32;
|
||||||
#debug("Sending `{}`", serialized);
|
#debug("Sending `{}`", serialized);
|
||||||
@@ -307,24 +487,24 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn run(&self, mut stream: #stream_type) {
|
async fn run(&self, mut stream: #stream_type) {
|
||||||
use tokio::io::AsyncWriteExt;
|
use ::tokio::io::AsyncWriteExt;
|
||||||
use tokio::io::AsyncReadExt;
|
use ::tokio::io::AsyncReadExt;
|
||||||
let mut buf = Vec::with_capacity(1024);
|
let mut buf = ::std::vec::Vec::with_capacity(1024);
|
||||||
self.send(&mut stream, 0, #answer_enum_name::Ready).await;
|
self.send(&mut stream, 0, #answer_enum_name::Ready).await;
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
::tokio::select! {
|
||||||
Ok(_) = stream.readable() => {
|
::std::result::Result::Ok(_) = stream.readable() => {
|
||||||
let mut read_buf = [0; 1024];
|
let mut read_buf = [0; 1024];
|
||||||
match stream.try_read(&mut read_buf) {
|
match stream.try_read(&mut read_buf) {
|
||||||
Ok(0) => break, // Stream closed
|
::std::result::Result::Ok(0) => break, // Stream closed
|
||||||
Ok(n) => {
|
::std::result::Result::Ok(n) => {
|
||||||
#debug("Received {} bytes (server)", n);
|
#debug("Received {} bytes (server)", n);
|
||||||
buf.extend_from_slice(&read_buf[..n]);
|
buf.extend_from_slice(&read_buf[..n]);
|
||||||
loop {
|
while buf.len() >= 4 {
|
||||||
let len = u32::from_le_bytes(buf[..4].try_into().expect("Failed to convert bytes to u32"));
|
let len = u32::from_le_bytes(buf[..4].try_into().expect("Failed to convert bytes to u32"));
|
||||||
if buf.len() >= (4 + len as usize) {
|
if buf.len() >= (4 + len as usize) {
|
||||||
let serialized = std::str::from_utf8(&buf[4..(4 + len as usize)]).expect("Failed to convert bytes to string");
|
let serialized = ::std::str::from_utf8(&buf[4..(4 + len as usize)]).expect("Failed to convert bytes to string");
|
||||||
let (nonce, question): (u64, #question_enum_name) = ron::de::from_str(serialized).expect("Failed to deserialize query!");
|
let (nonce, question): (u64, #question_enum_name) = ::ron::de::from_str(serialized).expect("Failed to deserialize query!");
|
||||||
let answer = self.handle(question).await;
|
let answer = self.handle(question).await;
|
||||||
self.send(&mut stream, nonce, answer).await;
|
self.send(&mut stream, nonce, answer).await;
|
||||||
buf.drain(0..(4 + len as usize));
|
buf.drain(0..(4 + len as usize));
|
||||||
@@ -333,8 +513,8 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(ref e) if e.kind() == ::std::io::ErrorKind::WouldBlock => { continue; },
|
::std::result::Result::Err(ref e) if e.kind() == ::std::io::ErrorKind::WouldBlock => { continue; },
|
||||||
Err(e) => eprintln!("Error reading from stream: {:?}", e),
|
::std::result::Result::Err(e) => ::std::eprintln!("Error reading from stream: {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,21 +539,21 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&self, nonce: u64, query: #query_enum_name) {
|
pub fn insert(&self, nonce: u64, query: #query_enum_name) {
|
||||||
self.queries.lock().unwrap().insert(nonce, query);
|
self.queries.lock().expect("Could not insert new query; Mutex has been poisoned.").insert(nonce, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, nonce: &u64) -> Option<#query_enum_name> {
|
pub fn get(&self, nonce: &u64) -> ::std::option::Option<#query_enum_name> {
|
||||||
self.queries.lock().unwrap().get(nonce).cloned()
|
self.queries.lock().expect("Could not get query; Mutex has been poisoned.").get(nonce).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_answer(&self, nonce: u64, answer: #answer_enum_name) {
|
pub fn set_answer(&self, nonce: u64, answer: #answer_enum_name) {
|
||||||
if let Some(query) = self.queries.lock().unwrap().get_mut(&nonce) {
|
if let ::std::option::Option::Some(query) = self.queries.lock().expect("Could not set answer to query; Mutex has been poisoned.").get_mut(&nonce) {
|
||||||
query.set_answer(answer);
|
query.set_answer(answer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.queries.lock().unwrap().len()
|
self.queries.lock().expect("Could not get query count; Mutex has been poisoned.").len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -381,16 +561,16 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
// Create a struct to handle the connection from the client to the server
|
// Create a struct to handle the connection from the client to the server
|
||||||
let cc_struct = quote! {
|
let cc_struct = quote! {
|
||||||
struct #client_connection_struct_name {
|
struct #client_connection_struct_name {
|
||||||
to_send: tokio::sync::mpsc::Receiver<(u64, #question_enum_name)>,
|
to_send: ::tokio::sync::mpsc::Receiver<(u64, #question_enum_name)>,
|
||||||
received: tokio::sync::mpsc::Sender<(u64, #answer_enum_name)>,
|
received: ::tokio::sync::mpsc::Sender<(u64, #answer_enum_name)>,
|
||||||
ready: std::sync::Arc<tokio::sync::Notify>,
|
ready: ::std::sync::Arc<tokio::sync::Notify>,
|
||||||
stream: #stream_type,
|
stream: #stream_type,
|
||||||
}
|
}
|
||||||
impl #client_connection_struct_name {
|
impl #client_connection_struct_name {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
to_send: tokio::sync::mpsc::Receiver<(u64, #question_enum_name)>,
|
to_send: ::tokio::sync::mpsc::Receiver<(u64, #question_enum_name)>,
|
||||||
received: tokio::sync::mpsc::Sender<(u64, #answer_enum_name)>,
|
received: ::tokio::sync::mpsc::Sender<(u64, #answer_enum_name)>,
|
||||||
ready: std::sync::Arc<tokio::sync::Notify>,
|
ready: ::std::sync::Arc<::tokio::sync::Notify>,
|
||||||
stream: #stream_type,
|
stream: #stream_type,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -402,23 +582,23 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(mut self) {
|
pub async fn run(mut self) {
|
||||||
use tokio::io::AsyncWriteExt;
|
use ::tokio::io::AsyncWriteExt;
|
||||||
use tokio::io::AsyncReadExt;
|
use ::tokio::io::AsyncReadExt;
|
||||||
let mut buf = Vec::with_capacity(1024);
|
let mut buf = ::std::vec::Vec::with_capacity(1024);
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
::tokio::select! {
|
||||||
Some(msg) = self.to_send.recv() => {
|
::std::option::Option::Some(msg) = self.to_send.recv() => {
|
||||||
let serialized = ron::ser::to_string(&msg).expect("Failed to serialize query!");
|
let serialized = ron::ser::to_string(&msg).expect("Failed to serialize query!");
|
||||||
let len = serialized.len() as u32;
|
let len = serialized.len() as u32;
|
||||||
#debug("Sending `{}`", serialized);
|
#debug("Sending `{}`", serialized);
|
||||||
self.stream.write_all(&len.to_le_bytes()).await.expect("Failed to write length!");
|
self.stream.write_all(&len.to_le_bytes()).await.expect("Failed to write length!");
|
||||||
self.stream.write_all(serialized.as_bytes()).await.expect("Failed to write query!");
|
self.stream.write_all(serialized.as_bytes()).await.expect("Failed to write query!");
|
||||||
},
|
},
|
||||||
Ok(_) = self.stream.readable() => {
|
::std::result::Result::Ok(_) = self.stream.readable() => {
|
||||||
let mut read_buf = [0; 1024];
|
let mut read_buf = [0; 1024];
|
||||||
match self.stream.try_read(&mut read_buf) {
|
match self.stream.try_read(&mut read_buf) {
|
||||||
Ok(0) => { break; },
|
::std::result::Result::Ok(0) => { break; },
|
||||||
Ok(n) => {
|
::std::result::Result::Ok(n) => {
|
||||||
#debug("Received {} bytes (client)", n);
|
#debug("Received {} bytes (client)", n);
|
||||||
buf.extend_from_slice(&read_buf[..n]);
|
buf.extend_from_slice(&read_buf[..n]);
|
||||||
while buf.len() >= 4 {
|
while buf.len() >= 4 {
|
||||||
@@ -430,7 +610,12 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
#debug("Received ready signal");
|
#debug("Received ready signal");
|
||||||
self.ready.notify_one();
|
self.ready.notify_one();
|
||||||
} else {
|
} else {
|
||||||
self.received.send(response).await.expect("Failed to send response!");
|
match self.received.send(response).await {
|
||||||
|
::std::result::Result::Ok(_) => {},
|
||||||
|
::std::result::Result::Err(e) => {
|
||||||
|
#error("Failed to send received answer to Client: {:?}", e);
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
buf.drain(0..(4 + len as usize));
|
buf.drain(0..(4 + len as usize));
|
||||||
} else {
|
} else {
|
||||||
@@ -438,8 +623,8 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(ref e) if e.kind() == ::std::io::ErrorKind::WouldBlock => { continue; },
|
::std::result::Result::Err(ref e) if e.kind() == ::std::io::ErrorKind::WouldBlock => { continue; },
|
||||||
Err(e) => eprintln!("Error reading from stream: {:?}", e),
|
::std::result::Result::Err(e) => eprintln!("Error reading from stream: {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -450,33 +635,33 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
// Create a struct which the client will use to communicate
|
// Create a struct which the client will use to communicate
|
||||||
let client_recv_queue_wrapper = format_ident!("__{}RecvQueueWrapper", name);
|
let client_recv_queue_wrapper = format_ident!("__{}RecvQueueWrapper", name);
|
||||||
let client_struct = quote! {
|
let client_struct = quote! {
|
||||||
#[derive(Clone)]
|
#[derive(::std::clone::Clone)]
|
||||||
struct #client_recv_queue_wrapper {
|
struct #client_recv_queue_wrapper {
|
||||||
recv_queue: ::std::sync::Arc<::tokio::sync::Mutex<tokio::sync::mpsc::Receiver<(u64, #answer_enum_name)>>>,
|
recv_queue: ::std::sync::Arc<::tokio::sync::Mutex<::tokio::sync::mpsc::Receiver<(u64, #answer_enum_name)>>>,
|
||||||
}
|
}
|
||||||
impl #client_recv_queue_wrapper {
|
impl #client_recv_queue_wrapper {
|
||||||
fn new(recv_queue: tokio::sync::mpsc::Receiver<(u64, #answer_enum_name)>) -> Self {
|
fn new(recv_queue: ::tokio::sync::mpsc::Receiver<(u64, #answer_enum_name)>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
recv_queue: ::std::sync::Arc::new(::tokio::sync::Mutex::new(recv_queue)),
|
recv_queue: ::std::sync::Arc::new(::tokio::sync::Mutex::new(recv_queue)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn recv(&self) -> Option<(u64, #answer_enum_name)> {
|
async fn recv(&self) -> ::std::option::Option<(u64, #answer_enum_name)> {
|
||||||
self.recv_queue.lock().await.recv().await
|
self.recv_queue.lock().await.recv().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#vis struct #client_struct_name {
|
#vis struct #client_struct_name {
|
||||||
queries: #queries_struct_name,
|
queries: #queries_struct_name,
|
||||||
send_queue: tokio::sync::mpsc::Sender<(u64, #question_enum_name)>,
|
send_queue: ::tokio::sync::mpsc::Sender<(u64, #question_enum_name)>,
|
||||||
recv_queue: #client_recv_queue_wrapper,
|
recv_queue: #client_recv_queue_wrapper,
|
||||||
ready: ::std::sync::Arc<tokio::sync::Mutex<bool>>,
|
ready: ::std::sync::Arc<tokio::sync::Mutex<bool>>,
|
||||||
ready_notify: ::std::sync::Arc<tokio::sync::Notify>,
|
ready_notify: ::std::sync::Arc<tokio::sync::Notify>,
|
||||||
connection_task: Option<::std::sync::Arc<tokio::task::JoinHandle<()>>>,
|
connection_task: ::std::option::Option<::std::sync::Arc<#join_handle_guard_name<()>>>,
|
||||||
}
|
}
|
||||||
impl #client_struct_name {
|
impl #client_struct_name {
|
||||||
pub fn new(send_queue: tokio::sync::mpsc::Sender<(u64, #question_enum_name)>,
|
pub fn new(send_queue: ::tokio::sync::mpsc::Sender<(u64, #question_enum_name)>,
|
||||||
recv_queue: tokio::sync::mpsc::Receiver<(u64, #answer_enum_name)>,
|
recv_queue: ::tokio::sync::mpsc::Receiver<(u64, #answer_enum_name)>,
|
||||||
connection_task: Option<::std::sync::Arc<tokio::task::JoinHandle<()>>>,
|
connection_task: ::std::option::Option<::std::sync::Arc<#join_handle_guard_name<()>>>,
|
||||||
ready_notify: ::std::sync::Arc<tokio::sync::Notify>) -> Self {
|
ready_notify: ::std::sync::Arc<tokio::sync::Notify>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
queries: #queries_struct_name::new(),
|
queries: #queries_struct_name::new(),
|
||||||
@@ -490,19 +675,14 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
pub async fn connect<A: #stream_addr_trait + ::std::fmt::Display>(addr: A) -> Result<Self, std::io::Error> {
|
pub async fn connect<A: #stream_addr_trait + ::std::fmt::Display>(addr: A) -> Result<Self, std::io::Error> {
|
||||||
#info("Connecting to server at address {}", addr);
|
#info("Connecting to server at address {}", addr);
|
||||||
let stream = #stream_type::connect(addr).await?;
|
let stream = #stream_type::connect(addr).await?;
|
||||||
let (send_queue, to_send) = tokio::sync::mpsc::channel(16);
|
let (send_queue, to_send) = ::tokio::sync::mpsc::channel(16);
|
||||||
let (to_recv, recv_queue) = tokio::sync::mpsc::channel(16);
|
let (to_recv, recv_queue) = ::tokio::sync::mpsc::channel(16);
|
||||||
let ready_notify = ::std::sync::Arc::new(tokio::sync::Notify::new());
|
let ready_notify = ::std::sync::Arc::new(tokio::sync::Notify::new());
|
||||||
let connection = #client_connection_struct_name::new(to_send, to_recv, ready_notify.clone(), stream);
|
let connection = #client_connection_struct_name::new(to_send, to_recv, ready_notify.clone(), stream);
|
||||||
let connection_task = tokio::spawn(connection.run());
|
let connection_task = ::tokio::spawn(connection.run());
|
||||||
Ok(Self::new(send_queue, recv_queue, Some(::std::sync::Arc::new(connection_task)), ready_notify))
|
Ok(Self::new(send_queue, recv_queue, ::std::option::Option::Some(::std::sync::Arc::new(connection_task.into())), ready_notify))
|
||||||
}
|
}
|
||||||
pub fn close(self) {
|
async fn send(&self, query: #question_enum_name) -> ::std::result::Result<u64, #error_enum_name> {
|
||||||
if let Some(task) = self.connection_task {
|
|
||||||
task.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async fn send(&self, query: #question_enum_name) -> Result<u64, #error_enum_name> {
|
|
||||||
// Wait until the connection is ready
|
// Wait until the connection is ready
|
||||||
if !*self.ready.lock().await {
|
if !*self.ready.lock().await {
|
||||||
self.ready_notify.notified().await;
|
self.ready_notify.notified().await;
|
||||||
@@ -512,28 +692,28 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
let nonce = self.queries.len() as u64;
|
let nonce = self.queries.len() as u64;
|
||||||
let res = self.send_queue.send((nonce, query.clone())).await;
|
let res = self.send_queue.send((nonce, query.clone())).await;
|
||||||
match res {
|
match res {
|
||||||
Ok(_) => {
|
::std::result::Result::Ok(_) => {
|
||||||
self.queries.insert(nonce, query.into());
|
self.queries.insert(nonce, query.into());
|
||||||
Ok(nonce)
|
::std::result::Result::Ok(nonce)
|
||||||
}
|
}
|
||||||
Err(e) => Err(#error_enum_name::SendError(e)),
|
::std::result::Result::Err(e) => ::std::result::Result::Err(#error_enum_name::SendError(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn recv_until(&self, id: u64) -> Result<#answer_enum_name, #error_enum_name> {
|
async fn recv_until(&self, id: u64) -> ::std::result::Result<#answer_enum_name, #error_enum_name> {
|
||||||
loop {
|
loop {
|
||||||
// Check if we've received the answer for the query we're looking for
|
// Check if we've received the answer for the query we're looking for
|
||||||
if let Some(query) = self.queries.get(&id) {
|
if let ::std::option::Option::Some(query) = self.queries.get(&id) {
|
||||||
if let Some(answer) = query.get_answer() {
|
if let ::std::option::Option::Some(answer) = query.get_answer() {
|
||||||
#info("Found answer for query {}", id);
|
#info("Found answer for query {}", id);
|
||||||
return Ok(answer);
|
return Ok(answer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match self.recv_queue.recv().await {
|
match self.recv_queue.recv().await {
|
||||||
Some((nonce, answer)) => {
|
::std::option::Option::Some((nonce, answer)) => {
|
||||||
#info("Received answer for query {}", nonce);
|
#info("Received answer for query {}", nonce);
|
||||||
self.queries.set_answer(nonce, answer.clone());
|
self.queries.set_answer(nonce, answer.clone());
|
||||||
}
|
}
|
||||||
None => return Err(#error_enum_name::Closed),
|
::std::option::Option::None => return ::std::result::Result::Err(#error_enum_name::Closed),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -542,6 +722,7 @@ fn derive_protocol(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream
|
|||||||
};
|
};
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
|
#join_handle_guard // TODO: This should just be regular code and not in the macro!
|
||||||
#error_enum
|
#error_enum
|
||||||
#answer_enum
|
#answer_enum
|
||||||
#question_enum
|
#question_enum
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Eagle - A library for easy communication in full-stack Rust applications
|
Eagle - A simple library for RPC in Rust
|
||||||
Copyright (c) 2024 KodiCraft
|
Copyright (c) 2024 KodiCraft
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
@@ -24,9 +24,10 @@ use tokio::sync::{
|
|||||||
Notify,
|
Notify,
|
||||||
};
|
};
|
||||||
|
|
||||||
static INIT: Once = Once::new();
|
static LOG_INIT: Once = Once::new();
|
||||||
|
static CONSOLE_INIT: Once = Once::new();
|
||||||
pub fn init_logger() {
|
pub fn init_logger() {
|
||||||
INIT.call_once(|| {
|
LOG_INIT.call_once(|| {
|
||||||
let env = Env::default()
|
let env = Env::default()
|
||||||
.filter_or("RUST_LOG", "info")
|
.filter_or("RUST_LOG", "info")
|
||||||
.write_style_or("LOG_STYLE", "always");
|
.write_style_or("LOG_STYLE", "always");
|
||||||
@@ -34,6 +35,11 @@ pub fn init_logger() {
|
|||||||
Builder::from_env(env).format_timestamp_nanos().init();
|
Builder::from_env(env).format_timestamp_nanos().init();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
pub fn init_console() {
|
||||||
|
CONSOLE_INIT.call_once(|| {
|
||||||
|
console_subscriber::init();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Protocol)]
|
#[derive(Protocol)]
|
||||||
enum TestProtocol {
|
enum TestProtocol {
|
||||||
@@ -46,6 +52,7 @@ enum TestProtocol {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn client() {
|
async fn client() {
|
||||||
init_logger();
|
init_logger();
|
||||||
|
init_console();
|
||||||
let (qtx, qrx) = mpsc::channel(16);
|
let (qtx, qrx) = mpsc::channel(16);
|
||||||
let (atx, arx) = mpsc::channel(16);
|
let (atx, arx) = mpsc::channel(16);
|
||||||
let ready_notify = Arc::new(Notify::new());
|
let ready_notify = Arc::new(Notify::new());
|
||||||
@@ -110,6 +117,7 @@ async fn server_loop(
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn heavy_async() {
|
async fn heavy_async() {
|
||||||
init_logger();
|
init_logger();
|
||||||
|
init_console();
|
||||||
let (qtx, qrx) = mpsc::channel(16);
|
let (qtx, qrx) = mpsc::channel(16);
|
||||||
let (atx, arx) = mpsc::channel(16);
|
let (atx, arx) = mpsc::channel(16);
|
||||||
let ready_notify = Arc::new(Notify::new());
|
let ready_notify = Arc::new(Notify::new());
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Eagle - A library for easy communication in full-stack Rust applications
|
Eagle - A simple library for RPC in Rust
|
||||||
Copyright (c) 2024 KodiCraft
|
Copyright (c) 2024 KodiCraft
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
@@ -18,10 +18,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
use eagle::Protocol;
|
use eagle::Protocol;
|
||||||
use env_logger::{Builder, Env};
|
use env_logger::{Builder, Env};
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
static INIT: Once = Once::new();
|
static LOG_INIT: Once = Once::new();
|
||||||
|
static CONSOLE_INIT: Once = Once::new();
|
||||||
pub fn init_logger() {
|
pub fn init_logger() {
|
||||||
INIT.call_once(|| {
|
LOG_INIT.call_once(|| {
|
||||||
let env = Env::default()
|
let env = Env::default()
|
||||||
.filter_or("RUST_LOG", "info")
|
.filter_or("RUST_LOG", "info")
|
||||||
.write_style_or("LOG_STYLE", "always");
|
.write_style_or("LOG_STYLE", "always");
|
||||||
@@ -29,6 +31,11 @@ pub fn init_logger() {
|
|||||||
Builder::from_env(env).format_timestamp_nanos().init();
|
Builder::from_env(env).format_timestamp_nanos().init();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
pub fn init_console() {
|
||||||
|
CONSOLE_INIT.call_once(|| {
|
||||||
|
console_subscriber::init();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Protocol)]
|
#[derive(Protocol)]
|
||||||
enum TestProtocol {
|
enum TestProtocol {
|
||||||
@@ -40,7 +47,7 @@ enum TestProtocol {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct TrivialServer;
|
struct TrivialServer;
|
||||||
impl TestProtocolServerTrait for TrivialServer {
|
impl TestProtocolServerHandler for TrivialServer {
|
||||||
async fn addition(&mut self, a: i32, b: i32) -> i32 {
|
async fn addition(&mut self, a: i32, b: i32) -> i32 {
|
||||||
a + b
|
a + b
|
||||||
}
|
}
|
||||||
@@ -53,29 +60,41 @@ impl TestProtocolServerTrait for TrivialServer {
|
|||||||
async fn void(&mut self) {}
|
async fn void(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Cleanup {
|
||||||
|
address: String,
|
||||||
|
}
|
||||||
|
impl Drop for Cleanup {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
std::fs::remove_file(&self.address).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn e2e() {
|
async fn e2e() {
|
||||||
init_logger();
|
init_logger();
|
||||||
|
init_console();
|
||||||
#[cfg(feature = "unix")]
|
#[cfg(feature = "unix")]
|
||||||
let address = "/tmp/eagle-test.sock";
|
let address = format!("/tmp/eagle-test-{}.sock", rand::random::<u64>());
|
||||||
|
#[cfg(feature = "unix")]
|
||||||
|
let _cleanup = Cleanup {
|
||||||
|
address: address.clone(),
|
||||||
|
};
|
||||||
#[cfg(feature = "tcp")]
|
#[cfg(feature = "tcp")]
|
||||||
let address = format!("127.0.0.1:{}", 10000 + rand::random::<u64>() % 1000);
|
let address = format!("127.0.0.1:{}", 10000 + rand::random::<u64>() % 1000);
|
||||||
let server_task = tokio::spawn(TestProtocolServer::bind(TrivialServer, address.clone()));
|
let _server = TestProtocolServer::bind(TrivialServer, address.clone()).await;
|
||||||
// Wait for the server to start
|
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; // Wait for the server to start
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
|
|
||||||
let client = TestProtocolClient::connect(address).await.unwrap();
|
let client = TestProtocolClient::connect(address).await.unwrap();
|
||||||
let res = client.addition(2, 5).await.unwrap();
|
assert_eq!(client.addition(2, 5).await.unwrap(), 7);
|
||||||
// assert_eq!(client.addition(2, 5).await.unwrap(), 7);
|
assert_eq!(
|
||||||
// assert_eq!(
|
client
|
||||||
// client.some_kind_of_question("Hello, world!".to_string())
|
.some_kind_of_question("Hello, world!".to_string())
|
||||||
// .await
|
.await
|
||||||
// .unwrap(),
|
.unwrap(),
|
||||||
// "Hello, world!".len() as i32
|
"Hello, world!".len() as i32
|
||||||
// );
|
);
|
||||||
// assert_eq!(
|
assert_eq!(
|
||||||
// client.this_responds_with_a_string(42).await.unwrap(),
|
client.this_responds_with_a_string(42).await.unwrap(),
|
||||||
// "The number is 42"
|
"The number is 42"
|
||||||
// );
|
);
|
||||||
// client.void().await.unwrap();
|
client.void().await.unwrap();
|
||||||
// server_task.abort();
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user