Compare commits

..

22 Commits
v0.2.0 ... main

Author SHA1 Message Date
62282eacd5
Fix compile error due to attempting to derive incorrect trait
All checks were successful
Build library & run tests / build (unix) (push) Successful in 1m27s
Build library & run tests / build (tcp) (push) Successful in 1m28s
Build library & run tests / docs (push) Successful in 1m28s
2024-07-05 13:13:23 +02:00
a5c975d113
Attempt to change the way errors are created
Some checks failed
Build library & run tests / docs (push) Failing after 2m31s
Build library & run tests / build (tcp) (push) Failing after 2m41s
Build library & run tests / build (unix) (push) Failing after 2m42s
2024-07-05 13:09:31 +02:00
ef1faf5bd9
Barely better error reporting 2024-06-26 11:28:14 +02:00
d47f62cdbb
Attempt to deal with task/memory leaks
All checks were successful
Build library & run tests / docs (push) Successful in 2m20s
Build library & run tests / build (unix) (push) Successful in 2m23s
Build library & run tests / build (tcp) (push) Successful in 2m27s
2024-06-26 11:16:20 +02:00
a1e10f93ce
bump
Some checks failed
Build library & run tests / build (unix) (push) Successful in 57s
Build library & run tests / build (tcp) (push) Successful in 54s
Publish library / publish (push) Failing after 21s
Build library & run tests / docs (push) Successful in 22s
2024-06-25 18:19:35 +02:00
2cf0b9abe4
Don't run doctests which would break on unix
All checks were successful
Build library & run tests / build (unix) (push) Successful in 28s
Build library & run tests / build (tcp) (push) Successful in 29s
Build library & run tests / docs (push) Successful in 30s
2024-06-25 11:48:47 +02:00
8b0f01e606
Add information about dependencies to README
Some checks failed
Build library & run tests / build (unix) (push) Failing after 48s
Build library & run tests / docs (push) Successful in 49s
Build library & run tests / build (tcp) (push) Successful in 53s
2024-06-25 11:44:25 +02:00
beda8c151d
Changes in dependencies 2024-06-25 11:43:04 +02:00
84f7009ad2
Add more proper cleanup for the server
Some checks failed
Build library & run tests / build (unix) (push) Failing after 34s
Build library & run tests / build (tcp) (push) Successful in 35s
Build library & run tests / docs (push) Successful in 37s
2024-06-25 11:39:07 +02:00
267b741ac4
implement std::error::Error for the error type
All checks were successful
Build library & run tests / build (unix) (push) Successful in 33s
Build library & run tests / build (tcp) (push) Successful in 34s
Build library & run tests / docs (push) Successful in 35s
2024-06-25 00:03:29 +02:00
bffb41e8a1
implement Drop for client struct
All checks were successful
Build library & run tests / build (unix) (push) Successful in 34s
Build library & run tests / build (tcp) (push) Successful in 35s
Build library & run tests / docs (push) Successful in 37s
2024-06-24 23:44:44 +02:00
b5870e62fe
Implement Display for the error enum
All checks were successful
Build library & run tests / build (unix) (push) Successful in 33s
Build library & run tests / build (tcp) (push) Successful in 35s
Build library & run tests / docs (push) Successful in 36s
2024-06-24 23:01:58 +02:00
f4d65a2c51
Sanitization improvements
Some checks failed
Build library & run tests / build (unix) (push) Successful in 19s
Build library & run tests / build (tcp) (push) Successful in 20s
Build library & run tests / docs (push) Successful in 23s
Publish library / publish (push) Failing after 26s
2024-06-24 22:32:03 +02:00
912b69ef93
Try to fix publish.yaml workflow
All checks were successful
Build library & run tests / build (unix) (push) Successful in 33s
Build library & run tests / build (tcp) (push) Successful in 34s
Build library & run tests / docs (push) Successful in 35s
2024-06-24 21:54:28 +02:00
2353c1648e
Bump for mistake in deploy workflow
Some checks failed
Build library & run tests / build (unix) (push) Successful in 20s
Build library & run tests / build (tcp) (push) Successful in 21s
Build library & run tests / docs (push) Successful in 24s
Publish library / publish (push) Failing after 26s
2024-06-24 21:34:30 +02:00
e1f453fa8b
Update publish.yaml to properly format token for gitea
All checks were successful
Build library & run tests / build (unix) (push) Successful in 34s
Build library & run tests / build (tcp) (push) Successful in 35s
Build library & run tests / docs (push) Successful in 36s
2024-06-24 21:33:34 +02:00
4dff84f4e7
Move rand to dev-dependencies
Some checks failed
Build library & run tests / build (tcp) (push) Successful in 20s
Build library & run tests / build (unix) (push) Successful in 19s
Build library & run tests / docs (push) Successful in 24s
Publish library / publish (push) Failing after 25s
2024-06-24 21:29:48 +02:00
4fc0359625
Lift dry run flag from publish.yaml
All checks were successful
Build library & run tests / build (tcp) (push) Successful in 34s
Build library & run tests / build (unix) (push) Successful in 33s
Build library & run tests / docs (push) Successful in 37s
2024-06-24 21:28:16 +02:00
8313209e0e
Bump for testing
All checks were successful
Build library & run tests / build (unix) (push) Successful in 1m7s
Build library & run tests / build (tcp) (push) Successful in 1m10s
Build library & run tests / docs (push) Successful in 22s
Publish library / publish (push) Successful in 32s
2024-06-24 21:20:40 +02:00
91deddc1d2
Add publishing to gitea releases for the release workflow
All checks were successful
Build library & run tests / build (unix) (push) Successful in 34s
Build library & run tests / build (tcp) (push) Successful in 35s
Build library & run tests / docs (push) Successful in 35s
2024-06-24 21:20:02 +02:00
0d018d0869
Attempt to add publish workflow
All checks were successful
Build library & run tests / build (unix) (push) Successful in 34s
Build library & run tests / build (tcp) (push) Successful in 34s
Build library & run tests / docs (push) Successful in 35s
2024-06-24 21:12:14 +02:00
71adf67727
Add description and repository to manifest
All checks were successful
Build library & run tests / build (unix) (push) Successful in 57s
Build library & run tests / docs (push) Successful in 58s
Build library & run tests / build (tcp) (push) Successful in 1m1s
2024-06-24 21:04:36 +02:00
9 changed files with 934 additions and 140 deletions

