├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── rust-toolchain.toml ├── rustfmt.toml └── src └── lib.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | pull_request: 5 | branches: [main] 6 | push: 7 | branches: [main] 8 | tags: 9 | - '*' 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build-and-test: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Clone repository 17 | uses: actions/checkout@v4 18 | - uses: dsherret/rust-toolchain-file@v1 19 | - name: Format 20 | run: cargo fmt --all -- --check 21 | - name: Lint 22 | run: cargo clippy --all-targets --all-features --release 23 | - name: Build 24 | run: cargo build --all-targets --all-features --release 25 | - name: Test 26 | run: cargo test --all-targets --all-features --release 27 | - name: Publish 28 | if: | 29 | github.repository == 'denoland/vnotify' && 30 | startsWith(github.ref, 'refs/tags/') 31 | env: 32 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 33 | run: | 34 | cargo publish 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 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 = "allocator-api2" 31 | version = "0.2.21" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 34 | 35 | [[package]] 36 | name = "anstream" 37 | version = "0.6.18" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 40 | dependencies = [ 41 | "anstyle", 42 | "anstyle-parse", 43 | "anstyle-query", 44 | "anstyle-wincon", 45 | "colorchoice", 46 | "is_terminal_polyfill", 47 | "utf8parse", 48 | ] 49 | 50 | [[package]] 51 | name = "anstyle" 52 | version = "1.0.10" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 55 | 56 | [[package]] 57 | name = "anstyle-parse" 58 | version = "0.2.6" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 61 | dependencies = [ 62 | "utf8parse", 63 | ] 64 | 65 | [[package]] 66 | name = "anstyle-query" 67 | version = "1.1.2" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 70 | dependencies = [ 71 | "windows-sys 0.59.0", 72 | ] 73 | 74 | [[package]] 75 | name = "anstyle-wincon" 76 | version = "3.0.7" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" 79 | dependencies = [ 80 | "anstyle", 81 | "once_cell", 82 | "windows-sys 0.59.0", 83 | ] 84 | 85 | [[package]] 86 | name = "anyhow" 87 | version = "1.0.95" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" 90 | 91 | [[package]] 92 | name = "arrayref" 93 | version = "0.3.9" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" 96 | 97 | [[package]] 98 | name = "arrayvec" 99 | version = "0.7.6" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" 102 | 103 | [[package]] 104 | name = "async-lock" 105 | version = "3.4.0" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" 108 | dependencies = [ 109 | "event-listener", 110 | "event-listener-strategy", 111 | "pin-project-lite", 112 | ] 113 | 114 | [[package]] 115 | name = "autocfg" 116 | version = "1.4.0" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 119 | 120 | [[package]] 121 | name = "aws-credential-types" 122 | version = "1.2.1" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "60e8f6b615cb5fc60a98132268508ad104310f0cfb25a1c22eee76efdf9154da" 125 | dependencies = [ 126 | "aws-smithy-async", 127 | "aws-smithy-runtime-api", 128 | "aws-smithy-types", 129 | "zeroize", 130 | ] 131 | 132 | [[package]] 133 | name = "aws-runtime" 134 | version = "1.5.4" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "bee7643696e7fdd74c10f9eb42848a87fe469d35eae9c3323f80aa98f350baac" 137 | dependencies = [ 138 | "aws-credential-types", 139 | "aws-sigv4", 140 | "aws-smithy-async", 141 | "aws-smithy-eventstream", 142 | "aws-smithy-http", 143 | "aws-smithy-runtime", 144 | "aws-smithy-runtime-api", 145 | "aws-smithy-types", 146 | "aws-types", 147 | "bytes", 148 | "fastrand", 149 | "http 0.2.12", 150 | "http-body 0.4.6", 151 | "once_cell", 152 | "percent-encoding", 153 | "pin-project-lite", 154 | "tracing", 155 | "uuid", 156 | ] 157 | 158 | [[package]] 159 | name = "aws-sdk-s3" 160 | version = "1.71.0" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "705cb534fb7b620f540d2fac268d378918dc67d25b173f67edcab3851fe19392" 163 | dependencies = [ 164 | "aws-credential-types", 165 | "aws-runtime", 166 | "aws-sigv4", 167 | "aws-smithy-async", 168 | "aws-smithy-checksums", 169 | "aws-smithy-eventstream", 170 | "aws-smithy-http", 171 | "aws-smithy-json", 172 | "aws-smithy-runtime", 173 | "aws-smithy-runtime-api", 174 | "aws-smithy-types", 175 | "aws-smithy-xml", 176 | "aws-types", 177 | "bytes", 178 | "fastrand", 179 | "hex", 180 | "hmac", 181 | "http 0.2.12", 182 | "http-body 0.4.6", 183 | "lru", 184 | "once_cell", 185 | "percent-encoding", 186 | "regex-lite", 187 | "sha2", 188 | "tracing", 189 | "url", 190 | ] 191 | 192 | [[package]] 193 | name = "aws-sigv4" 194 | version = "1.2.7" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "690118821e46967b3c4501d67d7d52dd75106a9c54cf36cefa1985cedbe94e05" 197 | dependencies = [ 198 | "aws-credential-types", 199 | "aws-smithy-eventstream", 200 | "aws-smithy-http", 201 | "aws-smithy-runtime-api", 202 | "aws-smithy-types", 203 | "bytes", 204 | "crypto-bigint 0.5.5", 205 | "form_urlencoded", 206 | "hex", 207 | "hmac", 208 | "http 0.2.12", 209 | "http 1.2.0", 210 | "once_cell", 211 | "p256", 212 | "percent-encoding", 213 | "ring", 214 | "sha2", 215 | "subtle", 216 | "time", 217 | "tracing", 218 | "zeroize", 219 | ] 220 | 221 | [[package]] 222 | name = "aws-smithy-async" 223 | version = "1.2.4" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "fa59d1327d8b5053c54bf2eaae63bf629ba9e904434d0835a28ed3c0ed0a614e" 226 | dependencies = [ 227 | "futures-util", 228 | "pin-project-lite", 229 | "tokio", 230 | ] 231 | 232 | [[package]] 233 | name = "aws-smithy-checksums" 234 | version = "0.62.0" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "f2f45a1c384d7a393026bc5f5c177105aa9fa68e4749653b985707ac27d77295" 237 | dependencies = [ 238 | "aws-smithy-http", 239 | "aws-smithy-types", 240 | "bytes", 241 | "crc32c", 242 | "crc32fast", 243 | "crc64fast-nvme", 244 | "hex", 245 | "http 0.2.12", 246 | "http-body 0.4.6", 247 | "md-5", 248 | "pin-project-lite", 249 | "sha1", 250 | "sha2", 251 | "tracing", 252 | ] 253 | 254 | [[package]] 255 | name = "aws-smithy-eventstream" 256 | version = "0.60.6" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "8b18559a41e0c909b77625adf2b8c50de480a8041e5e4a3f5f7d177db70abc5a" 259 | dependencies = [ 260 | "aws-smithy-types", 261 | "bytes", 262 | "crc32fast", 263 | ] 264 | 265 | [[package]] 266 | name = "aws-smithy-http" 267 | version = "0.60.12" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "7809c27ad8da6a6a68c454e651d4962479e81472aa19ae99e59f9aba1f9713cc" 270 | dependencies = [ 271 | "aws-smithy-eventstream", 272 | "aws-smithy-runtime-api", 273 | "aws-smithy-types", 274 | "bytes", 275 | "bytes-utils", 276 | "futures-core", 277 | "http 0.2.12", 278 | "http-body 0.4.6", 279 | "once_cell", 280 | "percent-encoding", 281 | "pin-project-lite", 282 | "pin-utils", 283 | "tracing", 284 | ] 285 | 286 | [[package]] 287 | name = "aws-smithy-json" 288 | version = "0.61.2" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "623a51127f24c30776c8b374295f2df78d92517386f77ba30773f15a30ce1422" 291 | dependencies = [ 292 | "aws-smithy-types", 293 | ] 294 | 295 | [[package]] 296 | name = "aws-smithy-runtime" 297 | version = "1.7.7" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "865f7050bbc7107a6c98a397a9fcd9413690c27fa718446967cf03b2d3ac517e" 300 | dependencies = [ 301 | "aws-smithy-async", 302 | "aws-smithy-http", 303 | "aws-smithy-runtime-api", 304 | "aws-smithy-types", 305 | "bytes", 306 | "fastrand", 307 | "h2", 308 | "http 0.2.12", 309 | "http-body 0.4.6", 310 | "http-body 1.0.1", 311 | "httparse", 312 | "hyper", 313 | "hyper-rustls", 314 | "once_cell", 315 | "pin-project-lite", 316 | "pin-utils", 317 | "rustls", 318 | "tokio", 319 | "tracing", 320 | ] 321 | 322 | [[package]] 323 | name = "aws-smithy-runtime-api" 324 | version = "1.7.3" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "92165296a47a812b267b4f41032ff8069ab7ff783696d217f0994a0d7ab585cd" 327 | dependencies = [ 328 | "aws-smithy-async", 329 | "aws-smithy-types", 330 | "bytes", 331 | "http 0.2.12", 332 | "http 1.2.0", 333 | "pin-project-lite", 334 | "tokio", 335 | "tracing", 336 | "zeroize", 337 | ] 338 | 339 | [[package]] 340 | name = "aws-smithy-types" 341 | version = "1.2.12" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "a28f6feb647fb5e0d5b50f0472c19a7db9462b74e2fec01bb0b44eedcc834e97" 344 | dependencies = [ 345 | "base64-simd", 346 | "bytes", 347 | "bytes-utils", 348 | "futures-core", 349 | "http 0.2.12", 350 | "http 1.2.0", 351 | "http-body 0.4.6", 352 | "http-body 1.0.1", 353 | "http-body-util", 354 | "itoa", 355 | "num-integer", 356 | "pin-project-lite", 357 | "pin-utils", 358 | "ryu", 359 | "serde", 360 | "time", 361 | "tokio", 362 | "tokio-util", 363 | ] 364 | 365 | [[package]] 366 | name = "aws-smithy-xml" 367 | version = "0.60.9" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" 370 | dependencies = [ 371 | "xmlparser", 372 | ] 373 | 374 | [[package]] 375 | name = "aws-types" 376 | version = "1.3.4" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "b0df5a18c4f951c645300d365fec53a61418bcf4650f604f85fe2a665bfaa0c2" 379 | dependencies = [ 380 | "aws-credential-types", 381 | "aws-smithy-async", 382 | "aws-smithy-runtime-api", 383 | "aws-smithy-types", 384 | "rustc_version", 385 | "tracing", 386 | ] 387 | 388 | [[package]] 389 | name = "backtrace" 390 | version = "0.3.74" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 393 | dependencies = [ 394 | "addr2line", 395 | "cfg-if", 396 | "libc", 397 | "miniz_oxide", 398 | "object", 399 | "rustc-demangle", 400 | "windows-targets", 401 | ] 402 | 403 | [[package]] 404 | name = "base16ct" 405 | version = "0.1.1" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" 408 | 409 | [[package]] 410 | name = "base64" 411 | version = "0.21.7" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 414 | 415 | [[package]] 416 | name = "base64-simd" 417 | version = "0.8.0" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" 420 | dependencies = [ 421 | "outref", 422 | "vsimd", 423 | ] 424 | 425 | [[package]] 426 | name = "base64ct" 427 | version = "1.6.0" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 430 | 431 | [[package]] 432 | name = "bitflags" 433 | version = "2.8.0" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 436 | 437 | [[package]] 438 | name = "blake3" 439 | version = "1.5.5" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" 442 | dependencies = [ 443 | "arrayref", 444 | "arrayvec", 445 | "cc", 446 | "cfg-if", 447 | "constant_time_eq", 448 | ] 449 | 450 | [[package]] 451 | name = "block-buffer" 452 | version = "0.10.4" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 455 | dependencies = [ 456 | "generic-array", 457 | ] 458 | 459 | [[package]] 460 | name = "byteorder" 461 | version = "1.5.0" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 464 | 465 | [[package]] 466 | name = "bytes" 467 | version = "1.9.0" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 470 | 471 | [[package]] 472 | name = "bytes-utils" 473 | version = "0.1.4" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" 476 | dependencies = [ 477 | "bytes", 478 | "either", 479 | ] 480 | 481 | [[package]] 482 | name = "cbindgen" 483 | version = "0.27.0" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb" 486 | dependencies = [ 487 | "clap", 488 | "heck", 489 | "indexmap", 490 | "log", 491 | "proc-macro2", 492 | "quote", 493 | "serde", 494 | "serde_json", 495 | "syn", 496 | "tempfile", 497 | "toml", 498 | ] 499 | 500 | [[package]] 501 | name = "cc" 502 | version = "1.2.10" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" 505 | dependencies = [ 506 | "shlex", 507 | ] 508 | 509 | [[package]] 510 | name = "cfg-if" 511 | version = "1.0.0" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 514 | 515 | [[package]] 516 | name = "clap" 517 | version = "4.5.27" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" 520 | dependencies = [ 521 | "clap_builder", 522 | ] 523 | 524 | [[package]] 525 | name = "clap_builder" 526 | version = "4.5.27" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" 529 | dependencies = [ 530 | "anstream", 531 | "anstyle", 532 | "clap_lex", 533 | "strsim", 534 | ] 535 | 536 | [[package]] 537 | name = "clap_lex" 538 | version = "0.7.4" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 541 | 542 | [[package]] 543 | name = "colorchoice" 544 | version = "1.0.3" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 547 | 548 | [[package]] 549 | name = "concurrent-queue" 550 | version = "2.5.0" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 553 | dependencies = [ 554 | "crossbeam-utils", 555 | ] 556 | 557 | [[package]] 558 | name = "const-oid" 559 | version = "0.9.6" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 562 | 563 | [[package]] 564 | name = "constant_time_eq" 565 | version = "0.3.1" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" 568 | 569 | [[package]] 570 | name = "core-foundation" 571 | version = "0.9.4" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 574 | dependencies = [ 575 | "core-foundation-sys", 576 | "libc", 577 | ] 578 | 579 | [[package]] 580 | name = "core-foundation-sys" 581 | version = "0.8.7" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 584 | 585 | [[package]] 586 | name = "cpufeatures" 587 | version = "0.2.17" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 590 | dependencies = [ 591 | "libc", 592 | ] 593 | 594 | [[package]] 595 | name = "crc" 596 | version = "3.2.1" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" 599 | dependencies = [ 600 | "crc-catalog", 601 | ] 602 | 603 | [[package]] 604 | name = "crc-catalog" 605 | version = "2.4.0" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 608 | 609 | [[package]] 610 | name = "crc32c" 611 | version = "0.6.8" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" 614 | dependencies = [ 615 | "rustc_version", 616 | ] 617 | 618 | [[package]] 619 | name = "crc32fast" 620 | version = "1.4.2" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 623 | dependencies = [ 624 | "cfg-if", 625 | ] 626 | 627 | [[package]] 628 | name = "crc64fast-nvme" 629 | version = "1.1.1" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "d5e2ee08013e3f228d6d2394116c4549a6df77708442c62d887d83f68ef2ee37" 632 | dependencies = [ 633 | "cbindgen", 634 | "crc", 635 | ] 636 | 637 | [[package]] 638 | name = "crossbeam-channel" 639 | version = "0.5.14" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" 642 | dependencies = [ 643 | "crossbeam-utils", 644 | ] 645 | 646 | [[package]] 647 | name = "crossbeam-epoch" 648 | version = "0.9.18" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 651 | dependencies = [ 652 | "crossbeam-utils", 653 | ] 654 | 655 | [[package]] 656 | name = "crossbeam-utils" 657 | version = "0.8.21" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 660 | 661 | [[package]] 662 | name = "crypto-bigint" 663 | version = "0.4.9" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" 666 | dependencies = [ 667 | "generic-array", 668 | "rand_core", 669 | "subtle", 670 | "zeroize", 671 | ] 672 | 673 | [[package]] 674 | name = "crypto-bigint" 675 | version = "0.5.5" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" 678 | dependencies = [ 679 | "rand_core", 680 | "subtle", 681 | ] 682 | 683 | [[package]] 684 | name = "crypto-common" 685 | version = "0.1.6" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 688 | dependencies = [ 689 | "generic-array", 690 | "typenum", 691 | ] 692 | 693 | [[package]] 694 | name = "der" 695 | version = "0.6.1" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" 698 | dependencies = [ 699 | "const-oid", 700 | "zeroize", 701 | ] 702 | 703 | [[package]] 704 | name = "deranged" 705 | version = "0.3.11" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 708 | dependencies = [ 709 | "powerfmt", 710 | ] 711 | 712 | [[package]] 713 | name = "digest" 714 | version = "0.10.7" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 717 | dependencies = [ 718 | "block-buffer", 719 | "crypto-common", 720 | "subtle", 721 | ] 722 | 723 | [[package]] 724 | name = "displaydoc" 725 | version = "0.2.5" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 728 | dependencies = [ 729 | "proc-macro2", 730 | "quote", 731 | "syn", 732 | ] 733 | 734 | [[package]] 735 | name = "ecdsa" 736 | version = "0.14.8" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" 739 | dependencies = [ 740 | "der", 741 | "elliptic-curve", 742 | "rfc6979", 743 | "signature", 744 | ] 745 | 746 | [[package]] 747 | name = "either" 748 | version = "1.13.0" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 751 | 752 | [[package]] 753 | name = "elliptic-curve" 754 | version = "0.12.3" 755 | source = "registry+https://github.com/rust-lang/crates.io-index" 756 | checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" 757 | dependencies = [ 758 | "base16ct", 759 | "crypto-bigint 0.4.9", 760 | "der", 761 | "digest", 762 | "ff", 763 | "generic-array", 764 | "group", 765 | "pkcs8", 766 | "rand_core", 767 | "sec1", 768 | "subtle", 769 | "zeroize", 770 | ] 771 | 772 | [[package]] 773 | name = "equivalent" 774 | version = "1.0.1" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 777 | 778 | [[package]] 779 | name = "errno" 780 | version = "0.3.10" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 783 | dependencies = [ 784 | "libc", 785 | "windows-sys 0.59.0", 786 | ] 787 | 788 | [[package]] 789 | name = "event-listener" 790 | version = "5.4.0" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" 793 | dependencies = [ 794 | "concurrent-queue", 795 | "parking", 796 | "pin-project-lite", 797 | ] 798 | 799 | [[package]] 800 | name = "event-listener-strategy" 801 | version = "0.5.3" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" 804 | dependencies = [ 805 | "event-listener", 806 | "pin-project-lite", 807 | ] 808 | 809 | [[package]] 810 | name = "faster-hex" 811 | version = "0.9.0" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" 814 | dependencies = [ 815 | "serde", 816 | ] 817 | 818 | [[package]] 819 | name = "fastrand" 820 | version = "2.3.0" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 823 | 824 | [[package]] 825 | name = "ff" 826 | version = "0.12.1" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" 829 | dependencies = [ 830 | "rand_core", 831 | "subtle", 832 | ] 833 | 834 | [[package]] 835 | name = "fnv" 836 | version = "1.0.7" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 839 | 840 | [[package]] 841 | name = "foldhash" 842 | version = "0.1.4" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" 845 | 846 | [[package]] 847 | name = "form_urlencoded" 848 | version = "1.2.1" 849 | source = "registry+https://github.com/rust-lang/crates.io-index" 850 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 851 | dependencies = [ 852 | "percent-encoding", 853 | ] 854 | 855 | [[package]] 856 | name = "futures" 857 | version = "0.3.31" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 860 | dependencies = [ 861 | "futures-channel", 862 | "futures-core", 863 | "futures-executor", 864 | "futures-io", 865 | "futures-sink", 866 | "futures-task", 867 | "futures-util", 868 | ] 869 | 870 | [[package]] 871 | name = "futures-channel" 872 | version = "0.3.31" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 875 | dependencies = [ 876 | "futures-core", 877 | "futures-sink", 878 | ] 879 | 880 | [[package]] 881 | name = "futures-core" 882 | version = "0.3.31" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 885 | 886 | [[package]] 887 | name = "futures-executor" 888 | version = "0.3.31" 889 | source = "registry+https://github.com/rust-lang/crates.io-index" 890 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 891 | dependencies = [ 892 | "futures-core", 893 | "futures-task", 894 | "futures-util", 895 | ] 896 | 897 | [[package]] 898 | name = "futures-io" 899 | version = "0.3.31" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 902 | 903 | [[package]] 904 | name = "futures-macro" 905 | version = "0.3.31" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 908 | dependencies = [ 909 | "proc-macro2", 910 | "quote", 911 | "syn", 912 | ] 913 | 914 | [[package]] 915 | name = "futures-sink" 916 | version = "0.3.31" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 919 | 920 | [[package]] 921 | name = "futures-task" 922 | version = "0.3.31" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 925 | 926 | [[package]] 927 | name = "futures-util" 928 | version = "0.3.31" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 931 | dependencies = [ 932 | "futures-channel", 933 | "futures-core", 934 | "futures-io", 935 | "futures-macro", 936 | "futures-sink", 937 | "futures-task", 938 | "memchr", 939 | "pin-project-lite", 940 | "pin-utils", 941 | "slab", 942 | ] 943 | 944 | [[package]] 945 | name = "generator" 946 | version = "0.8.4" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" 949 | dependencies = [ 950 | "cfg-if", 951 | "libc", 952 | "log", 953 | "rustversion", 954 | "windows", 955 | ] 956 | 957 | [[package]] 958 | name = "generic-array" 959 | version = "0.14.7" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 962 | dependencies = [ 963 | "typenum", 964 | "version_check", 965 | ] 966 | 967 | [[package]] 968 | name = "getrandom" 969 | version = "0.2.15" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 972 | dependencies = [ 973 | "cfg-if", 974 | "libc", 975 | "wasi", 976 | ] 977 | 978 | [[package]] 979 | name = "gimli" 980 | version = "0.31.1" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 983 | 984 | [[package]] 985 | name = "group" 986 | version = "0.12.1" 987 | source = "registry+https://github.com/rust-lang/crates.io-index" 988 | checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" 989 | dependencies = [ 990 | "ff", 991 | "rand_core", 992 | "subtle", 993 | ] 994 | 995 | [[package]] 996 | name = "h2" 997 | version = "0.3.26" 998 | source = "registry+https://github.com/rust-lang/crates.io-index" 999 | checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 1000 | dependencies = [ 1001 | "bytes", 1002 | "fnv", 1003 | "futures-core", 1004 | "futures-sink", 1005 | "futures-util", 1006 | "http 0.2.12", 1007 | "indexmap", 1008 | "slab", 1009 | "tokio", 1010 | "tokio-util", 1011 | "tracing", 1012 | ] 1013 | 1014 | [[package]] 1015 | name = "hashbrown" 1016 | version = "0.15.2" 1017 | source = "registry+https://github.com/rust-lang/crates.io-index" 1018 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 1019 | dependencies = [ 1020 | "allocator-api2", 1021 | "equivalent", 1022 | "foldhash", 1023 | ] 1024 | 1025 | [[package]] 1026 | name = "heck" 1027 | version = "0.4.1" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 1030 | 1031 | [[package]] 1032 | name = "hex" 1033 | version = "0.4.3" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 1036 | 1037 | [[package]] 1038 | name = "hmac" 1039 | version = "0.12.1" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 1042 | dependencies = [ 1043 | "digest", 1044 | ] 1045 | 1046 | [[package]] 1047 | name = "http" 1048 | version = "0.2.12" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 1051 | dependencies = [ 1052 | "bytes", 1053 | "fnv", 1054 | "itoa", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "http" 1059 | version = "1.2.0" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" 1062 | dependencies = [ 1063 | "bytes", 1064 | "fnv", 1065 | "itoa", 1066 | ] 1067 | 1068 | [[package]] 1069 | name = "http-body" 1070 | version = "0.4.6" 1071 | source = "registry+https://github.com/rust-lang/crates.io-index" 1072 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 1073 | dependencies = [ 1074 | "bytes", 1075 | "http 0.2.12", 1076 | "pin-project-lite", 1077 | ] 1078 | 1079 | [[package]] 1080 | name = "http-body" 1081 | version = "1.0.1" 1082 | source = "registry+https://github.com/rust-lang/crates.io-index" 1083 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 1084 | dependencies = [ 1085 | "bytes", 1086 | "http 1.2.0", 1087 | ] 1088 | 1089 | [[package]] 1090 | name = "http-body-util" 1091 | version = "0.1.2" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 1094 | dependencies = [ 1095 | "bytes", 1096 | "futures-util", 1097 | "http 1.2.0", 1098 | "http-body 1.0.1", 1099 | "pin-project-lite", 1100 | ] 1101 | 1102 | [[package]] 1103 | name = "httparse" 1104 | version = "1.9.5" 1105 | source = "registry+https://github.com/rust-lang/crates.io-index" 1106 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 1107 | 1108 | [[package]] 1109 | name = "httpdate" 1110 | version = "1.0.3" 1111 | source = "registry+https://github.com/rust-lang/crates.io-index" 1112 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 1113 | 1114 | [[package]] 1115 | name = "hyper" 1116 | version = "0.14.32" 1117 | source = "registry+https://github.com/rust-lang/crates.io-index" 1118 | checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" 1119 | dependencies = [ 1120 | "bytes", 1121 | "futures-channel", 1122 | "futures-core", 1123 | "futures-util", 1124 | "h2", 1125 | "http 0.2.12", 1126 | "http-body 0.4.6", 1127 | "httparse", 1128 | "httpdate", 1129 | "itoa", 1130 | "pin-project-lite", 1131 | "socket2", 1132 | "tokio", 1133 | "tower-service", 1134 | "tracing", 1135 | "want", 1136 | ] 1137 | 1138 | [[package]] 1139 | name = "hyper-rustls" 1140 | version = "0.24.2" 1141 | source = "registry+https://github.com/rust-lang/crates.io-index" 1142 | checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" 1143 | dependencies = [ 1144 | "futures-util", 1145 | "http 0.2.12", 1146 | "hyper", 1147 | "log", 1148 | "rustls", 1149 | "rustls-native-certs", 1150 | "tokio", 1151 | "tokio-rustls", 1152 | ] 1153 | 1154 | [[package]] 1155 | name = "icu_collections" 1156 | version = "1.5.0" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 1159 | dependencies = [ 1160 | "displaydoc", 1161 | "yoke", 1162 | "zerofrom", 1163 | "zerovec", 1164 | ] 1165 | 1166 | [[package]] 1167 | name = "icu_locid" 1168 | version = "1.5.0" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 1171 | dependencies = [ 1172 | "displaydoc", 1173 | "litemap", 1174 | "tinystr", 1175 | "writeable", 1176 | "zerovec", 1177 | ] 1178 | 1179 | [[package]] 1180 | name = "icu_locid_transform" 1181 | version = "1.5.0" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 1184 | dependencies = [ 1185 | "displaydoc", 1186 | "icu_locid", 1187 | "icu_locid_transform_data", 1188 | "icu_provider", 1189 | "tinystr", 1190 | "zerovec", 1191 | ] 1192 | 1193 | [[package]] 1194 | name = "icu_locid_transform_data" 1195 | version = "1.5.0" 1196 | source = "registry+https://github.com/rust-lang/crates.io-index" 1197 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 1198 | 1199 | [[package]] 1200 | name = "icu_normalizer" 1201 | version = "1.5.0" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 1204 | dependencies = [ 1205 | "displaydoc", 1206 | "icu_collections", 1207 | "icu_normalizer_data", 1208 | "icu_properties", 1209 | "icu_provider", 1210 | "smallvec", 1211 | "utf16_iter", 1212 | "utf8_iter", 1213 | "write16", 1214 | "zerovec", 1215 | ] 1216 | 1217 | [[package]] 1218 | name = "icu_normalizer_data" 1219 | version = "1.5.0" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 1222 | 1223 | [[package]] 1224 | name = "icu_properties" 1225 | version = "1.5.1" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 1228 | dependencies = [ 1229 | "displaydoc", 1230 | "icu_collections", 1231 | "icu_locid_transform", 1232 | "icu_properties_data", 1233 | "icu_provider", 1234 | "tinystr", 1235 | "zerovec", 1236 | ] 1237 | 1238 | [[package]] 1239 | name = "icu_properties_data" 1240 | version = "1.5.0" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 1243 | 1244 | [[package]] 1245 | name = "icu_provider" 1246 | version = "1.5.0" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 1249 | dependencies = [ 1250 | "displaydoc", 1251 | "icu_locid", 1252 | "icu_provider_macros", 1253 | "stable_deref_trait", 1254 | "tinystr", 1255 | "writeable", 1256 | "yoke", 1257 | "zerofrom", 1258 | "zerovec", 1259 | ] 1260 | 1261 | [[package]] 1262 | name = "icu_provider_macros" 1263 | version = "1.5.0" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 1266 | dependencies = [ 1267 | "proc-macro2", 1268 | "quote", 1269 | "syn", 1270 | ] 1271 | 1272 | [[package]] 1273 | name = "idna" 1274 | version = "1.0.3" 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" 1276 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 1277 | dependencies = [ 1278 | "idna_adapter", 1279 | "smallvec", 1280 | "utf8_iter", 1281 | ] 1282 | 1283 | [[package]] 1284 | name = "idna_adapter" 1285 | version = "1.2.0" 1286 | source = "registry+https://github.com/rust-lang/crates.io-index" 1287 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 1288 | dependencies = [ 1289 | "icu_normalizer", 1290 | "icu_properties", 1291 | ] 1292 | 1293 | [[package]] 1294 | name = "indexmap" 1295 | version = "2.7.1" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" 1298 | dependencies = [ 1299 | "equivalent", 1300 | "hashbrown", 1301 | ] 1302 | 1303 | [[package]] 1304 | name = "is_terminal_polyfill" 1305 | version = "1.70.1" 1306 | source = "registry+https://github.com/rust-lang/crates.io-index" 1307 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 1308 | 1309 | [[package]] 1310 | name = "itoa" 1311 | version = "1.0.14" 1312 | source = "registry+https://github.com/rust-lang/crates.io-index" 1313 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 1314 | 1315 | [[package]] 1316 | name = "lazy_static" 1317 | version = "1.5.0" 1318 | source = "registry+https://github.com/rust-lang/crates.io-index" 1319 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 1320 | 1321 | [[package]] 1322 | name = "libc" 1323 | version = "0.2.169" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 1326 | 1327 | [[package]] 1328 | name = "linux-raw-sys" 1329 | version = "0.4.15" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 1332 | 1333 | [[package]] 1334 | name = "litemap" 1335 | version = "0.7.4" 1336 | source = "registry+https://github.com/rust-lang/crates.io-index" 1337 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 1338 | 1339 | [[package]] 1340 | name = "lock_api" 1341 | version = "0.4.12" 1342 | source = "registry+https://github.com/rust-lang/crates.io-index" 1343 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1344 | dependencies = [ 1345 | "autocfg", 1346 | "scopeguard", 1347 | ] 1348 | 1349 | [[package]] 1350 | name = "log" 1351 | version = "0.4.25" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" 1354 | 1355 | [[package]] 1356 | name = "loom" 1357 | version = "0.7.2" 1358 | source = "registry+https://github.com/rust-lang/crates.io-index" 1359 | checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" 1360 | dependencies = [ 1361 | "cfg-if", 1362 | "generator", 1363 | "scoped-tls", 1364 | "tracing", 1365 | "tracing-subscriber", 1366 | ] 1367 | 1368 | [[package]] 1369 | name = "lru" 1370 | version = "0.12.5" 1371 | source = "registry+https://github.com/rust-lang/crates.io-index" 1372 | checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" 1373 | dependencies = [ 1374 | "hashbrown", 1375 | ] 1376 | 1377 | [[package]] 1378 | name = "matchers" 1379 | version = "0.1.0" 1380 | source = "registry+https://github.com/rust-lang/crates.io-index" 1381 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 1382 | dependencies = [ 1383 | "regex-automata 0.1.10", 1384 | ] 1385 | 1386 | [[package]] 1387 | name = "md-5" 1388 | version = "0.10.6" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" 1391 | dependencies = [ 1392 | "cfg-if", 1393 | "digest", 1394 | ] 1395 | 1396 | [[package]] 1397 | name = "memchr" 1398 | version = "2.7.4" 1399 | source = "registry+https://github.com/rust-lang/crates.io-index" 1400 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 1401 | 1402 | [[package]] 1403 | name = "miniz_oxide" 1404 | version = "0.8.3" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" 1407 | dependencies = [ 1408 | "adler2", 1409 | ] 1410 | 1411 | [[package]] 1412 | name = "mio" 1413 | version = "1.0.3" 1414 | source = "registry+https://github.com/rust-lang/crates.io-index" 1415 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 1416 | dependencies = [ 1417 | "libc", 1418 | "wasi", 1419 | "windows-sys 0.52.0", 1420 | ] 1421 | 1422 | [[package]] 1423 | name = "moka" 1424 | version = "0.12.10" 1425 | source = "registry+https://github.com/rust-lang/crates.io-index" 1426 | checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" 1427 | dependencies = [ 1428 | "async-lock", 1429 | "crossbeam-channel", 1430 | "crossbeam-epoch", 1431 | "crossbeam-utils", 1432 | "event-listener", 1433 | "futures-util", 1434 | "loom", 1435 | "parking_lot", 1436 | "portable-atomic", 1437 | "rustc_version", 1438 | "smallvec", 1439 | "tagptr", 1440 | "thiserror", 1441 | "uuid", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "nu-ansi-term" 1446 | version = "0.46.0" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1449 | dependencies = [ 1450 | "overload", 1451 | "winapi", 1452 | ] 1453 | 1454 | [[package]] 1455 | name = "num-conv" 1456 | version = "0.1.0" 1457 | source = "registry+https://github.com/rust-lang/crates.io-index" 1458 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1459 | 1460 | [[package]] 1461 | name = "num-integer" 1462 | version = "0.1.46" 1463 | source = "registry+https://github.com/rust-lang/crates.io-index" 1464 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1465 | dependencies = [ 1466 | "num-traits", 1467 | ] 1468 | 1469 | [[package]] 1470 | name = "num-traits" 1471 | version = "0.2.19" 1472 | source = "registry+https://github.com/rust-lang/crates.io-index" 1473 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1474 | dependencies = [ 1475 | "autocfg", 1476 | ] 1477 | 1478 | [[package]] 1479 | name = "object" 1480 | version = "0.36.7" 1481 | source = "registry+https://github.com/rust-lang/crates.io-index" 1482 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 1483 | dependencies = [ 1484 | "memchr", 1485 | ] 1486 | 1487 | [[package]] 1488 | name = "once_cell" 1489 | version = "1.20.2" 1490 | source = "registry+https://github.com/rust-lang/crates.io-index" 1491 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 1492 | 1493 | [[package]] 1494 | name = "openssl-probe" 1495 | version = "0.1.6" 1496 | source = "registry+https://github.com/rust-lang/crates.io-index" 1497 | checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 1498 | 1499 | [[package]] 1500 | name = "outref" 1501 | version = "0.5.2" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" 1504 | 1505 | [[package]] 1506 | name = "overload" 1507 | version = "0.1.1" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1510 | 1511 | [[package]] 1512 | name = "p256" 1513 | version = "0.11.1" 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" 1515 | checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" 1516 | dependencies = [ 1517 | "ecdsa", 1518 | "elliptic-curve", 1519 | "sha2", 1520 | ] 1521 | 1522 | [[package]] 1523 | name = "parking" 1524 | version = "2.2.1" 1525 | source = "registry+https://github.com/rust-lang/crates.io-index" 1526 | checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 1527 | 1528 | [[package]] 1529 | name = "parking_lot" 1530 | version = "0.12.3" 1531 | source = "registry+https://github.com/rust-lang/crates.io-index" 1532 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1533 | dependencies = [ 1534 | "lock_api", 1535 | "parking_lot_core", 1536 | ] 1537 | 1538 | [[package]] 1539 | name = "parking_lot_core" 1540 | version = "0.9.10" 1541 | source = "registry+https://github.com/rust-lang/crates.io-index" 1542 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1543 | dependencies = [ 1544 | "cfg-if", 1545 | "libc", 1546 | "redox_syscall", 1547 | "smallvec", 1548 | "windows-targets", 1549 | ] 1550 | 1551 | [[package]] 1552 | name = "percent-encoding" 1553 | version = "2.3.1" 1554 | source = "registry+https://github.com/rust-lang/crates.io-index" 1555 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1556 | 1557 | [[package]] 1558 | name = "pin-project-lite" 1559 | version = "0.2.16" 1560 | source = "registry+https://github.com/rust-lang/crates.io-index" 1561 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1562 | 1563 | [[package]] 1564 | name = "pin-utils" 1565 | version = "0.1.0" 1566 | source = "registry+https://github.com/rust-lang/crates.io-index" 1567 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1568 | 1569 | [[package]] 1570 | name = "pkcs8" 1571 | version = "0.9.0" 1572 | source = "registry+https://github.com/rust-lang/crates.io-index" 1573 | checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" 1574 | dependencies = [ 1575 | "der", 1576 | "spki", 1577 | ] 1578 | 1579 | [[package]] 1580 | name = "portable-atomic" 1581 | version = "1.10.0" 1582 | source = "registry+https://github.com/rust-lang/crates.io-index" 1583 | checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" 1584 | 1585 | [[package]] 1586 | name = "powerfmt" 1587 | version = "0.2.0" 1588 | source = "registry+https://github.com/rust-lang/crates.io-index" 1589 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1590 | 1591 | [[package]] 1592 | name = "ppv-lite86" 1593 | version = "0.2.20" 1594 | source = "registry+https://github.com/rust-lang/crates.io-index" 1595 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 1596 | dependencies = [ 1597 | "zerocopy", 1598 | ] 1599 | 1600 | [[package]] 1601 | name = "proc-macro2" 1602 | version = "1.0.93" 1603 | source = "registry+https://github.com/rust-lang/crates.io-index" 1604 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 1605 | dependencies = [ 1606 | "unicode-ident", 1607 | ] 1608 | 1609 | [[package]] 1610 | name = "quote" 1611 | version = "1.0.38" 1612 | source = "registry+https://github.com/rust-lang/crates.io-index" 1613 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 1614 | dependencies = [ 1615 | "proc-macro2", 1616 | ] 1617 | 1618 | [[package]] 1619 | name = "rand" 1620 | version = "0.8.5" 1621 | source = "registry+https://github.com/rust-lang/crates.io-index" 1622 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1623 | dependencies = [ 1624 | "libc", 1625 | "rand_chacha", 1626 | "rand_core", 1627 | ] 1628 | 1629 | [[package]] 1630 | name = "rand_chacha" 1631 | version = "0.3.1" 1632 | source = "registry+https://github.com/rust-lang/crates.io-index" 1633 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1634 | dependencies = [ 1635 | "ppv-lite86", 1636 | "rand_core", 1637 | ] 1638 | 1639 | [[package]] 1640 | name = "rand_core" 1641 | version = "0.6.4" 1642 | source = "registry+https://github.com/rust-lang/crates.io-index" 1643 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1644 | dependencies = [ 1645 | "getrandom", 1646 | ] 1647 | 1648 | [[package]] 1649 | name = "redox_syscall" 1650 | version = "0.5.8" 1651 | source = "registry+https://github.com/rust-lang/crates.io-index" 1652 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 1653 | dependencies = [ 1654 | "bitflags", 1655 | ] 1656 | 1657 | [[package]] 1658 | name = "regex" 1659 | version = "1.11.1" 1660 | source = "registry+https://github.com/rust-lang/crates.io-index" 1661 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1662 | dependencies = [ 1663 | "aho-corasick", 1664 | "memchr", 1665 | "regex-automata 0.4.9", 1666 | "regex-syntax 0.8.5", 1667 | ] 1668 | 1669 | [[package]] 1670 | name = "regex-automata" 1671 | version = "0.1.10" 1672 | source = "registry+https://github.com/rust-lang/crates.io-index" 1673 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1674 | dependencies = [ 1675 | "regex-syntax 0.6.29", 1676 | ] 1677 | 1678 | [[package]] 1679 | name = "regex-automata" 1680 | version = "0.4.9" 1681 | source = "registry+https://github.com/rust-lang/crates.io-index" 1682 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1683 | dependencies = [ 1684 | "aho-corasick", 1685 | "memchr", 1686 | "regex-syntax 0.8.5", 1687 | ] 1688 | 1689 | [[package]] 1690 | name = "regex-lite" 1691 | version = "0.1.6" 1692 | source = "registry+https://github.com/rust-lang/crates.io-index" 1693 | checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" 1694 | 1695 | [[package]] 1696 | name = "regex-syntax" 1697 | version = "0.6.29" 1698 | source = "registry+https://github.com/rust-lang/crates.io-index" 1699 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 1700 | 1701 | [[package]] 1702 | name = "regex-syntax" 1703 | version = "0.8.5" 1704 | source = "registry+https://github.com/rust-lang/crates.io-index" 1705 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1706 | 1707 | [[package]] 1708 | name = "rfc6979" 1709 | version = "0.3.1" 1710 | source = "registry+https://github.com/rust-lang/crates.io-index" 1711 | checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" 1712 | dependencies = [ 1713 | "crypto-bigint 0.4.9", 1714 | "hmac", 1715 | "zeroize", 1716 | ] 1717 | 1718 | [[package]] 1719 | name = "ring" 1720 | version = "0.17.8" 1721 | source = "registry+https://github.com/rust-lang/crates.io-index" 1722 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1723 | dependencies = [ 1724 | "cc", 1725 | "cfg-if", 1726 | "getrandom", 1727 | "libc", 1728 | "spin", 1729 | "untrusted", 1730 | "windows-sys 0.52.0", 1731 | ] 1732 | 1733 | [[package]] 1734 | name = "rustc-demangle" 1735 | version = "0.1.24" 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" 1737 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1738 | 1739 | [[package]] 1740 | name = "rustc_version" 1741 | version = "0.4.1" 1742 | source = "registry+https://github.com/rust-lang/crates.io-index" 1743 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 1744 | dependencies = [ 1745 | "semver", 1746 | ] 1747 | 1748 | [[package]] 1749 | name = "rustix" 1750 | version = "0.38.44" 1751 | source = "registry+https://github.com/rust-lang/crates.io-index" 1752 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 1753 | dependencies = [ 1754 | "bitflags", 1755 | "errno", 1756 | "libc", 1757 | "linux-raw-sys", 1758 | "windows-sys 0.59.0", 1759 | ] 1760 | 1761 | [[package]] 1762 | name = "rustls" 1763 | version = "0.21.12" 1764 | source = "registry+https://github.com/rust-lang/crates.io-index" 1765 | checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" 1766 | dependencies = [ 1767 | "log", 1768 | "ring", 1769 | "rustls-webpki", 1770 | "sct", 1771 | ] 1772 | 1773 | [[package]] 1774 | name = "rustls-native-certs" 1775 | version = "0.6.3" 1776 | source = "registry+https://github.com/rust-lang/crates.io-index" 1777 | checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" 1778 | dependencies = [ 1779 | "openssl-probe", 1780 | "rustls-pemfile", 1781 | "schannel", 1782 | "security-framework", 1783 | ] 1784 | 1785 | [[package]] 1786 | name = "rustls-pemfile" 1787 | version = "1.0.4" 1788 | source = "registry+https://github.com/rust-lang/crates.io-index" 1789 | checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" 1790 | dependencies = [ 1791 | "base64", 1792 | ] 1793 | 1794 | [[package]] 1795 | name = "rustls-webpki" 1796 | version = "0.101.7" 1797 | source = "registry+https://github.com/rust-lang/crates.io-index" 1798 | checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" 1799 | dependencies = [ 1800 | "ring", 1801 | "untrusted", 1802 | ] 1803 | 1804 | [[package]] 1805 | name = "rustversion" 1806 | version = "1.0.19" 1807 | source = "registry+https://github.com/rust-lang/crates.io-index" 1808 | checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" 1809 | 1810 | [[package]] 1811 | name = "ryu" 1812 | version = "1.0.18" 1813 | source = "registry+https://github.com/rust-lang/crates.io-index" 1814 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1815 | 1816 | [[package]] 1817 | name = "schannel" 1818 | version = "0.1.27" 1819 | source = "registry+https://github.com/rust-lang/crates.io-index" 1820 | checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 1821 | dependencies = [ 1822 | "windows-sys 0.59.0", 1823 | ] 1824 | 1825 | [[package]] 1826 | name = "scoped-tls" 1827 | version = "1.0.1" 1828 | source = "registry+https://github.com/rust-lang/crates.io-index" 1829 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 1830 | 1831 | [[package]] 1832 | name = "scopeguard" 1833 | version = "1.2.0" 1834 | source = "registry+https://github.com/rust-lang/crates.io-index" 1835 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1836 | 1837 | [[package]] 1838 | name = "sct" 1839 | version = "0.7.1" 1840 | source = "registry+https://github.com/rust-lang/crates.io-index" 1841 | checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" 1842 | dependencies = [ 1843 | "ring", 1844 | "untrusted", 1845 | ] 1846 | 1847 | [[package]] 1848 | name = "sec1" 1849 | version = "0.3.0" 1850 | source = "registry+https://github.com/rust-lang/crates.io-index" 1851 | checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" 1852 | dependencies = [ 1853 | "base16ct", 1854 | "der", 1855 | "generic-array", 1856 | "pkcs8", 1857 | "subtle", 1858 | "zeroize", 1859 | ] 1860 | 1861 | [[package]] 1862 | name = "security-framework" 1863 | version = "2.11.1" 1864 | source = "registry+https://github.com/rust-lang/crates.io-index" 1865 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1866 | dependencies = [ 1867 | "bitflags", 1868 | "core-foundation", 1869 | "core-foundation-sys", 1870 | "libc", 1871 | "security-framework-sys", 1872 | ] 1873 | 1874 | [[package]] 1875 | name = "security-framework-sys" 1876 | version = "2.14.0" 1877 | source = "registry+https://github.com/rust-lang/crates.io-index" 1878 | checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" 1879 | dependencies = [ 1880 | "core-foundation-sys", 1881 | "libc", 1882 | ] 1883 | 1884 | [[package]] 1885 | name = "semver" 1886 | version = "1.0.25" 1887 | source = "registry+https://github.com/rust-lang/crates.io-index" 1888 | checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" 1889 | 1890 | [[package]] 1891 | name = "serde" 1892 | version = "1.0.217" 1893 | source = "registry+https://github.com/rust-lang/crates.io-index" 1894 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 1895 | dependencies = [ 1896 | "serde_derive", 1897 | ] 1898 | 1899 | [[package]] 1900 | name = "serde_derive" 1901 | version = "1.0.217" 1902 | source = "registry+https://github.com/rust-lang/crates.io-index" 1903 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 1904 | dependencies = [ 1905 | "proc-macro2", 1906 | "quote", 1907 | "syn", 1908 | ] 1909 | 1910 | [[package]] 1911 | name = "serde_json" 1912 | version = "1.0.137" 1913 | source = "registry+https://github.com/rust-lang/crates.io-index" 1914 | checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" 1915 | dependencies = [ 1916 | "itoa", 1917 | "memchr", 1918 | "ryu", 1919 | "serde", 1920 | ] 1921 | 1922 | [[package]] 1923 | name = "serde_spanned" 1924 | version = "0.6.8" 1925 | source = "registry+https://github.com/rust-lang/crates.io-index" 1926 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1927 | dependencies = [ 1928 | "serde", 1929 | ] 1930 | 1931 | [[package]] 1932 | name = "sha1" 1933 | version = "0.10.6" 1934 | source = "registry+https://github.com/rust-lang/crates.io-index" 1935 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1936 | dependencies = [ 1937 | "cfg-if", 1938 | "cpufeatures", 1939 | "digest", 1940 | ] 1941 | 1942 | [[package]] 1943 | name = "sha2" 1944 | version = "0.10.8" 1945 | source = "registry+https://github.com/rust-lang/crates.io-index" 1946 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1947 | dependencies = [ 1948 | "cfg-if", 1949 | "cpufeatures", 1950 | "digest", 1951 | ] 1952 | 1953 | [[package]] 1954 | name = "sharded-slab" 1955 | version = "0.1.7" 1956 | source = "registry+https://github.com/rust-lang/crates.io-index" 1957 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1958 | dependencies = [ 1959 | "lazy_static", 1960 | ] 1961 | 1962 | [[package]] 1963 | name = "shlex" 1964 | version = "1.3.0" 1965 | source = "registry+https://github.com/rust-lang/crates.io-index" 1966 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1967 | 1968 | [[package]] 1969 | name = "signature" 1970 | version = "1.6.4" 1971 | source = "registry+https://github.com/rust-lang/crates.io-index" 1972 | checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" 1973 | dependencies = [ 1974 | "digest", 1975 | "rand_core", 1976 | ] 1977 | 1978 | [[package]] 1979 | name = "slab" 1980 | version = "0.4.9" 1981 | source = "registry+https://github.com/rust-lang/crates.io-index" 1982 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1983 | dependencies = [ 1984 | "autocfg", 1985 | ] 1986 | 1987 | [[package]] 1988 | name = "smallvec" 1989 | version = "1.13.2" 1990 | source = "registry+https://github.com/rust-lang/crates.io-index" 1991 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1992 | 1993 | [[package]] 1994 | name = "socket2" 1995 | version = "0.5.8" 1996 | source = "registry+https://github.com/rust-lang/crates.io-index" 1997 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 1998 | dependencies = [ 1999 | "libc", 2000 | "windows-sys 0.52.0", 2001 | ] 2002 | 2003 | [[package]] 2004 | name = "spin" 2005 | version = "0.9.8" 2006 | source = "registry+https://github.com/rust-lang/crates.io-index" 2007 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 2008 | 2009 | [[package]] 2010 | name = "spki" 2011 | version = "0.6.0" 2012 | source = "registry+https://github.com/rust-lang/crates.io-index" 2013 | checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" 2014 | dependencies = [ 2015 | "base64ct", 2016 | "der", 2017 | ] 2018 | 2019 | [[package]] 2020 | name = "stable_deref_trait" 2021 | version = "1.2.0" 2022 | source = "registry+https://github.com/rust-lang/crates.io-index" 2023 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 2024 | 2025 | [[package]] 2026 | name = "strsim" 2027 | version = "0.11.1" 2028 | source = "registry+https://github.com/rust-lang/crates.io-index" 2029 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 2030 | 2031 | [[package]] 2032 | name = "subtle" 2033 | version = "2.6.1" 2034 | source = "registry+https://github.com/rust-lang/crates.io-index" 2035 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 2036 | 2037 | [[package]] 2038 | name = "syn" 2039 | version = "2.0.96" 2040 | source = "registry+https://github.com/rust-lang/crates.io-index" 2041 | checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" 2042 | dependencies = [ 2043 | "proc-macro2", 2044 | "quote", 2045 | "unicode-ident", 2046 | ] 2047 | 2048 | [[package]] 2049 | name = "synstructure" 2050 | version = "0.13.1" 2051 | source = "registry+https://github.com/rust-lang/crates.io-index" 2052 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 2053 | dependencies = [ 2054 | "proc-macro2", 2055 | "quote", 2056 | "syn", 2057 | ] 2058 | 2059 | [[package]] 2060 | name = "tagptr" 2061 | version = "0.2.0" 2062 | source = "registry+https://github.com/rust-lang/crates.io-index" 2063 | checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" 2064 | 2065 | [[package]] 2066 | name = "tempfile" 2067 | version = "3.15.0" 2068 | source = "registry+https://github.com/rust-lang/crates.io-index" 2069 | checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" 2070 | dependencies = [ 2071 | "cfg-if", 2072 | "fastrand", 2073 | "getrandom", 2074 | "once_cell", 2075 | "rustix", 2076 | "windows-sys 0.59.0", 2077 | ] 2078 | 2079 | [[package]] 2080 | name = "thiserror" 2081 | version = "1.0.69" 2082 | source = "registry+https://github.com/rust-lang/crates.io-index" 2083 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 2084 | dependencies = [ 2085 | "thiserror-impl", 2086 | ] 2087 | 2088 | [[package]] 2089 | name = "thiserror-impl" 2090 | version = "1.0.69" 2091 | source = "registry+https://github.com/rust-lang/crates.io-index" 2092 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 2093 | dependencies = [ 2094 | "proc-macro2", 2095 | "quote", 2096 | "syn", 2097 | ] 2098 | 2099 | [[package]] 2100 | name = "thread_local" 2101 | version = "1.1.8" 2102 | source = "registry+https://github.com/rust-lang/crates.io-index" 2103 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 2104 | dependencies = [ 2105 | "cfg-if", 2106 | "once_cell", 2107 | ] 2108 | 2109 | [[package]] 2110 | name = "time" 2111 | version = "0.3.37" 2112 | source = "registry+https://github.com/rust-lang/crates.io-index" 2113 | checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" 2114 | dependencies = [ 2115 | "deranged", 2116 | "num-conv", 2117 | "powerfmt", 2118 | "serde", 2119 | "time-core", 2120 | "time-macros", 2121 | ] 2122 | 2123 | [[package]] 2124 | name = "time-core" 2125 | version = "0.1.2" 2126 | source = "registry+https://github.com/rust-lang/crates.io-index" 2127 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 2128 | 2129 | [[package]] 2130 | name = "time-macros" 2131 | version = "0.2.19" 2132 | source = "registry+https://github.com/rust-lang/crates.io-index" 2133 | checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" 2134 | dependencies = [ 2135 | "num-conv", 2136 | "time-core", 2137 | ] 2138 | 2139 | [[package]] 2140 | name = "tinystr" 2141 | version = "0.7.6" 2142 | source = "registry+https://github.com/rust-lang/crates.io-index" 2143 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 2144 | dependencies = [ 2145 | "displaydoc", 2146 | "zerovec", 2147 | ] 2148 | 2149 | [[package]] 2150 | name = "tokio" 2151 | version = "1.43.0" 2152 | source = "registry+https://github.com/rust-lang/crates.io-index" 2153 | checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" 2154 | dependencies = [ 2155 | "backtrace", 2156 | "bytes", 2157 | "libc", 2158 | "mio", 2159 | "pin-project-lite", 2160 | "socket2", 2161 | "windows-sys 0.52.0", 2162 | ] 2163 | 2164 | [[package]] 2165 | name = "tokio-rustls" 2166 | version = "0.24.1" 2167 | source = "registry+https://github.com/rust-lang/crates.io-index" 2168 | checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" 2169 | dependencies = [ 2170 | "rustls", 2171 | "tokio", 2172 | ] 2173 | 2174 | [[package]] 2175 | name = "tokio-util" 2176 | version = "0.7.13" 2177 | source = "registry+https://github.com/rust-lang/crates.io-index" 2178 | checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" 2179 | dependencies = [ 2180 | "bytes", 2181 | "futures-core", 2182 | "futures-sink", 2183 | "pin-project-lite", 2184 | "tokio", 2185 | ] 2186 | 2187 | [[package]] 2188 | name = "toml" 2189 | version = "0.8.19" 2190 | source = "registry+https://github.com/rust-lang/crates.io-index" 2191 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 2192 | dependencies = [ 2193 | "serde", 2194 | "serde_spanned", 2195 | "toml_datetime", 2196 | "toml_edit", 2197 | ] 2198 | 2199 | [[package]] 2200 | name = "toml_datetime" 2201 | version = "0.6.8" 2202 | source = "registry+https://github.com/rust-lang/crates.io-index" 2203 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 2204 | dependencies = [ 2205 | "serde", 2206 | ] 2207 | 2208 | [[package]] 2209 | name = "toml_edit" 2210 | version = "0.22.22" 2211 | source = "registry+https://github.com/rust-lang/crates.io-index" 2212 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 2213 | dependencies = [ 2214 | "indexmap", 2215 | "serde", 2216 | "serde_spanned", 2217 | "toml_datetime", 2218 | "winnow", 2219 | ] 2220 | 2221 | [[package]] 2222 | name = "tower-service" 2223 | version = "0.3.3" 2224 | source = "registry+https://github.com/rust-lang/crates.io-index" 2225 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 2226 | 2227 | [[package]] 2228 | name = "tracing" 2229 | version = "0.1.41" 2230 | source = "registry+https://github.com/rust-lang/crates.io-index" 2231 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 2232 | dependencies = [ 2233 | "pin-project-lite", 2234 | "tracing-attributes", 2235 | "tracing-core", 2236 | ] 2237 | 2238 | [[package]] 2239 | name = "tracing-attributes" 2240 | version = "0.1.28" 2241 | source = "registry+https://github.com/rust-lang/crates.io-index" 2242 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 2243 | dependencies = [ 2244 | "proc-macro2", 2245 | "quote", 2246 | "syn", 2247 | ] 2248 | 2249 | [[package]] 2250 | name = "tracing-core" 2251 | version = "0.1.33" 2252 | source = "registry+https://github.com/rust-lang/crates.io-index" 2253 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 2254 | dependencies = [ 2255 | "once_cell", 2256 | "valuable", 2257 | ] 2258 | 2259 | [[package]] 2260 | name = "tracing-log" 2261 | version = "0.2.0" 2262 | source = "registry+https://github.com/rust-lang/crates.io-index" 2263 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 2264 | dependencies = [ 2265 | "log", 2266 | "once_cell", 2267 | "tracing-core", 2268 | ] 2269 | 2270 | [[package]] 2271 | name = "tracing-subscriber" 2272 | version = "0.3.19" 2273 | source = "registry+https://github.com/rust-lang/crates.io-index" 2274 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 2275 | dependencies = [ 2276 | "matchers", 2277 | "nu-ansi-term", 2278 | "once_cell", 2279 | "regex", 2280 | "sharded-slab", 2281 | "smallvec", 2282 | "thread_local", 2283 | "tracing", 2284 | "tracing-core", 2285 | "tracing-log", 2286 | ] 2287 | 2288 | [[package]] 2289 | name = "try-lock" 2290 | version = "0.2.5" 2291 | source = "registry+https://github.com/rust-lang/crates.io-index" 2292 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2293 | 2294 | [[package]] 2295 | name = "typenum" 2296 | version = "1.17.0" 2297 | source = "registry+https://github.com/rust-lang/crates.io-index" 2298 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 2299 | 2300 | [[package]] 2301 | name = "unicode-ident" 2302 | version = "1.0.15" 2303 | source = "registry+https://github.com/rust-lang/crates.io-index" 2304 | checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" 2305 | 2306 | [[package]] 2307 | name = "untrusted" 2308 | version = "0.9.0" 2309 | source = "registry+https://github.com/rust-lang/crates.io-index" 2310 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2311 | 2312 | [[package]] 2313 | name = "url" 2314 | version = "2.5.4" 2315 | source = "registry+https://github.com/rust-lang/crates.io-index" 2316 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 2317 | dependencies = [ 2318 | "form_urlencoded", 2319 | "idna", 2320 | "percent-encoding", 2321 | ] 2322 | 2323 | [[package]] 2324 | name = "utf16_iter" 2325 | version = "1.0.5" 2326 | source = "registry+https://github.com/rust-lang/crates.io-index" 2327 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 2328 | 2329 | [[package]] 2330 | name = "utf8_iter" 2331 | version = "1.0.4" 2332 | source = "registry+https://github.com/rust-lang/crates.io-index" 2333 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 2334 | 2335 | [[package]] 2336 | name = "utf8parse" 2337 | version = "0.2.2" 2338 | source = "registry+https://github.com/rust-lang/crates.io-index" 2339 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 2340 | 2341 | [[package]] 2342 | name = "uuid" 2343 | version = "1.12.1" 2344 | source = "registry+https://github.com/rust-lang/crates.io-index" 2345 | checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" 2346 | dependencies = [ 2347 | "getrandom", 2348 | ] 2349 | 2350 | [[package]] 2351 | name = "valuable" 2352 | version = "0.1.1" 2353 | source = "registry+https://github.com/rust-lang/crates.io-index" 2354 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 2355 | 2356 | [[package]] 2357 | name = "version_check" 2358 | version = "0.9.5" 2359 | source = "registry+https://github.com/rust-lang/crates.io-index" 2360 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 2361 | 2362 | [[package]] 2363 | name = "vnotify" 2364 | version = "0.1.0" 2365 | dependencies = [ 2366 | "anyhow", 2367 | "aws-sdk-s3", 2368 | "blake3", 2369 | "bytes", 2370 | "faster-hex", 2371 | "futures", 2372 | "moka", 2373 | "rand", 2374 | "tokio", 2375 | "tracing", 2376 | ] 2377 | 2378 | [[package]] 2379 | name = "vsimd" 2380 | version = "0.8.0" 2381 | source = "registry+https://github.com/rust-lang/crates.io-index" 2382 | checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" 2383 | 2384 | [[package]] 2385 | name = "want" 2386 | version = "0.3.1" 2387 | source = "registry+https://github.com/rust-lang/crates.io-index" 2388 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2389 | dependencies = [ 2390 | "try-lock", 2391 | ] 2392 | 2393 | [[package]] 2394 | name = "wasi" 2395 | version = "0.11.0+wasi-snapshot-preview1" 2396 | source = "registry+https://github.com/rust-lang/crates.io-index" 2397 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2398 | 2399 | [[package]] 2400 | name = "winapi" 2401 | version = "0.3.9" 2402 | source = "registry+https://github.com/rust-lang/crates.io-index" 2403 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2404 | dependencies = [ 2405 | "winapi-i686-pc-windows-gnu", 2406 | "winapi-x86_64-pc-windows-gnu", 2407 | ] 2408 | 2409 | [[package]] 2410 | name = "winapi-i686-pc-windows-gnu" 2411 | version = "0.4.0" 2412 | source = "registry+https://github.com/rust-lang/crates.io-index" 2413 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2414 | 2415 | [[package]] 2416 | name = "winapi-x86_64-pc-windows-gnu" 2417 | version = "0.4.0" 2418 | source = "registry+https://github.com/rust-lang/crates.io-index" 2419 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2420 | 2421 | [[package]] 2422 | name = "windows" 2423 | version = "0.58.0" 2424 | source = "registry+https://github.com/rust-lang/crates.io-index" 2425 | checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" 2426 | dependencies = [ 2427 | "windows-core", 2428 | "windows-targets", 2429 | ] 2430 | 2431 | [[package]] 2432 | name = "windows-core" 2433 | version = "0.58.0" 2434 | source = "registry+https://github.com/rust-lang/crates.io-index" 2435 | checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" 2436 | dependencies = [ 2437 | "windows-implement", 2438 | "windows-interface", 2439 | "windows-result", 2440 | "windows-strings", 2441 | "windows-targets", 2442 | ] 2443 | 2444 | [[package]] 2445 | name = "windows-implement" 2446 | version = "0.58.0" 2447 | source = "registry+https://github.com/rust-lang/crates.io-index" 2448 | checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" 2449 | dependencies = [ 2450 | "proc-macro2", 2451 | "quote", 2452 | "syn", 2453 | ] 2454 | 2455 | [[package]] 2456 | name = "windows-interface" 2457 | version = "0.58.0" 2458 | source = "registry+https://github.com/rust-lang/crates.io-index" 2459 | checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" 2460 | dependencies = [ 2461 | "proc-macro2", 2462 | "quote", 2463 | "syn", 2464 | ] 2465 | 2466 | [[package]] 2467 | name = "windows-result" 2468 | version = "0.2.0" 2469 | source = "registry+https://github.com/rust-lang/crates.io-index" 2470 | checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" 2471 | dependencies = [ 2472 | "windows-targets", 2473 | ] 2474 | 2475 | [[package]] 2476 | name = "windows-strings" 2477 | version = "0.1.0" 2478 | source = "registry+https://github.com/rust-lang/crates.io-index" 2479 | checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" 2480 | dependencies = [ 2481 | "windows-result", 2482 | "windows-targets", 2483 | ] 2484 | 2485 | [[package]] 2486 | name = "windows-sys" 2487 | version = "0.52.0" 2488 | source = "registry+https://github.com/rust-lang/crates.io-index" 2489 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2490 | dependencies = [ 2491 | "windows-targets", 2492 | ] 2493 | 2494 | [[package]] 2495 | name = "windows-sys" 2496 | version = "0.59.0" 2497 | source = "registry+https://github.com/rust-lang/crates.io-index" 2498 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 2499 | dependencies = [ 2500 | "windows-targets", 2501 | ] 2502 | 2503 | [[package]] 2504 | name = "windows-targets" 2505 | version = "0.52.6" 2506 | source = "registry+https://github.com/rust-lang/crates.io-index" 2507 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2508 | dependencies = [ 2509 | "windows_aarch64_gnullvm", 2510 | "windows_aarch64_msvc", 2511 | "windows_i686_gnu", 2512 | "windows_i686_gnullvm", 2513 | "windows_i686_msvc", 2514 | "windows_x86_64_gnu", 2515 | "windows_x86_64_gnullvm", 2516 | "windows_x86_64_msvc", 2517 | ] 2518 | 2519 | [[package]] 2520 | name = "windows_aarch64_gnullvm" 2521 | version = "0.52.6" 2522 | source = "registry+https://github.com/rust-lang/crates.io-index" 2523 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2524 | 2525 | [[package]] 2526 | name = "windows_aarch64_msvc" 2527 | version = "0.52.6" 2528 | source = "registry+https://github.com/rust-lang/crates.io-index" 2529 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2530 | 2531 | [[package]] 2532 | name = "windows_i686_gnu" 2533 | version = "0.52.6" 2534 | source = "registry+https://github.com/rust-lang/crates.io-index" 2535 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2536 | 2537 | [[package]] 2538 | name = "windows_i686_gnullvm" 2539 | version = "0.52.6" 2540 | source = "registry+https://github.com/rust-lang/crates.io-index" 2541 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2542 | 2543 | [[package]] 2544 | name = "windows_i686_msvc" 2545 | version = "0.52.6" 2546 | source = "registry+https://github.com/rust-lang/crates.io-index" 2547 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2548 | 2549 | [[package]] 2550 | name = "windows_x86_64_gnu" 2551 | version = "0.52.6" 2552 | source = "registry+https://github.com/rust-lang/crates.io-index" 2553 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2554 | 2555 | [[package]] 2556 | name = "windows_x86_64_gnullvm" 2557 | version = "0.52.6" 2558 | source = "registry+https://github.com/rust-lang/crates.io-index" 2559 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2560 | 2561 | [[package]] 2562 | name = "windows_x86_64_msvc" 2563 | version = "0.52.6" 2564 | source = "registry+https://github.com/rust-lang/crates.io-index" 2565 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2566 | 2567 | [[package]] 2568 | name = "winnow" 2569 | version = "0.6.24" 2570 | source = "registry+https://github.com/rust-lang/crates.io-index" 2571 | checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" 2572 | dependencies = [ 2573 | "memchr", 2574 | ] 2575 | 2576 | [[package]] 2577 | name = "write16" 2578 | version = "1.0.0" 2579 | source = "registry+https://github.com/rust-lang/crates.io-index" 2580 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 2581 | 2582 | [[package]] 2583 | name = "writeable" 2584 | version = "0.5.5" 2585 | source = "registry+https://github.com/rust-lang/crates.io-index" 2586 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 2587 | 2588 | [[package]] 2589 | name = "xmlparser" 2590 | version = "0.13.6" 2591 | source = "registry+https://github.com/rust-lang/crates.io-index" 2592 | checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" 2593 | 2594 | [[package]] 2595 | name = "yoke" 2596 | version = "0.7.5" 2597 | source = "registry+https://github.com/rust-lang/crates.io-index" 2598 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 2599 | dependencies = [ 2600 | "serde", 2601 | "stable_deref_trait", 2602 | "yoke-derive", 2603 | "zerofrom", 2604 | ] 2605 | 2606 | [[package]] 2607 | name = "yoke-derive" 2608 | version = "0.7.5" 2609 | source = "registry+https://github.com/rust-lang/crates.io-index" 2610 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 2611 | dependencies = [ 2612 | "proc-macro2", 2613 | "quote", 2614 | "syn", 2615 | "synstructure", 2616 | ] 2617 | 2618 | [[package]] 2619 | name = "zerocopy" 2620 | version = "0.7.35" 2621 | source = "registry+https://github.com/rust-lang/crates.io-index" 2622 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2623 | dependencies = [ 2624 | "byteorder", 2625 | "zerocopy-derive", 2626 | ] 2627 | 2628 | [[package]] 2629 | name = "zerocopy-derive" 2630 | version = "0.7.35" 2631 | source = "registry+https://github.com/rust-lang/crates.io-index" 2632 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2633 | dependencies = [ 2634 | "proc-macro2", 2635 | "quote", 2636 | "syn", 2637 | ] 2638 | 2639 | [[package]] 2640 | name = "zerofrom" 2641 | version = "0.1.5" 2642 | source = "registry+https://github.com/rust-lang/crates.io-index" 2643 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 2644 | dependencies = [ 2645 | "zerofrom-derive", 2646 | ] 2647 | 2648 | [[package]] 2649 | name = "zerofrom-derive" 2650 | version = "0.1.5" 2651 | source = "registry+https://github.com/rust-lang/crates.io-index" 2652 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 2653 | dependencies = [ 2654 | "proc-macro2", 2655 | "quote", 2656 | "syn", 2657 | "synstructure", 2658 | ] 2659 | 2660 | [[package]] 2661 | name = "zeroize" 2662 | version = "1.8.1" 2663 | source = "registry+https://github.com/rust-lang/crates.io-index" 2664 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2665 | 2666 | [[package]] 2667 | name = "zerovec" 2668 | version = "0.10.4" 2669 | source = "registry+https://github.com/rust-lang/crates.io-index" 2670 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 2671 | dependencies = [ 2672 | "yoke", 2673 | "zerofrom", 2674 | "zerovec-derive", 2675 | ] 2676 | 2677 | [[package]] 2678 | name = "zerovec-derive" 2679 | version = "0.10.3" 2680 | source = "registry+https://github.com/rust-lang/crates.io-index" 2681 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 2682 | dependencies = [ 2683 | "proc-macro2", 2684 | "quote", 2685 | "syn", 2686 | ] 2687 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vnotify" 3 | description = "Efficiently monitor S3 changes without external dependencies" 4 | version = "0.1.0" 5 | edition = "2021" 6 | authors = ["the Deno authors"] 7 | license = "MIT" 8 | repository = "https://github.com/denoland/vnotify" 9 | 10 | [dependencies] 11 | anyhow = "1" 12 | aws-sdk-s3 = "1" 13 | blake3 = "1" 14 | bytes = "1" 15 | faster-hex = "0.9" 16 | futures = "0.3" 17 | moka = { version = "0.12", features = ["future", "sync"] } 18 | rand = "0.8" 19 | tokio = { version = "1", features = ["sync", "time"] } 20 | tracing = "0.1" 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2025 the Deno authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vnotify 2 | 3 | `vnotify` ("vectorized notification") is a lightweight library for monitoring S3 4 | changes efficiently without external dependencies. It allows to detect changes 5 | on millions of objects with one `HeadObject` and sometimes one `ListObjectsV2` 6 | call. 7 | 8 | `vnotify` uses a fixed-size S3 keyspace as a "hash map" to signal bucket-wide 9 | changes. For example, when an update is made to `path/to/object`: 10 | 11 | - an index into the hashmap is calculated as 12 | `vnotify_index = uint64_le(blake3("path/to/object")[0..8]) % vnotify_keyspace_size` 13 | - a random string is written into `vnotify_prefix/vnotify_index`. 14 | - a random string is written into `vnotify_prefix/_`. 15 | 16 | The S3 `ListObjectsV2` API returns the ETag of each object, and a change in ETag 17 | indicates that this "hash map" slot has changed and clients' local cache needs 18 | to be invalidated for that shard. 19 | 20 | AWS S3 `ListObjectsV2` can return a maximum of 1000 keys per invocation, so 21 | `vnotify_keyspace_size` is set to `1000`. A client that wishes to listen for 22 | changes only needs to make 1 `HeadObject` call to `vnotify_prefix/_` to check if 23 | any changes have been made, and then make 1 `ListObjectsV2` call in order to 24 | revalidate its entire local cache. 25 | 26 | ``` 27 | /vnotify/_ 28 | /vnotify/0 29 | /vnotify/1 30 | /vnotify/2 31 | /vnotify/3 32 | ... 33 | /vnotify/999 34 | ``` 35 | 36 | ## Causal consistency 37 | 38 | Certain use cases require causal consistency. Specifically, if an object is 39 | created based on the assumption that a set of updates have been made to other 40 | objects, a reader must not observe inversed causality. 41 | 42 | `vnotify` solves this problem by forcing a revalidation after a newly-seen 43 | object is loaded from S3. The revalidation `HeadObject` call happens 44 | concurrently with the `GetObject` call, so this operation does not incur 45 | additional latency in the optimistic case. 46 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.84.0" 3 | components = ["rustfmt", "clippy"] 4 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | tab_spaces = 2 2 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2025 the Deno authors. MIT license. 2 | 3 | use std::{ 4 | cmp::Reverse, 5 | collections::{BinaryHeap, HashSet}, 6 | sync::{ 7 | atomic::{AtomicU64, AtomicUsize, Ordering}, 8 | Arc, 9 | }, 10 | time::{Duration, Instant, SystemTime}, 11 | }; 12 | 13 | use aws_sdk_s3::primitives::ByteStream; 14 | use bytes::Bytes; 15 | use futures::{stream::FuturesUnordered, StreamExt, TryFutureExt}; 16 | use rand::Rng; 17 | use tokio::{sync::oneshot, task::JoinSet}; 18 | 19 | /// Max number of keys returned in an S3 ListObjectsV2 response 20 | pub const LIST_OBJECT_LIMIT: u32 = 1000; 21 | 22 | pub struct VnotifyCache { 23 | _join_set: JoinSet<()>, 24 | shards: Arc<[Shard]>, 25 | client: aws_sdk_s3::Client, 26 | config: Config, 27 | fencing_queue_tx: tokio::sync::mpsc::UnboundedSender>, 28 | } 29 | 30 | #[derive(Debug, Clone)] 31 | pub enum WriteCondition { 32 | Unconditional, 33 | IfNotPresent, 34 | IfMatchEtag(String), 35 | } 36 | 37 | // Configuration for a `VnotifyCache`. 38 | #[derive(Clone, Debug)] 39 | pub struct Config { 40 | /// S3 bucket name 41 | pub bucket: String, 42 | 43 | /// S3 bucket prefix 44 | pub prefix: String, 45 | 46 | /// Cache revalidation interval. Defaults to 1s. 47 | pub refresh_interval: Duration, 48 | 49 | /// Number of shards. This defaults to 1000, and normally should not be changed. 50 | /// All `VnotifyCache` instances that share the same S3 bucket and prefix must 51 | /// use the same `shards` value. 52 | /// 53 | /// Must be between 1 and `LIST_OBJECT_LIMIT` (1000), inclusively. 54 | pub shards: u32, 55 | 56 | /// Max number of stale-while-revalidate entries per shard after invalidation. 57 | /// Sorted by last access time, descending. Entries exceeding this limit will be dropped from cache. 58 | /// 59 | /// Defaults to 3. 60 | pub revalidate_limit: usize, 61 | 62 | time_base: Instant, 63 | } 64 | 65 | struct Shard { 66 | entries: moka::future::Cache, Option>>, 67 | } 68 | 69 | struct Entry { 70 | body: Bytes, 71 | object_etag: String, 72 | last_used_ms: AtomicU64, 73 | } 74 | 75 | #[derive(Debug, Clone)] 76 | pub struct Item { 77 | pub body: Bytes, 78 | pub object_etag: String, 79 | } 80 | 81 | impl<'a> From<&'a Entry> for Item { 82 | fn from(entry: &'a Entry) -> Self { 83 | Self { 84 | body: entry.body.clone(), 85 | object_etag: entry.object_etag.clone(), 86 | } 87 | } 88 | } 89 | 90 | impl Config { 91 | pub fn with_bucket_and_prefix(bucket: String, prefix: String) -> Self { 92 | Self { 93 | bucket, 94 | prefix, 95 | refresh_interval: Duration::from_secs(1), 96 | shards: LIST_OBJECT_LIMIT, 97 | revalidate_limit: 3, 98 | time_base: Instant::now(), 99 | } 100 | } 101 | } 102 | 103 | impl VnotifyCache { 104 | pub fn new(client: aws_sdk_s3::Client, config: Config) -> Self { 105 | assert!(config.shards >= 1 && config.shards <= LIST_OBJECT_LIMIT); 106 | tracing::info!( 107 | num_shards = config.shards, 108 | bucket = config.bucket, 109 | prefix = config.prefix, 110 | refresh_interval = ?config.refresh_interval, 111 | "created vnotify cache" 112 | ); 113 | let shards = (0..config.shards) 114 | .map(|_| Shard { 115 | entries: moka::future::Cache::builder() 116 | .time_to_idle(Duration::from_secs(600)) 117 | .support_invalidation_closures() 118 | .build(), 119 | }) 120 | .collect::>(); 121 | let (fencing_queue_tx, fencing_queue_rx) = tokio::sync::mpsc::unbounded_channel(); 122 | let mut join_set: JoinSet<()> = JoinSet::new(); 123 | join_set.spawn(refresh_worker( 124 | client.clone(), 125 | config.clone(), 126 | shards.clone(), 127 | fencing_queue_rx, 128 | )); 129 | Self { 130 | _join_set: join_set, 131 | client, 132 | shards, 133 | config, 134 | fencing_queue_tx, 135 | } 136 | } 137 | 138 | pub async fn try_get(&self, key: &str) -> Option { 139 | let shard_index = get_shard_index_for_key(key, self.config.shards); 140 | let shard = &self.shards[shard_index]; 141 | shard 142 | .entries 143 | .get(key) 144 | .await 145 | .flatten() 146 | .map(|x| Item::from(&*x)) 147 | } 148 | 149 | pub async fn get(&self, key: &str) -> anyhow::Result> { 150 | let shard_index = get_shard_index_for_key(key, self.config.shards); 151 | let shard = &self.shards[shard_index]; 152 | shard 153 | .entries 154 | .try_get_with(Box::from(key), async { 155 | let start_time = Instant::now(); 156 | let (tx, rx) = oneshot::channel::<()>(); 157 | 158 | // Perform fencing to ensure that any potential dependency of the newly seen object is fresh. 159 | // See ARCHITECTURE.md for more details. 160 | self 161 | .fencing_queue_tx 162 | .send(tx) 163 | .map_err(|_| "fencing_queue_tx closed".to_string())?; 164 | let x = get_from_origin(&self.client, &self.config, key, None).await?; 165 | let origin_fetch_duration = start_time.elapsed(); 166 | match x { 167 | OriginResponse::Success(x) => { 168 | rx.await 169 | .map_err(|_| "failed to wait for fencing_queue response".to_string())?; 170 | let total_duration = start_time.elapsed(); 171 | tracing::info!( 172 | key, 173 | origin_fetch_duration = ?origin_fetch_duration, 174 | total_duration = ?total_duration, 175 | "fetched object from origin" 176 | ); 177 | Ok::<_, String>(Some(x)) 178 | } 179 | _ => Ok(None), 180 | } 181 | }) 182 | .map_ok(|x| { 183 | x.map(|x| { 184 | x.last_used_ms.store( 185 | self.config.time_base.elapsed().as_millis() as u64, 186 | Ordering::Relaxed, 187 | ); 188 | Item::from(&*x) 189 | }) 190 | }) 191 | .map_err(|e| anyhow::anyhow!("failed to load object from s3: {:?}", e)) 192 | .await 193 | } 194 | 195 | pub async fn evict(&self, key: &str) { 196 | let shard_index = get_shard_index_for_key(key, self.config.shards); 197 | let shard = &self.shards[shard_index]; 198 | shard.entries.invalidate(key).await; 199 | } 200 | 201 | pub async fn put(&self, key: &str, body: Bytes, cond: WriteCondition) -> anyhow::Result<()> { 202 | let shard_index = get_shard_index_for_key(key, self.config.shards); 203 | let shard = &self.shards[shard_index]; 204 | let res = self 205 | .client 206 | .put_object() 207 | .bucket(&self.config.bucket) 208 | .key(key); 209 | let res = match cond { 210 | WriteCondition::Unconditional => res, 211 | WriteCondition::IfNotPresent => res.if_none_match("*"), 212 | WriteCondition::IfMatchEtag(etag) => res.if_match(etag), 213 | }; 214 | let res = res.body(ByteStream::from(body.clone())).send().await?; 215 | let object_etag = res.e_tag.unwrap_or_default(); 216 | shard 217 | .entries 218 | .insert( 219 | Box::from(key), 220 | Some(Arc::new(Entry { 221 | body, 222 | object_etag, 223 | last_used_ms: AtomicU64::new(self.config.time_base.elapsed().as_millis() as u64), 224 | })), 225 | ) 226 | .await; 227 | let body = Bytes::from( 228 | format!( 229 | "{},{}", 230 | SystemTime::now() 231 | .duration_since(SystemTime::UNIX_EPOCH) 232 | .unwrap() 233 | .as_millis(), 234 | faster_hex::hex_string(&rand::thread_rng().gen::<[u8; 16]>()) 235 | ) 236 | .into_bytes(), 237 | ); 238 | self 239 | .client 240 | .put_object() 241 | .bucket(&self.config.bucket) 242 | .key(format!("{}{}", self.config.prefix, shard_index)) 243 | .body(ByteStream::from(body.clone())) 244 | .send() 245 | .await?; 246 | self 247 | .client 248 | .put_object() 249 | .bucket(&self.config.bucket) 250 | .key(format!("{}_", self.config.prefix)) 251 | .body(ByteStream::from(body)) 252 | .send() 253 | .await?; 254 | Ok(()) 255 | } 256 | } 257 | 258 | enum OriginResponse { 259 | Success(Arc), 260 | NotModified, 261 | Missing, 262 | } 263 | 264 | async fn get_from_origin( 265 | client: &aws_sdk_s3::Client, 266 | config: &Config, 267 | key: &str, 268 | if_none_match: Option, 269 | ) -> Result { 270 | let mut req = client.get_object().bucket(&config.bucket).key(key); 271 | if let Some(x) = if_none_match { 272 | req = req.if_none_match(x); 273 | } 274 | let res = req.send().await; 275 | match res { 276 | Ok(x) => x 277 | .body 278 | .collect() 279 | .await 280 | .map(|x| x.into_bytes()) 281 | .map_err(|e| e.to_string()) 282 | .map(|body| { 283 | OriginResponse::Success(Arc::new(Entry { 284 | body, 285 | object_etag: x.e_tag.unwrap_or_default(), 286 | last_used_ms: AtomicU64::new(config.time_base.elapsed().as_millis() as u64), 287 | })) 288 | }), 289 | 290 | Err(aws_sdk_s3::error::SdkError::ServiceError(x)) if x.raw().status().as_u16() == 304 => { 291 | Ok(OriginResponse::NotModified) 292 | } 293 | Err(aws_sdk_s3::error::SdkError::ServiceError(x)) 294 | if matches!( 295 | x.err(), 296 | aws_sdk_s3::operation::get_object::GetObjectError::NoSuchKey(_), 297 | ) => 298 | { 299 | Ok(OriginResponse::Missing) 300 | } 301 | Err(error) => Err(error.to_string()), 302 | } 303 | } 304 | fn get_shard_index_for_key(key: &str, shards: u32) -> usize { 305 | (u64::from_le_bytes(<[u8; 8]>::try_from(&blake3::hash(key.as_bytes()).as_bytes()[..8]).unwrap()) 306 | % shards as u64) as usize 307 | } 308 | 309 | async fn refresh_worker( 310 | client: aws_sdk_s3::Client, 311 | config: Config, 312 | shards: Arc<[Shard]>, 313 | mut fencing_queue_rx: tokio::sync::mpsc::UnboundedReceiver>, 314 | ) { 315 | struct Revalidation { 316 | shard_index: usize, 317 | key: Arc>, 318 | object_etag: String, 319 | } 320 | let mut global_etag: String = String::new(); 321 | 322 | let mut etags: Vec> = (0..shards.len()).map(|_| Box::from("")).collect(); 323 | 324 | let mut background = JoinSet::new(); 325 | 326 | // moka worker 327 | let shards_clone = shards.clone(); 328 | background.spawn(async move { 329 | loop { 330 | tokio::time::sleep(Duration::from_secs(5)).await; 331 | for shard in &*shards_clone { 332 | shard.entries.run_pending_tasks().await; 333 | } 334 | } 335 | }); 336 | 337 | loop { 338 | let mut fencing_requests: Vec> = vec![]; 339 | match tokio::time::timeout(config.refresh_interval, fencing_queue_rx.recv()).await { 340 | Ok(Some(x)) => { 341 | fencing_requests.push(x); 342 | while let Ok(x) = fencing_queue_rx.try_recv() { 343 | fencing_requests.push(x); 344 | } 345 | } 346 | Ok(None) => return, 347 | Err(_) => {} 348 | } 349 | let new_global_etag = match client 350 | .head_object() 351 | .bucket(&config.bucket) 352 | .key(format!("{}_", config.prefix)) 353 | .send() 354 | .await 355 | { 356 | Ok(x) => x.e_tag.unwrap_or_default(), 357 | Err(aws_sdk_s3::error::SdkError::ServiceError(x)) 358 | if matches!( 359 | x.err(), 360 | aws_sdk_s3::operation::head_object::HeadObjectError::NotFound(_), 361 | ) => 362 | { 363 | String::new() 364 | } 365 | Err(error) => { 366 | tracing::error!(?error, "head_object failed"); 367 | continue; 368 | } 369 | }; 370 | let objects = if new_global_etag == global_etag { 371 | vec![] 372 | } else { 373 | tracing::info!( 374 | old_global_etag = global_etag, 375 | new_global_etag, 376 | "global etag changed, scanning prefix" 377 | ); 378 | global_etag = new_global_etag; 379 | let res = client 380 | .list_objects_v2() 381 | .bucket(&config.bucket) 382 | .prefix(&config.prefix) 383 | .max_keys(LIST_OBJECT_LIMIT as i32) 384 | .send() 385 | .await; 386 | let res = match res { 387 | Ok(x) => x, 388 | Err(error) => { 389 | tracing::error!(?error, "refresh failed"); 390 | continue; 391 | } 392 | }; 393 | res.contents.unwrap_or_default() 394 | }; 395 | let mut revalidate_queue: Vec = vec![]; 396 | for object in &objects { 397 | let Some(etag) = object.e_tag() else { 398 | continue; 399 | }; 400 | let Some(key) = object.key().and_then(|x| x.strip_prefix(&config.prefix)) else { 401 | continue; 402 | }; 403 | if key == "_" { 404 | continue; 405 | } 406 | let Ok(shard_index) = key.parse::() else { 407 | continue; 408 | }; 409 | if shard_index >= config.shards as usize { 410 | continue; 411 | } 412 | if etag == &*etags[shard_index] { 413 | continue; 414 | } 415 | etags[shard_index] = Box::from(etag); 416 | let shard = &shards[shard_index]; 417 | let num_entries = shard.entries.entry_count(); 418 | if num_entries != 0 { 419 | #[allow(clippy::type_complexity)] 420 | let mut most_recent_entries: BinaryHeap>, String)>> = 421 | BinaryHeap::new(); 422 | let now_ms = config.time_base.elapsed().as_millis() as u64; 423 | for (k, v) in shard.entries.iter() { 424 | let Some(v) = v else { 425 | continue; 426 | }; 427 | let last_used_ms = v.last_used_ms.load(Ordering::Relaxed); 428 | if now_ms.saturating_sub(last_used_ms) > 30_000 { 429 | continue; 430 | } 431 | most_recent_entries.push(Reverse(( 432 | v.last_used_ms.load(Ordering::Relaxed), 433 | k, 434 | v.object_etag.clone(), 435 | ))); 436 | if most_recent_entries.len() > config.revalidate_limit { 437 | most_recent_entries.pop(); 438 | } 439 | } 440 | for entry in &most_recent_entries { 441 | revalidate_queue.push(Revalidation { 442 | shard_index, 443 | key: entry.0 .1.clone(), 444 | object_etag: entry.0 .2.clone(), 445 | }); 446 | } 447 | let num_most_recent_entries = most_recent_entries.len(); 448 | let most_recent_keys = most_recent_entries 449 | .into_iter() 450 | .map(|x| x.0 .1) 451 | .collect::>(); 452 | shard 453 | .entries 454 | .invalidate_entries_if(move |k, _| !most_recent_keys.contains(k)) 455 | .unwrap(); 456 | tracing::info!( 457 | shard_index, 458 | num_entries, 459 | num_most_recent_entries, 460 | "evicting entries in shard" 461 | ); 462 | } 463 | } 464 | 465 | let revalidation_start_time = Instant::now(); 466 | let num_updated = AtomicUsize::new(0usize); 467 | let num_deleted = AtomicUsize::new(0usize); 468 | let num_unmodified = AtomicUsize::new(0usize); 469 | let num_failed = AtomicUsize::new(0usize); 470 | let mut revalidate_futures = Vec::with_capacity(revalidate_queue.len()); 471 | for revalidation in revalidate_queue { 472 | let client = &client; 473 | let config = &config; 474 | let shards = &*shards; 475 | let num_updated = &num_updated; 476 | let num_deleted = &num_deleted; 477 | let num_unmodified = &num_unmodified; 478 | let num_failed = &num_failed; 479 | revalidate_futures.push(async move { 480 | match tokio::time::timeout( 481 | Duration::from_secs(5), 482 | get_from_origin( 483 | client, 484 | config, 485 | &revalidation.key, 486 | Some(revalidation.object_etag), 487 | ), 488 | ) 489 | .await 490 | { 491 | Ok(Ok(x)) => match x { 492 | OriginResponse::Success(x) => { 493 | tracing::info!( 494 | shard_index = revalidation.shard_index, 495 | key = &**revalidation.key, 496 | "revalidation updated object" 497 | ); 498 | shards[revalidation.shard_index] 499 | .entries 500 | .insert((*revalidation.key).clone(), Some(x)) 501 | .await; 502 | num_updated.fetch_add(1, Ordering::Relaxed); 503 | } 504 | OriginResponse::Missing => { 505 | tracing::info!( 506 | shard_index = revalidation.shard_index, 507 | key = &**revalidation.key, 508 | "revalidation deleted object" 509 | ); 510 | shards[revalidation.shard_index] 511 | .entries 512 | .insert((*revalidation.key).clone(), None) 513 | .await; 514 | num_deleted.fetch_add(1, Ordering::Relaxed); 515 | } 516 | OriginResponse::NotModified => { 517 | tracing::info!( 518 | shard_index = revalidation.shard_index, 519 | key = &**revalidation.key, 520 | "revalidation returned 304" 521 | ); 522 | num_unmodified.fetch_add(1, Ordering::Relaxed); 523 | } 524 | }, 525 | Ok(Err(error)) => { 526 | tracing::error!( 527 | shard_index = revalidation.shard_index, 528 | key = &**revalidation.key, 529 | error, 530 | "error while revalidating entry, deleting from cache" 531 | ); 532 | shards[revalidation.shard_index] 533 | .entries 534 | .invalidate(&*revalidation.key) 535 | .await; 536 | num_failed.fetch_add(1, Ordering::Relaxed); 537 | } 538 | Err(_) => { 539 | tracing::error!( 540 | shard_index = revalidation.shard_index, 541 | key = &**revalidation.key, 542 | "revalidation timeout, deleting from cache" 543 | ); 544 | shards[revalidation.shard_index] 545 | .entries 546 | .invalidate(&*revalidation.key) 547 | .await; 548 | num_failed.fetch_add(1, Ordering::Relaxed); 549 | } 550 | } 551 | }); 552 | } 553 | let num_revalidations = revalidate_futures.len(); 554 | FuturesUnordered::from_iter(revalidate_futures.into_iter()) 555 | .collect::>() 556 | .await; 557 | if num_revalidations != 0 { 558 | tracing::info!( 559 | duration = ?revalidation_start_time.elapsed(), 560 | num_revalidations, 561 | num_updated = num_updated.load(Ordering::Relaxed), 562 | num_deleted = num_deleted.load(Ordering::Relaxed), 563 | num_unmodified = num_unmodified.load(Ordering::Relaxed), 564 | num_failed = num_failed.load(Ordering::Relaxed), 565 | "completed revalidations"); 566 | } 567 | for fencing_request in fencing_requests { 568 | let _ = fencing_request.send(()); 569 | } 570 | } 571 | } 572 | --------------------------------------------------------------------------------