diff --git a/README.md b/README.md index e4dfeba..7102f0e 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,4 @@ Web framework comparison in my stack. - Nodejs - Deno - Bunjs + - [ ] Elysia diff --git a/frameworks/Rust/axum-xitca/.editorconfig b/frameworks/Rust/axum-xitca/.editorconfig new file mode 100644 index 0000000..780d697 --- /dev/null +++ b/frameworks/Rust/axum-xitca/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +indent_style = space +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +indent_size = 4 +charset = utf-8 + +[*.{yml,yaml}] +indent_size = 2 + +[Makefile] +indent_style = tab diff --git a/frameworks/Rust/axum-xitca/.env.example b/frameworks/Rust/axum-xitca/.env.example new file mode 100644 index 0000000..68cc604 --- /dev/null +++ b/frameworks/Rust/axum-xitca/.env.example @@ -0,0 +1 @@ +PHTHONUS_PORT=4000 diff --git a/frameworks/Rust/axum-xitca/.gitignore b/frameworks/Rust/axum-xitca/.gitignore new file mode 100644 index 0000000..14ee500 --- /dev/null +++ b/frameworks/Rust/axum-xitca/.gitignore @@ -0,0 +1,2 @@ +target/ +.env diff --git a/frameworks/Rust/axum-xitca/Cargo.lock b/frameworks/Rust/axum-xitca/Cargo.lock new file mode 100644 index 0000000..11b3d4a --- /dev/null +++ b/frameworks/Rust/axum-xitca/Cargo.lock @@ -0,0 +1,1280 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "anyhow" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" + +[[package]] +name = "async-compression" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "zstd", + "zstd-safe", +] + +[[package]] +name = "async-trait" +version = "0.1.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "axum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 1.0.1", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-xitca" +version = "0.1.0" +dependencies = [ + "anyhow", + "axum", + "dotenvy", + "http-body", + "serde", + "serde_json", + "serde_repr", + "thiserror", + "tokio", + "tower", + "tower-http", + "tracing", + "tracing-subscriber", + "xitca-http", + "xitca-io", + "xitca-server", + "xitca-service", + "xitca-unsafe-collection", + "xitca-web", +] + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" + +[[package]] +name = "cc" +version = "1.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[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.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "flate2" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +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 = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "io-uring" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595a0399f411a508feb2ec1e970a4a30c249351e30208960d58298de8660b0e5" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "iri-string" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c25163201be6ded9e686703e85532f8f852ea1f92ba625cb3c51f7fe6d07a4a" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "thiserror" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tokio" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.7", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-uring" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "748482e3e13584a34664a710168ad5068e8cb1d968aa4ffa887e83ca6dd27967" +dependencies = [ + "bytes", + "futures-util", + "io-uring", + "libc", + "slab", + "socket2 0.4.10", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" +dependencies = [ + "async-compression", + "base64", + "bitflags 2.6.0", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "http-range-header", + "httpdate", + "iri-string", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", + "uuid", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +dependencies = [ + "getrandom", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[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.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "xitca-http" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b5b036e32261c69d4f0e81bcb28c2e058ed569518959336fd75fc086208d3f" +dependencies = [ + "futures-core", + "http", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.7", + "tokio", + "tokio-uring", + "tracing", + "xitca-io", + "xitca-router", + "xitca-service", + "xitca-unsafe-collection", +] + +[[package]] +name = "xitca-io" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b91b7a5ff9e3bed167b7e3bcc7b4462d2cb16d05e3ae913dbc384e463fdd7f" +dependencies = [ + "bytes", + "tokio", + "tokio-uring", + "xitca-unsafe-collection", +] + +[[package]] +name = "xitca-router" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a771113f381c9a2f5ae1096b70d629ed241a1a473304ea902258c3d528f536" +dependencies = [ + "xitca-unsafe-collection", +] + +[[package]] +name = "xitca-server" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a40a05f18780f1de843c5077583e4650b08d0518fcf9cf7948e28bc92e489736" +dependencies = [ + "socket2 0.5.7", + "tokio", + "tracing", + "xitca-io", + "xitca-service", + "xitca-unsafe-collection", +] + +[[package]] +name = "xitca-service" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74b093ca75b264924773d53e445de08a937100bf1cbe4f62d4dc2c0d04a3ba4b" + +[[package]] +name = "xitca-unsafe-collection" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467b95b08735dcd7061be626d02aea062bc0b99918bc9de11b8fc15d901158ae" +dependencies = [ + "bytes", +] + +[[package]] +name = "xitca-web" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4f8f16791ea2a8845f617f1e87887f917835e0603d01f03a51e638b9613d0c" +dependencies = [ + "futures-core", + "http-body", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "xitca-http", + "xitca-server", + "xitca-service", + "xitca-unsafe-collection", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/frameworks/Rust/axum-xitca/Cargo.toml b/frameworks/Rust/axum-xitca/Cargo.toml new file mode 100644 index 0000000..6bd586e --- /dev/null +++ b/frameworks/Rust/axum-xitca/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "axum-xitca" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { version = "1.40.0", features = ["full"] } +axum = { version = "0.7.6", default-features = false, features = [ + "json", + "query", +] } +xitca-server = "0.4.0" +xitca-http = { version = "0.6.0", features = ["io-uring"] } +xitca-io = { version = "0.4.1", features = [ + "tokio-uring", + "tokio", + "runtime-uring", +] } +xitca-service = "0.2.0" +xitca-web = { version = "0.6.2", features = ["tower-http-compat"] } +tower = "0.5.1" +tower-http = { version = "0.6.1", features = ["full"] } +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } +# error +anyhow = "1.0.89" +thiserror = "1.0.64" +# tools +dotenvy = "0.15.7" +serde = { version = "1.0.210", features = ["derive", "serde_derive"] } +serde_json = { version = "1.0.128" } +serde_repr = "0.1.19" +http-body = "1.0.1" +xitca-unsafe-collection = "0.2.0" diff --git a/frameworks/Rust/axum-xitca/Makefile b/frameworks/Rust/axum-xitca/Makefile new file mode 100644 index 0000000..fc6ba34 --- /dev/null +++ b/frameworks/Rust/axum-xitca/Makefile @@ -0,0 +1,62 @@ +CARGO = cargo +RUSTC = rustc +CROSS = cross + +all: build + +build: + $(CARGO) build + +release: clean + $(CARGO) build --release + +dev: + PHTHONUS_LOG=debug $(CARGO) watch -x run + +run: + $(CARGO) run + +test: + $(CARGO) test + +clean: + $(CARGO) clean + +clean-release: + rm -rf ./target/release/ + rm -rf ./target/debug/ + +check: + $(CARGO) check + +format: + $(CARGO) fmt + +lint: + $(CARGO) clippy + +fix: + $(CARGO) fix --allow-dirty --all-features && $(CARGO) fmt + +linux-musl: clean-release + $(CROSS) build --release --target x86_64-unknown-linux-musl + +linux-gnu: clean-release + $(CROSS) build --release --target x86_64-unknown-linux-gnu + +windows-gnu: clean-release + $(CROSS) build --release --target x86_64-pc-windows-gnu + +freebsd: clean-release + $(CROSS) build --release --target x86_64-unknown-freebsd + +loongarch: clean-release + $(CROSS) build --release --target loongarch64-unknown-linux-gnu + +deps: + python -m venv venus \ + && source venus/bin/activate \ + && pip install -r scripts/requirements.txt \ + && python scripts/download-core.py + +.PHONY: all diff --git a/frameworks/Rust/axum-xitca/rust-toolchain.toml b/frameworks/Rust/axum-xitca/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/frameworks/Rust/axum-xitca/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/frameworks/Rust/axum-xitca/src/consts.rs b/frameworks/Rust/axum-xitca/src/consts.rs new file mode 100644 index 0000000..608a2a9 --- /dev/null +++ b/frameworks/Rust/axum-xitca/src/consts.rs @@ -0,0 +1,3 @@ +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const NAME: &str = env!("CARGO_PKG_NAME"); +pub const DEFAULT_PORT: u16 = 4000; diff --git a/frameworks/Rust/axum-xitca/src/error.rs b/frameworks/Rust/axum-xitca/src/error.rs new file mode 100644 index 0000000..b92b11d --- /dev/null +++ b/frameworks/Rust/axum-xitca/src/error.rs @@ -0,0 +1,98 @@ +use std::fmt::Display; + +use axum::{ + extract::rejection::{FormRejection, JsonRejection}, + http::StatusCode, + response::{IntoResponse, Response}, + Json, +}; +use serde_json::json; +use serde_repr::*; +use tracing::error; + +#[derive(thiserror::Error, Debug)] +pub enum AppError { + #[error("{0}")] + Any(#[from] anyhow::Error), + + // axum + #[error(transparent)] + AxumFormRejection(#[from] FormRejection), + #[error(transparent)] + AxumJsonRejection(#[from] JsonRejection), + // route + // 路由通常错误 错误信息直接返回用户 + // #[error("{0}")] + // AuthorizeFailed(Cow<'static, str>), + // #[error("{0}")] + // UserConflict(Cow<'static, str>), +} + +#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)] +#[repr(u16)] +pub enum ErrorCode { + Normal = 200, + InternalError = 1000, + //NotAuthorized = 1001, + AuthorizeFailed = 1002, + UserConflict = 1003, + ParameterIncorrect = 1004, +} + +impl Display for ErrorCode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use ErrorCode::*; + + let res = match self { + Normal => "", + InternalError => "服务器内部错误", + //NotAuthorized => "未登录", + AuthorizeFailed => "用户名或密码错误", + UserConflict => "该用户已经存在", + ParameterIncorrect => "请求参数错误", + }; + f.write_str(res)?; + Ok(()) + } +} + +/// Log and return INTERNAL_SERVER_ERROR +fn log_internal_error(err: T) -> (StatusCode, ErrorCode, String) { + use ErrorCode::*; + + error!("{err}"); + ( + StatusCode::INTERNAL_SERVER_ERROR, + InternalError, + "internal server error".to_string(), + ) +} + +// Tell axum how to convert `AppError` into a response. +impl IntoResponse for AppError { + fn into_response(self) -> Response { + use ErrorCode::*; + + let (status_code, code, err_message) = match self { + AppError::Any(err) => log_internal_error(err), + AppError::AxumFormRejection(_) | AppError::AxumJsonRejection(_) => ( + StatusCode::BAD_REQUEST, + ParameterIncorrect, + self.to_string(), + ), + // route + // AppError::AuthorizeFailed(err) => { + // (StatusCode::UNAUTHORIZED, AuthorizeFailed, err.to_string()) + // } + // AppError::UserConflict(err) => (StatusCode::CONFLICT, UserConflict, err.to_string()), + }; + let body = Json(json!({ + "code": code, + "message": code.to_string(), + "error": err_message + })); + (status_code, body).into_response() + } +} + +pub type AppResult = Result; diff --git a/frameworks/Rust/axum-xitca/src/main.rs b/frameworks/Rust/axum-xitca/src/main.rs new file mode 100644 index 0000000..93ce138 --- /dev/null +++ b/frameworks/Rust/axum-xitca/src/main.rs @@ -0,0 +1,30 @@ +use std::env; + +use consts::{DEFAULT_PORT, NAME}; +use dotenvy::dotenv; +use tower_compat::TowerHttp; +use utils::init_logger; + +mod consts; +mod error; +mod middlewares; +mod routes; +mod tower_compat; +mod utils; + +#[tokio::main] +async fn main() -> std::io::Result<()> { + dotenv().ok(); + init_logger(); + + let service = TowerHttp::service(|| async { Ok(routes::routes()) }); + + let port = env::var("PHTHONUS_PORT") + .map(|port| port.parse::().unwrap_or(DEFAULT_PORT)) + .unwrap_or(DEFAULT_PORT); + + xitca_server::Builder::new() + .bind(NAME, format!("0.0.0.0:{port}"), service)? + .build() + .await +} diff --git a/frameworks/Rust/axum-xitca/src/middlewares/mod.rs b/frameworks/Rust/axum-xitca/src/middlewares/mod.rs new file mode 100644 index 0000000..78c2c02 --- /dev/null +++ b/frameworks/Rust/axum-xitca/src/middlewares/mod.rs @@ -0,0 +1,69 @@ +use std::time::Duration; + +use axum::{ + body::Bytes, + extract::Request, + http::{HeaderMap, HeaderValue}, + middleware::Next, + response::{IntoResponse, Response}, + Router, +}; +use tower_http::classify::ServerErrorsFailureClass; +use tower_http::trace::TraceLayer; +use tracing::{error, info, info_span, Span}; + +use crate::{ + consts::{NAME, VERSION}, + error::AppResult, +}; + +/// Middleware for adding version information to each response's headers. +/// +/// This middleware takes an incoming `Request` and a `Next` handler, which represents the +/// subsequent middleware or route in the chain. It then asynchronously runs the next handler, +/// obtaining the response. After receiving the response, it appends two headers: +/// - "Server": The name of the server extracted from the Cargo package name. +/// - "S-Version": The version of the server extracted from the Cargo package version. +pub async fn add_version( + req: Request, + next: Next, +) -> AppResult { + let mut res = next.run(req).await; + let headers = res.headers_mut(); + headers.append("Server", HeaderValue::from_static(NAME)); + headers.append("Phthonus-Version", HeaderValue::from_static(VERSION)); + Ok(res) +} + +/// Middleware for logging each request. +/// +/// This middleware will calculate each request latency +/// and add request's information to each info_span. +pub fn logging_route(router: Router) -> Router { + router.layer( + TraceLayer::new_for_http() + .make_span_with(|req: &Request<_>| { + let unknown = &HeaderValue::from_static("Unknown"); + let empty = &HeaderValue::from_static(""); + let headers = req.headers(); + let ua = headers + .get("User-Agent") + .unwrap_or(unknown) + .to_str() + .unwrap_or("Unknown"); + let host = headers.get("Host").unwrap_or(empty).to_str().unwrap_or(""); + info_span!("HTTP", method = ?req.method(), host, uri = ?req.uri(), ua) + }) + .on_request(|_req: &Request<_>, _span: &Span| {}) + .on_response(|res: &Response, latency: Duration, _span: &Span| { + info!("{} {}μs", res.status(), latency.as_micros()); + }) + .on_body_chunk(|_chunk: &Bytes, _latency: Duration, _span: &Span| {}) + .on_eos(|_trailers: Option<&HeaderMap>, _stream_duration: Duration, _span: &Span| {}) + .on_failure( + |error: ServerErrorsFailureClass, _latency: Duration, _span: &Span| { + error!("{}", error); + }, + ), + ) +} diff --git a/frameworks/Rust/axum-xitca/src/routes/mod.rs b/frameworks/Rust/axum-xitca/src/routes/mod.rs new file mode 100644 index 0000000..d511294 --- /dev/null +++ b/frameworks/Rust/axum-xitca/src/routes/mod.rs @@ -0,0 +1,99 @@ +use std::{borrow::Cow, collections::HashMap, time::Duration}; + +use axum::{ + async_trait, + extract::{FromRequestParts, Path}, + http::{request::Parts, StatusCode, Uri}, + middleware, + response::{IntoResponse, Response}, + routing::get, + Json, RequestPartsExt, Router, +}; +use serde::Serialize; +use tower::ServiceBuilder; +use tower_http::timeout::TimeoutLayer; +use tracing::info; + +use crate::{ + error::{AppResult, ErrorCode}, + middlewares::{add_version, logging_route}, +}; + +#[derive(Debug, Serialize)] +pub struct RouteResponse +where + T: Serialize, +{ + code: ErrorCode, + #[serde(skip_serializing_if = "Option::is_none")] + message: Option>, + data: T, +} +pub type RouteResult = AppResult>>; + +pub fn routes() -> Router { + let router = Router::new() + .route("/", get(hello).post(hello)) + .layer( + ServiceBuilder::new() + .layer(middleware::from_fn(add_version)) + .layer(TimeoutLayer::new(Duration::from_secs(15))), + ) + .fallback(fallback); + logging_route(router) +} + +/// hello world +pub async fn hello() -> String { + format!("hello {}", env!("CARGO_PKG_NAME")) +} + +/// Fallback route handler for handling unmatched routes. +/// +/// This asynchronous function takes a `Uri` as an argument, representing the unmatched route. +/// It logs a message indicating that the specified route is not found and returns a standard +/// "Not Found" response with a `StatusCode` of `404`. +/// +/// # Arguments +/// +/// - `uri`: The `Uri` representing the unmatched route. +/// +/// # Returns +/// +/// Returns a tuple `(StatusCode, &str)` where `StatusCode` is set to `NOT_FOUND` (404), +/// indicating that the route was not found, and the string "Not found" as the response body. +pub async fn fallback(uri: Uri) -> impl IntoResponse { + info!("route {} not found", uri); + (StatusCode::NOT_FOUND, "Not found") +} + +#[derive(Debug)] +enum Version { + V1, + V2, + V3, +} + +#[async_trait] +impl FromRequestParts for Version +where + S: Send + Sync, +{ + type Rejection = Response; + + async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { + let params: Path> = + parts.extract().await.map_err(IntoResponse::into_response)?; + + let version = params + .get("version") + .ok_or_else(|| (StatusCode::NOT_FOUND, "version param missing").into_response())?; + + match version.as_str() { + "v1" => Ok(Version::V1), + "v2" => Ok(Version::V2), + "v3" => Ok(Version::V3), + _ => Err((StatusCode::NOT_FOUND, "unknown version").into_response()), + } + } +} diff --git a/frameworks/Rust/axum-xitca/src/tower_compat.rs b/frameworks/Rust/axum-xitca/src/tower_compat.rs new file mode 100644 index 0000000..0f377e6 --- /dev/null +++ b/frameworks/Rust/axum-xitca/src/tower_compat.rs @@ -0,0 +1,73 @@ +use core::{cell::RefCell, fmt, future::Future, marker::PhantomData}; + +use std::net::SocketAddr; + +use http_body::Body; +use xitca_http::{ + bytes::Bytes, + h1::RequestBody, + http::{Request, RequestExt, Response}, + HttpServiceBuilder, +}; +use xitca_io::net::io_uring::TcpStream; +use xitca_service::{ + fn_build, middleware::UncheckedReady, ready::ReadyService, Service, ServiceExt, +}; +use xitca_web::service::tower_http_compat::{CompatReqBody, CompatResBody}; + +pub struct TowerHttp { + service: RefCell, + _p: PhantomData, +} + +pub type Error = Box; + +impl TowerHttp { + pub fn service( + func: F, + ) -> impl Service< + Response = impl ReadyService + Service<(TcpStream, SocketAddr)>, + Error = impl fmt::Debug, + > + where + F: Fn() -> Fut + Send + Sync + Clone, + Fut: Future>, + S: tower::Service< + Request, ()>>, + Response = Response, + >, + S::Error: fmt::Debug, + B: Body + Send + 'static, + { + fn_build(move |_| { + let func = func.clone(); + async move { + func().await.map(|service| TowerHttp { + service: RefCell::new(service), + _p: PhantomData, + }) + } + }) + .enclosed(UncheckedReady) + .enclosed(HttpServiceBuilder::h1().io_uring()) + } +} + +impl Service>> for TowerHttp +where + S: tower::Service, ()>>, Response = Response>, +{ + type Response = Response>; + type Error = S::Error; + + async fn call( + &self, + req: Request>, + ) -> Result { + let (parts, ext) = req.into_parts(); + let req = Request::from_parts(parts, CompatReqBody::new(ext, ())); + let fut = self.service.borrow_mut().call(req); + let (parts, body) = fut.await?.into_parts(); + Ok(Response::from_parts(parts, CompatResBody::new(body))) + } +} diff --git a/frameworks/Rust/axum-xitca/src/utils/mod.rs b/frameworks/Rust/axum-xitca/src/utils/mod.rs new file mode 100644 index 0000000..dbe3e01 --- /dev/null +++ b/frameworks/Rust/axum-xitca/src/utils/mod.rs @@ -0,0 +1,81 @@ +use tokio::signal; +use tracing_subscriber::{fmt, prelude::*, registry, EnvFilter}; + +/// Initializes the logger for tracing. +pub fn init_logger() { + let formatting_layer = fmt::layer() + // .pretty() + .with_thread_ids(false) + .with_target(false) + .with_writer(std::io::stdout); + + let env_layer = EnvFilter::try_from_env("axum").unwrap_or_else(|_| "info".into()); + + registry().with(env_layer).with(formatting_layer).init(); +} + +/// Asynchronously waits for a shutdown signal and executes a callback function when a signal is received. +/// +/// This function listens for shutdown signals in the form of `Ctrl+C` and termination signals. When one of +/// these signals is received, it invokes the provided callback function `shutdown_cb`. +/// +/// The behavior of the signal handling depends on the operating system: +/// +/// - On Unix-based systems (e.g., Linux, macOS), it listens for termination signals (such as SIGTERM). +/// - On non-Unix systems (e.g., Windows), it only listens for `Ctrl+C` and ignores termination signals. +/// +/// The `shutdown_cb` callback function is executed when either signal is received. This function should +/// contain the logic needed to gracefully shut down the application or perform any necessary cleanup tasks. +/// # Parameters +/// +/// - `shutdown_cb`: A closure or function to call when a shutdown signal is received. The function should +/// have the signature `Fn()`. This callback is executed without any parameters. +/// +/// # Errors +/// +/// - If setting up the signal handlers fails, the function will panic with an error message. +/// +/// # Panics +/// +/// - Panics if the setup for `Ctrl+C` or termination signal handlers fails. +/// +/// # Platform-specific behavior +/// +/// - On Unix-based systems, termination signals are handled using the `signal` crate for Unix signals. +/// - On non-Unix systems, only `Ctrl+C` signals are handled, and termination signals are not supported. +/// +/// # Future +/// +/// This function returns a future that resolves when either `Ctrl+C` or a termination signal is received +/// and the callback function has been executed. +pub async fn shutdown_signal(shutdown_cb: F) +where + F: Fn(), +{ + let ctrl_c = async { + signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + }; + + #[cfg(unix)] + let terminate = async { + signal::unix::signal(signal::unix::SignalKind::terminate()) + .expect("failed to install signal handler") + .recv() + .await; + }; + + #[cfg(not(unix))] + let terminate = std::future::pending::<()>(); + + tokio::select! { + _ = ctrl_c => { + shutdown_cb() + // let _ = stop_core().map_err(log_err); + }, + _ = terminate => { + shutdown_cb() + }, + } +} diff --git a/frameworks/Rust/axum/src/main.rs b/frameworks/Rust/axum/src/main.rs index 4f76f6e..0b13256 100644 --- a/frameworks/Rust/axum/src/main.rs +++ b/frameworks/Rust/axum/src/main.rs @@ -20,7 +20,6 @@ type Result = std::result::Result>; async fn main() -> Result<()> { dotenv().ok(); init_logger(); - info!("Hello, world!"); let port = env::var("PHTHONUS_PORT") .map(|port| port.parse::().unwrap_or(DEFAULT_PORT)) diff --git a/frameworks/Rust/axum/src/utils/mod.rs b/frameworks/Rust/axum/src/utils/mod.rs index eb7c3a6..dbe3e01 100644 --- a/frameworks/Rust/axum/src/utils/mod.rs +++ b/frameworks/Rust/axum/src/utils/mod.rs @@ -2,20 +2,6 @@ use tokio::signal; use tracing_subscriber::{fmt, prelude::*, registry, EnvFilter}; /// Initializes the logger for tracing. -/// -/// This function sets up the necessary layers for tracing using the `tracing_subscriber` -/// crate. It configures the formatting layer and environment filter based on the value -/// of the `LIMOS_LOG` environment variable (defaulting to "info" if not set). -/// -/// # Example -/// -/// ```rust -/// use utils::init_logger; -/// -/// fn test() { -/// init_logger(); -/// } -/// ``` pub fn init_logger() { let formatting_layer = fmt::layer() // .pretty()