2
.cargo/config.toml Normal file
View File

@ -0,0 +1,2 @@
[build]
rustflags = ["--cfg", "tokio_unstable"]

View 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

731
Cargo.lock generated
View File

@ -75,6 +75,12 @@ 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]] [[package]]
name = "async-stream" name = "async-stream"
version = "0.3.5" version = "0.3.5"
@ -97,6 +103,68 @@ dependencies = [
"syn", "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"
@ -118,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"
@ -127,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"
@ -152,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",
@ -163,10 +306,17 @@ dependencies = [
"ron", "ron",
"serde", "serde",
"syn", "syn",
"thiserror",
"tokio", "tokio",
"tokio-test", "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"
@ -190,12 +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]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.30" version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 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"
@ -213,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"
@ -243,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"
@ -269,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"
@ -288,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"
@ -309,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"
@ -356,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]]
@ -368,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"
@ -384,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",
] ]
@ -395,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"
@ -415,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"
@ -436,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"
@ -450,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"
@ -488,6 +1067,131 @@ dependencies = [
"tokio-stream", "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"
@ -500,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"

View File

@ -1,33 +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"
log = "0.4.21"
tokio-test = "0.4.4" tokio-test = "0.4.4"
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

View File

@ -9,6 +9,8 @@ Eagle is still in early development. Performance is not ideal, the interface is
Eagle is a library which allows you to easily build an [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) protocol. Eagle is a library which allows you to easily build an [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) protocol.
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. 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.
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, 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. 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.
@ -67,9 +69,9 @@ Your handler can now be used by the server. You can easily bind your server to a
use shared::ExampleServer; use shared::ExampleServer;
let handler = ExampleHandler { state: 0 }; let handler = ExampleHandler { state: 0 };
let server_task = tokio::spawn(ExampleServer::bind(handler, "127.0.0.1:1234")); let server_task = ExampleServer::bind(handler, "127.0.0.1:1234").await;
// Or, if you're using the 'unix' feature... // Or, if you're using the 'unix' feature...
let server_task = tokio::spawn(ExampleServer::bind(handler, "/tmp/sock")); let server_task = ExampleServer::bind(handler, "/tmp/sock").await;
``` ```

View File

@ -14,7 +14,18 @@
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;

View File

@ -102,13 +102,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
//! # tokio_test::block_on(async { //! # tokio_test::block_on(async {
//! let handler = Handler; //! let handler = Handler;
//! let address = "127.0.0.1:12345"; // Or, if using the 'unix' feature, "/tmp/eagle.sock" //! let address = "127.0.0.1:12345"; // Or, if using the 'unix' feature, "/tmp/eagle.sock"
//! let server_task = tokio::spawn(ExampleServer::bind(handler, address)); //! let server = ExampleServer::bind(handler, address).await;
//! # }); //! # });
//! ``` //! ```
//! //! Once bound, the server will begin listening for incoming connections and
//! Please note the usage of `tokio::spawn`. This is because the `bind` function //! queries.
//! will not return until the server is closed. You can use the `abort` method
//! on the task to close the server.
//! //!
//! On the client side, you can simply use the generated client struct to connect //! On the client side, you can simply use the generated client struct to connect
//! to the server and begin sending queries. //! to the server and begin sending queries.
@ -136,16 +134,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
//! # tokio_test::block_on(async { //! # tokio_test::block_on(async {
//! # let handler = Handler; //! # let handler = Handler;
//! let address = "127.0.0.1:12345"; // Or, if using the 'unix' feature, "/tmp/eagle.sock" //! let address = "127.0.0.1:12345"; // Or, if using the 'unix' feature, "/tmp/eagle.sock"
//! # let server_task = tokio::spawn(ExampleServer::bind(handler, address)); //! # 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(); //! let client = ExampleClient::connect(address).await.unwrap();
//! # // Wait for the server to start, the developer is responsible for this in production
//! # tokio::time::sleep(std::time::Duration::from_millis(10)).await;
//! assert_eq!(client.add(2, 5).await.unwrap(), 7); //! assert_eq!(client.add(2, 5).await.unwrap(), 7);
//! # }); //! # });
//! ``` //! ```
//!
//! The client can be closed by calling the `close` method on the client struct.
//! This will abort the connection.
#![warn(missing_docs)] #![warn(missing_docs)]
use proc_macro::TokenStream; use proc_macro::TokenStream;
@ -198,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 {
@ -255,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)
@ -299,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
@ -313,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! {
@ -323,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), *
} }
@ -368,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)*
} }
@ -384,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! {
@ -414,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());
} }
} }
@ -458,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);
@ -467,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]);
while buf.len() >= 4 { 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));
@ -493,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),
} }
} }
} }
@ -519,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()
} }
} }
}; };
@ -541,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 {
@ -562,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 {
@ -590,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 {
@ -598,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),
} }
} }
} }
@ -610,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(),
@ -650,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;
@ -672,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),
}; };
} }
} }
@ -702,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

View File

@ -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());

View File

@ -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 {
@ -65,6 +72,7 @@ impl Drop for Cleanup {
#[tokio::test] #[tokio::test]
async fn e2e() { async fn e2e() {
init_logger(); init_logger();
init_console();
#[cfg(feature = "unix")] #[cfg(feature = "unix")]
let address = format!("/tmp/eagle-test-{}.sock", rand::random::<u64>()); let address = format!("/tmp/eagle-test-{}.sock", rand::random::<u64>());
#[cfg(feature = "unix")] #[cfg(feature = "unix")]
@ -73,9 +81,8 @@ async fn e2e() {
}; };
#[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, the developer is responsible for this in production 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();
assert_eq!(client.addition(2, 5).await.unwrap(), 7); assert_eq!(client.addition(2, 5).await.unwrap(), 7);
assert_eq!( assert_eq!(
@ -90,5 +97,4 @@ async fn e2e() {
"The number is 42" "The number is 42"
); );
client.void().await.unwrap(); client.void().await.unwrap();
server_task.abort();
} }