Initial commit
This commit is contained in:
commit
e137a74979
12 changed files with 1426 additions and 0 deletions
4
.envrc
Normal file
4
.envrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
if ! has nix_direnv_version || ! nix_direnv_version 2.3.0; then
|
||||||
|
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.3.0/direnvrc" "sha256-Dmd+j63L84wuzgyjITIfSxSD57Tx7v51DMxVZOsiUD8="
|
||||||
|
fi
|
||||||
|
use flake
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.direnv/
|
||||||
|
target/
|
702
Cargo.lock
generated
Normal file
702
Cargo.lock
generated
Normal file
|
@ -0,0 +1,702 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "addr2line"
|
||||||
|
version = "0.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||||
|
dependencies = [
|
||||||
|
"gimli",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler2"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.98"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de45108900e1f9b9242f7f2e254aa3e2c029c921c258fe9e6b4217eeebd54288"
|
||||||
|
dependencies = [
|
||||||
|
"axum-core",
|
||||||
|
"bytes",
|
||||||
|
"form_urlencoded",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"itoa",
|
||||||
|
"matchit",
|
||||||
|
"memchr",
|
||||||
|
"mime",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustversion",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_path_to_error",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"sync_wrapper",
|
||||||
|
"tokio",
|
||||||
|
"tower",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-core"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"mime",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustversion",
|
||||||
|
"sync_wrapper",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum_folder_router"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"axum",
|
||||||
|
"glob",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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 = "bitflags"
|
||||||
|
version = "2.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[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-channel"
|
||||||
|
version = "0.3.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gimli"
|
||||||
|
version = "0.31.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "1.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
|
||||||
|
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.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httparse"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
|
"itoa",
|
||||||
|
"pin-project-lite",
|
||||||
|
"smallvec",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-util"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.171"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||||
|
|
||||||
|
[[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.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchit"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
||||||
|
|
||||||
|
[[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 = "miniz_oxide"
|
||||||
|
version = "0.8.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||||
|
dependencies = [
|
||||||
|
"adler2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.36.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[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.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.94"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.5.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||||
|
|
||||||
|
[[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.219"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.219"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.140"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_path_to_error"
|
||||||
|
version = "0.1.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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 = "signal-hook-registry"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.5.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sync_wrapper"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.44.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace",
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"mio",
|
||||||
|
"parking_lot",
|
||||||
|
"pin-project-lite",
|
||||||
|
"signal-hook-registry",
|
||||||
|
"socket2",
|
||||||
|
"tokio-macros",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-macros"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"pin-project-lite",
|
||||||
|
"sync_wrapper",
|
||||||
|
"tokio",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[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"
|
32
Cargo.toml
Normal file
32
Cargo.toml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[package]
|
||||||
|
name = "axum_folder_router"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
readme = "./README.md"
|
||||||
|
authors = ["Tristan Druyen <ek36g2vcc@mozmail.com>"]
|
||||||
|
categories = ["web-programming"]
|
||||||
|
keywords = ["axum", "controller", "macro", "routing"]
|
||||||
|
description = "Helper macro for simple folder based routing of axum handlers"
|
||||||
|
homepage = "https://git.vlt81.de/vault81/axum-folder-router"
|
||||||
|
repository = "https://git.vlt81.de/vault81/axum-folder-router"
|
||||||
|
license = "AGPL-3.0-or-later"
|
||||||
|
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "./src/lib.rs"
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syn = "2.0"
|
||||||
|
quote = "1.0"
|
||||||
|
proc-macro2 = "1.0"
|
||||||
|
glob = "0.3"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
anyhow = "1.0.98"
|
||||||
|
axum = "0.8.3"
|
||||||
|
tokio = { version = "1.44.2", features = ["full"] }
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
github = { repository = "vault81/axum-folder-router" }
|
||||||
|
maintenance = { status = "actively-developed" }
|
35
README.md
Normal file
35
README.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
[](https://crates.io/crates/axum-folder-router)
|
||||||
|
[](https://github.com/vault81/axum-folder-router/actions?query=workflow%3A%22main%22)
|
||||||
|

|
||||||
|
|
||||||
|
# axum_folder_router
|
||||||
|
|
||||||
|
## ```axum_folder_router``` Macro Documentation
|
||||||
|
|
||||||
|
```folder_router``` is a procedural macro for the Axum web framework that automatically generates router configurations based on your file structure. It simplifies route organization by using filesystem conventions to define your API routes.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
Add the dependency to your ```Cargo.toml```:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
axum_folder_router = "0.1.0"
|
||||||
|
axum = "0.7"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
The macro scans a directory for ```route.rs``` files and automatically creates an Axum router based on the file structure:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This repository, like all my personal projects, is licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later).
|
||||||
|
This ensures that modifications to the code remain open source when used in network services.
|
||||||
|
Contact me if this doesn't suit your needs.
|
||||||
|
|
||||||
|
### Contribution
|
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later) license, shall be licensed as above, without any additional terms or conditions.
|
16
README.tpl
Normal file
16
README.tpl
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[](https://crates.io/crates/axum-folder-router)
|
||||||
|
{{badges}}
|
||||||
|
|
||||||
|
# {{crate}}
|
||||||
|
|
||||||
|
{{readme}}
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This repository, like all my personal projects, is licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later).
|
||||||
|
This ensures that modifications to the code remain open source when used in network services.
|
||||||
|
Contact me if this doesn't suit your needs.
|
||||||
|
|
||||||
|
### Contribution
|
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later) license, shall be licensed as above, without any additional terms or conditions.
|
10
examples/simple/api/route.rs
Normal file
10
examples/simple/api/route.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use axum::response::{Html, IntoResponse};
|
||||||
|
|
||||||
|
pub async fn get() -> impl IntoResponse {
|
||||||
|
Html("<h1>Hello World!</h1>").into_response()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn post() -> impl IntoResponse {
|
||||||
|
"Posted successfully".into_response()
|
||||||
|
}
|
||||||
|
|
31
examples/simple/main.rs
Normal file
31
examples/simple/main.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use axum_folder_router::folder_router;
|
||||||
|
use tokio;
|
||||||
|
use axum::Router;
|
||||||
|
use anyhow;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct AppState {
|
||||||
|
_foo: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
// Create app state
|
||||||
|
let app_state = AppState {
|
||||||
|
_foo: "".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate the router using the macro
|
||||||
|
let folder_router: Router<AppState>= folder_router!("./examples/simple/api", AppState);
|
||||||
|
|
||||||
|
// Build the router and provide the state
|
||||||
|
let app: Router<()> = folder_router
|
||||||
|
.with_state(app_state);
|
||||||
|
|
||||||
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
||||||
|
println!("Listening on http://{}", listener.local_addr()?);
|
||||||
|
axum::serve(listener, app).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
162
flake.lock
generated
Normal file
162
flake.lock
generated
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"devshell": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1735644329,
|
||||||
|
"narHash": "sha256-tO3HrHriyLvipc4xr+Ewtdlo7wM1OjXNjlWRgmM7peY=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "devshell",
|
||||||
|
"rev": "f7795ede5b02664b57035b3b757876703e2c3eac",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "devshell",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1735774679,
|
||||||
|
"narHash": "sha256-soePLBazJk0qQdDVhdbM98vYdssfs3WFedcq+raipRI=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "f2f7418ce0ab4a5309a4596161d154cfc877af66",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1722073938,
|
||||||
|
"narHash": "sha256-OpX0StkL8vpXyWOGUD6G+MA26wAXK6SpT94kLJXo6B4=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "e36e9f57337d0ff0cf77aceb58af4c805472bfae",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1735774519,
|
||||||
|
"narHash": "sha256-CewEm1o2eVAnoqb6Ml+Qi9Gg/EfNAxbRx1lANGVyoLI=",
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://github.com/NixOS/nixpkgs/archive/e9b51731911566bbf7e4895475a87fe06961de0b.tar.gz"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://github.com/NixOS/nixpkgs/archive/e9b51731911566bbf7e4895475a87fe06961de0b.tar.gz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1741010256,
|
||||||
|
"narHash": "sha256-WZNlK/KX7Sni0RyqLSqLPbK8k08Kq7H7RijPJbq9KHM=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "ba487dbc9d04e0634c64e3b1f0d25839a0a68246",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1736320768,
|
||||||
|
"narHash": "sha256-nIYdTAiKIGnFNugbomgBJR+Xv5F1ZQU+HfaBqJKroC0=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "4bc9c909d9ac828a039f288cf872d16d38185db8",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"devshell": "devshell",
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs_2",
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_3"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1741055476,
|
||||||
|
"narHash": "sha256-52vwEV0oS2lCnx3c/alOFGglujZTLmObit7K8VblnS8=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "aefb7017d710f150970299685e8d8b549d653649",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
107
flake.nix
Normal file
107
flake.nix
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
{
|
||||||
|
description = "A Nix-flake-based Rust development environment";
|
||||||
|
nixConfig = {
|
||||||
|
extra-substituters = [
|
||||||
|
"https://nixcache.vlt81.de"
|
||||||
|
"https://cuda-maintainers.cachix.org"
|
||||||
|
];
|
||||||
|
extra-trusted-public-keys = [
|
||||||
|
"nixcache.vlt81.de:nw0FfUpePtL6P3IMNT9X6oln0Wg9REZINtkkI9SisqQ="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
|
devshell.url = "github:numtide/devshell";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{ self
|
||||||
|
, nixpkgs
|
||||||
|
, rust-overlay
|
||||||
|
, flake-utils
|
||||||
|
, devshell
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem
|
||||||
|
(system:
|
||||||
|
let
|
||||||
|
overlays = [
|
||||||
|
rust-overlay.overlays.default
|
||||||
|
devshell.overlays.default
|
||||||
|
(final: prev: {
|
||||||
|
customRustToolchain = prev.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system overlays;
|
||||||
|
config = {
|
||||||
|
allowUnfree = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
zlib
|
||||||
|
clang
|
||||||
|
libclang
|
||||||
|
gzip
|
||||||
|
coreutils
|
||||||
|
gdb
|
||||||
|
glib
|
||||||
|
glibc
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
packages = with pkgs;
|
||||||
|
[
|
||||||
|
customRustToolchain
|
||||||
|
bacon
|
||||||
|
binaryen
|
||||||
|
cacert
|
||||||
|
cargo-bloat
|
||||||
|
cargo-docset
|
||||||
|
cargo-machete
|
||||||
|
cargo-limit
|
||||||
|
cargo-deny
|
||||||
|
cargo-edit
|
||||||
|
cargo-watch
|
||||||
|
cargo-make
|
||||||
|
cargo-generate
|
||||||
|
cargo-udeps
|
||||||
|
cargo-outdated
|
||||||
|
cargo-release
|
||||||
|
cargo-readme
|
||||||
|
calc
|
||||||
|
fish
|
||||||
|
inotify-tools
|
||||||
|
mold
|
||||||
|
pkg-config
|
||||||
|
sccache
|
||||||
|
unzip
|
||||||
|
]
|
||||||
|
++ buildInputs;
|
||||||
|
|
||||||
|
buildInputs = buildInputs;
|
||||||
|
shellHook = ''
|
||||||
|
# export NIX_LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath buildInputs}:$NIX_LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath buildInputs}"
|
||||||
|
export MALLOC_CONF=thp:always,metadata_thp:always
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
packages = {
|
||||||
|
# default = pkgs.callPackage ./package.nix { };
|
||||||
|
};
|
||||||
|
}) // {
|
||||||
|
hydraJobs =
|
||||||
|
let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
# packages = self.packages."${system}";
|
||||||
|
devShells = self.devShells."${system}";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit devShells;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
16
rust-toolchain.toml
Normal file
16
rust-toolchain.toml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "nightly-2025-03-01"
|
||||||
|
components = [
|
||||||
|
"cargo",
|
||||||
|
"rust-analyzer",
|
||||||
|
"rust-src",
|
||||||
|
"rustc-codegen-cranelift",
|
||||||
|
"rustc-dev",
|
||||||
|
"rustfmt",
|
||||||
|
]
|
||||||
|
profile = "default"
|
||||||
|
targets = [
|
||||||
|
"wasm32-unknown-unknown",
|
||||||
|
"x86_64-pc-windows-msvc",
|
||||||
|
"x86_64-unknown-linux-gnu",
|
||||||
|
]
|
309
src/lib.rs
Normal file
309
src/lib.rs
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
//! # ```axum_folder_router``` Macro Documentation
|
||||||
|
//!
|
||||||
|
//! ```folder_router``` is a procedural macro for the Axum web framework that automatically generates router configurations based on your file structure. It simplifies route organization by using filesystem conventions to define your API routes.
|
||||||
|
//!
|
||||||
|
//! ## Installation
|
||||||
|
//!
|
||||||
|
//! Add the dependency to your ```Cargo.toml```:
|
||||||
|
//!
|
||||||
|
//! ```toml
|
||||||
|
//! [dependencies]
|
||||||
|
//! axum_folder_router = "0.1.0"
|
||||||
|
//! axum = "0.7"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Basic Usage
|
||||||
|
//!
|
||||||
|
//! The macro scans a directory for ```route.rs``` files and automatically creates an Axum router based on the file structure:
|
||||||
|
//!
|
||||||
|
//! ```rust,no_run
|
||||||
|
#![doc = include_str!("../examples/simple/main.rs")]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## File Structure Convention
|
||||||
|
//!
|
||||||
|
//! The macro converts your file structure into routes:
|
||||||
|
//!
|
||||||
|
//! ```text
|
||||||
|
//! src/api/
|
||||||
|
//! ├── route.rs -> "/"
|
||||||
|
//! ├── hello/
|
||||||
|
//! │ └── route.rs -> "/hello"
|
||||||
|
//! ├── users/
|
||||||
|
//! │ ├── route.rs -> "/users"
|
||||||
|
//! │ └── [id]/
|
||||||
|
//! │ └── route.rs -> "/users/{id}"
|
||||||
|
//! └── files/
|
||||||
|
//! └── [...path]/
|
||||||
|
//! └── route.rs -> "/files/*path"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Each ```route.rs``` file can contain HTTP method handlers that are automatically mapped to the corresponding route.
|
||||||
|
//!
|
||||||
|
//! ## Route Handlers
|
||||||
|
//!
|
||||||
|
//! Inside each ```route.rs``` file, define async functions named after HTTP methods:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
#![doc = include_str!("../examples/simple/api/route.rs")]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Supported Features
|
||||||
|
//!
|
||||||
|
//! ### HTTP Methods
|
||||||
|
//!
|
||||||
|
//! The macro supports all standard HTTP methods:
|
||||||
|
//! - ```get```
|
||||||
|
//! - ```post```
|
||||||
|
//! - ```put```
|
||||||
|
//! - ```delete```
|
||||||
|
//! - ```patch```
|
||||||
|
//! - ```head```
|
||||||
|
//! - ```options```
|
||||||
|
//!
|
||||||
|
//! ### Path Parameters
|
||||||
|
//!
|
||||||
|
//! Dynamic path segments are defined using brackets:
|
||||||
|
//!
|
||||||
|
//! ```text
|
||||||
|
//! src/api/users/[id]/route.rs -> "/users/{id}"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Inside the route handler:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use axum::{
|
||||||
|
//! extract::Path,
|
||||||
|
//! response::IntoResponse
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! pub async fn get(Path(id): Path<String>) -> impl IntoResponse {
|
||||||
|
//! format!("User ID: {}", id)
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Catch-all Parameters
|
||||||
|
//!
|
||||||
|
//! Use the spread syntax for catch-all segments:
|
||||||
|
//!
|
||||||
|
//! ```text
|
||||||
|
//! src/api/files/[...path]/route.rs -> "/files/*path"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use axum::{
|
||||||
|
//! extract::Path,
|
||||||
|
//! response::IntoResponse
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! pub async fn get(Path(path): Path<String>) -> impl IntoResponse {
|
||||||
|
//! format!("Requested file path: {}", path)
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### State Extraction
|
||||||
|
//!
|
||||||
|
//! The state type provided to the macro is available in all route handlers:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use axum::{
|
||||||
|
//! extract::State,
|
||||||
|
//! response::IntoResponse
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! # #[derive(Debug, Clone)]
|
||||||
|
//! # struct AppState ();
|
||||||
|
//!
|
||||||
|
//! pub async fn get(State(state): State<AppState>) -> impl IntoResponse {
|
||||||
|
//! format!("State: {:?}", state)
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Limitations
|
||||||
|
//!
|
||||||
|
//! - **Compile-time Only**: The routing is determined at compile time, so dynamic route registration isn't supported.
|
||||||
|
//! - **File I/O**: The macro performs file I/O during compilation, which may have implications in certain build environments.
|
||||||
|
//! - **Single State Type**: All routes share the same state type, though you can use ```FromRef``` for more granular state extraction.
|
||||||
|
//!
|
||||||
|
//! ## Best Practices
|
||||||
|
//!
|
||||||
|
//! 1. **Consistent Structure**: Maintain a consistent file structure to make your API organization predictable.
|
||||||
|
//! 2. **Individual Route Files**: Use one ```route.rs``` file per route path for clarity.
|
||||||
|
//! 3. **Module Organization**: Consider grouping related functionality in directories.
|
||||||
|
//! 4. **Documentation**: Add comments to each route handler explaining its purpose.
|
||||||
|
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
use std::fs;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use syn::{parse::Parse, parse::ParseStream, parse_macro_input, Ident, LitStr, Result, Token};
|
||||||
|
|
||||||
|
struct FolderRouterArgs {
|
||||||
|
path: String,
|
||||||
|
state_type: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for FolderRouterArgs {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let path_lit = input.parse::<LitStr>()?;
|
||||||
|
input.parse::<Token![,]>()?;
|
||||||
|
let state_type = input.parse::<Ident>()?;
|
||||||
|
|
||||||
|
Ok(FolderRouterArgs {
|
||||||
|
path: path_lit.value(),
|
||||||
|
state_type,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an Axum router by scanning a directory for `route.rs` files.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `path` - A string literal pointing to the API directory, relative to the Cargo manifest directory
|
||||||
|
/// * `state_type` - The type name of your application state that will be shared across all routes
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use axum_folder_router::folder_router;
|
||||||
|
/// # #[derive(Debug, Clone)]
|
||||||
|
/// # struct AppState ();
|
||||||
|
/// #
|
||||||
|
/// let router = folder_router!("./src/api", AppState);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This will scan all `route.rs` files in the `./src/api` directory and its subdirectories,
|
||||||
|
/// automatically mapping their path structure to URL routes with the specified state type.
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn folder_router(input: TokenStream) -> TokenStream {
|
||||||
|
let args = parse_macro_input!(input as FolderRouterArgs);
|
||||||
|
let base_path = args.path;
|
||||||
|
let state_type = args.state_type;
|
||||||
|
|
||||||
|
// Get the project root directory
|
||||||
|
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||||
|
let base_dir = Path::new(&manifest_dir).join(&base_path);
|
||||||
|
|
||||||
|
// Collect route files
|
||||||
|
let mut routes = Vec::new();
|
||||||
|
collect_route_files(&base_dir, &base_dir, &mut routes);
|
||||||
|
|
||||||
|
// Generate module definitions and route registrations
|
||||||
|
let mut module_defs = Vec::new();
|
||||||
|
let mut route_registrations = Vec::new();
|
||||||
|
|
||||||
|
for (route_path, rel_path) in routes {
|
||||||
|
// Generate module name and axum path
|
||||||
|
let (axum_path, mod_name) = path_to_route_info(&rel_path);
|
||||||
|
let mod_ident = format_ident!("{}", mod_name);
|
||||||
|
|
||||||
|
// Create module path for include!
|
||||||
|
let rel_file_path = route_path.strip_prefix(&manifest_dir).unwrap();
|
||||||
|
let rel_file_str = rel_file_path.to_string_lossy().to_string();
|
||||||
|
|
||||||
|
// Add module definition
|
||||||
|
module_defs.push(quote! {
|
||||||
|
#[allow(warnings)]
|
||||||
|
mod #mod_ident {
|
||||||
|
include!(concat!(env!("CARGO_MANIFEST_DIR"), "/", #rel_file_str));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Read the file content to find HTTP methods
|
||||||
|
let file_content = fs::read_to_string(&route_path).unwrap_or_default();
|
||||||
|
let methods = ["get", "post", "put", "delete", "patch", "head", "options"];
|
||||||
|
|
||||||
|
let mut method_registrations = Vec::new();
|
||||||
|
for method in &methods {
|
||||||
|
if file_content.contains(&format!("pub async fn {}(", method)) {
|
||||||
|
let method_ident = format_ident!("{}", method);
|
||||||
|
method_registrations.push((method, method_ident));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !method_registrations.is_empty() {
|
||||||
|
let (_first_method, first_method_ident) = &method_registrations[0];
|
||||||
|
|
||||||
|
let mut builder = quote! {
|
||||||
|
axum::routing::#first_method_ident(#mod_ident::#first_method_ident)
|
||||||
|
};
|
||||||
|
|
||||||
|
for (_method, method_ident) in &method_registrations[1..] {
|
||||||
|
builder = quote! {
|
||||||
|
#builder.#method_ident(#mod_ident::#method_ident)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let registration = quote! {
|
||||||
|
router = router.route(#axum_path, #builder);
|
||||||
|
};
|
||||||
|
route_registrations.push(registration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the final code
|
||||||
|
let expanded = quote! {
|
||||||
|
{
|
||||||
|
#(#module_defs)*
|
||||||
|
|
||||||
|
let mut router = axum::Router::<#state_type>::new();
|
||||||
|
#(#route_registrations)*
|
||||||
|
router
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
expanded.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively collect route.rs files
|
||||||
|
fn collect_route_files(base_dir: &Path, current_dir: &Path, routes: &mut Vec<(PathBuf, PathBuf)>) {
|
||||||
|
if let Ok(entries) = fs::read_dir(current_dir) {
|
||||||
|
for entry in entries.filter_map(std::result::Result::ok) {
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
if path.is_dir() {
|
||||||
|
collect_route_files(base_dir, &path, routes);
|
||||||
|
} else if path.file_name().unwrap_or_default() == "route.rs" {
|
||||||
|
if let Some(parent) = path.parent() {
|
||||||
|
if let Ok(rel_dir) = parent.strip_prefix(base_dir) {
|
||||||
|
routes.push((path.clone(), rel_dir.to_path_buf()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a relative path to (axum_path, mod_name)
|
||||||
|
fn path_to_route_info(rel_path: &Path) -> (String, String) {
|
||||||
|
if rel_path.components().count() == 0 {
|
||||||
|
return ("/".to_string(), "root".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut axum_path = String::new();
|
||||||
|
let mut mod_name = String::new();
|
||||||
|
|
||||||
|
for segment in rel_path.iter() {
|
||||||
|
let s = segment.to_str().unwrap_or_default();
|
||||||
|
if s.starts_with('[') && s.ends_with(']') {
|
||||||
|
let inner = &s[1..s.len() - 1];
|
||||||
|
if inner.starts_with("...") {
|
||||||
|
let param = &inner[3..];
|
||||||
|
axum_path.push_str(&format!("/*{}", param));
|
||||||
|
mod_name.push_str(&format!("__{}", param));
|
||||||
|
} else {
|
||||||
|
axum_path.push_str(&format!("/{{{}}}", inner));
|
||||||
|
mod_name.push_str(&format!("__{}", inner));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
axum_path.push('/');
|
||||||
|
axum_path.push_str(s);
|
||||||
|
mod_name.push_str("__");
|
||||||
|
mod_name.push_str(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(axum_path, mod_name.trim_start_matches('_').to_string())
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue