This is an automated email from the ASF dual-hosted git repository. liujun pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/dubbo-rust.git
commit e03e4cd915ba76d2b977a0b3f952ce6843e510b4 Author: yang <[email protected]> AuthorDate: Sun Jun 26 22:51:01 2022 +0800 feat(dubbo): define the API of protocol module, provide simple impl of tonic(grpc) --- Cargo.toml | 2 +- dubbo/Cargo.lock | 929 ++++++++++++++++++++++++++++++++ dubbo/Cargo.toml | 28 + dubbo/readme.md | 1 + dubbo/src/common/mod.rs | 1 + dubbo/src/common/url.rs | 5 + dubbo/src/helloworld/client.rs | 23 + dubbo/src/helloworld/helloworld.rs | 272 ++++++++++ dubbo/src/helloworld/mod.rs | 1 + dubbo/src/helloworld/server.rs | 0 dubbo/src/lib.rs | 6 + dubbo/src/main.rs | 10 + dubbo/src/service/grpc/grpc_exporter.rs | 34 ++ dubbo/src/service/grpc/grpc_invoker.rs | 73 +++ dubbo/src/service/grpc/grpc_protocol.rs | 60 +++ dubbo/src/service/grpc/grpc_server.rs | 116 ++++ dubbo/src/service/grpc/mod.rs | 59 ++ dubbo/src/service/invocation.rs | 45 ++ dubbo/src/service/mod.rs | 4 + dubbo/src/service/protocol.rs | 31 ++ dubbo/src/utils/boxed.rs | 74 +++ dubbo/src/utils/boxed_clone.rs | 88 +++ dubbo/src/utils/mod.rs | 2 + protocol/Cargo.toml | 8 - protocol/src/lib.rs | 25 - 25 files changed, 1863 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3720b7d..8c2e58e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [workspace] members = [ "xds", - "protocol", "registry", "metadata", "common", "config", + "dubbo" ] \ No newline at end of file diff --git a/dubbo/Cargo.lock b/dubbo/Cargo.lock new file mode 100644 index 0000000..a69c71b --- /dev/null +++ b/dubbo/Cargo.lock @@ -0,0 +1,929 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anyhow" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" + +[[package]] +name = "async-stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" +dependencies = [ + "async-stream-impl", + "futures-core", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc47084705629d09d15060d70a8dbfce479c842303d05929ce29c74c995916ae" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes 1.1.0", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde", + "sync_wrapper", + "tokio", + "tower", + "tower-http", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2efed1c501becea07ce48118786ebcf229531d0d3b28edf224a720020d9e106" +dependencies = [ + "async-trait", + "bytes 1.1.0", + "futures-util", + "http", + "http-body", + "mime", +] + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "dubbo" +version = "0.1.0" +dependencies = [ + "async-trait", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "lazy_static", + "prost 0.10.4", + "prost-derive 0.10.1", + "prost-types", + "tokio", + "tonic", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "h2" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +dependencies = [ + "bytes 1.1.0", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes 1.1.0", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes 1.1.0", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" +dependencies = [ + "bytes 1.1.0", + "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.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matchit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce49aefe0a6144a45de32927c77bd2859a5f7677b55f220ae5b744e87389c212" +dependencies = [ + "bytes 0.5.6", + "prost-derive 0.6.1", +] + +[[package]] +name = "prost" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" +dependencies = [ + "bytes 1.1.0", + "prost-derive 0.10.1", +] + +[[package]] +name = "prost-derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537aa19b95acde10a12fec4301466386f757403de4cd4e5b4fa78fb5ecb18f72" +dependencies = [ + "anyhow", + "itertools 0.8.2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" +dependencies = [ + "anyhow", + "itertools 0.10.3", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1834f67c0697c001304b75be76f67add9c89742eda3a085ad8ee0bb38c3417aa" +dependencies = [ + "bytes 0.5.6", + "prost 0.6.1", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" + +[[package]] +name = "tokio" +version = "1.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +dependencies = [ + "bytes 1.1.0", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[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]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +dependencies = [ + "bytes 1.1.0", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tonic" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9d60db39854b30b835107500cf0aca0b0d14d6e1c3de124217c23a29c2ddb" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64", + "bytes 1.1.0", + "flate2", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost 0.10.4", + "prost-derive 0.10.1", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tower" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e" +dependencies = [ + "futures-core", + "futures-util", + "indexmap", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba" +dependencies = [ + "bitflags", + "bytes 1.1.0", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709595b8878a4965ce5e87ebf880a7d39c9afc6837721b21a5a816a8117d921" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/dubbo/Cargo.toml b/dubbo/Cargo.toml new file mode 100644 index 0000000..7ce6865 --- /dev/null +++ b/dubbo/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "dubbo" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[[bin]] +name = "helloworld-client" +path = "src/helloworld/client.rs" + +[dependencies] +h2 = {version = "0.3", optional = true} +hyper = "0.14.19" +http = "0.2" +tonic = {version ="0.7.2", features = ["compression",]} +tower-service = "0.3.1" +http-body = "0.4.4" +tower = "0.4.12" +futures-util = {version = "0.3", default-features = false} +tokio = { version = "1.0", features = [ "rt-multi-thread", "time", "fs", "macros", "net", "signal"] } +prost-derive = {version = "0.10", optional = true} +prost = "0.10.4" +prost-types = { version = "0.6", default-features = false } +lazy_static = "1.3.0" +async-trait = "0.1.56" +tower-layer = "0.3" + diff --git a/dubbo/readme.md b/dubbo/readme.md new file mode 100644 index 0000000..0adef95 --- /dev/null +++ b/dubbo/readme.md @@ -0,0 +1 @@ +# Introduce \ No newline at end of file diff --git a/dubbo/src/common/mod.rs b/dubbo/src/common/mod.rs new file mode 100644 index 0000000..aff8e30 --- /dev/null +++ b/dubbo/src/common/mod.rs @@ -0,0 +1 @@ +pub mod url; \ No newline at end of file diff --git a/dubbo/src/common/url.rs b/dubbo/src/common/url.rs new file mode 100644 index 0000000..879a1a0 --- /dev/null +++ b/dubbo/src/common/url.rs @@ -0,0 +1,5 @@ +#[derive(Debug, Clone)] +pub struct Url { + pub url: String, + pub service_key: String +} \ No newline at end of file diff --git a/dubbo/src/helloworld/client.rs b/dubbo/src/helloworld/client.rs new file mode 100644 index 0000000..f4517b4 --- /dev/null +++ b/dubbo/src/helloworld/client.rs @@ -0,0 +1,23 @@ +use dubbo::helloworld::helloworld::greeter_client::GreeterClient; +use dubbo::helloworld::helloworld::HelloRequest; + +// pub mod hello_world { +// tonic::include_proto!("helloworld"); +// } + +// cargo run --bin helloworld-client + +#[tokio::main] +async fn main() -> Result<(), Box<dyn std::error::Error>> { + let mut client = GreeterClient::connect("http://[::1]:50051").await?; + + let request = tonic::Request::new(HelloRequest { + name: "Tonic".into(), + }); + + let response = client.say_hello(request).await?; + + println!("RESPONSE={:?}", response); + + Ok(()) +} \ No newline at end of file diff --git a/dubbo/src/helloworld/helloworld.rs b/dubbo/src/helloworld/helloworld.rs new file mode 100644 index 0000000..b951157 --- /dev/null +++ b/dubbo/src/helloworld/helloworld.rs @@ -0,0 +1,272 @@ +/// The request message containing the user's name. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HelloRequest { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, +} +/// The response message containing the greetings +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HelloReply { + #[prost(string, tag="1")] + pub message: ::prost::alloc::string::String, +} +/// Generated client implementations. +pub mod greeter_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + /// The greeting service definition. + #[derive(Debug, Clone)] + pub struct GreeterClient<T> { + inner: tonic::client::Grpc<T>, + } + impl GreeterClient<tonic::transport::Channel> { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error> + where + D: std::convert::TryInto<tonic::transport::Endpoint>, + D::Error: Into<StdError>, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl<T> GreeterClient<T> + where + T: tonic::client::GrpcService<tonic::body::BoxBody>, + T::Error: Into<StdError>, + T::ResponseBody: Body<Data = Bytes> + Send + 'static, + <T::ResponseBody as Body>::Error: Into<StdError> + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_interceptor<F>( + inner: T, + interceptor: F, + ) -> GreeterClient<InterceptedService<T, F>> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request<tonic::body::BoxBody>, + Response = http::Response< + <T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody, + >, + >, + <T as tonic::codegen::Service< + http::Request<tonic::body::BoxBody>, + >>::Error: Into<StdError> + Send + Sync, + { + GreeterClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with `gzip`. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_gzip(mut self) -> Self { + self.inner = self.inner.send_gzip(); + self + } + /// Enable decompressing responses with `gzip`. + #[must_use] + pub fn accept_gzip(mut self) -> Self { + self.inner = self.inner.accept_gzip(); + self + } + /// Sends a greeting + pub async fn say_hello( + &mut self, + request: impl tonic::IntoRequest<super::HelloRequest>, + ) -> Result<tonic::Response<super::HelloReply>, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/helloworld.Greeter/SayHello", + ); + self.inner.unary(request.into_request(), path, codec).await + } + } +} +/// Generated server implementations. +pub mod greeter_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + + use tonic::codegen::*; + use crate::service::protocol::Invoker; + use crate::service::grpc::grpc_server::DubboGrpcService; + use crate::service::grpc::grpc_server::ServiceDesc; + + ///Generated trait containing gRPC methods that should be implemented for use with GreeterServer. + #[async_trait] + pub trait Greeter: Send + Sync + 'static { + /// Sends a greeting + async fn say_hello( + &self, + request: tonic::Request<super::HelloRequest>, + ) -> Result<tonic::Response<super::HelloReply>, tonic::Status>; + } + /// The greeting service definition. + #[derive(Debug)] + pub struct GreeterServer<T: Greeter, I> { + inner: _Inner<T>, + invoker: Option<_Inner<I>>, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + } + struct _Inner<T>(Arc<T>); + impl<T: Greeter, I> GreeterServer<T, I> { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc<T>) -> Self { + let inner = _Inner(inner); + Self { + inner, + invoker: None, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + } + } + pub fn with_interceptor<F>( + inner: T, + interceptor: F, + ) -> InterceptedService<Self, F> + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with `gzip`. + #[must_use] + pub fn accept_gzip(mut self) -> Self { + self.accept_compression_encodings.enable_gzip(); + self + } + /// Compress responses with `gzip`, if the client supports it. + #[must_use] + pub fn send_gzip(mut self) -> Self { + self.send_compression_encodings.enable_gzip(); + self + } + } + impl<T, B, I> tonic::codegen::Service<http::Request<B>> for GreeterServer<T, I> + where + T: Greeter, + B: Body + Send + 'static, + B::Error: Into<StdError> + Send + 'static, + { + type Response = http::Response<tonic::body::BoxBody>; + type Error = std::convert::Infallible; + type Future = BoxFuture<Self::Response, Self::Error>; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll<Result<(), Self::Error>> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request<B>) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/helloworld.Greeter/SayHello" => { + #[allow(non_camel_case_types)] + struct SayHelloSvc<T: Greeter>(pub Arc<T>); + impl<T: Greeter> tonic::server::UnaryService<super::HelloRequest> + for SayHelloSvc<T> { + type Response = super::HelloReply; + type Future = BoxFuture< + tonic::Response<Self::Response>, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request<super::HelloRequest>, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).say_hello(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = SayHelloSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl<T: Greeter, I: Invoker+ Send+ Sync + 'static> Clone for GreeterServer<T, I> { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + invoker: None, + // invoker: if let Some(v) = self.invoker.borrow_mut() { + // Some(v.clone()) + // } else { + // None + // }, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + } + } + + } + + impl<T: Greeter> Clone for _Inner<T> { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } + impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl<T: Greeter, I: Invoker> DubboGrpcService<I> for GreeterServer<T, I> { + fn set_proxy_impl(&mut self, invoker: I) { + self.invoker = Some(_Inner(Arc::new(invoker))); + } + + fn service_desc(&self) -> ServiceDesc { + ServiceDesc::new("helloworld.Greeter".to_string(), std::collections::HashMap::new()) + } + } + + impl<T: Greeter, I> tonic::transport::NamedService for GreeterServer<T, I> { + const NAME: &'static str = "helloworld.Greeter"; + } +} diff --git a/dubbo/src/helloworld/mod.rs b/dubbo/src/helloworld/mod.rs new file mode 100644 index 0000000..5f1509d --- /dev/null +++ b/dubbo/src/helloworld/mod.rs @@ -0,0 +1 @@ +pub mod helloworld; \ No newline at end of file diff --git a/dubbo/src/helloworld/server.rs b/dubbo/src/helloworld/server.rs new file mode 100644 index 0000000..e69de29 diff --git a/dubbo/src/lib.rs b/dubbo/src/lib.rs new file mode 100644 index 0000000..7a10cf1 --- /dev/null +++ b/dubbo/src/lib.rs @@ -0,0 +1,6 @@ +pub mod helloworld; +pub mod service; +pub mod common; +pub mod utils; + +pub(crate) type Error = Box<dyn std::error::Error + Send + Sync>; \ No newline at end of file diff --git a/dubbo/src/main.rs b/dubbo/src/main.rs new file mode 100644 index 0000000..ecc7b56 --- /dev/null +++ b/dubbo/src/main.rs @@ -0,0 +1,10 @@ +pub mod service; +pub mod common; +pub mod utils; +pub mod helloworld; + +#[tokio::main] +async fn main() { + println!("hello, dubbo-rust~") +} + diff --git a/dubbo/src/service/grpc/grpc_exporter.rs b/dubbo/src/service/grpc/grpc_exporter.rs new file mode 100644 index 0000000..2940429 --- /dev/null +++ b/dubbo/src/service/grpc/grpc_exporter.rs @@ -0,0 +1,34 @@ + +use crate::service::protocol::*; +use crate::service::protocol::Invoker; + +pub struct GrpcExporter<T> { + invoker: T +} + +impl<T> GrpcExporter<T> { + pub fn new(key: String, invoker: T) -> GrpcExporter<T> { + Self { invoker } + } +} + +impl<T: Invoker+Clone> Exporter for GrpcExporter<T> +{ + type InvokerType = T; + + fn unexport(&self) { + } + + fn get_invoker(&self) -> Self::InvokerType { + self.invoker.clone() + } + +} + +impl<T: Invoker+Clone> Clone for GrpcExporter<T> { + + fn clone(&self) -> Self { + Self { invoker: self.invoker.clone() } + } + +} \ No newline at end of file diff --git a/dubbo/src/service/grpc/grpc_invoker.rs b/dubbo/src/service/grpc/grpc_invoker.rs new file mode 100644 index 0000000..fd48e73 --- /dev/null +++ b/dubbo/src/service/grpc/grpc_invoker.rs @@ -0,0 +1,73 @@ +use std::sync::Once; + +use tonic::client::Grpc; +use tonic::transport::Channel; +use tonic::transport::Endpoint; + +use crate::service::protocol::*; +use crate::service::invocation; +use crate::common::url::Url; + +pub struct GrpcInvoker { + client: Grpc<Channel>, + url: Url, + once: Once +} + + + +impl GrpcInvoker { + pub fn new(url: Url) -> GrpcInvoker { + + let endpoint = Endpoint::new(url.url.clone()).unwrap(); + let conn = endpoint.connect_lazy(); + Self { + url, + client: Grpc::new(conn), + once: Once::new() + } + } +} + +impl Invoker for GrpcInvoker { + + fn is_available(&self) -> bool { + true + } + + fn destroy(&self) { + self.once.call_once(|| { + println!("destroy...") + }) + } + + fn get_url(&self) -> Url { + self.url.to_owned() + } + + // 根据req中的数据发起req,由Client发起请求,获取响应 + fn invoke<M1>(&self, req: invocation::Request<M1>) -> invocation::Response<String> + where + M1: Send + 'static, + { + let (metadata, _) = req.into_parts(); + + let resp = invocation::Response::new("string"); + let (resp_meta, msg) = resp.into_parts(); + + invocation::Response::from_parts(metadata, msg.to_string()) + } +} + +impl<T> invocation::Request<T> { + + pub(crate) fn to_tonic_req(self) -> tonic::Request<T> { + tonic::Request::new(self.message) + } +} + +impl Clone for GrpcInvoker { + fn clone(&self) -> Self { + Self { client: self.client.clone(), url: self.url.clone(), once: Once::new() } + } +} \ No newline at end of file diff --git a/dubbo/src/service/grpc/grpc_protocol.rs b/dubbo/src/service/grpc/grpc_protocol.rs new file mode 100644 index 0000000..08fe921 --- /dev/null +++ b/dubbo/src/service/grpc/grpc_protocol.rs @@ -0,0 +1,60 @@ + +use std::collections::HashMap; + +use super::grpc_invoker::GrpcInvoker; +use super::grpc_exporter::GrpcExporter; +use crate::common::url::Url; +use crate::service::protocol::Protocol; +use super::grpc_server::GrpcServer; + +pub struct GrpcProtocol { + server_map: HashMap<String, GrpcServer>, + export_map: HashMap<String, GrpcExporter<GrpcInvoker>> +} + +impl GrpcProtocol { + pub fn new() -> Self { + Self { + server_map: HashMap::new(), + export_map: HashMap::new(), + } + } +} + +impl Default for GrpcProtocol { + fn default() -> Self { + Self::new() + } +} + +#[async_trait::async_trait] +impl Protocol for GrpcProtocol +{ + type Invoker = GrpcInvoker; + + type Exporter = GrpcExporter<Self::Invoker>; + + fn destroy(&self) { + todo!() + } + + async fn refer(&self, url: Url) -> Self::Invoker { + GrpcInvoker::new(url) + } + + async fn export(self, url: Url) -> Self::Exporter { + let service_key = url.service_key.clone(); + + let exporter: GrpcExporter<GrpcInvoker> = GrpcExporter::new(service_key.clone(), GrpcInvoker::new(url.clone())); + let mut export = self.export_map; + export.insert(service_key.clone(), exporter.clone()); + + // 启动服务 + + let server = super::grpc_server::GrpcServer::new(service_key.clone()); + let mut server_map = self.server_map; + server_map.insert(service_key.clone(), server.clone()); + server.serve(url.clone()).await; + exporter + } +} \ No newline at end of file diff --git a/dubbo/src/service/grpc/grpc_server.rs b/dubbo/src/service/grpc/grpc_server.rs new file mode 100644 index 0000000..3a9c6a8 --- /dev/null +++ b/dubbo/src/service/grpc/grpc_server.rs @@ -0,0 +1,116 @@ +use std::collections::HashMap; +use std::task::Context; +use std::task::Poll; + +use tonic::transport; +use tower::Service; +use tonic::transport::NamedService; +use tonic::codegen::BoxFuture; + + +use crate::common::url::Url; +use crate::helloworld::helloworld::greeter_server::GreeterServer; +use super::grpc_invoker::GrpcInvoker; +use crate::helloworld::helloworld::greeter_server::*; +use crate::utils::boxed_clone::BoxCloneService; + +pub trait DubboGrpcService<T> +{ + fn set_proxy_impl(&mut self, invoker: T); + fn service_desc(&self) -> ServiceDesc; +} + +//type ServiceDesc struct { +// ServiceName string +// // The pointer to the service interface. Used to check whether the user +// // provided implementation satisfies the interface requirements. +// HandlerType interface{} +// Methods []MethodDesc +// Streams []StreamDesc +// Metadata interface{} +// } + +pub struct ServiceDesc { + service_name: String, + methods: HashMap<String, String> // "/Greeter/hello": "unary" +} + +impl ServiceDesc { + pub fn new(service_name: String, methods: HashMap<String, String>) -> Self { + Self { service_name, methods } + } + + pub fn get_service_name(&self) -> String { + self.service_name.clone() + } +} + +// codegen +pub fn register_greeter_server<T: Greeter>(server: T) -> (super::GrpcBoxCloneService, super::DubboGrpcBox) { + let hello = GreeterServer::<T, GrpcInvoker>::new(server); + (BoxCloneService::new(hello.clone()), Box::new(hello.clone())) +} + +// 每个service对应一个Server +#[derive(Clone)] +pub struct GrpcServer { + inner: transport::Server, + name: String, +} + +impl GrpcServer +{ + pub fn new(name: String) -> GrpcServer { + Self { + inner: transport::Server::builder(), + name + } + } + + pub async fn serve(mut self, url: Url) + where + { + let addr = url.url.clone().parse().unwrap(); + let svc = super::GRPC_SERVICES.read().unwrap().get(self.name.as_str()).unwrap().clone(); + println!("server{:?} start...", url); + self.inner.add_service(MakeSvc::new(svc)).serve( + addr + ).await.unwrap(); + println!("server{:?} start...", url); + } + +} + +struct MakeSvc<T, U, E> { + inner: BoxCloneService<T, U, E> +} + +impl<T, U, E> MakeSvc<T, U, E> { + pub fn new(inner: BoxCloneService<T, U, E>) -> Self { + Self { inner} + } +} + +impl<T, U, E> NamedService for MakeSvc<T, U, E> { + const NAME: &'static str = "helloworld.Greeter"; +} + +impl<T, U, E> Service<T> for MakeSvc<T, U, E> { + type Response = U; + type Error = E; + type Future = BoxFuture<U, E>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), E>> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, request: T) -> BoxFuture<U, E> { + self.inner.call(request) + } +} + +impl<T, U, E> Clone for MakeSvc<T, U, E> { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} \ No newline at end of file diff --git a/dubbo/src/service/grpc/mod.rs b/dubbo/src/service/grpc/mod.rs new file mode 100644 index 0000000..3350638 --- /dev/null +++ b/dubbo/src/service/grpc/mod.rs @@ -0,0 +1,59 @@ +pub mod grpc_protocol; +pub mod grpc_invoker; +pub mod grpc_exporter; +pub mod grpc_server; + +use std::collections::HashMap; +use std::sync::RwLock; +use lazy_static::lazy_static; + +use grpc_server::DubboGrpcService; +use grpc_invoker::GrpcInvoker; +use crate::helloworld::helloworld::greeter_server::Greeter; +use crate::utils::boxed_clone::BoxCloneService; +use crate::helloworld::helloworld::{HelloRequest, HelloReply}; + +pub type GrpcBoxCloneService = BoxCloneService<http::Request<hyper::Body>, http::Response<tonic::body::BoxBody>, std::convert::Infallible>; + +pub type DubboGrpcBox = Box<dyn DubboGrpcService<GrpcInvoker>+ Send + Sync + 'static>; + +lazy_static! { + pub static ref DUBBO_GRPC_SERVICES: RwLock<HashMap<String, Box<dyn DubboGrpcService<GrpcInvoker> + Send + Sync + 'static>>> = RwLock::new(HashMap::new()); + pub static ref GRPC_SERVICES: RwLock<HashMap<String, GrpcBoxCloneService>> = RwLock::new(HashMap::new()); +} + +#[tokio::test] +async fn test_hello() { + use grpc_server::register_greeter_server; + use crate::service::protocol::Protocol; + use crate::common::url::Url; + + let (svc, dubbo_svc) = register_greeter_server(MyGreeter{}); + let svc_name = dubbo_svc.service_desc().get_service_name(); + DUBBO_GRPC_SERVICES.write().unwrap().insert(svc_name.clone(), dubbo_svc); + GRPC_SERVICES.write().unwrap().insert(svc_name.clone(), svc); + + // server start, api: 0.0.0.0:8888/helloworld.Greeter/SayHello + let pro = grpc_protocol::GrpcProtocol::new(); + pro.export(Url{url: "[::1]:50051".to_string(), service_key: svc_name.clone()}).await; + +} + + +#[derive(Default)] +pub struct MyGreeter {} + +#[tonic::async_trait] +impl Greeter for MyGreeter { + async fn say_hello( + &self, + request: tonic::Request<HelloRequest>, + ) -> Result<tonic::Response<HelloReply>, tonic::Status> { + println!("Got a request from {:?}", request.remote_addr()); + + let reply = HelloReply { + message: format!("Hello {}!", request.into_inner().name), + }; + Ok(tonic::Response::new(reply)) + } +} \ No newline at end of file diff --git a/dubbo/src/service/invocation.rs b/dubbo/src/service/invocation.rs new file mode 100644 index 0000000..dff46fa --- /dev/null +++ b/dubbo/src/service/invocation.rs @@ -0,0 +1,45 @@ +use tonic::metadata::MetadataMap; + +pub struct Request<T> { + pub message: T, + pub metadata: MetadataMap, +} + + +impl<T> Request<T> { + pub fn new(message: T) -> Request<T> { + Self { + message, + metadata: MetadataMap::new() + } + } + + pub fn into_parts(self) -> (MetadataMap, T) { + (self.metadata, self.message) + } +} + +pub struct Response<T> { + message: T, + metadata: MetadataMap, +} + +impl<T> Response<T> { + pub fn new(message: T) -> Response<T> { + Self { + message, + metadata: MetadataMap::new(), + } + } + + pub fn from_parts(metadata: MetadataMap, message: T) -> Self { + Self { + message, + metadata, + } + } + + pub fn into_parts(self) -> (MetadataMap, T) { + (self.metadata, self.message) + } +} \ No newline at end of file diff --git a/dubbo/src/service/mod.rs b/dubbo/src/service/mod.rs new file mode 100644 index 0000000..55bcb2f --- /dev/null +++ b/dubbo/src/service/mod.rs @@ -0,0 +1,4 @@ +pub mod protocol; +pub mod grpc; +pub mod invocation; + diff --git a/dubbo/src/service/protocol.rs b/dubbo/src/service/protocol.rs new file mode 100644 index 0000000..18d2d7b --- /dev/null +++ b/dubbo/src/service/protocol.rs @@ -0,0 +1,31 @@ +use super::invocation; +use crate::common::url::Url; + +use async_trait::async_trait; + +#[async_trait] +pub trait Protocol { + type Invoker; + type Exporter; + + fn destroy(&self); + async fn export(self, url: Url) -> Self::Exporter; + async fn refer(&self, url: Url) -> Self::Invoker; +} + + +pub trait Exporter { + type InvokerType: Invoker; + + fn unexport(&self); + fn get_invoker(&self) -> Self::InvokerType; +} + +pub trait Invoker { + fn invoke<M1>(&self, req: invocation::Request<M1>) -> invocation::Response<String> + where + M1: Send + 'static; + fn is_available(&self) -> bool; + fn destroy(&self); + fn get_url(&self) -> Url; +} \ No newline at end of file diff --git a/dubbo/src/utils/boxed.rs b/dubbo/src/utils/boxed.rs new file mode 100644 index 0000000..63297e9 --- /dev/null +++ b/dubbo/src/utils/boxed.rs @@ -0,0 +1,74 @@ +use tower::ServiceExt; +use tower_layer::{layer_fn, LayerFn}; +use tower_service::Service; + +use std::fmt; +use std::{ + future::Future, + pin::Pin, + task::{Context, Poll}, +}; + +/// A boxed `Service + Send` trait object. +/// +/// [`BoxService`] turns a service into a trait object, allowing the response +/// future type to be dynamic. This type requires both the service and the +/// response future to be [`Send`]. +/// +/// If you need a boxed [`Service`] that implements [`Clone`] consider using +/// [`BoxCloneService`](crate::util::BoxCloneService). +/// +/// See module level documentation for more details. +pub struct BoxService<T, U, E> { + inner: Box<dyn Service<T, Response = U, Error = E, Future = BoxFuture<U, E>> + Send+ Sync+>, +} + +/// A boxed `Future + Send` trait object. +/// +/// This type alias represents a boxed future that is [`Send`] and can be moved +/// across threads. +type BoxFuture<T, E> = Pin<Box<dyn Future<Output = Result<T, E>> + Send>>; + +impl<T, U, E> BoxService<T, U, E> { + #[allow(missing_docs)] + pub fn new<S>(inner: S) -> Self + where + S: Service<T, Response = U, Error = E> + Send + Sync + 'static, + S::Future: Send + 'static, + { + let inner = Box::new(inner.map_future(|f: S::Future| Box::pin(f) as _)); + BoxService { inner } + } + + // /// Returns a [`Layer`] for wrapping a [`Service`] in a [`BoxService`] + // /// middleware. + // /// + // /// [`Layer`]: crate::Layer + pub fn layer<S>() -> LayerFn<fn(S) -> Self> + where + S: Service<T, Response = U, Error = E> + Send + Sync + 'static, + S::Future: Send + 'static, + { + layer_fn(Self::new) + } +} + +impl<T, U, E> Service<T> for BoxService<T, U, E> { + type Response = U; + type Error = E; + type Future = BoxFuture<U, E>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), E>> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, request: T) -> BoxFuture<U, E> { + self.inner.call(request) + } +} + +impl<T, U, E> fmt::Debug for BoxService<T, U, E> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BoxService").finish() + } +} diff --git a/dubbo/src/utils/boxed_clone.rs b/dubbo/src/utils/boxed_clone.rs new file mode 100644 index 0000000..0e5e6c3 --- /dev/null +++ b/dubbo/src/utils/boxed_clone.rs @@ -0,0 +1,88 @@ +use tower::ServiceExt; +use futures_util::future::BoxFuture; +use std::{ + fmt, + task::{Context, Poll}, +}; +use tower_layer::{layer_fn, LayerFn}; +use tower_service::Service; + +pub struct BoxCloneService<T, U, E>( + Box< + dyn CloneService<T, Response = U, Error = E, Future = BoxFuture<'static, Result<U, E>>> + + Send+Sync, + >, +); + +impl<T, U, E> BoxCloneService<T, U, E> { + /// Create a new `BoxCloneService`. + pub fn new<S>(inner: S) -> Self + where + S: Service<T, Response = U, Error = E> + Clone + Send + Sync + 'static, + S::Future: Send + 'static, + { + let inner = inner.map_future(|f| Box::pin(f) as _); + BoxCloneService(Box::new(inner)) + } + + /// Returns a [`Layer`] for wrapping a [`Service`] in a [`BoxCloneService`] + /// middleware. + /// + /// [`Layer`]: crate::Layer + pub fn layer<S>() -> LayerFn<fn(S) -> Self> + where + S: Service<T, Response = U, Error = E> + Clone + Send + Sync + 'static, + S::Future: Send + 'static, + { + layer_fn(Self::new) + } +} + +impl<T, U, E> Service<T> for BoxCloneService<T, U, E> { + type Response = U; + type Error = E; + type Future = BoxFuture<'static, Result<U, E>>; + + #[inline] + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), E>> { + self.0.poll_ready(cx) + } + + #[inline] + fn call(&mut self, request: T) -> Self::Future { + self.0.call(request) + } +} + +impl<T, U, E> Clone for BoxCloneService<T, U, E> { + fn clone(&self) -> Self { + Self(self.0.clone_box()) + } +} + +trait CloneService<R>: Service<R> { + fn clone_box( + &self, + ) -> Box< + dyn CloneService<R, Response = Self::Response, Error = Self::Error, Future = Self::Future> + + Send + Sync, + >; +} + +impl<R, T> CloneService<R> for T +where + T: Service<R> + Send + Sync + Clone + 'static, +{ + fn clone_box( + &self, + ) -> Box<dyn CloneService<R, Response = T::Response, Error = T::Error, Future = T::Future> + Send + Sync> + { + Box::new(self.clone()) + } +} + +impl<T, U, E> fmt::Debug for BoxCloneService<T, U, E> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BoxCloneService").finish() + } +} diff --git a/dubbo/src/utils/mod.rs b/dubbo/src/utils/mod.rs new file mode 100644 index 0000000..a3bbaaa --- /dev/null +++ b/dubbo/src/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod boxed; +pub mod boxed_clone; \ No newline at end of file diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml deleted file mode 100644 index 77c8260..0000000 --- a/protocol/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "protocol" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs deleted file mode 100644 index 3e01853..0000000 --- a/protocol/src/lib.rs +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - let result = 2 + 2; - assert_eq!(result, 4); - } -}
