This is an automated email from the ASF dual-hosted git repository. lizhanhui pushed a commit to branch rust_dev in repository https://gitbox.apache.org/repos/asf/rocketmq-clients.git
commit 1d3bb4cb43a1aaae8c0b5f36ab45d25c0c97a024 Author: Li Zhanhui <lizhan...@gmail.com> AuthorDate: Mon Jul 4 19:04:14 2022 +0800 Set up boilerplate for rust client --- .gitignore | 3 + rust/Cargo.lock | 1549 ++++++++++++++++++++++++ rust/Cargo.toml | 21 + rust/build.rs | 14 + rust/proto/apache/rocketmq/v2/admin.proto | 43 + rust/proto/apache/rocketmq/v2/definition.proto | 447 +++++++ rust/proto/apache/rocketmq/v2/service.proto | 448 +++++++ rust/src/client.rs | 436 +++++++ rust/src/command.rs | 13 + rust/src/error.rs | 26 + rust/src/lib.rs | 26 + rust/src/main.rs | 20 + rust/src/producer.rs | 24 + 13 files changed, 3070 insertions(+) diff --git a/.gitignore b/.gitignore index f666658..7ead457 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ dependency-reduced-pom.xml # Java java/client/src/main/java/org/apache/rocketmq/client/java/example/ + +# Rust +rust/src/pb diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 0000000..cedd03b --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,1549 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" + +[[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 = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[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.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2cc6e8e8c993cb61a005fab8c1e5093a29199b7253b05a6883999312935c1ff" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes", + "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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4d047478b986f14a13edad31a009e2e05cb241f9805d0d75e4cba4e129ad4d" +dependencies = [ + "async-trait", + "bytes", + "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 = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "crossbeam-channel" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "crypto-common" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5999502d32b9c48d492abe66392408144895020ec4709e549e840799f3bb74c0" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "either" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[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 = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[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", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "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", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[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 = "js-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +dependencies = [ + "wasm-bindgen", +] + +[[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 = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[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 = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[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 = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "petgraph" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74" +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 = "prettyplease" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1516508b396cefe095485fdce673007422f5e48e82934b7b423dc26aa5e6a4" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae5a4388762d5815a9fc0dea33c56b021cdc8dde0c55e0c9ca57197254b0cab" +dependencies = [ + "bytes", + "cfg-if", + "cmake", + "heck", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prost", + "prost-types", + "regex", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" +dependencies = [ + "bytes", + "prost", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +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 = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rocketmq" +version = "0.1.0" +dependencies = [ + "hmac", + "hostname", + "parking_lot", + "prost", + "prost-types", + "slog", + "slog-async", + "slog-term", + "thiserror", + "tokio", + "tokio-rustls", + "tonic", + "tonic-build", +] + +[[package]] +name = "rustls" +version = "0.20.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" +dependencies = [ + "base64", +] + +[[package]] +name = "rustversion" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" + +[[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 = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" + +[[package]] +name = "slog-async" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "766c59b252e62a34651412870ff55d8c4e6d04df19b43eecb2703e417b097ffe" +dependencies = [ + "crossbeam-channel", + "slog", + "take_mut", + "thread_local", +] + +[[package]] +name = "slog-term" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87d29185c55b7b258b4f120eab00f48557d4d9bc814f41713f449d35b0f8977c" +dependencies = [ + "atty", + "slog", + "term", + "thread_local", + "time", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +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 = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "tokio" +version = "1.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "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-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[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", + "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", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "rustls-native-certs", + "rustls-pemfile", + "tokio", + "tokio-rustls", + "tokio-stream", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tonic-build" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9263bf4c9bfaae7317c1c2faf7f18491d2fe476f70c414b73bf5d445b00ffa1" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "quote", + "syn", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap", + "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", + "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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[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.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +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 = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[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 = "wasm-bindgen" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" + +[[package]] +name = "web-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "which" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +dependencies = [ + "either", + "lazy_static", + "libc", +] + +[[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/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 0000000..b290d64 --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "rocketmq" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { version = "1", features = ["full"] } +tonic = {version = "0.7", features = ["tls", "default", "channel", "tls-roots"]} +prost = "0.10" +prost-types = "0.10" +thiserror = "1.0" +slog = {version = "2.7.0", features=["max_level_trace", "release_max_level_info"]} +slog-term = "2.9.0" +slog-async = "2.7.0" +parking_lot = "0.12" +hmac = "0.12" +hostname = "0.3.1" +tokio-rustls = {version = "0.23", features = ["default", "dangerous_configuration"] } + +[build-dependencies] +tonic-build = "0.7" \ No newline at end of file diff --git a/rust/build.rs b/rust/build.rs new file mode 100644 index 0000000..eebab8a --- /dev/null +++ b/rust/build.rs @@ -0,0 +1,14 @@ +fn main() { + tonic_build::configure() + .build_client(true) + .build_server(false) + .out_dir("src/pb") + .compile( + &[ + "proto/apache/rocketmq/v2/service.proto", + "proto/apache/rocketmq/v2/admin.proto", + ], + &["proto"], + ) + .unwrap(); +} diff --git a/rust/proto/apache/rocketmq/v2/admin.proto b/rust/proto/apache/rocketmq/v2/admin.proto new file mode 100644 index 0000000..7dbb702 --- /dev/null +++ b/rust/proto/apache/rocketmq/v2/admin.proto @@ -0,0 +1,43 @@ +// 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. + +syntax = "proto3"; + +package apache.rocketmq.v2; + +option cc_enable_arenas = true; +option csharp_namespace = "Apache.Rocketmq.V2"; +option java_multiple_files = true; +option java_package = "apache.rocketmq.v2"; +option java_generate_equals_and_hash = true; +option java_string_check_utf8 = true; +option java_outer_classname = "MQAdmin"; + +message ChangeLogLevelRequest { + enum Level { + TRACE = 0; + DEBUG = 1; + INFO = 2; + WARN = 3; + ERROR = 4; + } + Level level = 1; +} + +message ChangeLogLevelResponse { string remark = 1; } + +service Admin { + rpc ChangeLogLevel(ChangeLogLevelRequest) returns (ChangeLogLevelResponse) {} +} \ No newline at end of file diff --git a/rust/proto/apache/rocketmq/v2/definition.proto b/rust/proto/apache/rocketmq/v2/definition.proto new file mode 100644 index 0000000..ea9514c --- /dev/null +++ b/rust/proto/apache/rocketmq/v2/definition.proto @@ -0,0 +1,447 @@ +// 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. + +syntax = "proto3"; + +import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; + +package apache.rocketmq.v2; + +option csharp_namespace = "Apache.Rocketmq.V2"; +option java_multiple_files = true; +option java_package = "apache.rocketmq.v2"; +option java_generate_equals_and_hash = true; +option java_string_check_utf8 = true; +option java_outer_classname = "MQDomain"; + +enum TransactionResolution { + TRANSACTION_RESOLUTION_UNSPECIFIED = 0; + COMMIT = 1; + ROLLBACK = 2; +} + +enum TransactionSource { + SOURCE_UNSPECIFIED = 0; + SOURCE_CLIENT = 1; + SOURCE_SERVER_CHECK = 2; +} + +enum Permission { + PERMISSION_UNSPECIFIED = 0; + NONE = 1; + READ = 2; + WRITE = 3; + READ_WRITE = 4; +} + +enum FilterType { + FILTER_TYPE_UNSPECIFIED = 0; + TAG = 1; + SQL = 2; +} + +message FilterExpression { + FilterType type = 1; + string expression = 2; +} + +message RetryPolicy { + int32 max_attempts = 1; + oneof strategy { + ExponentialBackoff exponential_backoff = 2; + CustomizedBackoff customized_backoff = 3; + } +} + +// https://en.wikipedia.org/wiki/Exponential_backoff +message ExponentialBackoff { + google.protobuf.Duration initial = 1; + google.protobuf.Duration max = 2; + float multiplier = 3; +} + +message CustomizedBackoff { + // To support classic backoff strategy which is arbitary defined by end users. + // Typical values are: `1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h` + repeated google.protobuf.Duration next = 1; +} + +message Resource { + string resource_namespace = 1; + + // Resource name identifier, which remains unique within the abstract resource + // namespace. + string name = 2; +} + +message SubscriptionEntry { + Resource topic = 1; + FilterExpression expression = 2; +} + +enum AddressScheme { + ADDRESS_SCHEME_UNSPECIFIED = 0; + IPv4 = 1; + IPv6 = 2; + DOMAIN_NAME = 3; +} + +message Address { + string host = 1; + int32 port = 2; +} + +message Endpoints { + AddressScheme scheme = 1; + repeated Address addresses = 2; +} + +message Broker { + // Name of the broker + string name = 1; + + // Broker index. Canonically, index = 0 implies that the broker is playing + // leader role while brokers with index > 0 play follower role. + int32 id = 2; + + // Address of the broker, complying with the following scheme + // 1. dns:[//authority/]host[:port] + // 2. ipv4:address[:port][,address[:port],...] – IPv4 addresses + // 3. ipv6:address[:port][,address[:port],...] – IPv6 addresses + Endpoints endpoints = 3; +} + +message MessageQueue { + Resource topic = 1; + int32 id = 2; + Permission permission = 3; + Broker broker = 4; + repeated MessageType accept_message_types = 5; +} + +enum MessageType { + MESSAGE_TYPE_UNSPECIFIED = 0; + + NORMAL = 1; + + // Sequenced message + FIFO = 2; + + // Messages that are delivered after the specified duration. + DELAY = 3; + + // Messages that are transactional. Only committed messages are delivered to + // subscribers. + TRANSACTION = 4; +} + +enum DigestType { + DIGEST_TYPE_UNSPECIFIED = 0; + + // CRC algorithm achieves goal of detecting random data error with lowest + // computation overhead. + CRC32 = 1; + + // MD5 algorithm achieves good balance between collision rate and computation + // overhead. + MD5 = 2; + + // SHA-family has substantially fewer collision with fair amount of + // computation. + SHA1 = 3; +} + +// When publishing messages to or subscribing messages from brokers, clients +// shall include or validate digests of message body to ensure data integrity. +// +// For message publishing, when an invalid digest were detected, brokers need +// respond client with BAD_REQUEST. +// +// For messages subscription, when an invalid digest were detected, consumers +// need to handle this case according to message type: +// 1) Standard messages should be negatively acknowledged instantly, causing +// immediate re-delivery; 2) FIFO messages require special RPC, to re-fetch +// previously acquired messages batch; +// +// Message consumption model also affects how invalid digest are handled. When +// messages are consumed in broadcasting way, +// TODO: define semantics of invalid-digest-when-broadcasting. +message Digest { + DigestType type = 1; + string checksum = 2; +} + +enum ClientType { + CLIENT_TYPE_UNSPECIFIED = 0; + PRODUCER = 1; + PUSH_CONSUMER = 2; + SIMPLE_CONSUMER = 3; +} + +enum Encoding { + ENCODING_UNSPECIFIED = 0; + + IDENTITY = 1; + + GZIP = 2; +} + +message SystemProperties { + // Tag, which is optional. + optional string tag = 1; + + // Message keys + repeated string keys = 2; + + // Message identifier, client-side generated, remains unique. + // if message_id is empty, the send message request will be aborted with + // status `INVALID_ARGUMENT` + string message_id = 3; + + // Message body digest + Digest body_digest = 4; + + // Message body encoding. Candidate options are identity, gzip, snappy etc. + Encoding body_encoding = 5; + + // Message type, normal, FIFO or transactional. + MessageType message_type = 6; + + // Message born time-point. + google.protobuf.Timestamp born_timestamp = 7; + + // Message born host. Valid options are IPv4, IPv6 or client host domain name. + string born_host = 8; + + // Time-point at which the message is stored in the broker, which is absent + // for message publishing. + optional google.protobuf.Timestamp store_timestamp = 9; + + // The broker that stores this message. It may be broker name, IP or arbitrary + // identifier that uniquely identify the server. + string store_host = 10; + + // Time-point at which broker delivers to clients, which is optional. + optional google.protobuf.Timestamp delivery_timestamp = 11; + + // If a message is acquired by way of POP, this field holds the receipt, + // which is absent for message publishing. + // Clients use the receipt to acknowledge or negatively acknowledge the + // message. + optional string receipt_handle = 12; + + // Message queue identifier in which a message is physically stored. + int32 queue_id = 13; + + // Message-queue offset at which a message is stored, which is absent for + // message publishing. + optional int64 queue_offset = 14; + + // Period of time servers would remain invisible once a message is acquired. + optional google.protobuf.Duration invisible_duration = 15; + + // Business code may failed to process messages for the moment. Hence, clients + // may request servers to deliver them again using certain back-off strategy, + // the attempt is 1 not 0 if message is delivered first time, and it is absent + // for message publishing. + optional int32 delivery_attempt = 16; + + // Define the group name of message in the same topic, which is optional. + optional string message_group = 17; + + // Trace context for each message, which is optional. + optional string trace_context = 18; + + // If a transactional message stay unresolved for more than + // `transaction_orphan_threshold`, it would be regarded as an + // orphan. Servers that manages orphan messages would pick up + // a capable publisher to resolve + optional google.protobuf.Duration orphaned_transaction_recovery_duration = 19; +} + +message Message { + + Resource topic = 1; + + // User defined key-value pairs. + // If user_properties contain the reserved keys by RocketMQ, + // the send message request will be aborted with status `INVALID_ARGUMENT`. + // See below links for the reserved keys + // https://github.com/apache/rocketmq/blob/master/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java#L58 + map<string, string> user_properties = 2; + + SystemProperties system_properties = 3; + + bytes body = 4; +} + +message Assignment { + MessageQueue message_queue = 1; +} + +enum Code { + CODE_UNSPECIFIED = 0; + + // Generic code for success. + OK = 20000; + + // Generic code for multiple return results. + MULTIPLE_RESULTS = 30000; + + // Generic code for bad request, indicating that required fields or headers are missing. + BAD_REQUEST = 40000; + // Format of access point is illegal. + ILLEGAL_ACCESS_POINT = 40001; + // Format of topic is illegal. + ILLEGAL_TOPIC = 40002; + // Format of consumer group is illegal. + ILLEGAL_CONSUMER_GROUP = 40003; + // Format of message tag is illegal. + ILLEGAL_MESSAGE_TAG = 40004; + // Format of message key is illegal. + ILLEGAL_MESSAGE_KEY = 40005; + // Format of message group is illegal. + ILLEGAL_MESSAGE_GROUP = 40006; + // Format of message property key is illegal. + ILLEGAL_MESSAGE_PROPERTY_KEY = 40007; + // Transaction id is invalid. + INVALID_TRANSACTION_ID = 40008; + // Format of message id is illegal. + ILLEGAL_MESSAGE_ID = 40009; + // Format of filter expression is illegal. + ILLEGAL_FILTER_EXPRESSION = 40010; + // Receipt handle of message is invalid. + INVALID_RECEIPT_HANDLE = 40011; + // Message property conflicts with its type. + MESSAGE_PROPERTY_CONFLICT_WITH_TYPE = 40012; + // Client type could not be recognized. + UNRECOGNIZED_CLIENT_TYPE = 40013; + // Message is corrupted. + MESSAGE_CORRUPTED = 40014; + // Request is rejected due to missing of x-mq-client-id header. + CLIENT_ID_REQUIRED = 40015; + + // Generic code indicates that the client request lacks valid authentication + // credentials for the requested resource. + UNAUTHORIZED = 40100; + + // Generic code indicates that the account is suspended due to overdue of payment. + PAYMENT_REQUIRED = 40200; + + // Generic code for the case that user does not have the permission to operate. + FORBIDDEN = 40300; + + // Generic code for resource not found. + NOT_FOUND = 40400; + // Message not found from server. + MESSAGE_NOT_FOUND = 40401; + // Topic resource does not exist. + TOPIC_NOT_FOUND = 40402; + // Consumer group resource does not exist. + CONSUMER_GROUP_NOT_FOUND = 40403; + + // Generic code representing client side timeout when connecting to, reading data from, or write data to server. + REQUEST_TIMEOUT = 40800; + + // Generic code represents that the request entity is larger than limits defined by server. + PAYLOAD_TOO_LARGE = 41300; + // Message body size exceeds the threshold. + MESSAGE_BODY_TOO_LARGE = 41301; + + // Generic code for use cases where pre-conditions are not met. + // For example, if a producer instance is used to publish messages without prior start() invocation, + // this error code will be raised. + PRECONDITION_FAILED = 42800; + + // Generic code indicates that too many requests are made in short period of duration. + // Requests are throttled. + TOO_MANY_REQUESTS = 42900; + + // Generic code for the case that the server is unwilling to process the request because its header fields are too large. + // The request may be resubmitted after reducing the size of the request header fields. + REQUEST_HEADER_FIELDS_TOO_LARGE = 43100; + // Message properties total size exceeds the threshold. + MESSAGE_PROPERTIES_TOO_LARGE = 43101; + + // Generic code indicates that server/client encountered an unexpected + // condition that prevented it from fulfilling the request. + INTERNAL_ERROR = 50000; + // Code indicates that the server encountered an unexpected condition + // that prevented it from fulfilling the request. + // This error response is a generic "catch-all" response. + // Usually, this indicates the server cannot find a better alternative + // error code to response. Sometimes, server administrators log error + // responses like the 500 status code with more details about the request + // to prevent the error from happening again in the future. + // + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500 + INTERNAL_SERVER_ERROR = 50001; + // The HA-mechanism is not working now. + HA_NOT_AVAILABLE = 50002; + + // Generic code means that the server or client does not support the + // functionality required to fulfill the request. + NOT_IMPLEMENTED = 50100; + + // Generic code represents that the server, which acts as a gateway or proxy, + // does not get an satisfied response in time from its upstream servers. + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504 + PROXY_TIMEOUT = 50400; + // Message persistence timeout. + MASTER_PERSISTENCE_TIMEOUT = 50401; + // Slave persistence timeout. + SLAVE_PERSISTENCE_TIMEOUT = 50402; + + // Generic code for unsupported operation. + UNSUPPORTED = 50500; + // Operation is not allowed in current version. + VERSION_UNSUPPORTED = 50501; + // Not allowed to verify message. Chances are that you are verifying + // a FIFO message, as is violating FIFO semantics. + VERIFY_FIFO_MESSAGE_UNSUPPORTED = 50502; + + // Generic code for failed message consumption. + FAILED_TO_CONSUME_MESSAGE = 60000; +} + +message Status { + Code code = 1; + string message = 2; +} + +enum Language { + LANGUAGE_UNSPECIFIED = 0; + JAVA = 1; + CPP = 2; + DOT_NET = 3; + GOLANG = 4; + RUST = 5; +} + +// User Agent +message UA { + // SDK language + Language language = 1; + + // SDK version + string version = 2; + + // Platform details, including OS name, version, arch etc. + string platform = 3; + + // Hostname of the node + string hostname = 4; +} \ No newline at end of file diff --git a/rust/proto/apache/rocketmq/v2/service.proto b/rust/proto/apache/rocketmq/v2/service.proto new file mode 100644 index 0000000..ac842e6 --- /dev/null +++ b/rust/proto/apache/rocketmq/v2/service.proto @@ -0,0 +1,448 @@ +// 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. + +syntax = "proto3"; + +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "apache/rocketmq/v2/definition.proto"; + +package apache.rocketmq.v2; + +option csharp_namespace = "Apache.Rocketmq.V2"; +option java_multiple_files = true; +option java_package = "apache.rocketmq.v2"; +option java_generate_equals_and_hash = true; +option java_string_check_utf8 = true; +option java_outer_classname = "MQService"; + +// Topics are destination of messages to publish to or subscribe from. Similar +// to domain names, they will be addressable after resolution through the +// provided access point. +// +// Access points are usually the addresses of name servers, which fulfill +// service discovery, load-balancing and other auxiliary services. Name servers +// receive periodic heartbeats from affiliate brokers and erase those which +// failed to maintain alive status. +// +// Name servers answer queries of QueryRouteRequest, responding clients with +// addressable message-queues, which they may directly publish messages to or +// subscribe messages from. +// +// QueryRouteRequest shall include source endpoints, aka, configured +// access-point, which annotates tenant-id, instance-id or other +// vendor-specific settings. Purpose-built name servers may respond customized +// results based on these particular requirements. +message QueryRouteRequest { + Resource topic = 1; + Endpoints endpoints = 2; +} + +message QueryRouteResponse { + Status status = 1; + + repeated MessageQueue message_queues = 2; +} + +message SendMessageRequest { + repeated Message messages = 1; +} + +message SendResultEntry { + Status status = 1; + string message_id = 2; + string transaction_id = 3; + int64 offset = 4; +} + +message SendMessageResponse { + Status status = 1; + + // Some implementation may have partial failure issues. Client SDK developers are expected to inspect + // each entry for best certainty. + repeated SendResultEntry entries = 2; +} + +message QueryAssignmentRequest { + Resource topic = 1; + Resource group = 2; + Endpoints endpoints = 3; +} + +message QueryAssignmentResponse { + Status status = 1; + repeated Assignment assignments = 2; +} + +message ReceiveMessageRequest { + Resource group = 1; + MessageQueue message_queue = 2; + FilterExpression filter_expression = 3; + int32 batch_size = 4; + // Required if client type is simple consumer. + optional google.protobuf.Duration invisible_duration = 5; + // For message auto renew and clean + bool auto_renew = 6; +} + +message ReceiveMessageResponse { + oneof content { + Status status = 1; + Message message = 2; + // The timestamp that brokers start to deliver status line or message. + google.protobuf.Timestamp delivery_timestamp = 3; + } +} + +message AckMessageEntry { + string message_id = 1; + string receipt_handle = 2; +} + +message AckMessageRequest { + Resource group = 1; + Resource topic = 2; + repeated AckMessageEntry entries = 3; +} + +message AckMessageResultEntry { + string message_id = 1; + string receipt_handle = 2; + + // Acknowledge result may be acquired through inspecting + // `status.code`; In case acknowledgement failed, `status.message` + // is the explanation of the failure. + Status status = 3; +} + +message AckMessageResponse { + + // RPC tier status, which is used to represent RPC-level errors including + // authentication, authorization, throttling and other general failures. + Status status = 1; + + repeated AckMessageResultEntry entries = 2; +} + +message ForwardMessageToDeadLetterQueueRequest { + Resource group = 1; + Resource topic = 2; + string receipt_handle = 3; + string message_id = 4; + int32 delivery_attempt = 5; + int32 max_delivery_attempts = 6; +} + +message ForwardMessageToDeadLetterQueueResponse { Status status = 1; } + +message HeartbeatRequest { + optional Resource group = 1; + ClientType client_type = 2; +} + +message HeartbeatResponse { Status status = 1; } + +message EndTransactionRequest { + Resource topic = 1; + string message_id = 2; + string transaction_id = 3; + TransactionResolution resolution = 4; + TransactionSource source = 5; + string trace_context = 6; +} + +message EndTransactionResponse { Status status = 1; } + +message PrintThreadStackTraceCommand { string nonce = 1; } + +message ThreadStackTrace { + string nonce = 1; + optional string thread_stack_trace = 2; +} + +message VerifyMessageCommand { + string nonce = 1; + MessageQueue message_queue = 2; + Message message = 3; +} + +message VerifyMessageResult { + string nonce = 1; +} + +message RecoverOrphanedTransactionCommand { + MessageQueue message_queue = 1; + Message orphaned_transactional_message = 2; + string transaction_id = 3; +} + +message Publishing { + // Publishing settings below here is appointed by client, thus it is + // unnecessary for server to push at present. + // + // List of topics to which messages will publish to. + repeated Resource topics = 1; + + // Publishing settings below here are from server, it is essential for + // server to push. + // + // Body of message will be deflated if its size in bytes exceeds the + // threshold. + int32 compress_body_threshold = 2; + + // If the message body size exceeds `max_body_size`, broker servers would + // reject the request. As a result, it is advisable that Producer performs + // client-side check validation. + int32 max_body_size = 3; + + // When `validate_message_type` flag set `false`, no need to validate message's type + // with messageQueue's `accept_message_types` before publising. + bool validate_message_type = 4; +} + +message Subscription { + // Subscription settings below here is appointed by client, thus it is + // unnecessary for server to push at present. + // + // Consumer group. + optional Resource group = 1; + + // Subscription for consumer. + repeated SubscriptionEntry subscriptions = 2; + + // Subscription settings below here are from server, it is essential for + // server to push. + // + // When FIFO flag is `true`, messages of the same message group are processed + // in first-in-first-out manner. + // + // Brokers will not deliver further messages of the same group utill prior + // ones are completely acknowledged. + optional bool fifo = 3; + + // Message receive batch size here is essential for push consumer. + optional int32 receive_batch_size = 4; + + // Long-polling timeout for `ReceiveMessageRequest`, which is essential for + // push consumer. + optional google.protobuf.Duration long_polling_timeout = 5; +} + +message Metric { + // Indicates that if client should export local metrics to server. + bool on = 1; + + // The endpoint that client metrics should be exported to, which is required if the switch is on. + optional Endpoints endpoints = 2; +} + +message Settings { + // Configurations for all clients. + optional ClientType client_type = 1; + + optional Endpoints access_point = 2; + + // If publishing of messages encounters throttling or server internal errors, + // publishers should implement automatic retries after progressive longer + // back-offs for consecutive errors. + // + // When processing message fails, `backoff_policy` describes an interval + // after which the message should be available to consume again. + // + // For FIFO messages, the interval should be relatively small because + // messages of the same message group would not be readily available utill + // the prior one depletes its lifecycle. + optional RetryPolicy backoff_policy = 3; + + // Request timeout for RPCs excluding long-polling. + optional google.protobuf.Duration request_timeout = 4; + + oneof pub_sub { + Publishing publishing = 5; + + Subscription subscription = 6; + } + + // User agent details + UA user_agent = 7; + + Metric metric = 8; +} + +message TelemetryCommand { + optional Status status = 1; + + oneof command { + // Client settings + Settings settings = 2; + + // These messages are from client. + // + // Report thread stack trace to server. + ThreadStackTrace thread_stack_trace = 3; + + // Report message verify result to server. + VerifyMessageResult verify_message_result = 4; + + // There messages are from server. + // + // Request client to recover the orphaned transaction message. + RecoverOrphanedTransactionCommand recover_orphaned_transaction_command = 5; + + // Request client to print thread stack trace. + PrintThreadStackTraceCommand print_thread_stack_trace_command = 6; + + // Request client to verify the consumption of the appointed message. + VerifyMessageCommand verify_message_command = 7; + } +} + +message NotifyClientTerminationRequest { + // Consumer group, which is absent for producer. + optional Resource group = 1; +} + +message NotifyClientTerminationResponse { Status status = 1; } + +message ChangeInvisibleDurationRequest { + Resource group = 1; + Resource topic = 2; + + // Unique receipt handle to identify message to change + string receipt_handle = 3; + + // New invisible duration + google.protobuf.Duration invisible_duration = 4; + + // For message tracing + string message_id = 5; +} + +message ChangeInvisibleDurationResponse { + Status status = 1; + + // Server may generate a new receipt handle for the message. + string receipt_handle = 2; +} + +// For all the RPCs in MessagingService, the following error handling policies +// apply: +// +// If the request doesn't bear a valid authentication credential, return a +// response with common.status.code == `UNAUTHENTICATED`. If the authenticated +// user is not granted with sufficient permission to execute the requested +// operation, return a response with common.status.code == `PERMISSION_DENIED`. +// If the per-user-resource-based quota is exhausted, return a response with +// common.status.code == `RESOURCE_EXHAUSTED`. If any unexpected server-side +// errors raise, return a response with common.status.code == `INTERNAL`. +service MessagingService { + + // Queries the route entries of the requested topic in the perspective of the + // given endpoints. On success, servers should return a collection of + // addressable message-queues. Note servers may return customized route + // entries based on endpoints provided. + // + // If the requested topic doesn't exist, returns `NOT_FOUND`. + // If the specific endpoints is empty, returns `INVALID_ARGUMENT`. + rpc QueryRoute(QueryRouteRequest) returns (QueryRouteResponse) {} + + // Producer or consumer sends HeartbeatRequest to servers periodically to + // keep-alive. Additionally, it also reports client-side configuration, + // including topic subscription, load-balancing group name, etc. + // + // Returns `OK` if success. + // + // If a client specifies a language that is not yet supported by servers, + // returns `INVALID_ARGUMENT` + rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse) {} + + // Delivers messages to brokers. + // Clients may further: + // 1. Refine a message destination to message-queues which fulfills parts of + // FIFO semantic; + // 2. Flag a message as transactional, which keeps it invisible to consumers + // until it commits; + // 3. Time a message, making it invisible to consumers till specified + // time-point; + // 4. And more... + // + // Returns message-id or transaction-id with status `OK` on success. + // + // If the destination topic doesn't exist, returns `NOT_FOUND`. + rpc SendMessage(SendMessageRequest) returns (SendMessageResponse) {} + + // Queries the assigned route info of a topic for current consumer, + // the returned assignment result is decided by server-side load balancer. + // + // If the corresponding topic doesn't exist, returns `NOT_FOUND`. + // If the specific endpoints is empty, returns `INVALID_ARGUMENT`. + rpc QueryAssignment(QueryAssignmentRequest) returns (QueryAssignmentResponse) { + } + + // Receives messages from the server in batch manner, returns a set of + // messages if success. The received messages should be acked or redelivered + // after processed. + // + // If the pending concurrent receive requests exceed the quota of the given + // consumer group, returns `UNAVAILABLE`. If the upstream store server hangs, + // return `DEADLINE_EXCEEDED` in a timely manner. If the corresponding topic + // or consumer group doesn't exist, returns `NOT_FOUND`. If there is no new + // message in the specific topic, returns `OK` with an empty message set. + // Please note that client may suffer from false empty responses. + // + // If failed to receive message from remote, server must return only one + // `ReceiveMessageResponse` as the reply to the request, whose `Status` indicates + // the specific reason of failure, otherwise, the reply is considered successful. + rpc ReceiveMessage(ReceiveMessageRequest) returns (stream ReceiveMessageResponse) { + } + + // Acknowledges the message associated with the `receipt_handle` or `offset` + // in the `AckMessageRequest`, it means the message has been successfully + // processed. Returns `OK` if the message server remove the relevant message + // successfully. + // + // If the given receipt_handle is illegal or out of date, returns + // `INVALID_ARGUMENT`. + rpc AckMessage(AckMessageRequest) returns (AckMessageResponse) {} + + // Forwards one message to dead letter queue if the max delivery attempts is + // exceeded by this message at client-side, return `OK` if success. + rpc ForwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest) + returns (ForwardMessageToDeadLetterQueueResponse) {} + + // Commits or rollback one transactional message. + rpc EndTransaction(EndTransactionRequest) returns (EndTransactionResponse) {} + + // Once a client starts, it would immediately establishes bi-lateral stream + // RPCs with brokers, reporting its settings as the initiative command. + // + // When servers have need of inspecting client status, they would issue + // telemetry commands to clients. After executing received instructions, + // clients shall report command execution results through client-side streams. + rpc Telemetry(stream TelemetryCommand) returns (stream TelemetryCommand) {} + + // Notify the server that the client is terminated. + rpc NotifyClientTermination(NotifyClientTerminationRequest) returns (NotifyClientTerminationResponse) { + } + + // Once a message is retrieved from consume queue on behalf of the group, it + // will be kept invisible to other clients of the same group for a period of + // time. The message is supposed to be processed within the invisible + // duration. If the client, which is in charge of the invisible message, is + // not capable of processing the message timely, it may use + // ChangeInvisibleDuration to lengthen invisible duration. + rpc ChangeInvisibleDuration(ChangeInvisibleDurationRequest) returns (ChangeInvisibleDurationResponse) { + } +} \ No newline at end of file diff --git a/rust/src/client.rs b/rust/src/client.rs new file mode 100644 index 0000000..9760fcc --- /dev/null +++ b/rust/src/client.rs @@ -0,0 +1,436 @@ +/* + * 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. + */ +use crate::command; +use crate::error; +use crate::pb::{self, QueryRouteRequest, Resource}; +use crate::{error::ClientError, pb::messaging_service_client::MessagingServiceClient}; +use parking_lot::Mutex; +use slog::info; +use slog::{debug, error, o, warn, Logger}; +use std::{ + collections::HashMap, + sync::Arc, + sync::{atomic::AtomicUsize, Weak}, +}; +use tokio::sync::oneshot; +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; + +#[derive(Debug, Clone)] +struct Session { + stub: MessagingServiceClient<Channel>, + logger: Logger, +} + +impl Session { + async fn new(endpoint: String, logger: &Logger) -> Result<Self, error::ClientError> { + debug!(logger, "Creating session to {}", endpoint); + let peer_addr = endpoint.clone(); + + let tls = ClientTlsConfig::default(); + + let channel = Channel::from_shared(endpoint) + .map_err(|e| { + error!(logger, "Failed to create channel. Cause: {:?}", e); + error::ClientError::Connect + })? + .tls_config(tls) + .map_err(|e| { + error!(logger, "Failed to configure TLS. Cause: {:?}", e); + error::ClientError::Connect + })? + .connect_timeout(std::time::Duration::from_secs(3)) + .tcp_nodelay(true) + .connect() + .await + .map_err(|e| { + error!(logger, "Failed to connect to {}. Cause: {:?}", peer_addr, e); + error::ClientError::Connect + })?; + + let stub = MessagingServiceClient::new(channel); + + Ok(Session { + stub, + logger: logger.new(o!("peer" => peer_addr)), + }) + } + + async fn query_route( + &mut self, + request: tonic::Request<pb::QueryRouteRequest>, + ) -> Result<tonic::Response<pb::QueryRouteResponse>, error::ClientError> { + match self.stub.query_route(request).await { + Ok(response) => { + return Ok(response); + } + Err(e) => { + error!(self.logger, "QueryRoute failed. Cause: {:?}", e); + return Err(error::ClientError::ClientInternal); + } + } + } +} + +#[derive(Debug)] +struct SessionManager { + logger: Logger, + tx: tokio::sync::mpsc::Sender<command::Command>, +} + +impl SessionManager { + fn new(logger: Logger) -> Self { + let (tx, mut rx) = tokio::sync::mpsc::channel(256); + + let submitter_logger = logger.new(o!("component" => "submitter")); + tokio::spawn(async move { + let mut session_map: HashMap<String, Session> = HashMap::new(); + loop { + match rx.recv().await { + Some(command) => match command { + command::Command::QueryRoute { peer, request, tx } => { + if !session_map.contains_key(&peer) { + match Session::new(peer.clone(), &submitter_logger).await { + Ok(session) => { + session_map.insert(peer.clone(), session); + } + Err(e) => { + error!( + submitter_logger, + "Failed to create session to {}. Cause: {:?}", peer, e + ); + let _ = tx.send(Err(ClientError::Connect)); + continue; + } + } + } + + match session_map.get(&peer) { + Some(session) => { + // Cloning Channel is cheap and encouraged + // https://docs.rs/tonic/0.7.2/tonic/transport/struct.Channel.html#multiplexing-requests + let mut session = session.clone(); + tokio::spawn(async move { + let result = session.query_route(request).await; + let _ = tx.send(result); + }); + } + None => {} + } + } + }, + None => { + info!(submitter_logger, "Submit loop exit"); + break; + } + } + } + }); + + SessionManager { logger, tx } + } + + async fn route( + &self, + endpoint: &str, + topic: &str, + client: Weak<&Client>, + ) -> Result<Route, error::ClientError> { + let client = match client.upgrade() { + Some(client) => client, + None => { + return Err(error::ClientError::ClientInternal); + } + }; + + let access_point = Client::access_point(); + let request = QueryRouteRequest { + topic: Some(Resource { + name: topic.to_owned(), + resource_namespace: client.arn().to_owned(), + }), + endpoints: Some(access_point), + }; + + let mut request = tonic::Request::new(request); + client.sign(request.metadata_mut()); + + let (tx1, rx1) = oneshot::channel(); + let command = command::Command::QueryRoute { + peer: endpoint.to_owned(), + request, + tx: tx1, + }; + + match self.tx.send(command).await { + Ok(_) => {} + Err(e) => { + error!(self.logger, "Failed to submit request"); + } + } + + match rx1.await { + Ok(result) => result.map(|_response| Route {}), + Err(e) => { + error!(self.logger, "oneshot channel error. Cause: {:?}", e); + Err(ClientError::ClientInternal) + } + } + } +} + +#[derive(Debug)] +struct Route {} + +#[derive(Debug)] +enum RouteStatus { + Querying(Vec<oneshot::Sender<Result<Arc<Route>, error::ClientError>>>), + Found(Arc<Route>), +} + +#[derive(Debug)] +pub(crate) struct Client { + session_manager: SessionManager, + logger: Logger, + route_table: Mutex<HashMap<String /* topic */, RouteStatus>>, + arn: String, + id: String, +} + +static CLIENT_ID_SEQUENCE: AtomicUsize = AtomicUsize::new(0); + +impl Client { + fn client_id() -> String { + let host = match hostname::get() { + Ok(name) => name, + Err(_) => "localhost".into(), + }; + + let host = match host.into_string() { + Ok(host) => host, + Err(_) => String::from("localhost"), + }; + + format!( + "{}@{}#{}", + host, + std::process::id(), + CLIENT_ID_SEQUENCE.fetch_add(1, std::sync::atomic::Ordering::Relaxed), + ) + } + + pub(crate) fn new(logger: Logger) -> Self { + let id = Self::client_id(); + Client { + session_manager: SessionManager::new(logger.new(o!("component" => "session_manager"))), + logger, + route_table: Mutex::new(HashMap::new()), + arn: String::from(""), + id, + } + } + + fn access_point() -> pb::Endpoints { + return pb::Endpoints { + scheme: pb::AddressScheme::IPv4 as i32, + addresses: vec![pb::Address { + host: String::from("127.0.0.1"), + port: 8081, + }], + }; + } + + fn arn(&self) -> &str { + &self.arn + } + + async fn query_route( + &self, + topic: &str, + lookup_cache: bool, + ) -> Result<Arc<Route>, error::ClientError> { + debug!(self.logger, "Query route for topic={}", topic); + let rx = match self + .route_table + .lock() + .entry(topic.to_owned()) + .or_insert_with(|| RouteStatus::Querying(Vec::new())) + { + RouteStatus::Found(route) => { + if lookup_cache { + return Ok(Arc::clone(route)); + } + None + } + RouteStatus::Querying(ref mut v) => { + if v.is_empty() { + None + } else { + let (tx, rx) = oneshot::channel(); + v.push(tx); + Some(rx) + } + } + }; + + if let Some(rx) = rx { + match rx.await { + Ok(route) => { + return route; + } + Err(_e) => { + return Err(error::ClientError::ClientInternal); + } + } + } + + let endpoint = "https://127.0.0.1:8081"; + let client = Arc::new(*&self); + let client_weak = Arc::downgrade(&client); + match self + .session_manager + .route(endpoint, topic, client_weak) + .await + { + Ok(route) => { + let route = Arc::new(route); + let prev = self + .route_table + .lock() + .insert(topic.to_owned(), RouteStatus::Found(Arc::clone(&route))); + + match prev { + Some(RouteStatus::Found(_)) => {} + Some(RouteStatus::Querying(mut v)) => { + for item in v.drain(..) { + let _ = item.send(Ok(Arc::clone(&route))); + } + } + None => {} + }; + return Ok(route); + } + Err(_e) => { + let prev = self.route_table.lock().remove(topic); + match prev { + Some(RouteStatus::Found(route)) => { + self.route_table + .lock() + .insert(topic.to_owned(), RouteStatus::Found(Arc::clone(&route))); + return Ok(route); + } + Some(RouteStatus::Querying(mut v)) => { + for tx in v.drain(..) { + let _ = tx.send(Err(error::ClientError::ClientInternal)); + } + return Err(error::ClientError::ClientInternal); + } + None => { + return Err(error::ClientError::ClientInternal); + } + }; + } + } + } + + fn sign(&self, metadata: &mut tonic::metadata::MetadataMap) { + let _ = tonic::metadata::AsciiMetadataValue::try_from(&self.id).and_then(|v| { + metadata.insert("x-mq-client-id", v); + Ok(()) + }); + + metadata.insert( + "x-mq-language", + tonic::metadata::AsciiMetadataValue::from_static("RUST"), + ); + metadata.insert( + "x-mq-client-version", + tonic::metadata::AsciiMetadataValue::from_static("5.0.0"), + ); + metadata.insert( + "x-mq-protocol-version", + tonic::metadata::AsciiMetadataValue::from_static("2.0.0"), + ); + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use slog::Drain; + + #[test] + fn test_client_id() { + let mut set = std::collections::HashSet::new(); + (0..256).for_each(|_| { + let id = Client::client_id(); + assert_eq!(false, set.contains(&id)); + set.insert(id); + }); + } + + #[tokio::test] + async fn test_session_manager_new() { + let _session_manager = SessionManager::new(create_logger()); + drop(_session_manager); + } + + #[tokio::test] + async fn test_session_new() { + // 121.196.167.124:8081 + let endpoint = "http://121.196.167.124:8081".to_string(); + let logger = create_logger(); + let _session = Session::new(endpoint, &logger) + .await + .expect("Failed to create a new session"); + } + + fn create_logger() -> Logger { + let decorator = slog_term::TermDecorator::new().build(); + let drain = slog_term::FullFormat::new(decorator).build().fuse(); + let drain = slog_async::Async::new(drain).build().fuse(); + slog::Logger::root(drain, o!()) + } + + #[tokio::test] + async fn test_session_query_route() -> Result<(), error::ClientError> { + let logger = create_logger(); + let endpoint = "http://localhost:8081"; + let mut session = Session::new(endpoint.to_owned(), &logger).await?; + let topic = "cpp_sdk_standard"; + + let request = pb::QueryRouteRequest { + topic: Some(pb::Resource { + name: topic.to_owned(), + resource_namespace: String::from(""), + }), + endpoints: Some(Client::access_point()), + }; + + let request = tonic::Request::new(request); + let _response = session.query_route(request).await?; + Ok(()) + } + + #[tokio::test] + async fn test_client_query_route() { + let _endpoint = "http://localhost:8081"; + let client = Client::new(create_logger()); + let topic = "cpp_sdk_standard"; + let _route = client.query_route(topic, true).await.unwrap(); + } +} diff --git a/rust/src/command.rs b/rust/src/command.rs new file mode 100644 index 0000000..5a3f3fa --- /dev/null +++ b/rust/src/command.rs @@ -0,0 +1,13 @@ +use crate::client::Client; +use crate::error::ClientError; +use crate::pb::{QueryRouteRequest, QueryRouteResponse}; +use tokio::sync::oneshot; +use tonic::{Request, Response}; + +pub(crate) enum Command { + QueryRoute { + peer: String, + request: Request<QueryRouteRequest>, + tx: oneshot::Sender<Result<Response<QueryRouteResponse>, ClientError>>, + }, +} diff --git a/rust/src/error.rs b/rust/src/error.rs new file mode 100644 index 0000000..f31f5d4 --- /dev/null +++ b/rust/src/error.rs @@ -0,0 +1,26 @@ +/* + * 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. + */ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ClientError { + #[error("Failed to create session")] + Connect, + + #[error("Client internal error")] + ClientInternal, +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs new file mode 100644 index 0000000..d974146 --- /dev/null +++ b/rust/src/lib.rs @@ -0,0 +1,26 @@ +/* + * 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. + */ +#[path = "pb/apache.rocketmq.v2.rs"] +mod pb; + +mod error; + +mod command; + +mod client; + +mod producer; diff --git a/rust/src/main.rs b/rust/src/main.rs new file mode 100644 index 0000000..d69ca78 --- /dev/null +++ b/rust/src/main.rs @@ -0,0 +1,20 @@ +/* + * 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. + */ + +fn main() { + println!("Hello, world!"); +} diff --git a/rust/src/producer.rs b/rust/src/producer.rs new file mode 100644 index 0000000..ade2d3a --- /dev/null +++ b/rust/src/producer.rs @@ -0,0 +1,24 @@ +use slog::Logger; + +use crate::client; + +struct Producer { + client: client::Client, +} + +impl Producer { + pub async fn new<T>(logger: Logger, topics: T) -> Self + where + T: IntoIterator, + T::Item: AsRef<str>, + { + let mut client = client::Client::new(logger); + for _topic in topics.into_iter() { + // client.subscribe(topic.as_ref()).await; + } + + Producer { client } + } + + pub fn start(&mut self) {} +}