at protocol indexer with flexible filtering, xrpc queries, and a cursor-backed event stream, built on fjall
at-protocol atproto indexer rust fjall

[all] drop jacquard, jacquard-axum, and some minor deps, use our own firehose stream impl

ptr.pet 69319002 bbcd660c

verified
+865 -1290
+3
.cargo/config.toml
··· 1 + [target.'cfg(target_os = "linux")'] 2 + linker = "clang" 3 + rustflags = ["-C", "link-arg=-fuse-ld=mold"]
+110 -1045
Cargo.lock
··· 18 18 checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 19 19 20 20 [[package]] 21 - name = "adler32" 22 - version = "1.2.0" 23 - source = "registry+https://github.com/rust-lang/crates.io-index" 24 - checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" 25 - 26 - [[package]] 27 21 name = "aho-corasick" 28 22 version = "1.1.4" 29 23 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 84 78 ] 85 79 86 80 [[package]] 87 - name = "ascii" 88 - version = "1.1.0" 89 - source = "registry+https://github.com/rust-lang/crates.io-index" 90 - checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" 91 - 92 - [[package]] 93 81 name = "async-compression" 94 82 version = "0.4.41" 95 83 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 102 90 ] 103 91 104 92 [[package]] 105 - name = "async-stream" 106 - version = "0.3.6" 107 - source = "registry+https://github.com/rust-lang/crates.io-index" 108 - checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" 109 - dependencies = [ 110 - "async-stream-impl", 111 - "futures-core", 112 - "pin-project-lite", 113 - ] 114 - 115 - [[package]] 116 - name = "async-stream-impl" 117 - version = "0.3.6" 118 - source = "registry+https://github.com/rust-lang/crates.io-index" 119 - checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" 120 - dependencies = [ 121 - "proc-macro2", 122 - "quote", 123 - "syn", 124 - ] 125 - 126 - [[package]] 127 93 name = "async-trait" 128 94 version = "0.1.89" 129 95 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 185 151 dependencies = [ 186 152 "axum-core", 187 153 "axum-macros", 188 - "base64 0.22.1", 154 + "base64", 189 155 "bytes", 190 156 "form_urlencoded", 191 157 "futures-util", ··· 207 173 "sha1", 208 174 "sync_wrapper", 209 175 "tokio", 210 - "tokio-tungstenite 0.28.0", 176 + "tokio-tungstenite", 211 177 "tower", 212 178 "tower-layer", 213 179 "tower-service", ··· 292 258 293 259 [[package]] 294 260 name = "base64" 295 - version = "0.13.1" 296 - source = "registry+https://github.com/rust-lang/crates.io-index" 297 - checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 298 - 299 - [[package]] 300 - name = "base64" 301 261 version = "0.22.1" 302 262 source = "registry+https://github.com/rust-lang/crates.io-index" 303 263 checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" ··· 355 315 checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" 356 316 dependencies = [ 357 317 "cfg_aliases", 358 - ] 359 - 360 - [[package]] 361 - name = "brotli" 362 - version = "3.5.0" 363 - source = "registry+https://github.com/rust-lang/crates.io-index" 364 - checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" 365 - dependencies = [ 366 - "alloc-no-stdlib", 367 - "alloc-stdlib", 368 - "brotli-decompressor 2.5.1", 369 318 ] 370 319 371 320 [[package]] ··· 376 325 dependencies = [ 377 326 "alloc-no-stdlib", 378 327 "alloc-stdlib", 379 - "brotli-decompressor 5.0.0", 380 - ] 381 - 382 - [[package]] 383 - name = "brotli-decompressor" 384 - version = "2.5.1" 385 - source = "registry+https://github.com/rust-lang/crates.io-index" 386 - checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" 387 - dependencies = [ 388 - "alloc-no-stdlib", 389 - "alloc-stdlib", 328 + "brotli-decompressor", 390 329 ] 391 330 392 331 [[package]] ··· 400 339 ] 401 340 402 341 [[package]] 403 - name = "buf_redux" 404 - version = "0.8.4" 405 - source = "registry+https://github.com/rust-lang/crates.io-index" 406 - checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" 407 - dependencies = [ 408 - "memchr", 409 - "safemem", 410 - ] 411 - 412 - [[package]] 413 342 name = "bumpalo" 414 343 version = "3.20.2" 415 344 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 507 436 ] 508 437 509 438 [[package]] 510 - name = "chunked_transfer" 511 - version = "1.5.0" 512 - source = "registry+https://github.com/rust-lang/crates.io-index" 513 - checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" 514 - 515 - [[package]] 516 439 name = "ciborium" 517 440 version = "0.2.2" 518 441 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 593 516 source = "registry+https://github.com/rust-lang/crates.io-index" 594 517 checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" 595 518 dependencies = [ 596 - "brotli 8.0.2", 519 + "brotli", 597 520 "compression-core", 598 521 "flate2", 599 522 "memchr", ··· 620 543 checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3" 621 544 622 545 [[package]] 623 - name = "convert_case" 624 - version = "0.10.0" 625 - source = "registry+https://github.com/rust-lang/crates.io-index" 626 - checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" 627 - dependencies = [ 628 - "unicode-segmentation", 629 - ] 630 - 631 - [[package]] 632 546 name = "cordyceps" 633 547 version = "0.3.4" 634 548 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 781 695 "fiat-crypto", 782 696 "rustc_version", 783 697 "subtle", 784 - "zeroize", 785 698 ] 786 699 787 700 [[package]] ··· 905 818 ] 906 819 907 820 [[package]] 908 - name = "deflate" 909 - version = "1.0.0" 910 - source = "registry+https://github.com/rust-lang/crates.io-index" 911 - checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" 912 - dependencies = [ 913 - "adler32", 914 - "gzip-header", 915 - ] 916 - 917 - [[package]] 918 821 name = "der" 919 822 version = "0.7.10" 920 823 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 940 843 source = "registry+https://github.com/rust-lang/crates.io-index" 941 844 checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" 942 845 dependencies = [ 943 - "derive_more-impl 1.0.0", 944 - ] 945 - 946 - [[package]] 947 - name = "derive_more" 948 - version = "2.1.1" 949 - source = "registry+https://github.com/rust-lang/crates.io-index" 950 - checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" 951 - dependencies = [ 952 - "derive_more-impl 2.1.1", 846 + "derive_more-impl", 953 847 ] 954 848 955 849 [[package]] ··· 965 859 ] 966 860 967 861 [[package]] 968 - name = "derive_more-impl" 969 - version = "2.1.1" 970 - source = "registry+https://github.com/rust-lang/crates.io-index" 971 - checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" 972 - dependencies = [ 973 - "convert_case", 974 - "proc-macro2", 975 - "quote", 976 - "rustc_version", 977 - "syn", 978 - "unicode-xid", 979 - ] 980 - 981 - [[package]] 982 862 name = "diatomic-waker" 983 863 version = "0.2.3" 984 864 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1046 926 "curve25519-dalek", 1047 927 "ed25519", 1048 928 "rand_core 0.6.4", 1049 - "serde", 1050 929 "sha2", 1051 930 "subtle", 1052 - "zeroize", 1053 931 ] 1054 932 1055 933 [[package]] ··· 1156 1034 checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" 1157 1035 1158 1036 [[package]] 1159 - name = "filetime" 1160 - version = "0.2.27" 1161 - source = "registry+https://github.com/rust-lang/crates.io-index" 1162 - checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" 1163 - dependencies = [ 1164 - "cfg-if", 1165 - "libc", 1166 - "libredox", 1167 - ] 1168 - 1169 - [[package]] 1170 1037 name = "find-msvc-tools" 1171 1038 version = "0.1.9" 1172 1039 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1221 1088 checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" 1222 1089 1223 1090 [[package]] 1091 + name = "foldhash" 1092 + version = "0.2.0" 1093 + source = "registry+https://github.com/rust-lang/crates.io-index" 1094 + checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" 1095 + 1096 + [[package]] 1224 1097 name = "form_urlencoded" 1225 1098 version = "1.2.2" 1226 1099 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1234 1107 version = "1.3.0" 1235 1108 source = "registry+https://github.com/rust-lang/crates.io-index" 1236 1109 checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" 1237 - 1238 - [[package]] 1239 - name = "futf" 1240 - version = "0.1.5" 1241 - source = "registry+https://github.com/rust-lang/crates.io-index" 1242 - checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" 1243 - dependencies = [ 1244 - "mac", 1245 - "new_debug_unreachable", 1246 - ] 1247 1110 1248 1111 [[package]] 1249 1112 name = "futures" ··· 1419 1282 checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" 1420 1283 dependencies = [ 1421 1284 "cfg-if", 1285 + "js-sys", 1422 1286 "libc", 1423 1287 "r-efi", 1424 1288 "rand_core 0.10.0", 1425 1289 "wasip2", 1426 1290 "wasip3", 1291 + "wasm-bindgen", 1427 1292 ] 1428 1293 1429 1294 [[package]] ··· 1439 1304 checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" 1440 1305 1441 1306 [[package]] 1442 - name = "gloo-storage" 1443 - version = "0.3.0" 1444 - source = "registry+https://github.com/rust-lang/crates.io-index" 1445 - checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a" 1446 - dependencies = [ 1447 - "gloo-utils", 1448 - "js-sys", 1449 - "serde", 1450 - "serde_json", 1451 - "thiserror 1.0.69", 1452 - "wasm-bindgen", 1453 - "web-sys", 1454 - ] 1455 - 1456 - [[package]] 1457 - name = "gloo-utils" 1458 - version = "0.2.0" 1459 - source = "registry+https://github.com/rust-lang/crates.io-index" 1460 - checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" 1461 - dependencies = [ 1462 - "js-sys", 1463 - "serde", 1464 - "serde_json", 1465 - "wasm-bindgen", 1466 - "web-sys", 1467 - ] 1468 - 1469 - [[package]] 1470 1307 name = "group" 1471 1308 version = "0.13.0" 1472 1309 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1475 1312 "ff", 1476 1313 "rand_core 0.6.4", 1477 1314 "subtle", 1478 - ] 1479 - 1480 - [[package]] 1481 - name = "gzip-header" 1482 - version = "1.0.0" 1483 - source = "registry+https://github.com/rust-lang/crates.io-index" 1484 - checksum = "95cc527b92e6029a62960ad99aa8a6660faa4555fe5f731aab13aa6a921795a2" 1485 - dependencies = [ 1486 - "crc32fast", 1487 1315 ] 1488 1316 1489 1317 [[package]] ··· 1537 1365 source = "registry+https://github.com/rust-lang/crates.io-index" 1538 1366 checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 1539 1367 dependencies = [ 1540 - "allocator-api2", 1541 - "equivalent", 1542 - "foldhash", 1368 + "foldhash 0.1.5", 1543 1369 ] 1544 1370 1545 1371 [[package]] ··· 1547 1373 version = "0.16.1" 1548 1374 source = "registry+https://github.com/rust-lang/crates.io-index" 1549 1375 checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" 1376 + dependencies = [ 1377 + "allocator-api2", 1378 + "equivalent", 1379 + "foldhash 0.2.0", 1380 + ] 1550 1381 1551 1382 [[package]] 1552 1383 name = "heapless" ··· 1575 1406 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 1576 1407 1577 1408 [[package]] 1578 - name = "hermit-abi" 1579 - version = "0.5.2" 1580 - source = "registry+https://github.com/rust-lang/crates.io-index" 1581 - checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" 1582 - 1583 - [[package]] 1584 1409 name = "hex" 1585 1410 version = "0.4.3" 1586 1411 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1588 1413 1589 1414 [[package]] 1590 1415 name = "hickory-proto" 1591 - version = "0.24.4" 1416 + version = "0.25.2" 1592 1417 source = "registry+https://github.com/rust-lang/crates.io-index" 1593 - checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" 1418 + checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" 1594 1419 dependencies = [ 1595 1420 "async-trait", 1596 1421 "cfg-if", ··· 1602 1427 "idna", 1603 1428 "ipnet", 1604 1429 "once_cell", 1605 - "rand 0.8.5", 1606 - "thiserror 1.0.69", 1430 + "rand 0.9.2", 1431 + "ring", 1432 + "thiserror 2.0.18", 1607 1433 "tinyvec", 1608 1434 "tokio", 1609 1435 "tracing", ··· 1612 1438 1613 1439 [[package]] 1614 1440 name = "hickory-resolver" 1615 - version = "0.24.4" 1441 + version = "0.25.2" 1616 1442 source = "registry+https://github.com/rust-lang/crates.io-index" 1617 - checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" 1443 + checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" 1618 1444 dependencies = [ 1619 1445 "cfg-if", 1620 1446 "futures-util", 1621 1447 "hickory-proto", 1622 1448 "ipconfig", 1623 - "lru-cache", 1449 + "moka", 1624 1450 "once_cell", 1625 1451 "parking_lot", 1626 - "rand 0.8.5", 1452 + "rand 0.9.2", 1627 1453 "resolv-conf", 1628 - "smallvec 1.15.1", 1629 - "thiserror 1.0.69", 1454 + "smallvec", 1455 + "thiserror 2.0.18", 1630 1456 "tokio", 1631 1457 "tracing", 1632 1458 ] ··· 1641 1467 ] 1642 1468 1643 1469 [[package]] 1644 - name = "html5ever" 1645 - version = "0.27.0" 1646 - source = "registry+https://github.com/rust-lang/crates.io-index" 1647 - checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" 1648 - dependencies = [ 1649 - "log", 1650 - "mac", 1651 - "markup5ever", 1652 - "proc-macro2", 1653 - "quote", 1654 - "syn", 1655 - ] 1656 - 1657 - [[package]] 1658 1470 name = "http" 1659 1471 version = "1.4.0" 1660 1472 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1710 1522 version = "0.1.0" 1711 1523 dependencies = [ 1712 1524 "arc-swap", 1713 - "async-stream", 1714 1525 "axum", 1715 1526 "chrono", 1716 1527 "cid", ··· 1720 1531 "glob", 1721 1532 "hex", 1722 1533 "humantime", 1723 - "jacquard", 1724 1534 "jacquard-api", 1725 - "jacquard-axum", 1726 1535 "jacquard-common", 1727 1536 "jacquard-derive", 1728 1537 "jacquard-identity", 1729 1538 "jacquard-repo", 1730 1539 "miette", 1731 1540 "mimalloc", 1732 - "n0-future 0.3.2", 1733 - "ordermap", 1734 1541 "rand 0.10.0", 1735 - "reqwest 0.12.28", 1736 - "reqwest 0.13.2", 1542 + "reqwest", 1737 1543 "reqwest-middleware", 1738 1544 "reqwest-retry", 1739 1545 "rmp-serde", ··· 1743 1549 "serde_bytes", 1744 1550 "serde_ipld_dagcbor", 1745 1551 "serde_json", 1746 - "smallvec 2.0.0-alpha.12", 1552 + "serde_urlencoded", 1747 1553 "smol_str", 1748 1554 "tempfile", 1749 1555 "thiserror 2.0.18", 1750 1556 "tokio", 1751 - "tokio-stream", 1557 + "tokio-tungstenite", 1752 1558 "tower-http", 1753 1559 "tracing", 1754 1560 "tracing-subscriber", ··· 1773 1579 "itoa", 1774 1580 "pin-project-lite", 1775 1581 "pin-utils", 1776 - "smallvec 1.15.1", 1582 + "smallvec", 1777 1583 "tokio", 1778 1584 "want", 1779 1585 ] ··· 1792 1598 "tokio", 1793 1599 "tokio-rustls", 1794 1600 "tower-service", 1795 - "webpki-roots", 1796 1601 ] 1797 1602 1798 1603 [[package]] ··· 1801 1606 source = "registry+https://github.com/rust-lang/crates.io-index" 1802 1607 checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" 1803 1608 dependencies = [ 1804 - "base64 0.22.1", 1609 + "base64", 1805 1610 "bytes", 1806 1611 "futures-channel", 1807 1612 "futures-util", ··· 1880 1685 "icu_normalizer_data", 1881 1686 "icu_properties", 1882 1687 "icu_provider", 1883 - "smallvec 1.15.1", 1688 + "smallvec", 1884 1689 "zerovec", 1885 1690 ] 1886 1691 ··· 1944 1749 checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 1945 1750 dependencies = [ 1946 1751 "idna_adapter", 1947 - "smallvec 1.15.1", 1752 + "smallvec", 1948 1753 "utf8_iter", 1949 1754 ] 1950 1755 ··· 2056 1861 checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" 2057 1862 2058 1863 [[package]] 2059 - name = "jacquard" 2060 - version = "0.9.5" 2061 - source = "git+https://tangled.org/nonbinary.computer/jacquard#bc1391738bd8aa8f1cfe49aca8d9dae469db9344" 2062 - dependencies = [ 2063 - "bytes", 2064 - "getrandom 0.2.17", 2065 - "gloo-storage", 2066 - "http", 2067 - "jacquard-api", 2068 - "jacquard-common", 2069 - "jacquard-derive", 2070 - "jacquard-identity", 2071 - "jacquard-oauth", 2072 - "jose-jwk", 2073 - "miette", 2074 - "n0-future 0.1.3", 2075 - "regex", 2076 - "regex-lite", 2077 - "reqwest 0.12.28", 2078 - "serde", 2079 - "serde_html_form", 2080 - "serde_json", 2081 - "smol_str", 2082 - "thiserror 2.0.18", 2083 - "tokio", 2084 - "trait-variant", 2085 - "url", 2086 - "webpage", 2087 - ] 2088 - 2089 - [[package]] 2090 1864 name = "jacquard-api" 2091 1865 version = "0.9.5" 2092 - source = "git+https://tangled.org/nonbinary.computer/jacquard#bc1391738bd8aa8f1cfe49aca8d9dae469db9344" 1866 + source = "git+https://tangled.org/ptr.pet/jacquard#da72566fde65f8cc76b8cb2bb99fc7f4d696dc05" 2093 1867 dependencies = [ 2094 1868 "bon", 2095 1869 "bytes", ··· 2106 1880 ] 2107 1881 2108 1882 [[package]] 2109 - name = "jacquard-axum" 2110 - version = "0.9.6" 2111 - source = "git+https://tangled.org/nonbinary.computer/jacquard#bc1391738bd8aa8f1cfe49aca8d9dae469db9344" 2112 - dependencies = [ 2113 - "axum", 2114 - "bytes", 2115 - "jacquard", 2116 - "jacquard-common", 2117 - "jacquard-derive", 2118 - "jacquard-identity", 2119 - "miette", 2120 - "multibase", 2121 - "serde", 2122 - "serde_html_form", 2123 - "serde_json", 2124 - "thiserror 2.0.18", 2125 - "tokio", 2126 - "tower-http", 2127 - "tracing", 2128 - ] 2129 - 2130 - [[package]] 2131 1883 name = "jacquard-common" 2132 1884 version = "0.9.5" 2133 - source = "git+https://tangled.org/nonbinary.computer/jacquard#bc1391738bd8aa8f1cfe49aca8d9dae469db9344" 1885 + source = "git+https://tangled.org/ptr.pet/jacquard#da72566fde65f8cc76b8cb2bb99fc7f4d696dc05" 2134 1886 dependencies = [ 2135 - "base64 0.22.1", 1887 + "base64", 2136 1888 "bon", 2137 1889 "bytes", 2138 1890 "chrono", ··· 2140 1892 "ciborium-io", 2141 1893 "cid", 2142 1894 "ed25519-dalek", 2143 - "futures", 2144 1895 "getrandom 0.2.17", 2145 - "getrandom 0.3.4", 2146 - "hashbrown 0.15.5", 1896 + "getrandom 0.4.1", 1897 + "hashbrown 0.16.1", 2147 1898 "http", 2148 1899 "ipld-core", 2149 1900 "k256", ··· 2151 1902 "miette", 2152 1903 "multibase", 2153 1904 "multihash", 2154 - "n0-future 0.1.3", 2155 1905 "ouroboros", 2156 1906 "oxilangtag", 2157 1907 "p256", ··· 2160 1910 "regex", 2161 1911 "regex-automata", 2162 1912 "regex-lite", 2163 - "reqwest 0.12.28", 1913 + "reqwest", 2164 1914 "serde", 2165 1915 "serde_bytes", 2166 1916 "serde_html_form", ··· 2171 1921 "spin 0.10.0", 2172 1922 "thiserror 2.0.18", 2173 1923 "tokio", 2174 - "tokio-tungstenite-wasm", 2175 1924 "tokio-util", 1925 + "tracing", 2176 1926 "trait-variant", 2177 1927 "url", 2178 1928 ] ··· 2180 1930 [[package]] 2181 1931 name = "jacquard-derive" 2182 1932 version = "0.9.5" 2183 - source = "git+https://tangled.org/nonbinary.computer/jacquard#bc1391738bd8aa8f1cfe49aca8d9dae469db9344" 1933 + source = "git+https://tangled.org/ptr.pet/jacquard#da72566fde65f8cc76b8cb2bb99fc7f4d696dc05" 2184 1934 dependencies = [ 2185 1935 "heck 0.5.0", 2186 1936 "jacquard-lexicon", ··· 2192 1942 [[package]] 2193 1943 name = "jacquard-identity" 2194 1944 version = "0.9.5" 2195 - source = "git+https://tangled.org/nonbinary.computer/jacquard#bc1391738bd8aa8f1cfe49aca8d9dae469db9344" 1945 + source = "git+https://tangled.org/ptr.pet/jacquard#da72566fde65f8cc76b8cb2bb99fc7f4d696dc05" 2196 1946 dependencies = [ 2197 1947 "bon", 2198 1948 "bytes", ··· 2202 1952 "jacquard-common", 2203 1953 "jacquard-lexicon", 2204 1954 "miette", 2205 - "mini-moka-wasm", 2206 - "n0-future 0.1.3", 1955 + "n0-future", 2207 1956 "percent-encoding", 2208 - "reqwest 0.12.28", 1957 + "reqwest", 2209 1958 "serde", 2210 1959 "serde_html_form", 2211 1960 "serde_json", 2212 1961 "thiserror 2.0.18", 2213 1962 "tokio", 1963 + "tracing", 2214 1964 "trait-variant", 2215 1965 "url", 2216 1966 "urlencoding", ··· 2219 1969 [[package]] 2220 1970 name = "jacquard-lexicon" 2221 1971 version = "0.9.5" 2222 - source = "git+https://tangled.org/nonbinary.computer/jacquard#bc1391738bd8aa8f1cfe49aca8d9dae469db9344" 1972 + source = "git+https://tangled.org/ptr.pet/jacquard#da72566fde65f8cc76b8cb2bb99fc7f4d696dc05" 2223 1973 dependencies = [ 2224 1974 "cid", 2225 1975 "dashmap", ··· 2244 1994 ] 2245 1995 2246 1996 [[package]] 2247 - name = "jacquard-oauth" 2248 - version = "0.9.6" 2249 - source = "git+https://tangled.org/nonbinary.computer/jacquard#bc1391738bd8aa8f1cfe49aca8d9dae469db9344" 2250 - dependencies = [ 2251 - "base64 0.22.1", 2252 - "bytes", 2253 - "chrono", 2254 - "dashmap", 2255 - "elliptic-curve", 2256 - "http", 2257 - "jacquard-common", 2258 - "jacquard-identity", 2259 - "jose-jwa", 2260 - "jose-jwk", 2261 - "miette", 2262 - "n0-future 0.1.3", 2263 - "p256", 2264 - "rand 0.8.5", 2265 - "rouille", 2266 - "serde", 2267 - "serde_html_form", 2268 - "serde_json", 2269 - "sha2", 2270 - "smol_str", 2271 - "thiserror 2.0.18", 2272 - "tokio", 2273 - "trait-variant", 2274 - "url", 2275 - "webbrowser", 2276 - ] 2277 - 2278 - [[package]] 2279 1997 name = "jacquard-repo" 2280 1998 version = "0.9.6" 2281 - source = "git+https://tangled.org/nonbinary.computer/jacquard#bc1391738bd8aa8f1cfe49aca8d9dae469db9344" 1999 + source = "git+https://tangled.org/ptr.pet/jacquard#da72566fde65f8cc76b8cb2bb99fc7f4d696dc05" 2282 2000 dependencies = [ 2283 2001 "bytes", 2284 2002 "cid", ··· 2289 2007 "k256", 2290 2008 "miette", 2291 2009 "multihash", 2292 - "n0-future 0.1.3", 2010 + "n0-future", 2293 2011 "p256", 2294 2012 "serde", 2295 2013 "serde_bytes", ··· 2334 2052 ] 2335 2053 2336 2054 [[package]] 2337 - name = "jose-b64" 2338 - version = "0.1.2" 2339 - source = "registry+https://github.com/rust-lang/crates.io-index" 2340 - checksum = "bec69375368709666b21c76965ce67549f2d2db7605f1f8707d17c9656801b56" 2341 - dependencies = [ 2342 - "base64ct", 2343 - "serde", 2344 - "subtle", 2345 - "zeroize", 2346 - ] 2347 - 2348 - [[package]] 2349 - name = "jose-jwa" 2350 - version = "0.1.2" 2351 - source = "registry+https://github.com/rust-lang/crates.io-index" 2352 - checksum = "9ab78e053fe886a351d67cf0d194c000f9d0dcb92906eb34d853d7e758a4b3a7" 2353 - dependencies = [ 2354 - "serde", 2355 - ] 2356 - 2357 - [[package]] 2358 - name = "jose-jwk" 2359 - version = "0.1.2" 2360 - source = "registry+https://github.com/rust-lang/crates.io-index" 2361 - checksum = "280fa263807fe0782ecb6f2baadc28dffc04e00558a58e33bfdb801d11fd58e7" 2362 - dependencies = [ 2363 - "jose-b64", 2364 - "jose-jwa", 2365 - "p256", 2366 - "p384", 2367 - "rsa", 2368 - "serde", 2369 - "zeroize", 2370 - ] 2371 - 2372 - [[package]] 2373 2055 name = "js-sys" 2374 2056 version = "0.3.91" 2375 2057 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2398 2080 version = "1.5.0" 2399 2081 source = "registry+https://github.com/rust-lang/crates.io-index" 2400 2082 checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 2401 - dependencies = [ 2402 - "spin 0.9.8", 2403 - ] 2404 2083 2405 2084 [[package]] 2406 2085 name = "leb128fmt" ··· 2415 2094 checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" 2416 2095 2417 2096 [[package]] 2418 - name = "libm" 2419 - version = "0.2.16" 2420 - source = "registry+https://github.com/rust-lang/crates.io-index" 2421 - checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" 2422 - 2423 - [[package]] 2424 2097 name = "libmimalloc-sys" 2425 2098 version = "0.1.44" 2426 2099 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2431 2104 ] 2432 2105 2433 2106 [[package]] 2434 - name = "libredox" 2435 - version = "0.1.14" 2436 - source = "registry+https://github.com/rust-lang/crates.io-index" 2437 - checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" 2438 - dependencies = [ 2439 - "bitflags", 2440 - "libc", 2441 - "plain", 2442 - "redox_syscall 0.7.3", 2443 - ] 2444 - 2445 - [[package]] 2446 - name = "linked-hash-map" 2447 - version = "0.5.6" 2448 - source = "registry+https://github.com/rust-lang/crates.io-index" 2449 - checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" 2450 - 2451 - [[package]] 2452 2107 name = "linux-raw-sys" 2453 2108 version = "0.12.1" 2454 2109 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2489 2144 ] 2490 2145 2491 2146 [[package]] 2492 - name = "lru-cache" 2493 - version = "0.1.2" 2494 - source = "registry+https://github.com/rust-lang/crates.io-index" 2495 - checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" 2496 - dependencies = [ 2497 - "linked-hash-map", 2498 - ] 2499 - 2500 - [[package]] 2501 2147 name = "lru-slab" 2502 2148 version = "0.1.2" 2503 2149 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2535 2181 ] 2536 2182 2537 2183 [[package]] 2538 - name = "mac" 2539 - version = "0.1.1" 2540 - source = "registry+https://github.com/rust-lang/crates.io-index" 2541 - checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" 2542 - 2543 - [[package]] 2544 2184 name = "maitake-sync" 2545 - version = "0.1.2" 2185 + version = "0.2.2" 2546 2186 source = "registry+https://github.com/rust-lang/crates.io-index" 2547 - checksum = "6816ab14147f80234c675b80ed6dc4f440d8a1cefc158e766067aedb84c0bcd5" 2187 + checksum = "748f86d9befd480b602c3bebc9ef30dbf2f3dfc8acc4a73d07b90f0117e6de3f" 2548 2188 dependencies = [ 2549 2189 "cordyceps", 2550 2190 "loom", 2191 + "mutex-traits", 2551 2192 "mycelium-bitfield", 2552 2193 "pin-project", 2553 2194 "portable-atomic", 2554 - ] 2555 - 2556 - [[package]] 2557 - name = "markup5ever" 2558 - version = "0.12.1" 2559 - source = "registry+https://github.com/rust-lang/crates.io-index" 2560 - checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" 2561 - dependencies = [ 2562 - "log", 2563 - "phf", 2564 - "phf_codegen", 2565 - "string_cache", 2566 - "string_cache_codegen", 2567 - "tendril", 2568 - ] 2569 - 2570 - [[package]] 2571 - name = "markup5ever_rcdom" 2572 - version = "0.3.0" 2573 - source = "registry+https://github.com/rust-lang/crates.io-index" 2574 - checksum = "edaa21ab3701bfee5099ade5f7e1f84553fd19228cf332f13cd6e964bf59be18" 2575 - dependencies = [ 2576 - "html5ever", 2577 - "markup5ever", 2578 - "tendril", 2579 - "xml5ever", 2195 + "tracing", 2580 2196 ] 2581 2197 2582 2198 [[package]] ··· 2657 2273 checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 2658 2274 2659 2275 [[package]] 2660 - name = "mime_guess" 2661 - version = "2.0.5" 2662 - source = "registry+https://github.com/rust-lang/crates.io-index" 2663 - checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" 2664 - dependencies = [ 2665 - "mime", 2666 - "unicase", 2667 - ] 2668 - 2669 - [[package]] 2670 - name = "mini-moka-wasm" 2671 - version = "0.10.99" 2672 - source = "git+https://tangled.org/nonbinary.computer/jacquard#bc1391738bd8aa8f1cfe49aca8d9dae469db9344" 2673 - dependencies = [ 2674 - "crossbeam-channel", 2675 - "crossbeam-utils", 2676 - "dashmap", 2677 - "smallvec 1.15.1", 2678 - "tagptr", 2679 - "triomphe", 2680 - "web-time", 2681 - ] 2682 - 2683 - [[package]] 2684 2276 name = "miniz_oxide" 2685 2277 version = "0.8.9" 2686 2278 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2702 2294 ] 2703 2295 2704 2296 [[package]] 2297 + name = "moka" 2298 + version = "0.12.14" 2299 + source = "registry+https://github.com/rust-lang/crates.io-index" 2300 + checksum = "85f8024e1c8e71c778968af91d43700ce1d11b219d127d79fb2934153b82b42b" 2301 + dependencies = [ 2302 + "crossbeam-channel", 2303 + "crossbeam-epoch", 2304 + "crossbeam-utils", 2305 + "equivalent", 2306 + "parking_lot", 2307 + "portable-atomic", 2308 + "smallvec", 2309 + "tagptr", 2310 + "uuid", 2311 + ] 2312 + 2313 + [[package]] 2705 2314 name = "multibase" 2706 2315 version = "0.9.2" 2707 2316 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2725 2334 ] 2726 2335 2727 2336 [[package]] 2728 - name = "multipart" 2729 - version = "0.18.0" 2337 + name = "mutex-traits" 2338 + version = "1.0.1" 2730 2339 source = "registry+https://github.com/rust-lang/crates.io-index" 2731 - checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" 2732 - dependencies = [ 2733 - "buf_redux", 2734 - "httparse", 2735 - "log", 2736 - "mime", 2737 - "mime_guess", 2738 - "quick-error", 2739 - "rand 0.8.5", 2740 - "safemem", 2741 - "tempfile", 2742 - "twoway", 2743 - ] 2340 + checksum = "3929f2b5633d29cf7b6624992e5f3c1e9334f1193423e12d17be4faf678cde3f" 2744 2341 2745 2342 [[package]] 2746 2343 name = "mycelium-bitfield" ··· 2755 2352 checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794" 2756 2353 dependencies = [ 2757 2354 "cfg_aliases", 2758 - "derive_more 1.0.0", 2759 - "futures-buffered", 2760 - "futures-lite", 2761 - "futures-util", 2762 - "js-sys", 2763 - "pin-project", 2764 - "send_wrapper", 2765 - "tokio", 2766 - "tokio-util", 2767 - "wasm-bindgen", 2768 - "wasm-bindgen-futures", 2769 - "web-time", 2770 - ] 2771 - 2772 - [[package]] 2773 - name = "n0-future" 2774 - version = "0.3.2" 2775 - source = "registry+https://github.com/rust-lang/crates.io-index" 2776 - checksum = "e2ab99dfb861450e68853d34ae665243a88b8c493d01ba957321a1e9b2312bbe" 2777 - dependencies = [ 2778 - "cfg_aliases", 2779 - "derive_more 2.1.1", 2355 + "derive_more", 2780 2356 "futures-buffered", 2781 2357 "futures-lite", 2782 2358 "futures-util", ··· 2791 2367 ] 2792 2368 2793 2369 [[package]] 2794 - name = "ndk-context" 2795 - version = "0.1.1" 2796 - source = "registry+https://github.com/rust-lang/crates.io-index" 2797 - checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" 2798 - 2799 - [[package]] 2800 - name = "new_debug_unreachable" 2801 - version = "1.0.6" 2802 - source = "registry+https://github.com/rust-lang/crates.io-index" 2803 - checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" 2804 - 2805 - [[package]] 2806 2370 name = "nu-ansi-term" 2807 2371 version = "0.50.3" 2808 2372 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2812 2376 ] 2813 2377 2814 2378 [[package]] 2815 - name = "num-bigint-dig" 2816 - version = "0.8.6" 2817 - source = "registry+https://github.com/rust-lang/crates.io-index" 2818 - checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" 2819 - dependencies = [ 2820 - "lazy_static", 2821 - "libm", 2822 - "num-integer", 2823 - "num-iter", 2824 - "num-traits", 2825 - "rand 0.8.5", 2826 - "smallvec 1.15.1", 2827 - "zeroize", 2828 - ] 2829 - 2830 - [[package]] 2831 2379 name = "num-conv" 2832 2380 version = "0.2.0" 2833 2381 source = "registry+https://github.com/rust-lang/crates.io-index" 2834 2382 checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" 2835 2383 2836 2384 [[package]] 2837 - name = "num-integer" 2838 - version = "0.1.46" 2839 - source = "registry+https://github.com/rust-lang/crates.io-index" 2840 - checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 2841 - dependencies = [ 2842 - "num-traits", 2843 - ] 2844 - 2845 - [[package]] 2846 - name = "num-iter" 2847 - version = "0.1.45" 2848 - source = "registry+https://github.com/rust-lang/crates.io-index" 2849 - checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 2850 - dependencies = [ 2851 - "autocfg", 2852 - "num-integer", 2853 - "num-traits", 2854 - ] 2855 - 2856 - [[package]] 2857 2385 name = "num-traits" 2858 2386 version = "0.2.19" 2859 2387 source = "registry+https://github.com/rust-lang/crates.io-index" 2860 2388 checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 2861 2389 dependencies = [ 2862 2390 "autocfg", 2863 - "libm", 2864 - ] 2865 - 2866 - [[package]] 2867 - name = "num_cpus" 2868 - version = "1.17.0" 2869 - source = "registry+https://github.com/rust-lang/crates.io-index" 2870 - checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" 2871 - dependencies = [ 2872 - "hermit-abi", 2873 - "libc", 2874 - ] 2875 - 2876 - [[package]] 2877 - name = "num_threads" 2878 - version = "0.1.7" 2879 - source = "registry+https://github.com/rust-lang/crates.io-index" 2880 - checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" 2881 - dependencies = [ 2882 - "libc", 2883 - ] 2884 - 2885 - [[package]] 2886 - name = "objc2" 2887 - version = "0.6.4" 2888 - source = "registry+https://github.com/rust-lang/crates.io-index" 2889 - checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" 2890 - dependencies = [ 2891 - "objc2-encode", 2892 - ] 2893 - 2894 - [[package]] 2895 - name = "objc2-encode" 2896 - version = "4.1.0" 2897 - source = "registry+https://github.com/rust-lang/crates.io-index" 2898 - checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" 2899 - 2900 - [[package]] 2901 - name = "objc2-foundation" 2902 - version = "0.3.2" 2903 - source = "registry+https://github.com/rust-lang/crates.io-index" 2904 - checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" 2905 - dependencies = [ 2906 - "bitflags", 2907 - "objc2", 2908 2391 ] 2909 2392 2910 2393 [[package]] ··· 2921 2404 version = "1.21.3" 2922 2405 source = "registry+https://github.com/rust-lang/crates.io-index" 2923 2406 checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 2407 + dependencies = [ 2408 + "critical-section", 2409 + "portable-atomic", 2410 + ] 2924 2411 2925 2412 [[package]] 2926 2413 name = "openssl-probe" 2927 2414 version = "0.2.1" 2928 2415 source = "registry+https://github.com/rust-lang/crates.io-index" 2929 2416 checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" 2930 - 2931 - [[package]] 2932 - name = "ordermap" 2933 - version = "1.1.0" 2934 - source = "registry+https://github.com/rust-lang/crates.io-index" 2935 - checksum = "cfa78c92071bbd3628c22b1a964f7e0eb201dc1456555db072beb1662ecd6715" 2936 - dependencies = [ 2937 - "indexmap", 2938 - "serde", 2939 - "serde_core", 2940 - ] 2941 2417 2942 2418 [[package]] 2943 2419 name = "ouroboros" ··· 2991 2467 ] 2992 2468 2993 2469 [[package]] 2994 - name = "p384" 2995 - version = "0.13.1" 2996 - source = "registry+https://github.com/rust-lang/crates.io-index" 2997 - checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" 2998 - dependencies = [ 2999 - "elliptic-curve", 3000 - "primeorder", 3001 - ] 3002 - 3003 - [[package]] 3004 2470 name = "parking" 3005 2471 version = "2.2.1" 3006 2472 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3024 2490 dependencies = [ 3025 2491 "cfg-if", 3026 2492 "libc", 3027 - "redox_syscall 0.5.18", 3028 - "smallvec 1.15.1", 2493 + "redox_syscall", 2494 + "smallvec", 3029 2495 "windows-link", 3030 2496 ] 3031 2497 ··· 3045 2511 checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 3046 2512 3047 2513 [[package]] 3048 - name = "phf" 3049 - version = "0.11.3" 3050 - source = "registry+https://github.com/rust-lang/crates.io-index" 3051 - checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" 3052 - dependencies = [ 3053 - "phf_shared", 3054 - ] 3055 - 3056 - [[package]] 3057 - name = "phf_codegen" 3058 - version = "0.11.3" 3059 - source = "registry+https://github.com/rust-lang/crates.io-index" 3060 - checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" 3061 - dependencies = [ 3062 - "phf_generator", 3063 - "phf_shared", 3064 - ] 3065 - 3066 - [[package]] 3067 - name = "phf_generator" 3068 - version = "0.11.3" 3069 - source = "registry+https://github.com/rust-lang/crates.io-index" 3070 - checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" 3071 - dependencies = [ 3072 - "phf_shared", 3073 - "rand 0.8.5", 3074 - ] 3075 - 3076 - [[package]] 3077 - name = "phf_shared" 3078 - version = "0.11.3" 3079 - source = "registry+https://github.com/rust-lang/crates.io-index" 3080 - checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" 3081 - dependencies = [ 3082 - "siphasher", 3083 - ] 3084 - 3085 - [[package]] 3086 2514 name = "pin-project" 3087 2515 version = "1.1.11" 3088 2516 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3115 2543 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 3116 2544 3117 2545 [[package]] 3118 - name = "pkcs1" 3119 - version = "0.7.5" 3120 - source = "registry+https://github.com/rust-lang/crates.io-index" 3121 - checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" 3122 - dependencies = [ 3123 - "der", 3124 - "pkcs8", 3125 - "spki", 3126 - ] 3127 - 3128 - [[package]] 3129 2546 name = "pkcs8" 3130 2547 version = "0.10.2" 3131 2548 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3140 2557 version = "0.3.32" 3141 2558 source = "registry+https://github.com/rust-lang/crates.io-index" 3142 2559 checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 3143 - 3144 - [[package]] 3145 - name = "plain" 3146 - version = "0.2.3" 3147 - source = "registry+https://github.com/rust-lang/crates.io-index" 3148 - checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 3149 2560 3150 2561 [[package]] 3151 2562 name = "portable-atomic" ··· 3191 2602 ] 3192 2603 3193 2604 [[package]] 3194 - name = "precomputed-hash" 3195 - version = "0.1.1" 3196 - source = "registry+https://github.com/rust-lang/crates.io-index" 3197 - checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 3198 - 3199 - [[package]] 3200 2605 name = "prettyplease" 3201 2606 version = "0.2.37" 3202 2607 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3236 2641 "version_check", 3237 2642 "yansi", 3238 2643 ] 3239 - 3240 - [[package]] 3241 - name = "quick-error" 3242 - version = "1.2.3" 3243 - source = "registry+https://github.com/rust-lang/crates.io-index" 3244 - checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 3245 2644 3246 2645 [[package]] 3247 2646 name = "quick_cache" ··· 3326 2725 3327 2726 [[package]] 3328 2727 name = "rand" 3329 - version = "0.8.5" 3330 - source = "registry+https://github.com/rust-lang/crates.io-index" 3331 - checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 3332 - dependencies = [ 3333 - "libc", 3334 - "rand_chacha 0.3.1", 3335 - "rand_core 0.6.4", 3336 - ] 3337 - 3338 - [[package]] 3339 - name = "rand" 3340 2728 version = "0.9.2" 3341 2729 source = "registry+https://github.com/rust-lang/crates.io-index" 3342 2730 checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" 3343 2731 dependencies = [ 3344 - "rand_chacha 0.9.0", 2732 + "rand_chacha", 3345 2733 "rand_core 0.9.5", 3346 2734 ] 3347 2735 ··· 3354 2742 "chacha20", 3355 2743 "getrandom 0.4.1", 3356 2744 "rand_core 0.10.0", 3357 - ] 3358 - 3359 - [[package]] 3360 - name = "rand_chacha" 3361 - version = "0.3.1" 3362 - source = "registry+https://github.com/rust-lang/crates.io-index" 3363 - checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 3364 - dependencies = [ 3365 - "ppv-lite86", 3366 - "rand_core 0.6.4", 3367 2745 ] 3368 2746 3369 2747 [[package]] ··· 3410 2788 ] 3411 2789 3412 2790 [[package]] 3413 - name = "redox_syscall" 3414 - version = "0.7.3" 3415 - source = "registry+https://github.com/rust-lang/crates.io-index" 3416 - checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" 3417 - dependencies = [ 3418 - "bitflags", 3419 - ] 3420 - 3421 - [[package]] 3422 2791 name = "regex" 3423 2792 version = "1.12.3" 3424 2793 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3455 2824 3456 2825 [[package]] 3457 2826 name = "reqwest" 3458 - version = "0.12.28" 3459 - source = "registry+https://github.com/rust-lang/crates.io-index" 3460 - checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" 3461 - dependencies = [ 3462 - "base64 0.22.1", 3463 - "bytes", 3464 - "encoding_rs", 3465 - "futures-core", 3466 - "futures-util", 3467 - "h2", 3468 - "http", 3469 - "http-body", 3470 - "http-body-util", 3471 - "hyper", 3472 - "hyper-rustls", 3473 - "hyper-util", 3474 - "js-sys", 3475 - "log", 3476 - "mime", 3477 - "percent-encoding", 3478 - "pin-project-lite", 3479 - "quinn", 3480 - "rustls", 3481 - "rustls-pki-types", 3482 - "serde", 3483 - "serde_json", 3484 - "serde_urlencoded", 3485 - "sync_wrapper", 3486 - "tokio", 3487 - "tokio-rustls", 3488 - "tokio-util", 3489 - "tower", 3490 - "tower-http", 3491 - "tower-service", 3492 - "url", 3493 - "wasm-bindgen", 3494 - "wasm-bindgen-futures", 3495 - "wasm-streams 0.4.2", 3496 - "web-sys", 3497 - "webpki-roots", 3498 - ] 3499 - 3500 - [[package]] 3501 - name = "reqwest" 3502 2827 version = "0.13.2" 3503 2828 source = "registry+https://github.com/rust-lang/crates.io-index" 3504 2829 checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" 3505 2830 dependencies = [ 3506 - "base64 0.22.1", 2831 + "base64", 3507 2832 "bytes", 2833 + "encoding_rs", 3508 2834 "futures-core", 3509 2835 "futures-util", 3510 2836 "h2", ··· 3516 2842 "hyper-util", 3517 2843 "js-sys", 3518 2844 "log", 2845 + "mime", 3519 2846 "percent-encoding", 3520 2847 "pin-project-lite", 3521 2848 "quinn", ··· 3534 2861 "url", 3535 2862 "wasm-bindgen", 3536 2863 "wasm-bindgen-futures", 3537 - "wasm-streams 0.5.0", 2864 + "wasm-streams", 3538 2865 "web-sys", 3539 2866 ] 3540 2867 ··· 3547 2874 "anyhow", 3548 2875 "async-trait", 3549 2876 "http", 3550 - "reqwest 0.13.2", 2877 + "reqwest", 3551 2878 "thiserror 2.0.18", 3552 2879 "tower-service", 3553 2880 ] ··· 3564 2891 "getrandom 0.2.17", 3565 2892 "http", 3566 2893 "hyper", 3567 - "reqwest 0.13.2", 2894 + "reqwest", 3568 2895 "reqwest-middleware", 3569 2896 "retry-policies", 3570 2897 "thiserror 2.0.18", ··· 3630 2957 ] 3631 2958 3632 2959 [[package]] 3633 - name = "rouille" 3634 - version = "3.6.2" 3635 - source = "registry+https://github.com/rust-lang/crates.io-index" 3636 - checksum = "3716fbf57fc1084d7a706adf4e445298d123e4a44294c4e8213caf1b85fcc921" 3637 - dependencies = [ 3638 - "base64 0.13.1", 3639 - "brotli 3.5.0", 3640 - "chrono", 3641 - "deflate", 3642 - "filetime", 3643 - "multipart", 3644 - "percent-encoding", 3645 - "rand 0.8.5", 3646 - "serde", 3647 - "serde_derive", 3648 - "serde_json", 3649 - "sha1_smol", 3650 - "threadpool", 3651 - "time", 3652 - "tiny_http", 3653 - "url", 3654 - ] 3655 - 3656 - [[package]] 3657 - name = "rsa" 3658 - version = "0.9.10" 3659 - source = "registry+https://github.com/rust-lang/crates.io-index" 3660 - checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" 3661 - dependencies = [ 3662 - "const-oid", 3663 - "digest", 3664 - "num-bigint-dig", 3665 - "num-integer", 3666 - "num-traits", 3667 - "pkcs1", 3668 - "pkcs8", 3669 - "rand_core 0.6.4", 3670 - "signature", 3671 - "spki", 3672 - "subtle", 3673 - "zeroize", 3674 - ] 3675 - 3676 - [[package]] 3677 2960 name = "rustc-demangle" 3678 2961 version = "0.1.27" 3679 2962 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3716 2999 "aws-lc-rs", 3717 3000 "log", 3718 3001 "once_cell", 3719 - "ring", 3720 3002 "rustls-pki-types", 3721 3003 "rustls-webpki", 3722 3004 "subtle", ··· 3803 3085 checksum = "16c7f49c9d5caa3bf4b3106900484b447b9253fe99670ceb81cb6cb5027855e1" 3804 3086 3805 3087 [[package]] 3806 - name = "safemem" 3807 - version = "0.3.3" 3808 - source = "registry+https://github.com/rust-lang/crates.io-index" 3809 - checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" 3810 - 3811 - [[package]] 3812 3088 name = "same-file" 3813 3089 version = "1.0.6" 3814 3090 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3850 3126 3851 3127 [[package]] 3852 3128 name = "sdd" 3853 - version = "4.6.5" 3129 + version = "4.6.7" 3854 3130 source = "registry+https://github.com/rust-lang/crates.io-index" 3855 - checksum = "4becc2f27bd39aafb78a8a1b4e1d6877ed0a6b5bf096722ed538dc028367a9b5" 3131 + checksum = "716318297c9f6208bda3eec88a9fdee0e2597be9461a1ab35f6ff68157527f99" 3856 3132 3857 3133 [[package]] 3858 3134 name = "sec1" ··· 4026 3302 source = "registry+https://github.com/rust-lang/crates.io-index" 4027 3303 checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" 4028 3304 dependencies = [ 4029 - "base64 0.22.1", 3305 + "base64", 4030 3306 "chrono", 4031 3307 "hex", 4032 3308 "serde_core", ··· 4068 3344 "cpufeatures 0.2.17", 4069 3345 "digest", 4070 3346 ] 4071 - 4072 - [[package]] 4073 - name = "sha1_smol" 4074 - version = "1.0.1" 4075 - source = "registry+https://github.com/rust-lang/crates.io-index" 4076 - checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" 4077 3347 4078 3348 [[package]] 4079 3349 name = "sha2" ··· 4128 3398 checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" 4129 3399 4130 3400 [[package]] 4131 - name = "siphasher" 4132 - version = "1.0.2" 4133 - source = "registry+https://github.com/rust-lang/crates.io-index" 4134 - checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" 4135 - 4136 - [[package]] 4137 3401 name = "slab" 4138 3402 version = "0.4.12" 4139 3403 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4144 3408 version = "1.15.1" 4145 3409 source = "registry+https://github.com/rust-lang/crates.io-index" 4146 3410 checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 4147 - 4148 - [[package]] 4149 - name = "smallvec" 4150 - version = "2.0.0-alpha.12" 4151 - source = "registry+https://github.com/rust-lang/crates.io-index" 4152 - checksum = "ef784004ca8777809dcdad6ac37629f0a97caee4c685fcea805278d81dd8b857" 4153 3411 4154 3412 [[package]] 4155 3413 name = "smol_str" ··· 4219 3477 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 4220 3478 4221 3479 [[package]] 4222 - name = "string_cache" 4223 - version = "0.8.9" 4224 - source = "registry+https://github.com/rust-lang/crates.io-index" 4225 - checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" 4226 - dependencies = [ 4227 - "new_debug_unreachable", 4228 - "parking_lot", 4229 - "phf_shared", 4230 - "precomputed-hash", 4231 - "serde", 4232 - ] 4233 - 4234 - [[package]] 4235 - name = "string_cache_codegen" 4236 - version = "0.5.4" 4237 - source = "registry+https://github.com/rust-lang/crates.io-index" 4238 - checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" 4239 - dependencies = [ 4240 - "phf_generator", 4241 - "phf_shared", 4242 - "proc-macro2", 4243 - "quote", 4244 - ] 4245 - 4246 - [[package]] 4247 3480 name = "strsim" 4248 3481 version = "0.11.1" 4249 3482 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4348 3581 ] 4349 3582 4350 3583 [[package]] 4351 - name = "tendril" 4352 - version = "0.4.3" 4353 - source = "registry+https://github.com/rust-lang/crates.io-index" 4354 - checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" 4355 - dependencies = [ 4356 - "futf", 4357 - "mac", 4358 - "utf-8", 4359 - ] 4360 - 4361 - [[package]] 4362 3584 name = "terminal_size" 4363 3585 version = "0.4.3" 4364 3586 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4428 3650 ] 4429 3651 4430 3652 [[package]] 4431 - name = "threadpool" 4432 - version = "1.8.1" 4433 - source = "registry+https://github.com/rust-lang/crates.io-index" 4434 - checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" 4435 - dependencies = [ 4436 - "num_cpus", 4437 - ] 4438 - 4439 - [[package]] 4440 3653 name = "time" 4441 3654 version = "0.3.47" 4442 3655 source = "registry+https://github.com/rust-lang/crates.io-index" 4443 3656 checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" 4444 3657 dependencies = [ 4445 3658 "deranged", 4446 - "libc", 4447 3659 "num-conv", 4448 - "num_threads", 4449 3660 "powerfmt", 4450 3661 "serde_core", 4451 3662 "time-core", ··· 4458 3669 checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" 4459 3670 4460 3671 [[package]] 4461 - name = "tiny_http" 4462 - version = "0.12.0" 4463 - source = "registry+https://github.com/rust-lang/crates.io-index" 4464 - checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82" 4465 - dependencies = [ 4466 - "ascii", 4467 - "chunked_transfer", 4468 - "httpdate", 4469 - "log", 4470 - ] 4471 - 4472 - [[package]] 4473 3672 name = "tinystr" 4474 3673 version = "0.8.2" 4475 3674 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4533 3732 ] 4534 3733 4535 3734 [[package]] 4536 - name = "tokio-stream" 4537 - version = "0.1.18" 4538 - source = "registry+https://github.com/rust-lang/crates.io-index" 4539 - checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" 4540 - dependencies = [ 4541 - "futures-core", 4542 - "pin-project-lite", 4543 - "tokio", 4544 - ] 4545 - 4546 - [[package]] 4547 3735 name = "tokio-tungstenite" 4548 - version = "0.24.0" 3736 + version = "0.28.0" 4549 3737 source = "registry+https://github.com/rust-lang/crates.io-index" 4550 - checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" 3738 + checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" 4551 3739 dependencies = [ 4552 3740 "futures-util", 4553 3741 "log", ··· 4556 3744 "rustls-pki-types", 4557 3745 "tokio", 4558 3746 "tokio-rustls", 4559 - "tungstenite 0.24.0", 4560 - ] 4561 - 4562 - [[package]] 4563 - name = "tokio-tungstenite" 4564 - version = "0.28.0" 4565 - source = "registry+https://github.com/rust-lang/crates.io-index" 4566 - checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" 4567 - dependencies = [ 4568 - "futures-util", 4569 - "log", 4570 - "tokio", 4571 - "tungstenite 0.28.0", 4572 - ] 4573 - 4574 - [[package]] 4575 - name = "tokio-tungstenite-wasm" 4576 - version = "0.4.0" 4577 - source = "registry+https://github.com/rust-lang/crates.io-index" 4578 - checksum = "e21a5c399399c3db9f08d8297ac12b500e86bca82e930253fdc62eaf9c0de6ae" 4579 - dependencies = [ 4580 - "futures-channel", 4581 - "futures-util", 4582 - "http", 4583 - "httparse", 4584 - "js-sys", 4585 - "rustls", 4586 - "thiserror 1.0.69", 4587 - "tokio", 4588 - "tokio-tungstenite 0.24.0", 4589 - "wasm-bindgen", 4590 - "web-sys", 3747 + "tungstenite", 4591 3748 ] 4592 3749 4593 3750 [[package]] ··· 4711 3868 "once_cell", 4712 3869 "regex-automata", 4713 3870 "sharded-slab", 4714 - "smallvec 1.15.1", 3871 + "smallvec", 4715 3872 "thread_local", 4716 3873 "tracing", 4717 3874 "tracing-core", ··· 4730 3887 ] 4731 3888 4732 3889 [[package]] 4733 - name = "triomphe" 4734 - version = "0.1.15" 4735 - source = "registry+https://github.com/rust-lang/crates.io-index" 4736 - checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" 4737 - 4738 - [[package]] 4739 3890 name = "try-lock" 4740 3891 version = "0.2.5" 4741 3892 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4743 3894 4744 3895 [[package]] 4745 3896 name = "tungstenite" 4746 - version = "0.24.0" 4747 - source = "registry+https://github.com/rust-lang/crates.io-index" 4748 - checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" 4749 - dependencies = [ 4750 - "byteorder", 4751 - "bytes", 4752 - "data-encoding", 4753 - "http", 4754 - "httparse", 4755 - "log", 4756 - "rand 0.8.5", 4757 - "rustls", 4758 - "rustls-pki-types", 4759 - "sha1", 4760 - "thiserror 1.0.69", 4761 - "utf-8", 4762 - ] 4763 - 4764 - [[package]] 4765 - name = "tungstenite" 4766 3897 version = "0.28.0" 4767 3898 source = "registry+https://github.com/rust-lang/crates.io-index" 4768 3899 checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" ··· 4773 3904 "httparse", 4774 3905 "log", 4775 3906 "rand 0.9.2", 3907 + "rustls", 3908 + "rustls-pki-types", 4776 3909 "sha1", 4777 3910 "thiserror 2.0.18", 4778 3911 "utf-8", 4779 3912 ] 4780 3913 4781 3914 [[package]] 4782 - name = "twoway" 4783 - version = "0.1.8" 4784 - source = "registry+https://github.com/rust-lang/crates.io-index" 4785 - checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" 4786 - dependencies = [ 4787 - "memchr", 4788 - ] 4789 - 4790 - [[package]] 4791 3915 name = "twox-hash" 4792 3916 version = "2.1.2" 4793 3917 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4798 3922 version = "1.19.0" 4799 3923 source = "registry+https://github.com/rust-lang/crates.io-index" 4800 3924 checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" 4801 - 4802 - [[package]] 4803 - name = "unicase" 4804 - version = "2.9.0" 4805 - source = "registry+https://github.com/rust-lang/crates.io-index" 4806 - checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" 4807 3925 4808 3926 [[package]] 4809 3927 name = "unicode-ident" ··· 4891 4009 checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 4892 4010 4893 4011 [[package]] 4012 + name = "uuid" 4013 + version = "1.21.0" 4014 + source = "registry+https://github.com/rust-lang/crates.io-index" 4015 + checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" 4016 + dependencies = [ 4017 + "getrandom 0.4.1", 4018 + "js-sys", 4019 + "wasm-bindgen", 4020 + ] 4021 + 4022 + [[package]] 4894 4023 name = "valuable" 4895 4024 version = "0.1.1" 4896 4025 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 5034 4163 5035 4164 [[package]] 5036 4165 name = "wasm-streams" 5037 - version = "0.4.2" 5038 - source = "registry+https://github.com/rust-lang/crates.io-index" 5039 - checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" 5040 - dependencies = [ 5041 - "futures-util", 5042 - "js-sys", 5043 - "wasm-bindgen", 5044 - "wasm-bindgen-futures", 5045 - "web-sys", 5046 - ] 5047 - 5048 - [[package]] 5049 - name = "wasm-streams" 5050 4166 version = "0.5.0" 5051 4167 source = "registry+https://github.com/rust-lang/crates.io-index" 5052 4168 checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" ··· 5105 4221 ] 5106 4222 5107 4223 [[package]] 5108 - name = "webbrowser" 5109 - version = "1.1.0" 5110 - source = "registry+https://github.com/rust-lang/crates.io-index" 5111 - checksum = "3f00bb839c1cf1e3036066614cbdcd035ecf215206691ea646aa3c60a24f68f2" 5112 - dependencies = [ 5113 - "core-foundation 0.10.1", 5114 - "jni", 5115 - "log", 5116 - "ndk-context", 5117 - "objc2", 5118 - "objc2-foundation", 5119 - "url", 5120 - "web-sys", 5121 - ] 5122 - 5123 - [[package]] 5124 - name = "webpage" 5125 - version = "2.0.1" 5126 - source = "registry+https://github.com/rust-lang/crates.io-index" 5127 - checksum = "70862efc041d46e6bbaa82bb9c34ae0596d090e86cbd14bd9e93b36ee6802eac" 5128 - dependencies = [ 5129 - "html5ever", 5130 - "markup5ever_rcdom", 5131 - "serde_json", 5132 - "url", 5133 - ] 5134 - 5135 - [[package]] 5136 4224 name = "webpki-root-certs" 5137 4225 version = "1.0.6" 5138 4226 source = "registry+https://github.com/rust-lang/crates.io-index" 5139 4227 checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" 5140 - dependencies = [ 5141 - "rustls-pki-types", 5142 - ] 5143 - 5144 - [[package]] 5145 - name = "webpki-roots" 5146 - version = "1.0.6" 5147 - source = "registry+https://github.com/rust-lang/crates.io-index" 5148 - checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" 5149 4228 dependencies = [ 5150 4229 "rustls-pki-types", 5151 4230 ] ··· 5628 4707 checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" 5629 4708 5630 4709 [[package]] 5631 - name = "xml5ever" 5632 - version = "0.18.1" 5633 - source = "registry+https://github.com/rust-lang/crates.io-index" 5634 - checksum = "9bbb26405d8e919bc1547a5aa9abc95cbfa438f04844f5fdd9dc7596b748bf69" 5635 - dependencies = [ 5636 - "log", 5637 - "mac", 5638 - "markup5ever", 5639 - ] 5640 - 5641 - [[package]] 5642 4710 name = "xxhash-rust" 5643 4711 version = "0.8.15" 5644 4712 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 5719 4787 version = "1.8.2" 5720 4788 source = "registry+https://github.com/rust-lang/crates.io-index" 5721 4789 checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" 5722 - dependencies = [ 5723 - "serde", 5724 - ] 5725 4790 5726 4791 [[package]] 5727 4792 name = "zerotrie"
+9 -15
Cargo.toml
··· 5 5 6 6 [dependencies] 7 7 tokio = { version = "1.0", features = ["full"] } 8 - n0-future = "0.3" 9 8 10 9 tracing = "0.1" 11 10 tracing-subscriber = { version = "0.3", features = ["env-filter"] } ··· 18 17 19 18 fjall = "3.0" 20 19 serde_ipld_dagcbor = "0.6" 20 + serde_urlencoded = "0.7" 21 21 22 22 url = "2.5" 23 23 smol_str = "0.3" 24 24 futures = "0.3" 25 - reqwest = { version = "0.12", features = ["json", "rustls-tls", "stream", "gzip", "brotli", "zstd", "http2"], default-features = false } 26 - reqwest-client = { package = "reqwest", version = "0.13.2", features = ["json", "rustls", "stream", "gzip", "brotli", "zstd", "http2"], default-features = false } 25 + reqwest = { version = "0.13.2", features = ["json", "rustls", "stream", "gzip", "brotli", "zstd", "http2"], default-features = false } 27 26 reqwest-middleware = { version = "0.5.1", default-features = false, features = ["http2", "rustls"] } 28 27 reqwest-retry = { version = "0.9.1" } 29 28 axum = { version = "0.8.8", features = ["ws", "macros"] } 30 29 tower-http = { version = "0.6.6", features = ["cors", "trace"] } 31 - tokio-stream = "0.1" 32 - async-stream = "0.3" 33 30 34 - jacquard = { git = "https://tangled.org/nonbinary.computer/jacquard", features = ["streaming"] } 35 - jacquard-common = { git = "https://tangled.org/nonbinary.computer/jacquard" } 36 - jacquard-api = { git = "https://tangled.org/nonbinary.computer/jacquard" } 37 - jacquard-identity = { git = "https://tangled.org/nonbinary.computer/jacquard", features = ["dns", "cache"] } 38 - jacquard-repo = { git = "https://tangled.org/nonbinary.computer/jacquard" } 39 - jacquard-axum = { git = "https://tangled.org/nonbinary.computer/jacquard" } 40 - jacquard-derive = { git = "https://tangled.org/nonbinary.computer/jacquard" } 31 + jacquard-common = { git = "https://tangled.org/ptr.pet/jacquard", default-features = false, features = ["tracing", "std", "crypto"] } 32 + jacquard-api = { git = "https://tangled.org/ptr.pet/jacquard" } 33 + jacquard-identity = { git = "https://tangled.org/ptr.pet/jacquard", features = ["dns", "tracing"] } 34 + jacquard-repo = { git = "https://tangled.org/ptr.pet/jacquard" } 35 + jacquard-derive = { git = "https://tangled.org/ptr.pet/jacquard" } 41 36 chrono = { version = "0.4.43", features = ["serde"] } 42 37 humantime = "2.3.0" 43 38 ··· 46 41 scc = "3" 47 42 data-encoding = "2.10.0" 48 43 cid = "0.11.1" 49 - smallvec = "2.0.0-alpha.12" 50 44 thiserror = "2.0.18" 51 45 rand = "0.10.0" 52 46 glob = "0.3" 53 - ordermap = { version = "1.1.0", features = ["serde"] } 54 47 arc-swap = "1.8.2" 55 - rustls = { version = "0.23", features = ["ring"] } 48 + rustls = { version = "0.23", features = ["aws-lc-rs"] } 49 + tokio-tungstenite = { version = "0.28.0", features = ["rustls-tls-native-roots"] } 56 50 57 51 [dev-dependencies] 58 52 tempfile = "3.26.0"
+2
flake.nix
··· 28 28 cmake 29 29 websocat 30 30 http-nu 31 + mold 32 + clang 31 33 ]; 32 34 }; 33 35 };
+2 -2
src/api/debug.rs
··· 6 6 extract::{Query, State}, 7 7 http::StatusCode, 8 8 }; 9 - use jacquard::types::cid::Cid; 10 - use jacquard::types::ident::AtIdentifier; 9 + use jacquard_common::types::cid::Cid; 10 + use jacquard_common::types::ident::AtIdentifier; 11 11 use serde::{Deserialize, Serialize}; 12 12 use serde_json::Value; 13 13 use std::str::FromStr;
+2 -6
src/api/mod.rs
··· 1 1 use crate::state::AppState; 2 2 use axum::{Router, routing::get}; 3 - use jacquard::xrpc::GenericXrpcError; 4 - use jacquard_axum::XrpcErrorResponse; 5 3 use std::{net::SocketAddr, sync::Arc}; 6 4 use tower_http::cors::CorsLayer; 7 5 use tower_http::trace::TraceLayer; 8 6 9 7 mod debug; 10 8 pub mod filter; 11 - pub mod repos; // Added this line 9 + pub mod repos; 12 10 pub mod stats; 13 11 mod stream; 14 12 pub mod xrpc; 15 13 16 - pub type XrpcResult<T> = Result<T, XrpcErrorResponse<GenericXrpcError>>; 17 - 18 14 pub async fn serve(state: Arc<AppState>, port: u16) -> miette::Result<()> { 19 15 let app = Router::new() 20 16 .route("/health", get(|| async { "OK" })) ··· 22 18 .route("/stream", get(stream::handle_stream)) 23 19 .merge(xrpc::router()) 24 20 .merge(filter::router()) 25 - .merge(repos::router()) // Added this line 21 + .merge(repos::router()) 26 22 .with_state(state) 27 23 .layer(TraceLayer::new_for_http()) 28 24 .layer(CorsLayer::permissive());
+1 -1
src/api/repos.rs
··· 8 8 response::{IntoResponse, Response}, 9 9 routing::{delete, get, put}, 10 10 }; 11 - use jacquard::{IntoStatic, types::did::Did}; 11 + use jacquard_common::{IntoStatic, types::did::Did}; 12 12 use miette::IntoDiagnostic; 13 13 use rand::Rng; 14 14 use serde::{Deserialize, Serialize};
+3 -4
src/api/stats.rs
··· 1 1 use crate::api::AppState; 2 2 use axum::{Json, extract::State, response::Result}; 3 - use ordermap::OrderMap; 4 3 use serde::Serialize; 5 - use std::sync::Arc; 4 + use std::{collections::BTreeMap, sync::Arc}; 6 5 7 6 #[derive(Serialize)] 8 7 pub struct StatsResponse { 9 - pub counts: OrderMap<&'static str, u64>, 8 + pub counts: BTreeMap<&'static str, u64>, 10 9 } 11 10 12 11 pub async fn get_stats(State(state): State<Arc<AppState>>) -> Result<Json<StatsResponse>> { 13 12 let db = &state.db; 14 13 15 - let mut counts: OrderMap<&'static str, u64> = futures::future::join_all( 14 + let mut counts: BTreeMap<&'static str, u64> = futures::future::join_all( 16 15 [ 17 16 "repos", 18 17 "pending",
+3 -2
src/api/stream.rs
··· 8 8 }, 9 9 response::IntoResponse, 10 10 }; 11 - use jacquard::CowStr; 11 + use jacquard_common::CowStr; 12 12 use jacquard_common::types::value::RawData; 13 13 use miette::{Context, IntoDiagnostic}; 14 14 use serde::Deserialize; ··· 123 123 rkey: CowStr::Owned(rkey.to_smolstr().into()), 124 124 action: CowStr::Borrowed(action.as_str()), 125 125 record: record_val, 126 - cid: cid.map(|c| jacquard::types::cid::Cid::ipld(c).into()), 126 + cid: cid 127 + .map(|c| jacquard_common::types::cid::Cid::ipld(c).into()), 127 128 }), 128 129 identity: None, 129 130 account: None,
+85 -32
src/api/xrpc.rs
··· 1 - use crate::api::{AppState, XrpcResult}; 1 + use crate::api::AppState; 2 2 use crate::db::types::DbRkey; 3 3 use crate::db::{self, Db, keys}; 4 + use axum::extract::FromRequest; 5 + use axum::response::IntoResponse; 4 6 use axum::{Json, Router, extract::State, http::StatusCode}; 5 7 use futures::TryFutureExt; 6 - use jacquard::cowstr::ToCowStr; 7 - use jacquard::types::ident::AtIdentifier; 8 - use jacquard::{ 9 - IntoStatic, 10 - api::com_atproto::repo::{ 11 - get_record::{GetRecordError, GetRecordOutput, GetRecordRequest}, 12 - list_records::{ListRecordsOutput, ListRecordsRequest, Record as RepoRecord}, 13 - }, 14 - xrpc::XrpcRequest, 8 + use jacquard_api::com_atproto::repo::{ 9 + get_record::{GetRecordError, GetRecordOutput, GetRecordRequest}, 10 + list_records::{ListRecordsOutput, ListRecordsRequest, Record as RepoRecord}, 15 11 }; 16 - use jacquard_api::com_atproto::repo::{get_record::GetRecord, list_records::ListRecords}; 17 - use jacquard_axum::{ExtractXrpc, IntoRouter, XrpcErrorResponse}; 12 + use jacquard_common::CowStr; 13 + use jacquard_common::cowstr::ToCowStr; 14 + use jacquard_common::types::ident::AtIdentifier; 15 + use jacquard_common::xrpc::{XrpcEndpoint, XrpcMethod}; 16 + use jacquard_common::{IntoStatic, xrpc::XrpcRequest}; 18 17 use jacquard_common::{ 19 18 types::{ 20 19 string::{AtUri, Cid}, ··· 30 29 31 30 pub fn router() -> Router<Arc<AppState>> { 32 31 Router::new() 33 - .merge(GetRecordRequest::into_router(handle_get_record)) 34 - .merge(ListRecordsRequest::into_router(handle_list_records)) 35 - .merge(CountRecords::into_router(handle_count_records)) 32 + .route( 33 + GetRecordRequest::PATH, 34 + axum::routing::get(handle_get_record), 35 + ) 36 + .route( 37 + ListRecordsRequest::PATH, 38 + axum::routing::get(handle_list_records), 39 + ) 40 + .route(CountRecords::PATH, axum::routing::get(handle_count_records)) 41 + } 42 + 43 + #[derive(Debug)] 44 + pub struct XrpcErrorResponse<E: IntoStatic + std::error::Error = GenericXrpcError> { 45 + pub status: StatusCode, 46 + pub error: XrpcError<E>, 47 + } 48 + 49 + impl<E: Serialize + IntoStatic + std::error::Error> IntoResponse for XrpcErrorResponse<E> { 50 + fn into_response(self) -> axum::response::Response { 51 + (self.status, Json(self.error)).into_response() 52 + } 53 + } 54 + 55 + pub type XrpcResult<T, E = GenericXrpcError> = Result<T, XrpcErrorResponse<E>>; 56 + 57 + pub struct ExtractXrpc<E: XrpcEndpoint>(pub E::Request<'static>); 58 + 59 + impl<S, E> FromRequest<S> for ExtractXrpc<E> 60 + where 61 + S: Send + Sync, 62 + E: XrpcEndpoint, 63 + E::Request<'static>: Send, 64 + for<'de> E::Request<'de>: Deserialize<'de> + IntoStatic<Output = E::Request<'static>>, 65 + { 66 + type Rejection = XrpcErrorResponse<GenericXrpcError>; 67 + 68 + async fn from_request( 69 + req: axum::extract::Request, 70 + _state: &S, 71 + ) -> Result<Self, Self::Rejection> { 72 + let nsid = E::Request::<'static>::NSID; 73 + match E::METHOD { 74 + XrpcMethod::Query => { 75 + let query = req.uri().query().unwrap_or(""); 76 + let res: E::Request<'_> = 77 + serde_urlencoded::from_str(query).map_err(|e| bad_request(nsid, e))?; 78 + Ok(ExtractXrpc(res.into_static())) 79 + } 80 + XrpcMethod::Procedure(_) => { 81 + let body = axum::body::to_bytes(req.into_body(), usize::MAX) 82 + .await 83 + .map_err(|e| internal_error(nsid, e))?; 84 + let res: E::Request<'_> = 85 + serde_json::from_slice(&body).map_err(|e| bad_request(nsid, e))?; 86 + Ok(ExtractXrpc(res.into_static())) 87 + } 88 + } 89 + } 36 90 } 37 91 38 92 fn internal_error<E: std::error::Error + IntoStatic>( ··· 76 130 .resolver 77 131 .resolve_did(&req.repo) 78 132 .await 79 - .map_err(|e| bad_request(GetRecord::NSID, e))?; 133 + .map_err(|e| bad_request(GetRecordRequest::PATH, e))?; 80 134 81 135 let db_key = keys::record_key( 82 136 &did, ··· 86 140 87 141 let cid_bytes = Db::get(db.records.clone(), db_key) 88 142 .await 89 - .map_err(|e| internal_error(GetRecord::NSID, e))?; 143 + .map_err(|e| internal_error(GetRecordRequest::PATH, e))?; 90 144 91 145 if let Some(cid_bytes) = cid_bytes { 92 146 // lookup block using binary cid 93 147 let block_bytes = Db::get(db.blocks.clone(), &cid_bytes) 94 148 .await 95 - .map_err(|e| internal_error(GetRecord::NSID, e))? 96 - .ok_or_else(|| internal_error(GetRecord::NSID, "not found"))?; 149 + .map_err(|e| internal_error(GetRecordRequest::PATH, e))? 150 + .ok_or_else(|| internal_error(GetRecordRequest::PATH, "not found"))?; 97 151 98 152 let value: Data = serde_ipld_dagcbor::from_slice(&block_bytes) 99 - .map_err(|e| internal_error(GetRecord::NSID, e))?; 153 + .map_err(|e| internal_error(GetRecordRequest::PATH, e))?; 100 154 101 155 let cid = Cid::new(&cid_bytes) 102 - .map_err(|e| internal_error(GetRecord::NSID, e))? 156 + .map_err(|e| internal_error(GetRecordRequest::PATH, e))? 103 157 .into_static(); 104 158 105 159 Ok(Json(GetRecordOutput { ··· 130 184 .resolver 131 185 .resolve_did(&req.repo) 132 186 .await 133 - .map_err(|e| bad_request(ListRecords::NSID, e))?; 187 + .map_err(|e| bad_request(ListRecordsRequest::PATH, e))?; 134 188 135 189 let ks = db.records.clone(); 136 190 ··· 206 260 Result::<_, miette::Report>::Ok((results, cursor)) 207 261 }) 208 262 .await 209 - .map_err(|e| internal_error(ListRecords::NSID, e))? 210 - .map_err(|e| internal_error(ListRecords::NSID, e))?; 263 + .map_err(|e| internal_error(ListRecordsRequest::PATH, e))? 264 + .map_err(|e| internal_error(ListRecordsRequest::PATH, e))?; 211 265 212 266 Ok(Json(ListRecordsOutput { 213 267 records: results, 214 - cursor: cursor.map(|c| jacquard::CowStr::Owned(c.to_smolstr())), 268 + cursor: cursor.map(|c| CowStr::Owned(c.to_smolstr())), 215 269 extra_data: Default::default(), 216 270 })) 217 271 } ··· 230 284 } 231 285 232 286 #[derive(Serialize, Deserialize, jacquard_derive::IntoStatic)] 233 - pub struct CountRecordsRequest<'i> { 287 + pub struct CountRecordsRequestData<'i> { 234 288 #[serde(borrow)] 235 289 pub identifier: AtIdentifier<'i>, 236 290 pub collection: String, 237 291 } 238 292 239 - impl<'a> jacquard_common::xrpc::XrpcRequest for CountRecordsRequest<'a> { 293 + impl<'a> jacquard_common::xrpc::XrpcRequest for CountRecordsRequestData<'a> { 240 294 const NSID: &'static str = "systems.gaze.hydrant.countRecords"; 241 295 const METHOD: jacquard_common::xrpc::XrpcMethod = jacquard_common::xrpc::XrpcMethod::Query; 242 296 type Response = CountRecordsResponse; ··· 246 300 impl jacquard_common::xrpc::XrpcEndpoint for CountRecords { 247 301 const PATH: &'static str = "/xrpc/systems.gaze.hydrant.countRecords"; 248 302 const METHOD: jacquard_common::xrpc::XrpcMethod = jacquard_common::xrpc::XrpcMethod::Query; 249 - type Request<'de> = CountRecordsRequest<'de>; 303 + type Request<'de> = CountRecordsRequestData<'de>; 250 304 type Response = CountRecordsResponse; 251 305 } 252 306 253 - #[axum::debug_handler] 254 307 pub async fn handle_count_records( 255 308 State(state): State<Arc<AppState>>, 256 309 ExtractXrpc(req): ExtractXrpc<CountRecords>, ··· 259 312 .resolver 260 313 .resolve_did(&req.identifier) 261 314 .await 262 - .map_err(|e| bad_request(CountRecordsRequest::NSID, e))?; 315 + .map_err(|e| bad_request(CountRecords::PATH, e))?; 263 316 264 317 let count = spawn_blocking(move || { 265 318 db::get_record_count(&state.db, &did, &req.collection) 266 - .map_err(|e| internal_error(CountRecordsRequest::NSID, e)) 319 + .map_err(|e| internal_error(CountRecords::PATH, e)) 267 320 }) 268 - .map_err(|e| internal_error(CountRecordsRequest::NSID, e)) 321 + .map_err(|e| internal_error(CountRecords::PATH, e)) 269 322 .await??; 270 323 271 324 Ok(Json(CountRecordsOutput { count }))
+6 -6
src/backfill/mod.rs
··· 10 10 }; 11 11 12 12 use fjall::Slice; 13 - use jacquard::api::com_atproto::sync::get_repo::{GetRepo, GetRepoError}; 14 - use jacquard::error::{ClientError, ClientErrorKind}; 15 - use jacquard::types::cid::Cid; 16 - use jacquard::types::did::Did; 17 - use jacquard::{CowStr, IntoStatic, prelude::*}; 18 - use jacquard_common::xrpc::XrpcError; 13 + use jacquard_api::com_atproto::sync::get_repo::{GetRepo, GetRepoError}; 14 + use jacquard_common::error::{ClientError, ClientErrorKind}; 15 + use jacquard_common::types::cid::Cid; 16 + use jacquard_common::types::did::Did; 17 + use jacquard_common::xrpc::{XrpcError, XrpcExt}; 18 + use jacquard_common::{CowStr, IntoStatic}; 19 19 use jacquard_repo::mst::Mst; 20 20 use jacquard_repo::{BlockStore, MemoryBlockStore}; 21 21 use miette::{Diagnostic, IntoDiagnostic, Result};
-104
src/bin/mst_dump.rs
··· 1 - use std::env; 2 - use std::sync::Arc; 3 - use std::time::Duration; 4 - 5 - use hydrant::resolver::Resolver; 6 - use jacquard::IntoStatic; 7 - use jacquard::api::com_atproto::sync::get_repo::GetRepo; 8 - use jacquard::prelude::XrpcExt; 9 - use jacquard::types::did::Did; 10 - use jacquard_common::types::ident::AtIdentifier; 11 - use jacquard_repo::MemoryBlockStore; 12 - use jacquard_repo::mst::Mst; 13 - use miette::{IntoDiagnostic, Result}; 14 - use tracing::{Level, info}; 15 - use tracing_subscriber::FmtSubscriber; 16 - use url::Url; 17 - 18 - #[tokio::main] 19 - async fn main() -> Result<()> { 20 - // Setup logging 21 - let subscriber = FmtSubscriber::builder() 22 - .with_max_level(Level::INFO) 23 - .finish(); 24 - tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); 25 - 26 - // Parse args 27 - let args: Vec<String> = env::args().collect(); 28 - if args.len() != 2 { 29 - eprintln!("Usage: {} <handle|did>", args[0]); 30 - std::process::exit(1); 31 - } 32 - let identifier_str = &args[1]; 33 - 34 - // Init resolver 35 - let plc_url = Url::parse("https://plc.directory").into_diagnostic()?; 36 - let resolver = Resolver::new(vec![plc_url], 100); 37 - 38 - // Resolve identity 39 - info!("Resolving {}...", identifier_str); 40 - let identifier = if identifier_str.starts_with("did:") { 41 - AtIdentifier::Did(Did::new(identifier_str).map_err(|e| miette::miette!("{}", e))?) 42 - } else { 43 - AtIdentifier::Handle(identifier_str.parse().into_diagnostic()?) 44 - }; 45 - 46 - let did = match identifier { 47 - AtIdentifier::Did(d) => d.into_static(), 48 - AtIdentifier::Handle(h) => { 49 - let d = resolver.resolve_did(&AtIdentifier::Handle(h)).await?; 50 - d 51 - } 52 - }; 53 - info!("Resolved to DID: {}", did); 54 - 55 - let (pds_url, _) = resolver.resolve_identity_info(&did).await?; 56 - info!("PDS URL: {}", pds_url); 57 - 58 - // Fetch repo 59 - info!("Fetching repo..."); 60 - let http = reqwest::Client::builder() 61 - .timeout(Duration::from_secs(30)) 62 - .build() 63 - .into_diagnostic()?; 64 - 65 - let req = GetRepo::new().did(did.clone()).build(); 66 - let resp = http.xrpc(pds_url).send(&req).await?; 67 - let car_bytes = resp.into_output().map_err(|e| miette::miette!("{}", e))?; // explicit map_err 68 - 69 - info!("Fetched {} bytes", car_bytes.body.len()); 70 - 71 - // Parse CAR 72 - let parsed = jacquard_repo::car::reader::parse_car_bytes(&car_bytes.body) 73 - .await 74 - .into_diagnostic()?; 75 - 76 - let store = Arc::new(MemoryBlockStore::new()); 77 - for (_cid, bytes) in &parsed.blocks { 78 - jacquard_repo::BlockStore::put(store.as_ref(), bytes) 79 - .await 80 - .into_diagnostic()?; 81 - } 82 - 83 - // Load MST 84 - let root_bytes = parsed 85 - .blocks 86 - .get(&parsed.root) 87 - .ok_or_else(|| miette::miette!("root block missing from CAR"))?; 88 - 89 - let root_commit = jacquard_repo::commit::Commit::from_cbor(root_bytes).into_diagnostic()?; 90 - info!("Repo rev: {}", root_commit.rev); 91 - 92 - let mst: Mst<MemoryBlockStore> = Mst::load(store.clone(), root_commit.data, None); 93 - let leaves = mst.leaves().await.into_diagnostic()?; 94 - let root = mst.root().await.into_diagnostic()?; 95 - 96 - info!("Found {} records", leaves.len()); 97 - 98 - println!("root -> {}", root); 99 - for (key, cid) in leaves { 100 - println!("{} -> {}", key, cid); 101 - } 102 - 103 - Ok(()) 104 - }
+2 -3
src/crawler/mod.rs
··· 1 1 use crate::db::{Db, keys, ser_repo_state}; 2 2 use crate::state::AppState; 3 3 use crate::types::RepoState; 4 - use jacquard::IntoStatic; 5 4 use jacquard_api::com_atproto::repo::list_records::ListRecordsOutput; 6 5 use jacquard_api::com_atproto::sync::list_repos::ListReposOutput; 7 - use jacquard_common::types::string::Did; 6 + use jacquard_common::{IntoStatic, types::string::Did}; 8 7 use miette::{IntoDiagnostic, Result}; 9 8 use rand::Rng; 10 9 use rand::rngs::SmallRng; ··· 35 34 let retry_policy = ExponentialBackoff::builder() 36 35 .jitter(Jitter::Bounded) 37 36 .build_with_max_retries(8); 38 - let reqwest_client = reqwest_client::Client::builder() 37 + let reqwest_client = reqwest::Client::builder() 39 38 .user_agent(concat!( 40 39 env!("CARGO_PKG_NAME"), 41 40 "/",
+3 -3
src/db/filter.rs
··· 1 1 use fjall::{Keyspace, OwnedWriteBatch}; 2 - use jacquard::IntoStatic; 3 - use jacquard::types::nsid::Nsid; 2 + use jacquard_common::IntoStatic; 3 + use jacquard_common::types::nsid::Nsid; 4 + use jacquard_common::types::string::Did; 4 5 use miette::{IntoDiagnostic, Result}; 5 6 6 7 use crate::db::types::TrimmedDid; 7 8 use crate::filter::{FilterConfig, FilterMode, SetUpdate}; 8 - use jacquard_common::types::string::Did; 9 9 10 10 pub const MODE_KEY: &[u8] = b"m"; 11 11 pub const SIGNAL_PREFIX: u8 = b's';
+1 -1
src/db/mod.rs
··· 1 1 use crate::types::{BroadcastEvent, RepoState}; 2 2 use fjall::config::BlockSizePolicy; 3 3 use fjall::{Database, Keyspace, KeyspaceCreateOptions, OwnedWriteBatch, PersistMode, Slice}; 4 - use jacquard::IntoStatic; 4 + use jacquard_common::IntoStatic; 5 5 use jacquard_common::types::string::Did; 6 6 use miette::{Context, IntoDiagnostic, Result}; 7 7 use scc::HashMap;
+1 -1
src/db/types.rs
··· 1 1 use data_encoding::BASE32_NOPAD; 2 2 use fjall::UserKey; 3 - use jacquard::{CowStr, IntoStatic}; 4 3 use jacquard_common::types::string::Did; 5 4 use jacquard_common::types::tid::Tid; 5 + use jacquard_common::{CowStr, IntoStatic}; 6 6 use serde::{Deserialize, Deserializer, Serialize, Serializer}; 7 7 use smol_str::{SmolStr, SmolStrBuilder, format_smolstr}; 8 8 use std::fmt::Display;
+1 -1
src/filter.rs
··· 1 - use jacquard::types::nsid::Nsid; 1 + use jacquard_common::types::nsid::Nsid; 2 2 use serde::{Deserialize, Serialize}; 3 3 use std::sync::Arc; 4 4
+30 -29
src/ingest/firehose.rs
··· 1 1 use crate::db; 2 2 use crate::filter::{FilterHandle, FilterMode}; 3 + use crate::ingest::stream::{FirehoseStream, SubscribeReposMessage, decode_frame}; 3 4 use crate::ingest::{BufferTx, IngestMessage}; 4 5 use crate::state::AppState; 5 - use jacquard::api::com_atproto::sync::subscribe_repos::{SubscribeRepos, SubscribeReposMessage}; 6 - use jacquard::types::did::Did; 7 - use jacquard_common::xrpc::{SubscriptionClient, TungsteniteSubscriptionClient}; 6 + use jacquard_common::IntoStatic; 7 + use jacquard_common::types::did::Did; 8 8 use miette::{IntoDiagnostic, Result}; 9 - use n0_future::StreamExt; 10 9 use std::sync::Arc; 11 10 use std::sync::atomic::Ordering; 12 11 use std::time::Duration; ··· 55 54 self.state.cur_firehose.store(c, Ordering::SeqCst); 56 55 } 57 56 58 - let client = TungsteniteSubscriptionClient::from_base_uri(self.relay_host.clone()); 59 - let params = SubscribeRepos::new; 60 - let params = start_cursor 61 - .map(|c| params().cursor(c)) 62 - .unwrap_or_else(params) 63 - .build(); 64 - 65 - let stream = match client.subscribe(&params).await { 66 - Ok(s) => s, 67 - Err(e) => { 68 - error!("failed to connect to firehose: {e}, retrying in 5s..."); 69 - tokio::time::sleep(Duration::from_secs(5)).await; 70 - continue; 71 - } 72 - }; 73 - 74 - let (_sink, mut messages) = stream.into_stream(); 57 + let mut stream = 58 + match FirehoseStream::connect(self.relay_host.clone(), start_cursor).await { 59 + Ok(s) => s, 60 + Err(e) => { 61 + error!("failed to connect to firehose: {e}, retrying in 5s..."); 62 + tokio::time::sleep(Duration::from_secs(5)).await; 63 + continue; 64 + } 65 + }; 75 66 76 67 info!("firehose connected"); 77 68 78 - while let Some(msg_res) = messages.next().await { 79 - match msg_res { 69 + while let Some(bytes_res) = stream.next().await { 70 + let bytes = match bytes_res { 71 + Ok(b) => b, 72 + Err(e) => { 73 + error!("firehose stream error: {e}"); 74 + break; 75 + } 76 + }; 77 + match decode_frame(&bytes) { 80 78 Ok(msg) => self.handle_message(msg).await, 81 79 Err(e) => { 82 80 error!("firehose stream error: {e}"); ··· 90 88 } 91 89 } 92 90 93 - async fn handle_message(&mut self, msg: SubscribeReposMessage<'static>) { 91 + async fn handle_message(&mut self, msg: SubscribeReposMessage<'_>) { 94 92 let did = match &msg { 95 93 SubscribeReposMessage::Commit(commit) => &commit.repo, 96 94 SubscribeReposMessage::Identity(identity) => &identity.did, ··· 108 106 trace!("skipping {did}: not in filter"); 109 107 return; 110 108 } 111 - debug!("forwarding message for {did} to ingest buffer"); 109 + trace!("forwarding message for {did} to ingest buffer"); 112 110 113 - if let Err(e) = self.buffer_tx.send(IngestMessage::Firehose(msg)) { 111 + if let Err(e) = self 112 + .buffer_tx 113 + .send(IngestMessage::Firehose(msg.into_static())) 114 + { 114 115 error!("failed to send message to buffer processor: {e}"); 115 116 } 116 117 } ··· 138 139 rmp_serde::from_slice(&state_bytes).into_diagnostic()?; 139 140 140 141 if repo_state.tracked { 141 - debug!("{did} is a tracked repo, processing"); 142 + trace!("{did} is a tracked repo, processing"); 142 143 return Ok(true); 143 144 } else { 144 145 debug!("{did} is known but explicitly untracked, skipping"); ··· 147 148 } 148 149 149 150 if !filter.signals.is_empty() { 150 - debug!("{did} is unknown — passing to worker for signal check"); 151 + trace!("{did} is unknown — passing to worker for signal check"); 151 152 Ok(true) 152 153 } else { 153 - debug!("{did} is unknown and no signals configured, skipping"); 154 + trace!("{did} is unknown and no signals configured, skipping"); 154 155 Ok(false) 155 156 } 156 157 }
+4 -3
src/ingest/mod.rs
··· 1 - use jacquard_api::com_atproto::sync::subscribe_repos::SubscribeReposMessage; 2 1 use tokio::sync::mpsc; 3 2 4 3 pub mod firehose; 4 + pub mod stream; 5 5 pub mod worker; 6 6 7 - use jacquard::types::did::Did; 7 + use jacquard_common::types::did::Did; 8 + 9 + use crate::ingest::stream::SubscribeReposMessage; 8 10 9 11 #[derive(Debug)] 10 12 pub enum IngestMessage { ··· 13 15 } 14 16 15 17 pub type BufferTx = mpsc::UnboundedSender<IngestMessage>; 16 - #[allow(dead_code)] 17 18 pub type BufferRx = mpsc::UnboundedReceiver<IngestMessage>;
+560
src/ingest/stream.rs
··· 1 + use std::convert::Infallible; 2 + use std::option::Option; 3 + 4 + use futures::StreamExt; 5 + use jacquard_common::bytes::Bytes; 6 + use jacquard_common::error::DecodeError; 7 + use jacquard_common::{ 8 + CowStr, 9 + types::{ 10 + cid::CidLink, 11 + string::{Did, Handle, Tid}, 12 + }, 13 + }; 14 + use miette::Diagnostic; 15 + use smol_str::format_smolstr; 16 + use thiserror::Error; 17 + use tokio::net::TcpStream; 18 + use tokio_tungstenite::{MaybeTlsStream, WebSocketStream, connect_async, tungstenite::Message}; 19 + use tracing::trace; 20 + use url::Url; 21 + 22 + #[derive(Debug, Error, Diagnostic)] 23 + pub enum FirehoseError { 24 + #[error("websocket error: {0}")] 25 + WebSocket(#[from] tokio_tungstenite::tungstenite::Error), 26 + #[error("unknown scheme: {0}")] 27 + UnknownScheme(String), 28 + #[error("decode error: {0}")] 29 + Decode(#[from] DecodeError), 30 + #[error("empty frame")] 31 + EmptyFrame, 32 + #[error("relay error {error}: {message:?}")] 33 + RelayError { 34 + error: String, 35 + message: Option<String>, 36 + }, 37 + #[error("unknown op: {0}")] 38 + UnknownOp(i64), 39 + #[error("missing type in header")] 40 + MissingType, 41 + #[error("unknown event type: {0}")] 42 + UnknownType(String), 43 + #[error("cbor decode error: {0}")] 44 + Cbor(String), 45 + } 46 + 47 + impl From<serde_ipld_dagcbor::DecodeError<Infallible>> for FirehoseError { 48 + fn from(e: serde_ipld_dagcbor::DecodeError<Infallible>) -> Self { 49 + Self::Cbor(e.to_string()) 50 + } 51 + } 52 + 53 + pub struct FirehoseStream { 54 + ws: WebSocketStream<MaybeTlsStream<TcpStream>>, 55 + } 56 + 57 + impl FirehoseStream { 58 + pub async fn connect(mut relay: Url, cursor: Option<i64>) -> Result<Self, FirehoseError> { 59 + let scheme = match relay.scheme() { 60 + "https" | "wss" => "wss", 61 + "http" | "ws" => "ws", 62 + x => return Err(FirehoseError::UnknownScheme(x.to_string())), 63 + }; 64 + relay.set_scheme(scheme).expect("to be valid url"); 65 + relay.set_path("/xrpc/com.atproto.sync.subscribeRepos"); 66 + let cursor = cursor.map(|c| format_smolstr!("cursor={c}")); 67 + relay.set_query(cursor.as_deref()); 68 + 69 + let (ws, _) = connect_async(relay.as_str()).await?; 70 + Ok(Self { ws }) 71 + } 72 + 73 + /// gets the next message bytes from the firehose 74 + pub async fn next(&mut self) -> Option<Result<Bytes, FirehoseError>> { 75 + loop { 76 + match self.ws.next().await? { 77 + Err(e) => return Some(Err(e.into())), 78 + Ok(Message::Binary(bytes)) => { 79 + if bytes.is_empty() { 80 + return Some(Err(FirehoseError::EmptyFrame)); 81 + } 82 + return Some(Ok(bytes)); 83 + } 84 + Ok(Message::Close(_)) => return None, 85 + Ok(x) => { 86 + trace!("relay sent unexpected message: {x:?}"); 87 + continue; 88 + } 89 + } 90 + } 91 + } 92 + } 93 + 94 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 95 + #[serde(try_from = "String")] 96 + pub struct Datetime(pub chrono::DateTime<chrono::FixedOffset>); 97 + 98 + impl TryFrom<String> for Datetime { 99 + type Error = chrono::ParseError; 100 + 101 + fn try_from(s: String) -> Result<Self, Self::Error> { 102 + chrono::DateTime::parse_from_rfc3339(&s) 103 + .map(Self) 104 + .or_else(|_| { 105 + // no timezone — warn and assume UTC 106 + tracing::warn!( 107 + value = %s, 108 + "datetime missing timezone suffix, assuming UTC" 109 + ); 110 + chrono::NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S%.f") 111 + .map(|ndt| Self(ndt.and_utc().fixed_offset())) 112 + }) 113 + } 114 + } 115 + 116 + impl jacquard_common::IntoStatic for Datetime { 117 + type Output = Datetime; 118 + fn into_static(self) -> Self::Output { 119 + self 120 + } 121 + } 122 + 123 + #[derive(Debug, Clone, PartialEq, Eq, Hash)] 124 + pub enum RepoOpAction<'a> { 125 + Create, 126 + Update, 127 + Delete, 128 + Other(jacquard_common::CowStr<'a>), 129 + } 130 + 131 + impl<'a> RepoOpAction<'a> { 132 + pub fn as_str(&self) -> &str { 133 + match self { 134 + Self::Create => "create", 135 + Self::Update => "update", 136 + Self::Delete => "delete", 137 + Self::Other(s) => s.as_ref(), 138 + } 139 + } 140 + } 141 + 142 + impl<'a> From<&'a str> for RepoOpAction<'a> { 143 + fn from(s: &'a str) -> Self { 144 + match s { 145 + "create" => Self::Create, 146 + "update" => Self::Update, 147 + "delete" => Self::Delete, 148 + _ => Self::Other(jacquard_common::CowStr::from(s)), 149 + } 150 + } 151 + } 152 + 153 + impl<'a> From<String> for RepoOpAction<'a> { 154 + fn from(s: String) -> Self { 155 + match s.as_str() { 156 + "create" => Self::Create, 157 + "update" => Self::Update, 158 + "delete" => Self::Delete, 159 + _ => Self::Other(jacquard_common::CowStr::from(s)), 160 + } 161 + } 162 + } 163 + 164 + impl<'a> core::fmt::Display for RepoOpAction<'a> { 165 + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 166 + write!(f, "{}", self.as_str()) 167 + } 168 + } 169 + 170 + impl<'a> AsRef<str> for RepoOpAction<'a> { 171 + fn as_ref(&self) -> &str { 172 + self.as_str() 173 + } 174 + } 175 + 176 + impl<'a> serde::Serialize for RepoOpAction<'a> { 177 + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 178 + where 179 + S: serde::Serializer, 180 + { 181 + serializer.serialize_str(self.as_str()) 182 + } 183 + } 184 + 185 + impl<'de, 'a> serde::Deserialize<'de> for RepoOpAction<'a> 186 + where 187 + 'de: 'a, 188 + { 189 + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 190 + where 191 + D: serde::Deserializer<'de>, 192 + { 193 + let s = <&'de str>::deserialize(deserializer)?; 194 + Ok(Self::from(s)) 195 + } 196 + } 197 + 198 + impl<'a> Default for RepoOpAction<'a> { 199 + fn default() -> Self { 200 + Self::Other(Default::default()) 201 + } 202 + } 203 + 204 + impl<'a> jacquard_common::IntoStatic for RepoOpAction<'a> { 205 + type Output = RepoOpAction<'static>; 206 + fn into_static(self) -> Self::Output { 207 + match self { 208 + RepoOpAction::Create => RepoOpAction::Create, 209 + RepoOpAction::Update => RepoOpAction::Update, 210 + RepoOpAction::Delete => RepoOpAction::Delete, 211 + RepoOpAction::Other(v) => RepoOpAction::Other(v.into_static()), 212 + } 213 + } 214 + } 215 + 216 + #[derive(serde::Deserialize, serde::Serialize, Debug, Clone, jacquard_derive::IntoStatic)] 217 + #[serde(rename_all = "camelCase")] 218 + pub struct RepoOp<'a> { 219 + #[serde(borrow)] 220 + pub action: RepoOpAction<'a>, 221 + /// For creates and updates, the new record CID. For deletions, null. 222 + #[serde(borrow)] 223 + pub cid: Option<CidLink<'a>>, 224 + #[serde(borrow)] 225 + pub path: jacquard_common::CowStr<'a>, 226 + /// For updates and deletes, the previous record CID (required for inductive firehose). For creations, field should not be defined. 227 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 228 + #[serde(borrow)] 229 + pub prev: Option<CidLink<'a>>, 230 + } 231 + 232 + #[derive(serde::Deserialize, serde::Serialize, Debug, Clone, jacquard_derive::IntoStatic)] 233 + #[serde(rename_all = "camelCase")] 234 + pub struct Commit<'a> { 235 + #[serde(borrow)] 236 + pub blobs: Vec<CidLink<'a>>, 237 + #[serde(with = "jacquard_common::serde_bytes_helper")] 238 + pub blocks: Bytes, 239 + #[serde(borrow)] 240 + pub commit: CidLink<'a>, 241 + #[serde(borrow)] 242 + pub ops: Vec<RepoOp<'a>>, 243 + #[serde(skip_serializing_if = "Option::is_none")] 244 + #[serde(borrow)] 245 + pub prev_data: Option<CidLink<'a>>, 246 + pub rebase: bool, 247 + #[serde(borrow)] 248 + pub repo: Did<'a>, 249 + pub rev: Tid, 250 + pub seq: i64, 251 + pub since: Option<Tid>, 252 + pub time: Datetime, 253 + pub too_big: bool, 254 + } 255 + 256 + #[derive(serde::Deserialize, Debug, Clone, jacquard_derive::IntoStatic)] 257 + #[serde(rename_all = "camelCase")] 258 + pub struct Identity<'a> { 259 + #[serde(borrow)] 260 + pub did: Did<'a>, 261 + #[serde(skip_serializing_if = "Option::is_none")] 262 + #[serde(borrow)] 263 + pub handle: Option<Handle<'a>>, 264 + pub seq: i64, 265 + pub time: Datetime, 266 + } 267 + 268 + #[derive(Debug, Clone, PartialEq, Eq, Hash)] 269 + pub enum AccountStatus<'a> { 270 + Takendown, 271 + Suspended, 272 + Deleted, 273 + Deactivated, 274 + Desynchronized, 275 + Throttled, 276 + Other(jacquard_common::CowStr<'a>), 277 + } 278 + 279 + impl<'a> AccountStatus<'a> { 280 + pub fn as_str(&self) -> &str { 281 + match self { 282 + Self::Takendown => "takendown", 283 + Self::Suspended => "suspended", 284 + Self::Deleted => "deleted", 285 + Self::Deactivated => "deactivated", 286 + Self::Desynchronized => "desynchronized", 287 + Self::Throttled => "throttled", 288 + Self::Other(s) => s.as_ref(), 289 + } 290 + } 291 + } 292 + 293 + impl<'a> From<&'a str> for AccountStatus<'a> { 294 + fn from(s: &'a str) -> Self { 295 + match s { 296 + "takendown" => Self::Takendown, 297 + "suspended" => Self::Suspended, 298 + "deleted" => Self::Deleted, 299 + "deactivated" => Self::Deactivated, 300 + "desynchronized" => Self::Desynchronized, 301 + "throttled" => Self::Throttled, 302 + _ => Self::Other(jacquard_common::CowStr::from(s)), 303 + } 304 + } 305 + } 306 + 307 + impl<'a> From<String> for AccountStatus<'a> { 308 + fn from(s: String) -> Self { 309 + match s.as_str() { 310 + "takendown" => Self::Takendown, 311 + "suspended" => Self::Suspended, 312 + "deleted" => Self::Deleted, 313 + "deactivated" => Self::Deactivated, 314 + "desynchronized" => Self::Desynchronized, 315 + "throttled" => Self::Throttled, 316 + _ => Self::Other(jacquard_common::CowStr::from(s)), 317 + } 318 + } 319 + } 320 + 321 + impl<'a> core::fmt::Display for AccountStatus<'a> { 322 + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 323 + write!(f, "{}", self.as_str()) 324 + } 325 + } 326 + 327 + impl<'a> AsRef<str> for AccountStatus<'a> { 328 + fn as_ref(&self) -> &str { 329 + self.as_str() 330 + } 331 + } 332 + 333 + impl<'a> serde::Serialize for AccountStatus<'a> { 334 + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 335 + where 336 + S: serde::Serializer, 337 + { 338 + serializer.serialize_str(self.as_str()) 339 + } 340 + } 341 + 342 + impl<'de, 'a> serde::Deserialize<'de> for AccountStatus<'a> 343 + where 344 + 'de: 'a, 345 + { 346 + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 347 + where 348 + D: serde::Deserializer<'de>, 349 + { 350 + let s = <&'de str>::deserialize(deserializer)?; 351 + Ok(Self::from(s)) 352 + } 353 + } 354 + 355 + impl<'a> Default for AccountStatus<'a> { 356 + fn default() -> Self { 357 + Self::Other(Default::default()) 358 + } 359 + } 360 + 361 + impl jacquard_common::IntoStatic for AccountStatus<'_> { 362 + type Output = AccountStatus<'static>; 363 + fn into_static(self) -> Self::Output { 364 + match self { 365 + AccountStatus::Takendown => AccountStatus::Takendown, 366 + AccountStatus::Suspended => AccountStatus::Suspended, 367 + AccountStatus::Deleted => AccountStatus::Deleted, 368 + AccountStatus::Deactivated => AccountStatus::Deactivated, 369 + AccountStatus::Desynchronized => AccountStatus::Desynchronized, 370 + AccountStatus::Throttled => AccountStatus::Throttled, 371 + AccountStatus::Other(v) => AccountStatus::Other(v.into_static()), 372 + } 373 + } 374 + } 375 + 376 + #[derive(serde::Deserialize, Debug, Clone, jacquard_derive::IntoStatic)] 377 + #[serde(rename_all = "camelCase")] 378 + pub struct Account<'a> { 379 + pub active: bool, 380 + #[serde(borrow)] 381 + pub did: Did<'a>, 382 + pub seq: i64, 383 + pub status: Option<AccountStatus<'a>>, 384 + pub time: Datetime, 385 + } 386 + 387 + #[derive(serde::Deserialize, Debug, Clone, jacquard_derive::IntoStatic)] 388 + #[serde(rename_all = "camelCase")] 389 + pub struct Sync<'a> { 390 + #[serde(with = "jacquard_common::serde_bytes_helper")] 391 + pub blocks: Bytes, 392 + #[serde(borrow)] 393 + pub did: Did<'a>, 394 + #[serde(borrow)] 395 + pub rev: CowStr<'a>, 396 + pub seq: i64, 397 + pub time: Datetime, 398 + } 399 + 400 + #[derive(Debug, Clone, PartialEq, Eq, Hash)] 401 + pub enum InfoName<'a> { 402 + OutdatedCursor, 403 + Other(jacquard_common::CowStr<'a>), 404 + } 405 + 406 + impl<'a> InfoName<'a> { 407 + pub fn as_str(&self) -> &str { 408 + match self { 409 + Self::OutdatedCursor => "OutdatedCursor", 410 + Self::Other(s) => s.as_ref(), 411 + } 412 + } 413 + } 414 + 415 + impl<'a> From<&'a str> for InfoName<'a> { 416 + fn from(s: &'a str) -> Self { 417 + match s { 418 + "OutdatedCursor" => Self::OutdatedCursor, 419 + _ => Self::Other(jacquard_common::CowStr::from(s)), 420 + } 421 + } 422 + } 423 + 424 + impl<'a> From<String> for InfoName<'a> { 425 + fn from(s: String) -> Self { 426 + match s.as_str() { 427 + "OutdatedCursor" => Self::OutdatedCursor, 428 + _ => Self::Other(jacquard_common::CowStr::from(s)), 429 + } 430 + } 431 + } 432 + 433 + impl<'a> core::fmt::Display for InfoName<'a> { 434 + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 435 + write!(f, "{}", self.as_str()) 436 + } 437 + } 438 + 439 + impl<'a> AsRef<str> for InfoName<'a> { 440 + fn as_ref(&self) -> &str { 441 + self.as_str() 442 + } 443 + } 444 + 445 + impl<'a> serde::Serialize for InfoName<'a> { 446 + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 447 + where 448 + S: serde::Serializer, 449 + { 450 + serializer.serialize_str(self.as_str()) 451 + } 452 + } 453 + 454 + impl<'de, 'a> serde::Deserialize<'de> for InfoName<'a> 455 + where 456 + 'de: 'a, 457 + { 458 + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 459 + where 460 + D: serde::Deserializer<'de>, 461 + { 462 + let s = <&'de str>::deserialize(deserializer)?; 463 + Ok(Self::from(s)) 464 + } 465 + } 466 + 467 + impl<'a> Default for InfoName<'a> { 468 + fn default() -> Self { 469 + Self::Other(Default::default()) 470 + } 471 + } 472 + 473 + impl<'a> jacquard_common::IntoStatic for InfoName<'a> { 474 + type Output = InfoName<'static>; 475 + fn into_static(self) -> Self::Output { 476 + match self { 477 + InfoName::OutdatedCursor => InfoName::OutdatedCursor, 478 + InfoName::Other(v) => InfoName::Other(v.into_static()), 479 + } 480 + } 481 + } 482 + 483 + #[derive(serde::Deserialize, Debug, Clone, jacquard_derive::IntoStatic)] 484 + #[serde(rename_all = "camelCase")] 485 + pub struct Info<'a> { 486 + #[serde(skip_serializing_if = "Option::is_none")] 487 + #[serde(borrow)] 488 + pub message: Option<CowStr<'a>>, 489 + #[serde(borrow)] 490 + pub name: InfoName<'a>, 491 + } 492 + 493 + #[derive(Debug, Clone, jacquard_derive::IntoStatic)] 494 + pub enum SubscribeReposMessage<'i> { 495 + Commit(Box<Commit<'i>>), 496 + Sync(Box<Sync<'i>>), 497 + Identity(Box<Identity<'i>>), 498 + Account(Box<Account<'i>>), 499 + Info(Box<Info<'i>>), 500 + } 501 + 502 + use serde::Deserialize; 503 + use serde_ipld_dagcbor::de::Deserializer; 504 + 505 + #[derive(Debug, Deserialize)] 506 + struct EventHeader { 507 + op: i64, 508 + t: Option<String>, 509 + } 510 + 511 + #[derive(Deserialize)] 512 + struct ErrorFrame { 513 + error: String, 514 + message: Option<String>, 515 + } 516 + 517 + pub fn decode_frame<'i>(bytes: &'i [u8]) -> Result<SubscribeReposMessage<'i>, FirehoseError> { 518 + let mut de = Deserializer::from_slice(bytes); 519 + let header = EventHeader::deserialize(&mut de)?; 520 + 521 + match header.op { 522 + -1 => { 523 + let err = ErrorFrame::deserialize(&mut de)?; 524 + return Err(FirehoseError::RelayError { 525 + error: err.error, 526 + message: err.message, 527 + }); 528 + } 529 + 1 => {} 530 + op => return Err(FirehoseError::UnknownOp(op)), 531 + } 532 + 533 + let t = header.t.ok_or(FirehoseError::MissingType)?; 534 + 535 + let msg = match t.as_str() { 536 + "#commit" => SubscribeReposMessage::Commit(Box::new(Deserialize::deserialize(&mut de)?)), 537 + "#account" => SubscribeReposMessage::Account(Box::new(Deserialize::deserialize(&mut de)?)), 538 + "#identity" => { 539 + SubscribeReposMessage::Identity(Box::new(Deserialize::deserialize(&mut de)?)) 540 + } 541 + "#sync" => SubscribeReposMessage::Sync(Box::new(Deserialize::deserialize(&mut de)?)), 542 + "#info" => SubscribeReposMessage::Info(Box::new(Deserialize::deserialize(&mut de)?)), 543 + other => return Err(FirehoseError::UnknownType(other.to_string())), 544 + }; 545 + 546 + Ok(msg) 547 + } 548 + 549 + #[cfg(test)] 550 + mod test { 551 + use super::{SubscribeReposMessage, decode_frame}; 552 + 553 + #[test] 554 + fn test_decode_account() { 555 + const FRAME: &[u8] = b"omF0aCNhY2NvdW50Ym9wAaRjZGlkeCBkaWQ6cGxjOjNuNDNncWY2YTZua3J3MzU1cnNjNnJ0ZGNzZXEbAAAAAlP5Zt5kdGltZXgbMjAyNi0wMi0yNFQxNDowNToyMC41MjE1NDY5ZmFjdGl2ZfU="; 556 + let bytes = data_encoding::BASE64.decode(FRAME).unwrap(); 557 + let msg = decode_frame(&bytes).unwrap(); 558 + assert!(matches!(msg, SubscribeReposMessage::Account(_))); 559 + } 560 + }
+5 -6
src/ingest/worker.rs
··· 1 1 use crate::db::{self, keys}; 2 2 use crate::filter::FilterMode; 3 + use crate::ingest::stream::{Commit, SubscribeReposMessage}; 3 4 use crate::ingest::{BufferRx, IngestMessage}; 4 5 use crate::ops; 5 6 use crate::resolver::{NoSigningKeyError, ResolverError}; 6 7 use crate::state::AppState; 7 8 use crate::types::{AccountEvt, BroadcastEvent, GaugeState, IdentityEvt, RepoState, RepoStatus}; 8 - use jacquard::api::com_atproto::sync::subscribe_repos::SubscribeReposMessage; 9 9 10 10 use fjall::OwnedWriteBatch; 11 11 12 - use jacquard::cowstr::ToCowStr; 13 - use jacquard::types::crypto::PublicKey; 14 - use jacquard::types::did::Did; 15 - use jacquard_api::com_atproto::sync::subscribe_repos::Commit; 16 12 use jacquard_common::IntoStatic; 13 + use jacquard_common::cowstr::ToCowStr; 14 + use jacquard_common::types::crypto::PublicKey; 15 + use jacquard_common::types::did::Did; 17 16 use jacquard_repo::error::CommitError; 18 17 use miette::{Context, Diagnostic, IntoDiagnostic, Result}; 19 18 use rand::Rng; ··· 376 375 }; 377 376 378 377 if !account.active { 379 - use jacquard::api::com_atproto::sync::subscribe_repos::AccountStatus; 378 + use crate::ingest::stream::AccountStatus; 380 379 match &account.status { 381 380 Some(AccountStatus::Deleted) => { 382 381 debug!("account {did} deleted, wiping data");
+12 -6
src/main.rs
··· 16 16 17 17 #[tokio::main] 18 18 async fn main() -> miette::Result<()> { 19 - rustls::crypto::ring::default_provider().install_default().ok(); 20 - 19 + rustls::crypto::aws_lc_rs::default_provider() 20 + .install_default() 21 + .ok(); 22 + 21 23 let cfg = Config::from_env()?; 22 24 23 25 let env_filter = tracing_subscriber::EnvFilter::new(&cfg.log_level); ··· 27 29 28 30 let state = AppState::new(&cfg)?; 29 31 30 - if cfg.full_network || cfg.filter_signals.is_some() || cfg.filter_collections.is_some() || cfg.filter_excludes.is_some() { 32 + if cfg.full_network 33 + || cfg.filter_signals.is_some() 34 + || cfg.filter_collections.is_some() 35 + || cfg.filter_excludes.is_some() 36 + { 31 37 let filter_ks = state.db.filter.clone(); 32 38 let inner = state.db.inner.clone(); 33 39 let full_network = cfg.full_network; ··· 38 44 tokio::task::spawn_blocking(move || { 39 45 use hydrant::filter::{FilterMode, SetUpdate}; 40 46 let mut batch = inner.batch(); 41 - 47 + 42 48 let mode = if full_network { 43 49 Some(FilterMode::Full) 44 50 } else { 45 51 None 46 52 }; 47 - 53 + 48 54 let signals_update = signals.map(SetUpdate::Set); 49 55 let collections_update = collections.map(SetUpdate::Set); 50 56 let excludes_update = excludes.map(SetUpdate::Set); ··· 57 63 collections_update, 58 64 excludes_update, 59 65 )?; 60 - 66 + 61 67 batch.commit().into_diagnostic() 62 68 }) 63 69 .await
+15 -15
src/ops.rs
··· 1 - use crate::db::types::{DbAction, DbRkey, DbTid, TrimmedDid}; 2 - use crate::db::{self, Db, keys, ser_repo_state}; 3 - use crate::filter::FilterConfig; 4 - use crate::types::{ 5 - AccountEvt, BroadcastEvent, IdentityEvt, MarshallableEvt, RepoState, RepoStatus, ResyncState, 6 - StoredEvent, 7 - }; 8 1 use fjall::OwnedWriteBatch; 9 - use jacquard::CowStr; 10 - use jacquard::IntoStatic; 11 - 12 - use jacquard::types::cid::Cid; 13 - use jacquard::types::did::Did; 14 - use jacquard_api::com_atproto::sync::subscribe_repos::Commit; 2 + use jacquard_common::CowStr; 3 + use jacquard_common::IntoStatic; 4 + use jacquard_common::types::cid::Cid; 15 5 use jacquard_common::types::crypto::PublicKey; 6 + use jacquard_common::types::did::Did; 16 7 use jacquard_repo::car::reader::parse_car_bytes; 17 8 use miette::{Context, IntoDiagnostic, Result}; 18 9 use rand::{Rng, rng}; ··· 21 12 use std::time::Instant; 22 13 use tracing::{debug, trace}; 23 14 15 + use crate::db::types::{DbAction, DbRkey, DbTid, TrimmedDid}; 16 + use crate::db::{self, Db, keys, ser_repo_state}; 17 + use crate::filter::FilterConfig; 18 + use crate::ingest::stream::Commit; 19 + use crate::types::{ 20 + AccountEvt, BroadcastEvent, IdentityEvt, MarshallableEvt, RepoState, RepoStatus, ResyncState, 21 + StoredEvent, 22 + }; 23 + 24 24 pub fn persist_to_resync_buffer(db: &Db, did: &Did, commit: &Commit) -> Result<()> { 25 25 let key = keys::resync_buffer_key(did, DbTid::from(&commit.rev)); 26 26 let value = rmp_serde::to_vec(commit).into_diagnostic()?; ··· 66 66 pub fn delete_repo<'batch>( 67 67 batch: &'batch mut OwnedWriteBatch, 68 68 db: &Db, 69 - did: &jacquard::types::did::Did, 69 + did: &Did, 70 70 repo_state: &RepoState, 71 71 ) -> Result<()> { 72 72 debug!("deleting repo {did}"); ··· 118 118 pub fn update_repo_status<'batch, 's>( 119 119 batch: &'batch mut OwnedWriteBatch, 120 120 db: &Db, 121 - did: &jacquard::types::did::Did, 121 + did: &Did, 122 122 mut repo_state: RepoState<'s>, 123 123 new_status: RepoStatus, 124 124 ) -> Result<RepoState<'s>> {
+3 -3
src/resolver.rs
··· 3 3 use std::sync::atomic::{AtomicUsize, Ordering}; 4 4 use std::time::Duration; 5 5 6 - use jacquard::IntoStatic; 7 - use jacquard::types::string::Handle; 6 + use jacquard_common::IntoStatic; 8 7 use jacquard_common::types::crypto::PublicKey; 9 8 use jacquard_common::types::ident::AtIdentifier; 10 9 use jacquard_common::types::string::Did; 10 + use jacquard_common::types::string::Handle; 11 11 use jacquard_identity::JacquardResolver; 12 12 use jacquard_identity::resolver::{ 13 13 IdentityError, IdentityErrorKind, IdentityResolver, PlcSource, ResolverOptions, ··· 69 69 opts.request_timeout = Some(Duration::from_secs(3)); 70 70 71 71 // no jacquard cache - we manage our own 72 - jacquards.push(JacquardResolver::new(http.clone(), opts)); 72 + jacquards.push(JacquardResolver::new(http.clone(), opts).with_system_dns()); 73 73 } 74 74 75 75 if jacquards.is_empty() {
+2 -2
src/types.rs
··· 1 1 use std::fmt::Display; 2 2 3 - use jacquard::{CowStr, IntoStatic, types::string::Handle}; 3 + use jacquard_common::types::cid::IpldCid; 4 4 use jacquard_common::types::string::Did; 5 + use jacquard_common::{CowStr, IntoStatic, types::string::Handle}; 5 6 use serde::{Deserialize, Serialize}; 6 7 use serde_json::Value; 7 8 use smol_str::SmolStr; 8 9 9 10 use crate::db::types::{DbAction, DbRkey, DbTid, TrimmedDid}; 10 - use jacquard::types::cid::IpldCid; 11 11 12 12 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 13 13 pub enum RepoStatus {