├── .dockerignore ├── .editorconfig ├── .github ├── rust.json └── workflows │ ├── ci.yml │ └── docker.yml ├── .gitignore ├── .rustfmt.toml ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE.md ├── README.md └── src └── main.rs /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !src/ 3 | !Cargo.lock 4 | !Cargo.toml 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.rs] 11 | indent_size = 4 12 | 13 | [*.md] 14 | indent_size = 4 15 | -------------------------------------------------------------------------------- /.github/rust.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "owner": "cargo-common", 5 | "pattern": [ 6 | { 7 | "regexp": "^(warning|warn|error)(\\[(\\S*)\\])?: (.*)$", 8 | "severity": 1, 9 | "message": 4, 10 | "code": 3 11 | }, 12 | { 13 | "regexp": "^\\s+-->\\s(\\S+):(\\d+):(\\d+)$", 14 | "file": 1, 15 | "line": 2, 16 | "column": 3 17 | } 18 | ] 19 | }, 20 | { 21 | "owner": "cargo-test", 22 | "pattern": [ 23 | { 24 | "regexp": "^.*panicked\\s+at\\s+'(.*)',\\s+(.*):(\\d+):(\\d+)$", 25 | "message": 1, 26 | "file": 2, 27 | "line": 3, 28 | "column": 4 29 | } 30 | ] 31 | }, 32 | { 33 | "owner": "cargo-fmt", 34 | "pattern": [ 35 | { 36 | "regexp": "^(Diff in (\\S+)) at line (\\d+):", 37 | "message": 1, 38 | "file": 2, 39 | "line": 3 40 | } 41 | ] 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | branches: 8 | - trunk 9 | 10 | jobs: 11 | check: 12 | name: check 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout sources 17 | uses: actions/checkout@v3 18 | 19 | - name: Install stable toolchain 20 | id: toolchain 21 | uses: dtolnay/rust-toolchain@master 22 | with: 23 | toolchain: stable 24 | 25 | - name: Setup cache 26 | uses: Swatinem/rust-cache@v2 27 | 28 | - run: cargo check 29 | 30 | clippy: 31 | name: clippy 32 | runs-on: ubuntu-latest 33 | 34 | steps: 35 | - name: Checkout sources 36 | uses: actions/checkout@v3 37 | 38 | - name: Install stable toolchain 39 | id: toolchain 40 | uses: dtolnay/rust-toolchain@master 41 | with: 42 | toolchain: stable 43 | components: clippy 44 | 45 | - name: Setup cache 46 | uses: Swatinem/rust-cache@v2 47 | 48 | - name: Add problem matchers 49 | run: echo "::add-matcher::.github/rust.json" 50 | 51 | - name: Run clippy 52 | run: cargo clippy --message-format=json 53 | 54 | rustfmt: 55 | name: rustfmt 56 | runs-on: ubuntu-latest 57 | 58 | steps: 59 | - name: Checkout sources 60 | uses: actions/checkout@v3 61 | 62 | - name: Install stable toolchain 63 | id: toolchain 64 | uses: dtolnay/rust-toolchain@master 65 | with: 66 | toolchain: stable 67 | components: rustfmt 68 | 69 | - name: Run cargo fmt 70 | run: cargo fmt --all -- --check 71 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker build 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | branches: 8 | - trunk 9 | 10 | jobs: 11 | build-images: 12 | name: Build Docker Images 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | include: 17 | - tag: amd64 18 | arch: amd64 19 | rust-target: x86_64-unknown-linux-musl 20 | musl-target: x86_64-linux-musl 21 | - tag: armv8 22 | arch: armv8 23 | rust-target: aarch64-unknown-linux-musl 24 | musl-target: aarch64-linux-musl 25 | 26 | steps: 27 | # Podman 4.x is necessary here because it supports --platform=$BUILDPLATFORM. Otherwise, podman 28 | # would pull the base image for aarch64 when building for aarch64. See https://github.com/containers/buildah/pull/3757 29 | # for the implementation. GitHub actions currently still ship Podman 3.x, even though 4.x has been 30 | # out for over a year. 31 | # The repository used is the same as GitHub actions uses for their source - just that it's the unstable version 32 | # rather than the stable one. 33 | # TODO: Once podman 4.x is available in actions by default (or in the Ubuntu repositories), remove this. 34 | - name: Install podman 4.x 35 | run: | 36 | sudo mkdir -p /etc/apt/keyrings 37 | curl -fsSL https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/Release.key \ 38 | | gpg --dearmor \ 39 | | sudo tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null 40 | echo \ 41 | "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg]\ 42 | https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/ /" \ 43 | | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null 44 | sudo apt -qq -y purge buildah podman 45 | sudo apt -qq -y autoremove --purge 46 | sudo apt update -qq 47 | sudo apt -qq -y install podman 48 | 49 | - name: Checkout sources 50 | uses: actions/checkout@v3 51 | 52 | - name: Login to ghcr 53 | if: github.ref == 'refs/heads/trunk' && github.event_name != 'pull_request' 54 | run: | 55 | echo "${{ secrets.GITHUB_TOKEN }}" | podman login -u ${{ github.repository_owner }} --password-stdin ghcr.io 56 | 57 | - name: Convert GITHUB_REPOSITORY into lowercase 58 | run: | 59 | echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} 60 | 61 | - name: Build ${{ matrix.tag }} 62 | run: | 63 | podman build \ 64 | --format docker \ 65 | --arch ${{ matrix.arch }} \ 66 | --build-arg RUST_TARGET=${{ matrix.rust-target }} \ 67 | --build-arg MUSL_TARGET=${{ matrix.musl-target }} \ 68 | -t gateway-queue:${{ matrix.tag }} \ 69 | . 70 | 71 | - name: Push image to ghcr 72 | if: github.ref == 'refs/heads/trunk' && github.event_name != 'pull_request' 73 | run: | 74 | podman tag gateway-queue:${{ matrix.tag }} ghcr.io/${REPO}:${{ matrix.tag }} 75 | podman push ghcr.io/${REPO}:${{ matrix.tag }} 76 | 77 | create-manifest: 78 | name: Create Docker manifests 79 | runs-on: ubuntu-latest 80 | needs: build-images 81 | if: github.ref == 'refs/heads/trunk' && github.event_name != 'pull_request' 82 | 83 | steps: 84 | - name: Login to ghcr 85 | run: | 86 | echo "${{ secrets.GITHUB_TOKEN }}" | podman login -u ${{ github.repository_owner }} --password-stdin ghcr.io 87 | 88 | - name: Convert GITHUB_REPOSITORY into lowercase 89 | run: | 90 | echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} 91 | 92 | - name: Create manifest and push it 93 | run: | 94 | podman manifest create gateway-queue-latest docker://ghcr.io/${REPO}:amd64 docker://ghcr.io/${REPO}:armv8 95 | podman manifest push --format v2s2 gateway-queue-latest docker://ghcr.io/${REPO}:latest 96 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.rs.bk 2 | target/ 3 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | use_field_init_shorthand = true 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.1.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "atomic-waker" 31 | version = "1.1.2" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 34 | 35 | [[package]] 36 | name = "autocfg" 37 | version = "1.4.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 40 | 41 | [[package]] 42 | name = "aws-lc-rs" 43 | version = "1.12.6" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "dabb68eb3a7aa08b46fddfd59a3d55c978243557a90ab804769f7e20e67d2b01" 46 | dependencies = [ 47 | "aws-lc-sys", 48 | "zeroize", 49 | ] 50 | 51 | [[package]] 52 | name = "aws-lc-sys" 53 | version = "0.27.1" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "77926887776171ced7d662120a75998e444d3750c951abfe07f90da130514b1f" 56 | dependencies = [ 57 | "bindgen", 58 | "cc", 59 | "cmake", 60 | "dunce", 61 | "fs_extra", 62 | ] 63 | 64 | [[package]] 65 | name = "backtrace" 66 | version = "0.3.74" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 69 | dependencies = [ 70 | "addr2line", 71 | "cfg-if", 72 | "libc", 73 | "miniz_oxide", 74 | "object", 75 | "rustc-demangle", 76 | "windows-targets", 77 | ] 78 | 79 | [[package]] 80 | name = "bindgen" 81 | version = "0.69.5" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" 84 | dependencies = [ 85 | "bitflags", 86 | "cexpr", 87 | "clang-sys", 88 | "itertools", 89 | "lazy_static", 90 | "lazycell", 91 | "log", 92 | "prettyplease", 93 | "proc-macro2", 94 | "quote", 95 | "regex", 96 | "rustc-hash", 97 | "shlex", 98 | "syn", 99 | "which", 100 | ] 101 | 102 | [[package]] 103 | name = "bitflags" 104 | version = "2.9.0" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 107 | 108 | [[package]] 109 | name = "bytes" 110 | version = "1.10.1" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 113 | 114 | [[package]] 115 | name = "cc" 116 | version = "1.2.17" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" 119 | dependencies = [ 120 | "jobserver", 121 | "libc", 122 | "shlex", 123 | ] 124 | 125 | [[package]] 126 | name = "cexpr" 127 | version = "0.6.0" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 130 | dependencies = [ 131 | "nom", 132 | ] 133 | 134 | [[package]] 135 | name = "cfg-if" 136 | version = "1.0.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 139 | 140 | [[package]] 141 | name = "clang-sys" 142 | version = "1.8.1" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" 145 | dependencies = [ 146 | "glob", 147 | "libc", 148 | "libloading", 149 | ] 150 | 151 | [[package]] 152 | name = "cmake" 153 | version = "0.1.54" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" 156 | dependencies = [ 157 | "cc", 158 | ] 159 | 160 | [[package]] 161 | name = "deranged" 162 | version = "0.4.1" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" 165 | dependencies = [ 166 | "powerfmt", 167 | ] 168 | 169 | [[package]] 170 | name = "dunce" 171 | version = "1.0.5" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" 174 | 175 | [[package]] 176 | name = "either" 177 | version = "1.15.0" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 180 | 181 | [[package]] 182 | name = "equivalent" 183 | version = "1.0.2" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 186 | 187 | [[package]] 188 | name = "errno" 189 | version = "0.3.10" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 192 | dependencies = [ 193 | "libc", 194 | "windows-sys 0.59.0", 195 | ] 196 | 197 | [[package]] 198 | name = "fastrand" 199 | version = "2.3.0" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 202 | 203 | [[package]] 204 | name = "fnv" 205 | version = "1.0.7" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 208 | 209 | [[package]] 210 | name = "form_urlencoded" 211 | version = "1.2.1" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 214 | dependencies = [ 215 | "percent-encoding", 216 | ] 217 | 218 | [[package]] 219 | name = "fs_extra" 220 | version = "1.3.0" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" 223 | 224 | [[package]] 225 | name = "futures-channel" 226 | version = "0.3.31" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 229 | dependencies = [ 230 | "futures-core", 231 | ] 232 | 233 | [[package]] 234 | name = "futures-core" 235 | version = "0.3.31" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 238 | 239 | [[package]] 240 | name = "futures-sink" 241 | version = "0.3.31" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 244 | 245 | [[package]] 246 | name = "futures-task" 247 | version = "0.3.31" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 250 | 251 | [[package]] 252 | name = "futures-util" 253 | version = "0.3.31" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 256 | dependencies = [ 257 | "futures-core", 258 | "futures-task", 259 | "pin-project-lite", 260 | "pin-utils", 261 | ] 262 | 263 | [[package]] 264 | name = "getrandom" 265 | version = "0.2.15" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 268 | dependencies = [ 269 | "cfg-if", 270 | "libc", 271 | "wasi", 272 | ] 273 | 274 | [[package]] 275 | name = "gimli" 276 | version = "0.31.1" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 279 | 280 | [[package]] 281 | name = "glob" 282 | version = "0.3.2" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" 285 | 286 | [[package]] 287 | name = "h2" 288 | version = "0.4.8" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" 291 | dependencies = [ 292 | "atomic-waker", 293 | "bytes", 294 | "fnv", 295 | "futures-core", 296 | "futures-sink", 297 | "http", 298 | "indexmap", 299 | "slab", 300 | "tokio", 301 | "tokio-util", 302 | "tracing", 303 | ] 304 | 305 | [[package]] 306 | name = "hashbrown" 307 | version = "0.15.2" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 310 | 311 | [[package]] 312 | name = "home" 313 | version = "0.5.11" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" 316 | dependencies = [ 317 | "windows-sys 0.59.0", 318 | ] 319 | 320 | [[package]] 321 | name = "http" 322 | version = "1.3.1" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 325 | dependencies = [ 326 | "bytes", 327 | "fnv", 328 | "itoa", 329 | ] 330 | 331 | [[package]] 332 | name = "http-body" 333 | version = "1.0.1" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 336 | dependencies = [ 337 | "bytes", 338 | "http", 339 | ] 340 | 341 | [[package]] 342 | name = "http-body-util" 343 | version = "0.1.3" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 346 | dependencies = [ 347 | "bytes", 348 | "futures-core", 349 | "http", 350 | "http-body", 351 | "pin-project-lite", 352 | ] 353 | 354 | [[package]] 355 | name = "httparse" 356 | version = "1.10.1" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 359 | 360 | [[package]] 361 | name = "httpdate" 362 | version = "1.0.3" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 365 | 366 | [[package]] 367 | name = "hyper" 368 | version = "1.6.0" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" 371 | dependencies = [ 372 | "bytes", 373 | "futures-channel", 374 | "futures-util", 375 | "h2", 376 | "http", 377 | "http-body", 378 | "httparse", 379 | "httpdate", 380 | "itoa", 381 | "pin-project-lite", 382 | "smallvec", 383 | "tokio", 384 | "want", 385 | ] 386 | 387 | [[package]] 388 | name = "hyper-rustls" 389 | version = "0.27.5" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" 392 | dependencies = [ 393 | "futures-util", 394 | "http", 395 | "hyper", 396 | "hyper-util", 397 | "rustls", 398 | "rustls-pki-types", 399 | "tokio", 400 | "tokio-rustls", 401 | "tower-service", 402 | "webpki-roots", 403 | ] 404 | 405 | [[package]] 406 | name = "hyper-util" 407 | version = "0.1.11" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" 410 | dependencies = [ 411 | "bytes", 412 | "futures-channel", 413 | "futures-util", 414 | "http", 415 | "http-body", 416 | "hyper", 417 | "libc", 418 | "pin-project-lite", 419 | "socket2", 420 | "tokio", 421 | "tower-service", 422 | "tracing", 423 | ] 424 | 425 | [[package]] 426 | name = "indexmap" 427 | version = "2.8.0" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" 430 | dependencies = [ 431 | "equivalent", 432 | "hashbrown", 433 | ] 434 | 435 | [[package]] 436 | name = "itertools" 437 | version = "0.12.1" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 440 | dependencies = [ 441 | "either", 442 | ] 443 | 444 | [[package]] 445 | name = "itoa" 446 | version = "1.0.15" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 449 | 450 | [[package]] 451 | name = "jobserver" 452 | version = "0.1.32" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" 455 | dependencies = [ 456 | "libc", 457 | ] 458 | 459 | [[package]] 460 | name = "lazy_static" 461 | version = "1.5.0" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 464 | 465 | [[package]] 466 | name = "lazycell" 467 | version = "1.3.0" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 470 | 471 | [[package]] 472 | name = "libc" 473 | version = "0.2.171" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" 476 | 477 | [[package]] 478 | name = "libloading" 479 | version = "0.8.6" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" 482 | dependencies = [ 483 | "cfg-if", 484 | "windows-targets", 485 | ] 486 | 487 | [[package]] 488 | name = "linux-raw-sys" 489 | version = "0.4.15" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 492 | 493 | [[package]] 494 | name = "log" 495 | version = "0.4.27" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 498 | 499 | [[package]] 500 | name = "matchers" 501 | version = "0.1.0" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 504 | dependencies = [ 505 | "regex-automata 0.1.10", 506 | ] 507 | 508 | [[package]] 509 | name = "memchr" 510 | version = "2.7.4" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 513 | 514 | [[package]] 515 | name = "minimal-lexical" 516 | version = "0.2.1" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 519 | 520 | [[package]] 521 | name = "miniz_oxide" 522 | version = "0.8.5" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" 525 | dependencies = [ 526 | "adler2", 527 | ] 528 | 529 | [[package]] 530 | name = "mio" 531 | version = "1.0.3" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 534 | dependencies = [ 535 | "libc", 536 | "wasi", 537 | "windows-sys 0.52.0", 538 | ] 539 | 540 | [[package]] 541 | name = "nom" 542 | version = "7.1.3" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 545 | dependencies = [ 546 | "memchr", 547 | "minimal-lexical", 548 | ] 549 | 550 | [[package]] 551 | name = "nu-ansi-term" 552 | version = "0.46.0" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 555 | dependencies = [ 556 | "overload", 557 | "winapi", 558 | ] 559 | 560 | [[package]] 561 | name = "num-conv" 562 | version = "0.1.0" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 565 | 566 | [[package]] 567 | name = "num-traits" 568 | version = "0.2.19" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 571 | dependencies = [ 572 | "autocfg", 573 | ] 574 | 575 | [[package]] 576 | name = "object" 577 | version = "0.36.7" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 580 | dependencies = [ 581 | "memchr", 582 | ] 583 | 584 | [[package]] 585 | name = "once_cell" 586 | version = "1.21.3" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 589 | 590 | [[package]] 591 | name = "ordered-float" 592 | version = "2.10.1" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" 595 | dependencies = [ 596 | "num-traits", 597 | ] 598 | 599 | [[package]] 600 | name = "overload" 601 | version = "0.1.1" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 604 | 605 | [[package]] 606 | name = "percent-encoding" 607 | version = "2.3.1" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 610 | 611 | [[package]] 612 | name = "pin-project-lite" 613 | version = "0.2.16" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 616 | 617 | [[package]] 618 | name = "pin-utils" 619 | version = "0.1.0" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 622 | 623 | [[package]] 624 | name = "powerfmt" 625 | version = "0.2.0" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 628 | 629 | [[package]] 630 | name = "prettyplease" 631 | version = "0.2.31" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" 634 | dependencies = [ 635 | "proc-macro2", 636 | "syn", 637 | ] 638 | 639 | [[package]] 640 | name = "proc-macro2" 641 | version = "1.0.94" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 644 | dependencies = [ 645 | "unicode-ident", 646 | ] 647 | 648 | [[package]] 649 | name = "quote" 650 | version = "1.0.40" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 653 | dependencies = [ 654 | "proc-macro2", 655 | ] 656 | 657 | [[package]] 658 | name = "regex" 659 | version = "1.11.1" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 662 | dependencies = [ 663 | "aho-corasick", 664 | "memchr", 665 | "regex-automata 0.4.9", 666 | "regex-syntax 0.8.5", 667 | ] 668 | 669 | [[package]] 670 | name = "regex-automata" 671 | version = "0.1.10" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 674 | dependencies = [ 675 | "regex-syntax 0.6.29", 676 | ] 677 | 678 | [[package]] 679 | name = "regex-automata" 680 | version = "0.4.9" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 683 | dependencies = [ 684 | "aho-corasick", 685 | "memchr", 686 | "regex-syntax 0.8.5", 687 | ] 688 | 689 | [[package]] 690 | name = "regex-syntax" 691 | version = "0.6.29" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 694 | 695 | [[package]] 696 | name = "regex-syntax" 697 | version = "0.8.5" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 700 | 701 | [[package]] 702 | name = "ring" 703 | version = "0.17.14" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 706 | dependencies = [ 707 | "cc", 708 | "cfg-if", 709 | "getrandom", 710 | "libc", 711 | "untrusted", 712 | "windows-sys 0.52.0", 713 | ] 714 | 715 | [[package]] 716 | name = "rustc-demangle" 717 | version = "0.1.24" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 720 | 721 | [[package]] 722 | name = "rustc-hash" 723 | version = "1.1.0" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 726 | 727 | [[package]] 728 | name = "rustix" 729 | version = "0.38.44" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 732 | dependencies = [ 733 | "bitflags", 734 | "errno", 735 | "libc", 736 | "linux-raw-sys", 737 | "windows-sys 0.59.0", 738 | ] 739 | 740 | [[package]] 741 | name = "rustls" 742 | version = "0.23.25" 743 | source = "registry+https://github.com/rust-lang/crates.io-index" 744 | checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" 745 | dependencies = [ 746 | "aws-lc-rs", 747 | "once_cell", 748 | "rustls-pki-types", 749 | "rustls-webpki", 750 | "subtle", 751 | "zeroize", 752 | ] 753 | 754 | [[package]] 755 | name = "rustls-pki-types" 756 | version = "1.11.0" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" 759 | 760 | [[package]] 761 | name = "rustls-webpki" 762 | version = "0.103.1" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" 765 | dependencies = [ 766 | "aws-lc-rs", 767 | "ring", 768 | "rustls-pki-types", 769 | "untrusted", 770 | ] 771 | 772 | [[package]] 773 | name = "ryu" 774 | version = "1.0.20" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 777 | 778 | [[package]] 779 | name = "serde" 780 | version = "1.0.219" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 783 | dependencies = [ 784 | "serde_derive", 785 | ] 786 | 787 | [[package]] 788 | name = "serde-value" 789 | version = "0.7.0" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" 792 | dependencies = [ 793 | "ordered-float", 794 | "serde", 795 | ] 796 | 797 | [[package]] 798 | name = "serde_derive" 799 | version = "1.0.219" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 802 | dependencies = [ 803 | "proc-macro2", 804 | "quote", 805 | "syn", 806 | ] 807 | 808 | [[package]] 809 | name = "serde_json" 810 | version = "1.0.140" 811 | source = "registry+https://github.com/rust-lang/crates.io-index" 812 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 813 | dependencies = [ 814 | "itoa", 815 | "memchr", 816 | "ryu", 817 | "serde", 818 | ] 819 | 820 | [[package]] 821 | name = "serde_repr" 822 | version = "0.1.20" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" 825 | dependencies = [ 826 | "proc-macro2", 827 | "quote", 828 | "syn", 829 | ] 830 | 831 | [[package]] 832 | name = "serde_urlencoded" 833 | version = "0.7.1" 834 | source = "registry+https://github.com/rust-lang/crates.io-index" 835 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 836 | dependencies = [ 837 | "form_urlencoded", 838 | "itoa", 839 | "ryu", 840 | "serde", 841 | ] 842 | 843 | [[package]] 844 | name = "sharded-slab" 845 | version = "0.1.7" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 848 | dependencies = [ 849 | "lazy_static", 850 | ] 851 | 852 | [[package]] 853 | name = "shlex" 854 | version = "1.3.0" 855 | source = "registry+https://github.com/rust-lang/crates.io-index" 856 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 857 | 858 | [[package]] 859 | name = "signal-hook-registry" 860 | version = "1.4.2" 861 | source = "registry+https://github.com/rust-lang/crates.io-index" 862 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 863 | dependencies = [ 864 | "libc", 865 | ] 866 | 867 | [[package]] 868 | name = "slab" 869 | version = "0.4.9" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 872 | dependencies = [ 873 | "autocfg", 874 | ] 875 | 876 | [[package]] 877 | name = "smallvec" 878 | version = "1.14.0" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" 881 | 882 | [[package]] 883 | name = "socket2" 884 | version = "0.5.9" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" 887 | dependencies = [ 888 | "libc", 889 | "windows-sys 0.52.0", 890 | ] 891 | 892 | [[package]] 893 | name = "subtle" 894 | version = "2.6.1" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 897 | 898 | [[package]] 899 | name = "syn" 900 | version = "2.0.100" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 903 | dependencies = [ 904 | "proc-macro2", 905 | "quote", 906 | "unicode-ident", 907 | ] 908 | 909 | [[package]] 910 | name = "thread_local" 911 | version = "1.1.8" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 914 | dependencies = [ 915 | "cfg-if", 916 | "once_cell", 917 | ] 918 | 919 | [[package]] 920 | name = "time" 921 | version = "0.3.41" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" 924 | dependencies = [ 925 | "deranged", 926 | "num-conv", 927 | "powerfmt", 928 | "serde", 929 | "time-core", 930 | "time-macros", 931 | ] 932 | 933 | [[package]] 934 | name = "time-core" 935 | version = "0.1.4" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" 938 | 939 | [[package]] 940 | name = "time-macros" 941 | version = "0.2.22" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" 944 | dependencies = [ 945 | "num-conv", 946 | "time-core", 947 | ] 948 | 949 | [[package]] 950 | name = "tokio" 951 | version = "1.44.2" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" 954 | dependencies = [ 955 | "backtrace", 956 | "bytes", 957 | "libc", 958 | "mio", 959 | "pin-project-lite", 960 | "signal-hook-registry", 961 | "socket2", 962 | "tokio-macros", 963 | "windows-sys 0.52.0", 964 | ] 965 | 966 | [[package]] 967 | name = "tokio-macros" 968 | version = "2.5.0" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 971 | dependencies = [ 972 | "proc-macro2", 973 | "quote", 974 | "syn", 975 | ] 976 | 977 | [[package]] 978 | name = "tokio-rustls" 979 | version = "0.26.2" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" 982 | dependencies = [ 983 | "rustls", 984 | "tokio", 985 | ] 986 | 987 | [[package]] 988 | name = "tokio-util" 989 | version = "0.7.14" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" 992 | dependencies = [ 993 | "bytes", 994 | "futures-core", 995 | "futures-sink", 996 | "pin-project-lite", 997 | "tokio", 998 | ] 999 | 1000 | [[package]] 1001 | name = "tower-service" 1002 | version = "0.3.3" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1005 | 1006 | [[package]] 1007 | name = "tracing" 1008 | version = "0.1.41" 1009 | source = "registry+https://github.com/rust-lang/crates.io-index" 1010 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1011 | dependencies = [ 1012 | "pin-project-lite", 1013 | "tracing-attributes", 1014 | "tracing-core", 1015 | ] 1016 | 1017 | [[package]] 1018 | name = "tracing-attributes" 1019 | version = "0.1.28" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 1022 | dependencies = [ 1023 | "proc-macro2", 1024 | "quote", 1025 | "syn", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "tracing-core" 1030 | version = "0.1.33" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1033 | dependencies = [ 1034 | "once_cell", 1035 | ] 1036 | 1037 | [[package]] 1038 | name = "tracing-subscriber" 1039 | version = "0.3.19" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 1042 | dependencies = [ 1043 | "matchers", 1044 | "nu-ansi-term", 1045 | "once_cell", 1046 | "regex", 1047 | "sharded-slab", 1048 | "thread_local", 1049 | "tracing", 1050 | "tracing-core", 1051 | ] 1052 | 1053 | [[package]] 1054 | name = "try-lock" 1055 | version = "0.2.5" 1056 | source = "registry+https://github.com/rust-lang/crates.io-index" 1057 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1058 | 1059 | [[package]] 1060 | name = "twilight-gateway-queue" 1061 | version = "0.1.0" 1062 | dependencies = [ 1063 | "http-body-util", 1064 | "hyper", 1065 | "hyper-util", 1066 | "serde", 1067 | "serde_urlencoded", 1068 | "tokio", 1069 | "tracing", 1070 | "tracing-subscriber", 1071 | "twilight-gateway-queue 0.16.0", 1072 | "twilight-http", 1073 | ] 1074 | 1075 | [[package]] 1076 | name = "twilight-gateway-queue" 1077 | version = "0.16.0" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "27c962bd4693da0a215abe6b431fd73eb87111f49c431b87951780f9f7985002" 1080 | dependencies = [ 1081 | "tokio", 1082 | "tracing", 1083 | ] 1084 | 1085 | [[package]] 1086 | name = "twilight-http" 1087 | version = "0.16.0" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "af9a2176638fd8bfeb867e7a2f644fee0db905eba6f7decfdcd75c8171109b74" 1090 | dependencies = [ 1091 | "fastrand", 1092 | "http", 1093 | "http-body-util", 1094 | "hyper", 1095 | "hyper-rustls", 1096 | "hyper-util", 1097 | "percent-encoding", 1098 | "rustls", 1099 | "serde", 1100 | "serde_json", 1101 | "tokio", 1102 | "tracing", 1103 | "twilight-http-ratelimiting", 1104 | "twilight-model", 1105 | "twilight-validate", 1106 | ] 1107 | 1108 | [[package]] 1109 | name = "twilight-http-ratelimiting" 1110 | version = "0.16.0" 1111 | source = "registry+https://github.com/rust-lang/crates.io-index" 1112 | checksum = "a36945d949920d6bb6aef30547e06ea645eefaa5575a14f56da608bf09d07ec8" 1113 | dependencies = [ 1114 | "tokio", 1115 | "tracing", 1116 | ] 1117 | 1118 | [[package]] 1119 | name = "twilight-model" 1120 | version = "0.16.0" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "191e2efa051dfbd9bed4c9f6bd3f5e007bda909c687a1db2760371a3d566617d" 1123 | dependencies = [ 1124 | "bitflags", 1125 | "serde", 1126 | "serde-value", 1127 | "serde_repr", 1128 | "time", 1129 | ] 1130 | 1131 | [[package]] 1132 | name = "twilight-validate" 1133 | version = "0.16.0" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "49f8d106028ede53708526364b03318bbf846babe146e3ff9e39821a0ca25ff4" 1136 | dependencies = [ 1137 | "twilight-model", 1138 | ] 1139 | 1140 | [[package]] 1141 | name = "unicode-ident" 1142 | version = "1.0.18" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 1145 | 1146 | [[package]] 1147 | name = "untrusted" 1148 | version = "0.9.0" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1151 | 1152 | [[package]] 1153 | name = "want" 1154 | version = "0.3.1" 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" 1156 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1157 | dependencies = [ 1158 | "try-lock", 1159 | ] 1160 | 1161 | [[package]] 1162 | name = "wasi" 1163 | version = "0.11.0+wasi-snapshot-preview1" 1164 | source = "registry+https://github.com/rust-lang/crates.io-index" 1165 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1166 | 1167 | [[package]] 1168 | name = "webpki-roots" 1169 | version = "0.26.8" 1170 | source = "registry+https://github.com/rust-lang/crates.io-index" 1171 | checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" 1172 | dependencies = [ 1173 | "rustls-pki-types", 1174 | ] 1175 | 1176 | [[package]] 1177 | name = "which" 1178 | version = "4.4.2" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 1181 | dependencies = [ 1182 | "either", 1183 | "home", 1184 | "once_cell", 1185 | "rustix", 1186 | ] 1187 | 1188 | [[package]] 1189 | name = "winapi" 1190 | version = "0.3.9" 1191 | source = "registry+https://github.com/rust-lang/crates.io-index" 1192 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1193 | dependencies = [ 1194 | "winapi-i686-pc-windows-gnu", 1195 | "winapi-x86_64-pc-windows-gnu", 1196 | ] 1197 | 1198 | [[package]] 1199 | name = "winapi-i686-pc-windows-gnu" 1200 | version = "0.4.0" 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" 1202 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1203 | 1204 | [[package]] 1205 | name = "winapi-x86_64-pc-windows-gnu" 1206 | version = "0.4.0" 1207 | source = "registry+https://github.com/rust-lang/crates.io-index" 1208 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1209 | 1210 | [[package]] 1211 | name = "windows-sys" 1212 | version = "0.52.0" 1213 | source = "registry+https://github.com/rust-lang/crates.io-index" 1214 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1215 | dependencies = [ 1216 | "windows-targets", 1217 | ] 1218 | 1219 | [[package]] 1220 | name = "windows-sys" 1221 | version = "0.59.0" 1222 | source = "registry+https://github.com/rust-lang/crates.io-index" 1223 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1224 | dependencies = [ 1225 | "windows-targets", 1226 | ] 1227 | 1228 | [[package]] 1229 | name = "windows-targets" 1230 | version = "0.52.6" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1233 | dependencies = [ 1234 | "windows_aarch64_gnullvm", 1235 | "windows_aarch64_msvc", 1236 | "windows_i686_gnu", 1237 | "windows_i686_gnullvm", 1238 | "windows_i686_msvc", 1239 | "windows_x86_64_gnu", 1240 | "windows_x86_64_gnullvm", 1241 | "windows_x86_64_msvc", 1242 | ] 1243 | 1244 | [[package]] 1245 | name = "windows_aarch64_gnullvm" 1246 | version = "0.52.6" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1249 | 1250 | [[package]] 1251 | name = "windows_aarch64_msvc" 1252 | version = "0.52.6" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1255 | 1256 | [[package]] 1257 | name = "windows_i686_gnu" 1258 | version = "0.52.6" 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" 1260 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1261 | 1262 | [[package]] 1263 | name = "windows_i686_gnullvm" 1264 | version = "0.52.6" 1265 | source = "registry+https://github.com/rust-lang/crates.io-index" 1266 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1267 | 1268 | [[package]] 1269 | name = "windows_i686_msvc" 1270 | version = "0.52.6" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1273 | 1274 | [[package]] 1275 | name = "windows_x86_64_gnu" 1276 | version = "0.52.6" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1279 | 1280 | [[package]] 1281 | name = "windows_x86_64_gnullvm" 1282 | version = "0.52.6" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1285 | 1286 | [[package]] 1287 | name = "windows_x86_64_msvc" 1288 | version = "0.52.6" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1291 | 1292 | [[package]] 1293 | name = "zeroize" 1294 | version = "1.8.1" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 1297 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Twilight Contributors"] 3 | documentation = "https://twilight-rs.github.io/chapter_3_services/section_5_gateway_queue.html" 4 | edition = "2018" 5 | homepage = "https://github.com/twilight-rs/gateway-queue" 6 | include = ["src/*.rs", "Cargo.toml"] 7 | keywords = ["discord", "discord-api", "twilight"] 8 | license = "ISC" 9 | name = "twilight-gateway-queue" 10 | publish = false 11 | readme = "README.md" 12 | repository = "https://github.com/twilight-rs/gateway-queue.git" 13 | version = "0.1.0" 14 | 15 | [dependencies] 16 | twilight-gateway-queue = { version = "0.16", default-features = false } 17 | twilight-http = { version = "0.16", default-features = false, features = ["rustls-aws_lc_rs", "rustls-webpki-roots"] } 18 | http-body-util = "0.1" 19 | hyper = { version = "1", default-features = false, features = ["http1"] } 20 | hyper-util = { version = "0.1", default-features = false, features = ["http1", "server", "server-graceful", "tokio"] } 21 | serde = { version = "1", default-features = false, features = ["derive"] } 22 | serde_urlencoded = { version = "0.7", default-features = false } 23 | tracing = { version = "0.1", default-features = false, features = ["std"] } 24 | tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "ansi", "fmt"] } 25 | tokio = { version = "1", default-features = false, features = ["rt", "macros", "signal"] } 26 | 27 | [profile.release] 28 | codegen-units = 1 29 | lto = true 30 | panic = 'abort' 31 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Rust syntax target, either x86_64-unknown-linux-musl, aarch64-unknown-linux-musl, arm-unknown-linux-musleabi etc. 2 | ARG RUST_TARGET="x86_64-unknown-linux-musl" 3 | # Musl target, either x86_64-linux-musl, aarch64-linux-musl, arm-linux-musleabi, etc. 4 | ARG MUSL_TARGET="x86_64-linux-musl" 5 | 6 | FROM --platform=$BUILDPLATFORM docker.io/alpine:latest as build 7 | ARG RUST_TARGET 8 | ARG MUSL_TARGET 9 | 10 | RUN apk upgrade && \ 11 | apk add curl gcc musl-dev && \ 12 | curl -sSf https://sh.rustup.rs | sh -s -- --profile minimal --default-toolchain nightly --component rust-src -y 13 | 14 | RUN source $HOME/.cargo/env && \ 15 | mkdir -p /app/.cargo && \ 16 | if [ "$RUST_TARGET" != $(rustup target list --installed) ]; then \ 17 | rustup target add $RUST_TARGET && \ 18 | curl -L "https://musl.cc/$MUSL_TARGET-cross.tgz" -o /toolchain.tgz && \ 19 | tar xf toolchain.tgz && \ 20 | ln -s "/$MUSL_TARGET-cross/bin/$MUSL_TARGET-gcc" "/usr/bin/$MUSL_TARGET-gcc" && \ 21 | ln -s "/$MUSL_TARGET-cross/bin/$MUSL_TARGET-ld" "/usr/bin/$MUSL_TARGET-ld" && \ 22 | ln -s "/$MUSL_TARGET-cross/bin/$MUSL_TARGET-strip" "/usr/bin/actual-strip" && \ 23 | GCC_VERSION=$($MUSL_TARGET-gcc --version | grep gcc | awk '{print $3}') && \ 24 | echo -e "\ 25 | [build]\n\ 26 | rustflags = [\"-L\", \"native=/$MUSL_TARGET-cross/$MUSL_TARGET/lib\", \"-L\", \"native=/$MUSL_TARGET-cross/lib/gcc/$MUSL_TARGET/$GCC_VERSION/\", \"-l\", \"static=gcc\", \"-Clink-self-contained=y\", \"-Clinker-flavor=gcc\"]\n\ 27 | [target.$RUST_TARGET]\n\ 28 | linker = \"$MUSL_TARGET-gcc\"\n\ 29 | [unstable]\n\ 30 | build-std = [\"std\", \"panic_abort\"]\n\ 31 | " > /app/.cargo/config; \ 32 | else \ 33 | echo "skipping toolchain as we are native" && \ 34 | echo -e "\ 35 | [build]\n\ 36 | rustflags = [\"-L\", \"native=/usr/lib\"]\n\ 37 | [unstable]\n\ 38 | build-std = [\"std\", \"panic_abort\"]\n\ 39 | " > /app/.cargo/config && \ 40 | ln -s /usr/bin/strip /usr/bin/actual-strip; \ 41 | fi 42 | 43 | WORKDIR /app 44 | 45 | COPY ./Cargo.lock ./Cargo.lock 46 | COPY ./Cargo.toml ./Cargo.toml 47 | 48 | # We need a source directory so that it builds the dependencies and an empty 49 | # binary. 50 | RUN mkdir src/ 51 | RUN echo 'fn main() {}' > ./src/main.rs 52 | RUN source $HOME/.cargo/env && \ 53 | cargo build --release \ 54 | --target="$RUST_TARGET" 55 | 56 | # Now, delete the fake source and copy in the actual source. This allows us to 57 | # have a previous compilation step for compiling the dependencies, while being 58 | # able to only copy in and compile the binary itself when something in the 59 | # source changes. 60 | # 61 | # This is very important. If we just copy in the source after copying in the 62 | # Cargo.lock and Cargo.toml, then every time the source changes the dependencies 63 | # would have to be re-downloaded and re-compiled. 64 | # 65 | # Also, remove the artifacts of building the binaries. 66 | RUN rm -f target/$RUST_TARGET/release/deps/twilight_gateway_queue* 67 | COPY ./src ./src 68 | 69 | RUN source $HOME/.cargo/env && \ 70 | cargo build --release \ 71 | --target="$RUST_TARGET" && \ 72 | cp target/$RUST_TARGET/release/twilight-gateway-queue /twilight-gateway-queue && \ 73 | actual-strip /twilight-gateway-queue 74 | 75 | FROM scratch 76 | 77 | # And now copy the binary over from the build container. The build container is 78 | # based on a heavy image. 79 | COPY --from=build /twilight-gateway-queue /twilight-gateway-queue 80 | 81 | CMD ["./twilight-gateway-queue"] 82 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ISC License (ISC) 2 | 3 | Copyright (c) 2020, Twilight Contributors 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any purpose 6 | with or without fee is hereby granted, provided that the above copyright notice 7 | and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 10 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 11 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 12 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 14 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 15 | THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![ci-badge][]][ci] [![license-badge][]][license] [![docs-badge][]][docs] [![rust badge]][rust link] 2 | 3 | # Gateway Queue 4 | 5 | If your bot's shards are multi-processed, then a good choice is to use the 6 | [Gateway Queue]. The Gateway Queue is a lightweight but powerful application 7 | that you can host to queue shards across all of your processes. 8 | 9 | The Gateway Queue is library and language agnostic, it's an HTTP server that you 10 | call whenever a shard needs to reconnect to the gateway. 11 | 12 | ### How it works 13 | 14 | When one of your shards disconnects and needs to perform a full reconnect, it 15 | needs to start a new session with the gateway. If you have multiple processes 16 | managing shards, you may not have communication between these processes. The 17 | problems start to happen when multiple shards from these processes try to 18 | reconnect at the same time, all but 1 will get rate-limited. 19 | 20 | This is because there's a 5 second ratelimit between new sessions. By sending an 21 | HTTP request to the Gateway Queue, it will ratelimit the requests and "stall" 22 | them, responding with a friendly message once that shard can reconnect: 23 | 24 | ```json 25 | { 26 | "message": "You're free to connect now! :)" 27 | } 28 | ``` 29 | 30 | ### Example 31 | 32 | The API is pretty minimal. It's just an HTTP request: 33 | 34 | ```rust 35 | reqwest::get("http://gateway-queue").await?; 36 | ``` 37 | 38 | No headers, body, or particular method need to be set, they're all ignored. 39 | The request will get a response once the request has gone through the queue. 40 | 41 | ### Using with large bots 42 | 43 | If the bot has access to bucketed identify, you will have to make slight 44 | configuration changes. Firstly you will need to set the `DISCORD_TOKEN` 45 | environment variable so that it is able to fetch the remaining identifies and what 46 | the `max_concurrency` is. Secondly, you will need to set the query parameter 47 | `shard` to the ID of the identifying shard. 48 | 49 | ```rust 50 | reqwest::get("http://gateway-queue?shard=42").await?; 51 | ``` 52 | 53 | ### Running it 54 | 55 | If you're using Docker, you can use the prebuilt Docker images from [Github's container registry]. 56 | 57 | ```sh 58 | $ docker run -itd -e HOST=0.0.0.0 -e PORT=5000 ghcr.io/twilight-rs/gateway-queue 59 | ``` 60 | 61 | If you're not, you can compile it via Cargo: 62 | 63 | ```sh 64 | $ cargo build --release 65 | $ HOST=0.0.0.0 PORT=5000 ./target/release/twilight-gateway-queue 66 | ``` 67 | 68 | `HOST` and `PORT` are the only two environment variables. 69 | 70 | [ci-badge]: https://github.com/twilight-rs/gateway-queue/workflows/Test/badge.svg 71 | [ci]: https://github.com/twilight-rs/gateway-queue/actions 72 | [docs]: https://twilight-rs.github.io/chapter_3_services/section_5_gateway_queue.html 73 | [docs-badge]: https://img.shields.io/badge/docs-online-5023dd.svg?style=flat-square 74 | [Github's container registry]: https://github.com/twilight-rs/gateway-queue/pkgs/container/gateway-queue 75 | [license-badge]: https://img.shields.io/badge/license-ISC-blue.svg?style=flat-square 76 | [license]: https://opensource.org/licenses/ISC 77 | [LICENSE.md]: https://github.com/twilight-rs/gateway-queue/blob/master/LICENSE.md 78 | [rust badge]: https://img.shields.io/badge/rust-1.44+-93450a.svg?style=flat-square 79 | [rust link]: https://blog.rust-lang.org/2020/06/04/Rust-1.44.0.html 80 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use http_body_util::Full; 2 | use hyper::{body::Bytes, Response}; 3 | use hyper_util::{rt::TokioIo, server::graceful::GracefulShutdown}; 4 | use serde::Deserialize; 5 | use std::{ 6 | env, 7 | error::Error, 8 | net::{IpAddr, SocketAddr}, 9 | pin::pin, 10 | str::FromStr, 11 | sync::Arc, 12 | time::Duration, 13 | }; 14 | use tokio::{ 15 | net::TcpListener, 16 | sync::Mutex, 17 | time::{self, sleep}, 18 | }; 19 | use tracing::{error, info, warn}; 20 | use tracing_subscriber::EnvFilter; 21 | use twilight_gateway_queue::{InMemoryQueue, Queue}; 22 | use twilight_http::Client; 23 | 24 | const PROCESSED: Bytes = Bytes::from_static(br#"{"message": "You're free to connect now! :)"}"#); 25 | 26 | #[cfg(windows)] 27 | async fn shutdown_signal() { 28 | tokio::signal::ctrl_c() 29 | .await 30 | .expect("failed to install CTRL+C signal handler"); 31 | } 32 | 33 | #[cfg(unix)] 34 | async fn shutdown_signal() { 35 | use tokio::signal::unix::{signal, SignalKind}; 36 | let mut sigint = signal(SignalKind::interrupt()).expect("failed to install SIGINT handler"); 37 | let mut sigterm = signal(SignalKind::terminate()).expect("failed to install SIGTERM handler"); 38 | 39 | tokio::select! { 40 | _ = sigint.recv() => {}, 41 | _ = sigterm.recv() => {}, 42 | }; 43 | } 44 | 45 | #[derive(Deserialize)] 46 | struct QueryParameters { 47 | shard: u32, 48 | } 49 | 50 | #[tokio::main(flavor = "current_thread")] 51 | async fn main() -> Result<(), Box> { 52 | tracing_subscriber::fmt() 53 | .with_env_filter( 54 | EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")), 55 | ) 56 | .init(); 57 | 58 | let host_raw = env::var("HOST").unwrap_or_else(|_| "0.0.0.0".into()); 59 | let host = IpAddr::from_str(&host_raw)?; 60 | let port = env::var("PORT").unwrap_or_else(|_| "80".into()).parse()?; 61 | 62 | let (client, queue) = { 63 | if let Ok(token) = env::var("DISCORD_TOKEN") { 64 | let client = Client::new(token); 65 | let session = client 66 | .gateway() 67 | .authed() 68 | .await? 69 | .model() 70 | .await? 71 | .session_start_limit; 72 | 73 | let reset_after = Duration::from_millis(session.reset_after); 74 | ( 75 | Some(Arc::new(( 76 | client, 77 | Mutex::new((time::Instant::now() + reset_after, session.remaining)), 78 | ))), 79 | InMemoryQueue::new( 80 | session.max_concurrency, 81 | session.remaining, 82 | reset_after, 83 | session.total, 84 | ), 85 | ) 86 | } else { 87 | (None, InMemoryQueue::default()) 88 | } 89 | }; 90 | 91 | let address = SocketAddr::from((host, port)); 92 | 93 | let tcp_listener = TcpListener::bind(address).await?; 94 | let server = hyper::server::conn::http1::Builder::new(); 95 | let graceful = GracefulShutdown::new(); 96 | let mut shutdown = pin!(shutdown_signal()); 97 | 98 | info!("Listening on http://{}", address); 99 | 100 | loop { 101 | tokio::select! { 102 | conn = tcp_listener.accept() => { 103 | let Ok((stream, _peer_addr)) = conn else { 104 | continue; 105 | }; 106 | 107 | let stream = TokioIo::new(stream); 108 | 109 | let client = client.clone(); 110 | let queue = queue.clone(); 111 | 112 | let conn = server.serve_connection(stream, hyper::service::service_fn(move |request| { 113 | let queue = queue.clone(); 114 | 115 | let mut shard = None; 116 | 117 | if client.is_some() { 118 | if let Some(query) = request.uri().query() { 119 | if let Ok(params) = serde_urlencoded::from_str::(query) { 120 | shard = Some(params.shard); 121 | } 122 | } 123 | 124 | if shard.is_none() { 125 | warn!( 126 | "No shard id set, defaulting to 0. Will not bucket requests correctly!" 127 | ); 128 | } 129 | } 130 | let client = client.clone(); 131 | 132 | async move { 133 | if let Some((client, lock)) = client.as_deref() { 134 | let mut lock = lock.lock().await; 135 | if lock.1 > 0 { 136 | lock.1 -= 1; 137 | } else { 138 | time::sleep_until(lock.0).await; 139 | 'label: { 140 | if let Ok(res) = client.gateway().authed().await { 141 | if let Ok(info) = res.model().await { 142 | let session = info.session_start_limit; 143 | let reset_after = 144 | Duration::from_millis(session.reset_after); 145 | info!("next session start limit in: {reset_after:.2?}"); 146 | 147 | lock.1 = session.remaining; 148 | lock.0 = time::Instant::now() + reset_after; 149 | 150 | queue.update( 151 | session.max_concurrency, 152 | session.remaining, 153 | reset_after, 154 | session.total, 155 | ); 156 | break 'label; 157 | } 158 | } 159 | 160 | warn!("unable to get new session limits, skipping (this may cause bad things)"); 161 | } 162 | } 163 | } 164 | 165 | queue 166 | .enqueue(shard.unwrap_or(0)) 167 | .await 168 | .expect("never cancels"); 169 | 170 | let body = Full::from(PROCESSED); 171 | 172 | Ok::>, hyper::Error>(Response::new(body)) 173 | } 174 | })); 175 | 176 | let conn = graceful.watch(conn); 177 | 178 | tokio::spawn(async move { 179 | if let Err(err) = conn.await { 180 | error!("Connection error: {}", err); 181 | } 182 | }); 183 | }, 184 | _ = shutdown.as_mut() => { 185 | drop(tcp_listener); 186 | info!("Shutdown signal received, initiating shutdown"); 187 | break; 188 | } 189 | } 190 | } 191 | 192 | tokio::select! { 193 | _ = graceful.shutdown() => { 194 | info!("Gracefully shutdown!"); 195 | }, 196 | _ = sleep(Duration::from_secs(10)) => { 197 | error!("Waited 10 seconds for graceful shutdown, aborting..."); 198 | } 199 | } 200 | 201 | Ok(()) 202 | } 203 | --------------------------------------------------------------------------------