diff --git a/Cargo.lock b/Cargo.lock index c38b5cce..88755425 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -915,7 +915,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" dependencies = [ "once_cell", - "proc-macro-crate 3.5.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.117", @@ -1604,9 +1604,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] @@ -1641,9 +1641,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1981,6 +1981,37 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.10", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.117", +] + [[package]] name = "derive_more" version = "0.99.20" @@ -2231,30 +2262,28 @@ dependencies = [ "defguard_wireguard_rs", "delegate", "derivative", + "derive_builder", "derive_more 2.1.1", - "easytier-rpc-build", "encoding", "flume 0.12.0", "forwarded-header-value", "futures", "futures-util", - "getset", + "gethostname 0.5.0", "git-version", "globwalk", "guarden", - "hickory-net", + "hickory-client", "hickory-proto", "hickory-resolver", "hickory-server", "hmac", - "hostname", "http", "http_req", "humansize", "humantime-serde", "idna 1.0.3", "igd-next", - "indexmap 2.14.0", "indoc", "itertools 0.14.0", "kcp-sys", @@ -2272,7 +2301,6 @@ dependencies = [ "nix 0.29.0", "once_cell", "openssl", - "optionize", "ordered_hash_map", "parking_lot", "paste", @@ -2280,7 +2308,8 @@ dependencies = [ "petgraph 0.8.1", "pin-project-lite", "pnet", - "prefix-trie 0.7.0", + "prefix-trie", + "proc-macro2", "prost", "prost-build", "prost-reflect", @@ -2290,6 +2319,7 @@ dependencies = [ "prost-wkt-types", "quinn", "quinn-plaintext", + "quote", "rand 0.8.5", "rcgen", "regex", @@ -2302,7 +2332,6 @@ dependencies = [ "rustls", "serde", "serde_json", - "serde_with", "serial_test", "service-manager", "sha2", @@ -2330,7 +2359,6 @@ dependencies = [ "tokio-util", "tokio-websockets", "toml 0.8.19", - "tonic-build", "tracing", "tracing-subscriber", "tun-easytier", @@ -2357,7 +2385,7 @@ version = "0.1.0" dependencies = [ "android_logger", "easytier", - "jni 0.21.1", + "jni", "log", "once_cell", "serde", @@ -2386,7 +2414,7 @@ dependencies = [ "dashmap", "dunce", "easytier", - "gethostname", + "gethostname 1.1.0", "libc", "once_cell", "security-framework-sys", @@ -2409,14 +2437,6 @@ dependencies = [ "windows 0.52.0", ] -[[package]] -name = "easytier-rpc-build" -version = "0.1.0" -dependencies = [ - "heck 0.5.0", - "prost-build", -] - [[package]] name = "easytier-uptime" version = "0.1.0" @@ -2681,6 +2701,24 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "enumflags2" version = "0.7.12" @@ -3238,6 +3276,19 @@ dependencies = [ "x11", ] +[[package]] +name = "generator" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" +dependencies = [ + "cfg-if", + "libc", + "log", + "rustversion", + "windows 0.58.0", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -3249,6 +3300,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "gethostname" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3655aa6818d65bc620d6911f05aa7b6aeb596291e1e9f79e52df85583d1e30" +dependencies = [ + "rustix 0.38.34", + "windows-targets 0.52.6", +] + [[package]] name = "gethostname" version = "1.1.0" @@ -3311,18 +3372,6 @@ dependencies = [ "wasip3", ] -[[package]] -name = "getset" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf0fc11e47561d47397154977bc219f4cf809b2974facc3ccb3b89e2436f912" -dependencies = [ - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "ghash" version = "0.5.1" @@ -3686,22 +3735,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hickory-net" -version = "0.26.0" +name = "hickory-client" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c61c8db47fae51ba9f8f2a2748bd87542acfbe22f2ec9cf9c8ec72d1ee6e9a6" +checksum = "c466cd63a4217d5b2b8e32f23f58312741ce96e3c84bf7438677d2baff0fc555" +dependencies = [ + "cfg-if", + "data-encoding", + "futures-channel", + "futures-util", + "hickory-proto", + "once_cell", + "radix_trie", + "rand 0.9.1", + "thiserror 2.0.11", + "tokio", + "tracing", +] + +[[package]] +name = "hickory-proto" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" dependencies = [ "async-trait", "cfg-if", "data-encoding", + "enum-as-inner", "futures-channel", "futures-io", "futures-util", - "hickory-proto", "idna 1.0.3", "ipnet", - "jni 0.22.4", - "rand 0.10.1", + "once_cell", + "rand 0.9.1", + "ring", "serde", "thiserror 2.0.11", "tinyvec", @@ -3710,49 +3779,23 @@ dependencies = [ "url", ] -[[package]] -name = "hickory-proto" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a916d0494600d99ecb15aadfab677ad97c4de559e8f1af0c129353a733ac1fcc" -dependencies = [ - "data-encoding", - "idna 1.0.3", - "ipnet", - "jni 0.22.4", - "once_cell", - "prefix-trie 0.8.2", - "rand 0.10.1", - "ring", - "serde", - "thiserror 2.0.11", - "tinyvec", - "tracing", - "url", -] - [[package]] name = "hickory-resolver" -version = "0.26.0" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a10bd64d950b4d38ca21e25c8ae230712e4955fb8290cfcb29a5e5dc6017e544" +checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" dependencies = [ "cfg-if", "futures-util", - "hickory-net", "hickory-proto", "ipconfig", - "ipnet", - "jni 0.22.4", "moka", - "ndk-context", "once_cell", "parking_lot", - "rand 0.10.1", + "rand 0.9.1", "resolv-conf", "serde", "smallvec", - "system-configuration 0.7.0", "thiserror 2.0.11", "tokio", "tracing", @@ -3760,20 +3803,20 @@ dependencies = [ [[package]] name = "hickory-server" -version = "0.26.0" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91725f56e8e6b1fc4e68d4f86cf15714f1050f68ae817da6916da67041949f02" +checksum = "d53e5fe811b941c74ee46b8818228bfd2bc2688ba276a0eaeb0f2c95ea3b2585" dependencies = [ "async-trait", "bytes", "cfg-if", "data-encoding", + "enum-as-inner", "futures-util", - "hickory-net", "hickory-proto", "hickory-resolver", "ipnet", - "prefix-trie 0.8.2", + "prefix-trie", "serde", "thiserror 2.0.11", "time", @@ -3809,17 +3852,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "hostname" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" -dependencies = [ - "cfg-if", - "libc", - "windows-link 0.2.1", -] - [[package]] name = "html5ever" version = "0.29.1" @@ -4005,7 +4037,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -4517,68 +4549,19 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys 0.3.0", + "jni-sys", "log", "thiserror 1.0.63", "walkdir", "windows-sys 0.45.0", ] -[[package]] -name = "jni" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" -dependencies = [ - "cfg-if", - "combine", - "jni-macros", - "jni-sys 0.4.1", - "log", - "simd_cesu8", - "thiserror 2.0.11", - "walkdir", - "windows-link 0.2.1", -] - -[[package]] -name = "jni-macros" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" -dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "simd_cesu8", - "syn 2.0.117", -] - [[package]] name = "jni-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" -[[package]] -name = "jni-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" -dependencies = [ - "jni-sys-macros", -] - -[[package]] -name = "jni-sys-macros" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" -dependencies = [ - "quote", - "syn 2.0.117", -] - [[package]] name = "jobserver" version = "0.1.32" @@ -4865,6 +4848,19 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "lru-slab" version = "0.1.2" @@ -5096,21 +5092,23 @@ dependencies = [ [[package]] name = "moka" -version = "0.12.15" +version = "0.12.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" +checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" dependencies = [ "async-lock", "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", - "equivalent", "event-listener", "futures-util", + "loom", "parking_lot", "portable-atomic", + "rustc_version", "smallvec", "tagptr", + "thiserror 1.0.63", "uuid", ] @@ -5205,7 +5203,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.8.0", - "jni-sys 0.3.0", + "jni-sys", "log", "ndk-sys", "num_enum", @@ -5225,7 +5223,7 @@ version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys 0.3.0", + "jni-sys", ] [[package]] @@ -5241,7 +5239,7 @@ dependencies = [ "netlink-packet-route 0.17.1", "netlink-sys", "once_cell", - "system-configuration 0.6.1", + "system-configuration", "windows-sys 0.52.0", ] @@ -5352,6 +5350,15 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + [[package]] name = "nix" version = "0.25.1" @@ -5570,7 +5577,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ - "proc-macro-crate 2.0.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.117", @@ -5921,30 +5928,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "optionize" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f15b218321873a7919c8b2a188ad488bf18c067478274be4c69c3d402b2be3ea" -dependencies = [ - "delegate", - "derive_more 2.1.1", - "optionize-macros", -] - -[[package]] -name = "optionize-macros" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1af5a2aba73a1808cbb39b451aabb5f8dc5c9c73d68ce5e61b79f8892f775a0f" -dependencies = [ - "darling 0.23.0", - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "ordered-float" version = "2.10.1" @@ -6674,17 +6657,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "prefix-trie" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23370be78b7e5bcbb0cab4a02047eb040279a693c78daad04c2c5f1c24a83503" -dependencies = [ - "either", - "ipnet", - "num-traits", -] - [[package]] name = "prettyplease" version = "0.2.20" @@ -6725,11 +6697,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.5.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.25.11+spec-1.1.0", + "toml_edit 0.22.20", ] [[package]] @@ -7082,6 +7054,16 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + [[package]] name = "rand" version = "0.7.3" @@ -7408,7 +7390,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration 0.6.1", + "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", @@ -7583,7 +7565,7 @@ checksum = "1f168d99749d307be9de54d23fd226628d99768225ef08f6ffb52e0182a27746" dependencies = [ "cfg-if", "glob", - "proc-macro-crate 3.5.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "regex", @@ -7792,7 +7774,7 @@ checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" dependencies = [ "core-foundation 0.10.0", "core-foundation-sys", - "jni 0.21.1", + "jni", "log", "once_cell", "rustls", @@ -7931,6 +7913,12 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -8585,16 +8573,6 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" -[[package]] -name = "simd_cesu8" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" -dependencies = [ - "rustc_version", - "simdutf8", -] - [[package]] name = "simdutf8" version = "0.1.5" @@ -9154,17 +9132,6 @@ dependencies = [ "system-configuration-sys", ] -[[package]] -name = "system-configuration" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" -dependencies = [ - "bitflags 2.8.0", - "core-foundation 0.9.4", - "system-configuration-sys", -] - [[package]] name = "system-configuration-sys" version = "0.6.0" @@ -9234,7 +9201,7 @@ dependencies = [ "gdkwayland-sys", "gdkx11-sys", "gtk", - "jni 0.21.1", + "jni", "libc", "log", "ndk", @@ -9296,7 +9263,7 @@ dependencies = [ "heck 0.5.0", "http", "image 0.25.10", - "jni 0.21.1", + "jni", "libc", "log", "mime", @@ -9431,7 +9398,7 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8f08346c8deb39e96f86973da0e2d76cbb933d7ac9b750f6dc4daf955a6f997" dependencies = [ - "gethostname", + "gethostname 1.1.0", "log", "os_info", "serde", @@ -9524,7 +9491,7 @@ dependencies = [ "dpi", "gtk", "http", - "jni 0.21.1", + "jni", "objc2", "objc2-ui-kit", "objc2-web-kit", @@ -9547,7 +9514,7 @@ checksum = "e11ea2e6f801d275fdd890d6c9603736012742a1c33b96d0db788c9cdebf7f9e" dependencies = [ "gtk", "http", - "jni 0.21.1", + "jni", "log", "objc2", "objc2-app-kit", @@ -9998,15 +9965,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" -dependencies = [ - "serde_core", -] - [[package]] name = "toml_edit" version = "0.19.15" @@ -10044,18 +10002,6 @@ dependencies = [ "winnow 0.6.18", ] -[[package]] -name = "toml_edit" -version = "0.25.11+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" -dependencies = [ - "indexmap 2.14.0", - "toml_datetime 1.1.1+spec-1.1.0", - "toml_parser", - "winnow 1.0.1", -] - [[package]] name = "toml_parser" version = "1.1.2+spec-1.1.0" @@ -10101,19 +10047,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tonic-build" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568392c5a2bd0020723e3f387891176aabafe36fd9fcd074ad309dfa0c8eb964" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "quote", - "syn 2.0.117", -] - [[package]] name = "tower" version = "0.4.13" @@ -11111,8 +11044,8 @@ dependencies = [ "webview2-com-sys", "windows 0.61.3", "windows-core 0.61.2", - "windows-implement", - "windows-interface", + "windows-implement 0.60.2", + "windows-interface 0.59.3", ] [[package]] @@ -11285,6 +11218,16 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows" version = "0.61.3" @@ -11337,14 +11280,27 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement", - "windows-interface", + "windows-implement 0.60.2", + "windows-interface 0.59.3", "windows-link 0.1.3", "windows-result 0.3.4", "windows-strings 0.4.2", @@ -11356,8 +11312,8 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement", - "windows-interface", + "windows-implement 0.60.2", + "windows-interface 0.59.3", "windows-link 0.2.1", "windows-result 0.4.1", "windows-strings 0.5.1", @@ -11385,6 +11341,17 @@ dependencies = [ "windows-threading 0.2.1", ] +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-implement" version = "0.60.2" @@ -11396,6 +11363,17 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-interface" version = "0.59.3" @@ -11871,9 +11849,6 @@ name = "winnow" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" -dependencies = [ - "memchr", -] [[package]] name = "winreg" @@ -12075,7 +12050,7 @@ dependencies = [ "html5ever", "http", "javascriptcore-rs", - "jni 0.21.1", + "jni", "kuchikiki", "libc", "ndk", @@ -12138,7 +12113,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" dependencies = [ - "gethostname", + "gethostname 1.1.0", "rustix 1.0.7", "x11rb-protocol", ] @@ -12255,7 +12230,7 @@ version = "5.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" dependencies = [ - "proc-macro-crate 3.5.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.117", @@ -12492,7 +12467,7 @@ version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c" dependencies = [ - "proc-macro-crate 3.5.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.117", diff --git a/Cargo.toml b/Cargo.toml index fecdef70..2a2eb144 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ resolver = "2" members = [ "easytier", "easytier-gui/src-tauri", - "easytier-rpc-build", "easytier-web", "easytier-contrib/easytier-ffi", "easytier-contrib/easytier-uptime", diff --git a/easytier-rpc-build/Cargo.toml b/easytier-rpc-build/Cargo.toml deleted file mode 100644 index 510d8381..00000000 --- a/easytier-rpc-build/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "easytier-rpc-build" -description = "Protobuf RPC Service Generator for EasyTier" -version = "0.1.0" -edition.workspace = true -homepage = "https://github.com/EasyTier/EasyTier" -repository = "https://github.com/EasyTier/EasyTier" -authors = ["kkrainbow"] -keywords = ["vpn", "p2p", "network", "easytier"] -categories = ["network-programming", "command-line-utilities"] -license-file = "LICENSE" -readme = "README.md" - -[dependencies] -heck = "0.5" -prost-build = "0.13" - -[features] -default = [] -internal-namespace = [] diff --git a/easytier-rpc-build/LICENSE b/easytier-rpc-build/LICENSE deleted file mode 120000 index ea5b6064..00000000 --- a/easytier-rpc-build/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE \ No newline at end of file diff --git a/easytier-rpc-build/README.md b/easytier-rpc-build/README.md deleted file mode 100644 index 66b1cae0..00000000 --- a/easytier-rpc-build/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Introduction - -This is a protobuf rpc service stub generator for [EasyTier](https://github.com/EasyTier/EasyTier) project. diff --git a/easytier-rpc-build/src/lib.rs b/easytier-rpc-build/src/lib.rs deleted file mode 100644 index f41f1e18..00000000 --- a/easytier-rpc-build/src/lib.rs +++ /dev/null @@ -1,449 +0,0 @@ -extern crate heck; -extern crate prost_build; - -use std::fmt; - -#[cfg(feature = "internal-namespace")] -const NAMESPACE: &str = "crate::proto::rpc_types"; - -#[cfg(not(feature = "internal-namespace"))] -const NAMESPACE: &str = "easytier::proto::rpc_types"; - -/// The service generator to be used with `prost-build` to generate RPC implementations for -/// `prost-simple-rpc`. -/// -/// See the crate-level documentation for more info. -#[allow(missing_copy_implementations)] -#[derive(Clone, Debug, Default)] -pub struct ServiceGenerator { - _private: (), -} - -impl prost_build::ServiceGenerator for ServiceGenerator { - fn generate(&mut self, service: prost_build::Service, mut buf: &mut String) { - use std::fmt::Write; - - let descriptor_name = format!("{}Descriptor", service.name); - let server_name = format!("{}Server", service.name); - let client_name = format!("{}Client", service.name); - let method_descriptor_name = format!("{}MethodDescriptor", service.name); - - let mut trait_methods = String::new(); - let mut weak_impl_methods = String::new(); - let mut enum_methods = String::new(); - let mut list_enum_methods = String::new(); - let mut client_methods = String::new(); - let mut client_own_methods = String::new(); - let mut match_name_methods = String::new(); - let mut match_proto_name_methods = String::new(); - let mut match_input_type_methods = String::new(); - let mut match_input_proto_type_methods = String::new(); - let mut match_output_type_methods = String::new(); - let mut match_output_proto_type_methods = String::new(); - let mut match_handle_methods = String::new(); - // generate trait default method Xxx::json_call_method match branch - let mut match_trait_json_methods = String::new(); - - let mut match_method_try_from = String::new(); - - for (idx, method) in service.methods.iter().enumerate() { - assert!( - !method.client_streaming, - "Client streaming not yet supported for method {}", - method.proto_name - ); - assert!( - !method.server_streaming, - "Server streaming not yet supported for method {}", - method.proto_name - ); - - ServiceGenerator::write_comments(&mut trait_methods, 4, &method.comments).unwrap(); - writeln!( - trait_methods, - r#" async fn {name}(&self, ctrl: Self::Controller, input: {input_type}) -> {namespace}::error::Result<{output_type}>;"#, - name = method.name, - input_type = method.input_type, - output_type = method.output_type, - namespace = NAMESPACE, - ) - .unwrap(); - - writeln!( - weak_impl_methods, - r#" async fn {method_name}(&self, ctrl: Self::Controller, input: {input_type}) -> {namespace}::error::Result<{output_type}> {{ - let Some(service) = self.upgrade() else {{ - return Err({namespace}::error::Error::Shutdown); - }}; - service.{method_name}(ctrl, input).await - }}"#, - method_name = method.name, - input_type = method.input_type, - output_type = method.output_type, - namespace = NAMESPACE, - ) - .unwrap(); - - ServiceGenerator::write_comments(&mut enum_methods, 4, &method.comments).unwrap(); - writeln!( - enum_methods, - " {name} = {index},", - name = method.proto_name, - index = idx + 1 - ) - .unwrap(); - - writeln!( - match_method_try_from, - " {index} => Ok({service_name}MethodDescriptor::{name}),", - service_name = service.name, - name = method.proto_name, - index = idx + 1, - ) - .unwrap(); - - writeln!( - list_enum_methods, - " {service_name}MethodDescriptor::{name},", - service_name = service.name, - name = method.proto_name - ) - .unwrap(); - - writeln!( - client_methods, - r#" async fn {name}(&self, ctrl: H::Controller, input: {input_type}) -> {namespace}::error::Result<{output_type}> {{ - {client_name}Client::{name}_inner(self.0.clone(), ctrl, input).await - }}"#, - name = method.name, - input_type = method.input_type, - output_type = method.output_type, - client_name = service.name, - namespace = NAMESPACE, - ) - .unwrap(); - - writeln!( - client_own_methods, - r#" async fn {name}_inner(handler: H, ctrl: H::Controller, input: {input_type}) -> {namespace}::error::Result<{output_type}> {{ - {namespace}::__rt::call_method(handler, ctrl, {method_descriptor_name}::{proto_name}, input).await - }}"#, - name = method.name, - method_descriptor_name = method_descriptor_name, - proto_name = method.proto_name, - input_type = method.input_type, - output_type = method.output_type, - namespace = NAMESPACE, - ).unwrap(); - - let case = format!( - " {service_name}MethodDescriptor::{proto_name} => ", - service_name = service.name, - proto_name = method.proto_name - ); - - writeln!(match_name_methods, "{}{:?},", case, method.name).unwrap(); - writeln!(match_proto_name_methods, "{}{:?},", case, method.proto_name).unwrap(); - writeln!( - match_input_type_methods, - "{}::std::any::TypeId::of::<{}>(),", - case, method.input_type - ) - .unwrap(); - writeln!( - match_input_proto_type_methods, - "{}{:?},", - case, method.input_proto_type - ) - .unwrap(); - writeln!( - match_output_type_methods, - "{}::std::any::TypeId::of::<{}>(),", - case, method.output_type - ) - .unwrap(); - writeln!( - match_output_proto_type_methods, - "{}{:?},", - case, method.output_proto_type - ) - .unwrap(); - write!( - match_handle_methods, - r#"{} {{ - let decoded: {input_type} = {namespace}::__rt::decode(input)?; - let ret = service.{name}(ctrl, decoded).await?; - {namespace}::__rt::encode(ret) - }} -"#, - case, - input_type = method.input_type, - name = method.name, - namespace = NAMESPACE, - ) - .unwrap(); - - write!( - match_trait_json_methods, - r#" "{name}" | "{proto_name}" => {{ - let req: {input_type} = ::serde_json::from_value(json).map_err(|e| {namespace}::error::Error::MalformatRpcPacket(format!("json error: {{}}", e)))?; - let resp = self.{typed_method}(ctrl, req).await?; - Ok(::serde_json::to_value(resp).map_err(|e| {namespace}::error::Error::MalformatRpcPacket(format!("json error: {{}}", e)))?) - }} -"#, - name = method.name, - proto_name = method.proto_name, - input_type = method.input_type, - typed_method = method.name, - namespace = NAMESPACE, - ) - .unwrap(); - } - - ServiceGenerator::write_comments(&mut buf, 0, &service.comments).unwrap(); - write!( - buf, - r#" -#[async_trait::async_trait] -#[auto_impl::auto_impl(&, Arc, Box)] -pub trait {name} {{ - type Controller: {namespace}::controller::Controller; - - {trait_methods} - - async fn json_call_method( - &self, - ctrl: Self::Controller, - method_name: &str, - json: ::serde_json::Value, - ) -> {namespace}::error::Result<::serde_json::Value> {{ - match method_name {{ -{match_trait_json_methods} - _ => Err({namespace}::error::Error::InvalidMethodIndex(0, method_name.to_string())), - }} - }} -}} - -#[async_trait::async_trait] -impl {name} for ::std::sync::Weak -where - T: Send + Sync + 'static, - ::std::sync::Arc: {name}, -{{ - type Controller = <::std::sync::Arc as {name}>::Controller; - - {weak_impl_methods} -}} - -/// A service descriptor for a `{name}`. -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Default)] -pub struct {descriptor_name}; - -/// Methods available on a `{name}`. -/// -/// This can be used as a key when routing requests for servers/clients of a `{name}`. -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] -#[repr(u8)] -pub enum {method_descriptor_name} {{ - {enum_methods} -}} - -impl std::convert::TryFrom for {method_descriptor_name} {{ - type Error = {namespace}::error::Error; - fn try_from(value: u8) -> {namespace}::error::Result {{ - match value {{ - {match_method_try_from} - _ => Err({namespace}::error::Error::InvalidMethodIndex(value, "{name}".to_string())), - }} - }} -}} - -/// A client for a `{name}`. -/// -/// This implements the `{name}` trait by dispatching all method calls to the supplied `Handler`. -#[derive(Clone, Debug)] -pub struct {client_name}(H) where H: {namespace}::handler::Handler; - -impl {client_name} where H: {namespace}::handler::Handler {{ - /// Creates a new client instance that delegates all method calls to the supplied handler. - pub fn new(handler: H) -> {client_name} {{ - {client_name}(handler) - }} -}} - -impl {client_name} where H: {namespace}::handler::Handler {{ - {client_own_methods} -}} - -#[async_trait::async_trait] -impl {name} for {client_name} where H: {namespace}::handler::Handler {{ - type Controller = H::Controller; - - {client_methods} -}} - -pub struct {client_name}Factory(std::marker::PhantomData); - -impl Clone for {client_name}Factory {{ - fn clone(&self) -> Self {{ - Self(std::marker::PhantomData) - }} -}} - -impl {namespace}::__rt::RpcClientFactory for {client_name}Factory where C: {namespace}::controller::Controller {{ - type Descriptor = {descriptor_name}; - type ClientImpl = Box + Send + Sync + 'static>; - type Controller = C; - - fn new(handler: impl {namespace}::handler::Handler) -> Self::ClientImpl {{ - Box::new({client_name}::new(handler)) - }} -}} - -/// A server for a `{name}`. -/// -/// This implements the `Server` trait by handling requests and dispatch them to methods on the -/// supplied `{name}`. -#[derive(Clone, Debug)] -pub struct {server_name}(A) where A: {name} + Clone + Send + 'static; - -impl {server_name}<::std::sync::Weak> -where - T: Send + Sync + 'static, - ::std::sync::Arc: {name}, -{{ - pub fn new_arc(service: ::std::sync::Arc) -> {server_name}<::std::sync::Weak> {{ - {server_name}(::std::sync::Arc::downgrade(&service)) - }} -}} - -impl {server_name} where A: {name} + Clone + Send + 'static {{ - /// Creates a new server instance that dispatches all calls to the supplied service. - pub fn new(service: A) -> {server_name} {{ - {server_name}(service) - }} - - async fn call_inner( - service: A, - method: {method_descriptor_name}, - ctrl: A::Controller, - input: ::bytes::Bytes) - -> {namespace}::error::Result<::bytes::Bytes> {{ - match method {{ - {match_handle_methods} - }} - }} -}} - -impl {namespace}::descriptor::ServiceDescriptor for {descriptor_name} {{ - type Method = {method_descriptor_name}; - fn name(&self) -> &'static str {{ {name:?} }} - fn proto_name(&self) -> &'static str {{ {proto_name:?} }} - fn package(&self) -> &'static str {{ {package:?} }} - fn methods(&self) -> &'static [Self::Method] {{ - &[ {list_enum_methods} ] - }} -}} - -#[async_trait::async_trait] -impl {namespace}::handler::Handler for {server_name} -where - A: {name} + Clone + Send + Sync + 'static {{ - type Descriptor = {descriptor_name}; - type Controller = A::Controller; - - async fn call( - &self, - ctrl: A::Controller, - method: {method_descriptor_name}, - input: ::bytes::Bytes) - -> {namespace}::error::Result<::bytes::Bytes> {{ - {server_name}::call_inner(self.0.clone(), method, ctrl, input).await - }} -}} - -impl {namespace}::descriptor::MethodDescriptor for {method_descriptor_name} {{ - fn name(&self) -> &'static str {{ - match *self {{ - {match_name_methods} - }} - }} - - fn proto_name(&self) -> &'static str {{ - match *self {{ - {match_proto_name_methods} - }} - }} - - fn input_type(&self) -> ::std::any::TypeId {{ - match *self {{ - {match_input_type_methods} - }} - }} - - fn input_proto_type(&self) -> &'static str {{ - match *self {{ - {match_input_proto_type_methods} - }} - }} - - fn output_type(&self) -> ::std::any::TypeId {{ - match *self {{ - {match_output_type_methods} - }} - }} - - fn output_proto_type(&self) -> &'static str {{ - match *self {{ - {match_output_proto_type_methods} - }} - }} - - fn index(&self) -> u8 {{ - *self as u8 - }} -}} -"#, - name = service.name, - descriptor_name = descriptor_name, - server_name = server_name, - client_name = client_name, - method_descriptor_name = method_descriptor_name, - proto_name = service.proto_name, - package = service.package, - trait_methods = trait_methods, - weak_impl_methods = weak_impl_methods, - enum_methods = enum_methods, - list_enum_methods = list_enum_methods, - client_own_methods = client_own_methods, - client_methods = client_methods, - match_name_methods = match_name_methods, - match_proto_name_methods = match_proto_name_methods, - match_input_type_methods = match_input_type_methods, - match_input_proto_type_methods = match_input_proto_type_methods, - match_output_type_methods = match_output_type_methods, - match_output_proto_type_methods = match_output_proto_type_methods, - match_handle_methods = match_handle_methods, - match_trait_json_methods = match_trait_json_methods, - namespace = NAMESPACE, - ).unwrap(); - } -} - -impl ServiceGenerator { - fn write_comments( - mut write: W, - indent: usize, - comments: &prost_build::Comments, - ) -> fmt::Result - where - W: fmt::Write, - { - for comment in &comments.leading { - for line in comment.lines().filter(|s| !s.is_empty()) { - writeln!(write, "{}///{}", " ".repeat(indent), line)?; - } - } - Ok(()) - } -} diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index 16b6aeb5..b94a45ab 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -11,6 +11,7 @@ keywords = ["vpn", "p2p", "network", "easytier"] categories = ["network-programming", "command-line-utilities"] license-file = "LICENSE" readme = "README.md" +build = "build/main.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -320,15 +321,14 @@ jemalloc-sys = { package = "tikv-jemalloc-sys", version = "0.6.0", features = [ [build-dependencies] cfg_aliases = "0.2.1" -tonic-build = "0.12" +indoc = "2.0" globwalk = "0.8.1" regex = "1" prost-build = "0.13.5" prost-wkt-build = "0.6" -easytier-rpc-build = { path = "../easytier-rpc-build", features = [ - "internal-namespace", -] } prost-reflect-build = { version = "0.14.0" } +proc-macro2 = "1" +quote = "1" thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = [ "win7", ] } diff --git a/easytier/build.rs b/easytier/build/main.rs similarity index 98% rename from easytier/build.rs rename to easytier/build/main.rs index 61a35b77..10f7e752 100644 --- a/easytier/build.rs +++ b/easytier/build/main.rs @@ -1,3 +1,6 @@ +mod rpc; + +use crate::rpc::ServiceGenerator; use cfg_aliases::cfg_aliases; use prost_wkt_build::{FileDescriptorSet, Message as _}; #[cfg(target_os = "windows")] @@ -203,7 +206,7 @@ fn main() -> Result<(), Box> { config .btree_map(["."]) - .service_generator(Box::new(easytier_rpc_build::ServiceGenerator::default())) + .service_generator(Box::new(ServiceGenerator::default())) .protoc_arg("--experimental_allow_proto3_optional") .file_descriptor_set_path(&descriptor_file) .compile_protos(&proto_files, &["src/proto/"])?; diff --git a/easytier/build/rpc.rs b/easytier/build/rpc.rs new file mode 100644 index 00000000..e8d4472d --- /dev/null +++ b/easytier/build/rpc.rs @@ -0,0 +1,720 @@ +#![allow(non_snake_case)] + +use indoc::formatdoc; +use proc_macro2::{Ident, TokenStream}; +use quote::{format_ident, quote}; +use std::str::FromStr; + +fn parse(value: &str) -> TokenStream { + TokenStream::from_str(value) + .unwrap_or_else(|err| panic!("Failed to parse tokens: {} ({})", value, err)) +} + +fn doc(comments: &prost_build::Comments) -> TokenStream { + let doc = comments + .leading + .iter() + .flat_map(|c| c.lines().filter(|s| !s.is_empty())); + quote! { #( #[doc = #doc] )* } +} + +const NAMESPACE: &str = "crate::proto::rpc_types"; + +struct Method { + index: u8, + doc: TokenStream, + method: Ident, + method_inner: Ident, + method_str: String, + method_proto: Ident, + method_proto_str: String, + Input: TokenStream, + Input_proto_str: String, + Output: TokenStream, + Output_proto_str: String, +} + +impl Method { + fn new(index: u8, method: prost_build::Method) -> Self { + assert!( + !method.client_streaming, + "Client streaming not yet supported for method {}", + method.proto_name + ); + assert!( + !method.server_streaming, + "Server streaming not yet supported for method {}", + method.proto_name + ); + Self { + index, + doc: doc(&method.comments), + method: format_ident!("{}", method.name), + method_inner: format_ident!("{}_inner", method.name), + method_str: method.name, + method_proto: format_ident!("{}", method.proto_name), + method_proto_str: method.proto_name, + Input: parse(&method.input_type), + Input_proto_str: method.input_proto_type, + Output: parse(&method.output_type), + Output_proto_str: method.output_proto_type, + } + } +} + +struct Service { + namespace: TokenStream, + doc: TokenStream, + Service: Ident, + ServiceDescriptor: Ident, + ServiceServer: Ident, + ServiceClient: Ident, + ServiceClientFactory: Ident, + ServiceMethodDescriptor: Ident, + Service_str: String, + Service_proto_str: String, + Service_package_str: String, + methods: Vec, +} + +impl Service { + fn new(service: prost_build::Service) -> Self { + let methods = service + .methods + .into_iter() + .enumerate() + .map(|(i, method)| Method::new((i + 1) as u8, method)) + .collect(); + + Self { + namespace: parse(NAMESPACE), + doc: doc(&service.comments), + Service: format_ident!("{}", service.name), + ServiceDescriptor: format_ident!("{}Descriptor", service.name), + ServiceServer: format_ident!("{}Server", service.name), + ServiceClient: format_ident!("{}Client", service.name), + ServiceClientFactory: format_ident!("{}ClientFactory", service.name), + ServiceMethodDescriptor: format_ident!("{}MethodDescriptor", service.name), + Service_str: service.name, + Service_proto_str: service.proto_name, + Service_package_str: service.package, + methods, + } + } + + fn trait_Service(&self) -> TokenStream { + let Self { + namespace, + doc, + Service, + methods, + .. + } = self; + + let match_json_call_method = methods.iter().map( + |Method { + method, + method_str, + method_proto_str, + Input, + .. + }| { + quote! { + #method_str | #method_proto_str => { + let req: #Input = ::serde_json::from_value(json) + .map_err(|e| #namespace::error::Error::MalformatRpcPacket(format!("json error: {}", e)))?; + let resp = self.#method(ctrl, req).await?; + Ok(::serde_json::to_value(resp) + .map_err(|e| #namespace::error::Error::MalformatRpcPacket(format!("json error: {}", e)))?) + } + } + }, + ); + + let methods = methods.iter().map( + |Method { + doc, + method, + Input, + Output, + .. + }| { + quote! { + #doc + async fn #method(&self, ctrl: Self::Controller, input: #Input) -> #namespace::error::Result<#Output>; + } + }, + ); + + quote! { + #doc + #[async_trait::async_trait] + #[auto_impl::auto_impl(&, Arc, Box)] + pub trait #Service { + type Controller: #namespace::controller::Controller; + + #(#methods)* + + async fn json_call_method( + &self, + ctrl: Self::Controller, + method: &str, + json: ::serde_json::Value, + ) -> #namespace::error::Result<::serde_json::Value> { + match method { + #(#match_json_call_method)* + _ => Err(#namespace::error::Error::InvalidMethodIndex(0, method.to_string())), + } + } + } + } + } + + fn impl_Service_for_Weak(&self) -> TokenStream { + let Self { + namespace, + Service, + methods, + .. + } = self; + let methods = methods.iter().map( + |Method { + method, + Input, + Output, + .. + }| { + quote! { + async fn #method(&self, ctrl: Self::Controller, input: #Input) -> #namespace::error::Result<#Output> { + let Some(service) = self.upgrade() else { + return Err(#namespace::error::Error::Shutdown); + }; + service.#method(ctrl, input).await + } + } + }, + ); + + quote! { + #[async_trait::async_trait] + impl #Service for ::std::sync::Weak + where + T: Send + Sync + 'static, + ::std::sync::Arc: #Service, + { + type Controller = <::std::sync::Arc as #Service>::Controller; + + #(#methods)* + } + } + } + + fn struct_ServiceDescriptor(&self) -> TokenStream { + let Self { + namespace, + ServiceDescriptor, + ServiceMethodDescriptor, + Service_str, + Service_proto_str, + Service_package_str, + methods, + .. + } = self; + + let doc = format!("A service descriptor for a `{}`.", Service_str); + + let methods = methods.iter().map(|Method { method_proto, .. }| { + quote! { #ServiceMethodDescriptor::#method_proto, } + }); + + quote! { + #[doc = #doc] + #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Default)] + pub struct #ServiceDescriptor; + + impl #namespace::descriptor::ServiceDescriptor for #ServiceDescriptor { + type Method = #ServiceMethodDescriptor; + fn name(&self) -> &'static str { #Service_str } + fn proto_name(&self) -> &'static str { #Service_proto_str } + fn package(&self) -> &'static str { #Service_package_str } + fn methods(&self) -> &'static [Self::Method] { + &[ #(#methods)* ] + } + } + } + } + + fn enum_ServiceMethodDescriptor(&self) -> TokenStream { + let Self { + ServiceMethodDescriptor, + Service_str, + methods, + .. + } = self; + + let doc = formatdoc! {" + Methods available on a `{Service_str}`. + + This can be used as a key when routing requests for servers/clients of a `{Service_str}`. + "}; + + let variants = methods.iter().map( + |Method { + method_proto, + index, + .. + }| { + quote! { #method_proto = #index, } + }, + ); + + let impl_MethodDescriptor = self.impl_MethodDescriptor_for_ServiceMethodDescriptor(); + let impl_TryFrom = self.impl_TryFrom_for_ServiceMethodDescriptor(); + quote! { + #[doc = #doc] + #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] + #[repr(u8)] + pub enum #ServiceMethodDescriptor { + #(#variants)* + } + + #impl_MethodDescriptor + + #impl_TryFrom + } + } + + fn impl_MethodDescriptor_for_ServiceMethodDescriptor(&self) -> TokenStream { + let Self { + namespace, + ServiceMethodDescriptor, + methods, + .. + } = self; + + let name = { + let arms = methods.iter().map( + |Method { + method_proto, + method_str, + .. + }| { + quote! { #ServiceMethodDescriptor::#method_proto => #method_str, } + }, + ); + + quote! { + fn name(&self) -> &'static str { + match *self { + #(#arms)* + } + } + } + }; + + let proto_name = { + let arms = methods.iter().map( + |Method { + method_proto, + method_proto_str, + .. + }| { + quote! { #ServiceMethodDescriptor::#method_proto => #method_proto_str, } + }, + ); + + quote! { + fn proto_name(&self) -> &'static str { + match *self { + #(#arms)* + } + } + } + }; + + let input_type = { + let arms = methods.iter().map(|Method { method_proto, Input, .. }| { + quote! { #ServiceMethodDescriptor::#method_proto => ::std::any::TypeId::of::<#Input>(), } + }); + + quote! { + fn input_type(&self) -> ::std::any::TypeId { + match *self { + #(#arms)* + } + } + } + }; + + let input_proto_type = { + let arms = methods.iter().map( + |Method { + method_proto, + Input_proto_str, + .. + }| { + quote! { #ServiceMethodDescriptor::#method_proto => #Input_proto_str, } + }, + ); + + quote! { + fn input_proto_type(&self) -> &'static str { + match *self { + #(#arms)* + } + } + } + }; + + let output_type = { + let arms = methods.iter().map(|Method { method_proto, Output, .. }| { + quote! { #ServiceMethodDescriptor::#method_proto => ::std::any::TypeId::of::<#Output>(), } + }); + + quote! { + fn output_type(&self) -> ::std::any::TypeId { + match *self { + #(#arms)* + } + } + } + }; + + let output_proto_type = { + let arms = methods.iter().map( + |Method { + method_proto, + Output_proto_str, + .. + }| { + quote! { #ServiceMethodDescriptor::#method_proto => #Output_proto_str, } + }, + ); + + quote! { + fn output_proto_type(&self) -> &'static str { + match *self { + #(#arms)* + } + } + } + }; + + quote! { + impl #namespace::descriptor::MethodDescriptor for #ServiceMethodDescriptor { + #name + + #proto_name + + #input_type + + #input_proto_type + + #output_type + + #output_proto_type + + fn index(&self) -> u8 { + *self as u8 + } + } + } + } + + fn impl_TryFrom_for_ServiceMethodDescriptor(&self) -> TokenStream { + let Self { + namespace, + ServiceMethodDescriptor, + Service_str, + methods, + .. + } = self; + + let arms = methods.iter().map( + |Method { + method_proto, + index, + .. + }| { + quote! { #index => Ok(#ServiceMethodDescriptor::#method_proto), } + }, + ); + + quote! { + impl std::convert::TryFrom for #ServiceMethodDescriptor { + type Error = #namespace::error::Error; + fn try_from(value: u8) -> #namespace::error::Result { + match value { + #(#arms)* + _ => Err(#namespace::error::Error::InvalidMethodIndex(value, #Service_str.to_string())), + } + } + } + } + } + + fn struct_ServiceClient(&self) -> TokenStream { + let Self { + namespace, + ServiceDescriptor, + ServiceClient, + Service_str, + .. + } = self; + + let doc = formatdoc! {" + A client for a `{Service_str}`. + + This implements the `{Service_str}` trait by dispatching all method calls to the supplied `Handler`. + "}; + + let impl_service_client = self.impl_ServiceClient(); + let impl_service_for_client = self.impl_Service_for_ServiceClient(); + quote! { + #[doc = #doc] + #[derive(Clone, Debug)] + pub struct #ServiceClient(H) where H: #namespace::handler::Handler; + + impl #ServiceClient where H: #namespace::handler::Handler { + /// Creates a new client instance that delegates all method calls to the supplied handler. + pub fn new(handler: H) -> Self { + Self(handler) + } + } + + #impl_service_client + + #impl_service_for_client + } + } + + fn impl_ServiceClient(&self) -> TokenStream { + let Self { + namespace, + ServiceClient, + ServiceDescriptor, + ServiceMethodDescriptor, + methods, + .. + } = self; + + let methods = methods.iter().map( + |Method { + method_inner, + method_proto, + Input, + Output, + .. + }| { + quote! { + async fn #method_inner(handler: H, ctrl: H::Controller, input: #Input) -> #namespace::error::Result<#Output> { + #namespace::__rt::call_method(handler, ctrl, #ServiceMethodDescriptor::#method_proto, input).await + } + } + }, + ); + + quote! { + impl #ServiceClient where H: #namespace::handler::Handler { + #(#methods)* + } + } + } + + fn impl_Service_for_ServiceClient(&self) -> TokenStream { + let Self { + namespace, + Service, + ServiceClient, + ServiceDescriptor, + methods, + .. + } = self; + + let methods = methods.iter().map( + |Method { + method, + method_inner, + Input, + Output, + .. + }| { + quote! { + async fn #method(&self, ctrl: H::Controller, input: #Input) -> #namespace::error::Result<#Output> { + #ServiceClient::#method_inner(self.0.clone(), ctrl, input).await + } + } + }, + ); + + quote! { + #[async_trait::async_trait] + impl #Service for #ServiceClient where H: #namespace::handler::Handler { + type Controller = H::Controller; + + #(#methods)* + } + } + } + + fn struct_ServiceClientFactory(&self) -> TokenStream { + let Self { + namespace, + Service, + ServiceClient, + ServiceClientFactory, + ServiceDescriptor, + .. + } = self; + + quote! { + pub struct #ServiceClientFactory(std::marker::PhantomData); + + impl Clone for #ServiceClientFactory { + fn clone(&self) -> Self { + Self(std::marker::PhantomData) + } + } + + impl #namespace::__rt::RpcClientFactory for #ServiceClientFactory where C: #namespace::controller::Controller { + type Descriptor = #ServiceDescriptor; + type ClientImpl = Box + Send + Sync + 'static>; + type Controller = C; + + fn new(handler: impl #namespace::handler::Handler) -> Self::ClientImpl { + Box::new(#ServiceClient::new(handler)) + } + } + } + } + + fn struct_ServiceServer(&self) -> TokenStream { + let Self { + namespace, + Service, + ServiceDescriptor, + ServiceServer, + ServiceMethodDescriptor, + Service_str, + methods, + .. + } = self; + + let doc = formatdoc! {" + A server for a `{Service_str}`. + + This implements the `Server` trait by handling requests and dispatch them to methods on the + supplied `{Service_str}`. + "}; + + let arms = methods.iter().map( + |Method { + method_proto, + method, + Input, + .. + }| { + quote! { + #ServiceMethodDescriptor::#method_proto => { + let decoded: #Input = #namespace::__rt::decode(input)?; + let ret = service.#method(ctrl, decoded).await?; + #namespace::__rt::encode(ret) + } + } + }, + ); + + quote! { + #[doc = #doc] + #[derive(Clone, Debug)] + pub struct #ServiceServer(A) where A: #Service + Clone + Send + 'static; + + impl #ServiceServer<::std::sync::Weak> + where + T: Send + Sync + 'static, + ::std::sync::Arc: #Service, + { + pub fn new_arc(service: ::std::sync::Arc) -> #ServiceServer<::std::sync::Weak> { + #ServiceServer(::std::sync::Arc::downgrade(&service)) + } + } + + impl #ServiceServer where A: #Service + Clone + Send + 'static { + /// Creates a new server instance that dispatches all calls to the supplied service. + pub fn new(service: A) -> #ServiceServer { + #ServiceServer(service) + } + + async fn call_inner( + service: A, + method: #ServiceMethodDescriptor, + ctrl: A::Controller, + input: ::bytes::Bytes) + -> #namespace::error::Result<::bytes::Bytes> { + match method { + #(#arms)* + } + } + } + + #[async_trait::async_trait] + impl #namespace::handler::Handler for #ServiceServer + where + A: #Service + Clone + Send + Sync + 'static { + type Descriptor = #ServiceDescriptor; + type Controller = A::Controller; + + async fn call( + &self, + ctrl: A::Controller, + method: #ServiceMethodDescriptor, + input: ::bytes::Bytes) + -> #namespace::error::Result<::bytes::Bytes> { + #ServiceServer::call_inner(self.0.clone(), method, ctrl, input).await + } + } + } + } +} + +/// The service generator to be used with `prost-build` to generate RPC implementations for +/// `prost-simple-rpc`. +/// +/// See the crate-level documentation for more info. +#[non_exhaustive] +#[derive(Debug, Default)] +pub struct ServiceGenerator; + +impl prost_build::ServiceGenerator for ServiceGenerator { + fn generate(&mut self, service: prost_build::Service, buf: &mut String) { + let info = Service::new(service); + + let trait_Service = info.trait_Service(); + let impl_Service_for_Weak = info.impl_Service_for_Weak(); + let struct_ServiceDescriptor = info.struct_ServiceDescriptor(); + let enum_ServiceMethodDescriptor = info.enum_ServiceMethodDescriptor(); + let struct_ServiceClient = info.struct_ServiceClient(); + let struct_ServiceClientFactory = info.struct_ServiceClientFactory(); + let struct_ServiceServer = info.struct_ServiceServer(); + + let tokens = quote! { + #trait_Service + + #impl_Service_for_Weak + + #struct_ServiceDescriptor + + #enum_ServiceMethodDescriptor + + #struct_ServiceClient + + #struct_ServiceClientFactory + + #struct_ServiceServer + }; + + buf.push('\n'); + buf.push_str(&tokens.to_string()); + buf.push('\n'); + } +}