A decentralized music tracking and discovery platform built on AT Protocol 🎵 rocksky.app
spotify atproto lastfm musicbrainz scrobbling listenbrainz

feat(feed): implement feed service #8

closed opened by tsiry-sandratraina.com targeting main from feat/feed-generator
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:7vdlgi2bflelz7mmuxoqjfcr/sh.tangled.repo.pull/3lztmzurcri22
+989 -22
Diff #1
+632 -22
Cargo.lock
··· 417 417 418 418 [[package]] 419 419 name = "anyhow" 420 - version = "1.0.98" 420 + version = "1.0.100" 421 421 source = "registry+https://github.com/rust-lang/crates.io-index" 422 - checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 422 + checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" 423 423 424 424 [[package]] 425 425 name = "arc-swap" ··· 607 607 ] 608 608 609 609 [[package]] 610 + name = "async-compression" 611 + version = "0.4.31" 612 + source = "registry+https://github.com/rust-lang/crates.io-index" 613 + checksum = "9611ec0b6acea03372540509035db2f7f1e9f04da5d27728436fa994033c00a0" 614 + dependencies = [ 615 + "compression-codecs", 616 + "compression-core", 617 + "futures-core", 618 + "pin-project-lite", 619 + "tokio", 620 + ] 621 + 622 + [[package]] 623 + name = "async-lock" 624 + version = "3.4.1" 625 + source = "registry+https://github.com/rust-lang/crates.io-index" 626 + checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" 627 + dependencies = [ 628 + "event-listener", 629 + "event-listener-strategy", 630 + "pin-project-lite", 631 + ] 632 + 633 + [[package]] 610 634 name = "async-nats" 611 635 version = "0.39.0" 612 636 ··· 707 731 checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 708 732 709 733 [[package]] 734 + name = "atrium-api" 735 + version = "0.25.5" 736 + source = "registry+https://github.com/rust-lang/crates.io-index" 737 + checksum = "8bceed6a87be6213040945254aa94191490fea22b7f49dec584e349f336cc17a" 738 + dependencies = [ 739 + "atrium-common", 740 + "atrium-xrpc", 741 + "chrono", 742 + "http 1.3.1", 743 + "ipld-core", 744 + "langtag", 745 + "regex", 746 + "serde", 747 + "serde_bytes", 748 + "serde_json", 749 + "thiserror 1.0.69", 750 + "tokio", 751 + "trait-variant", 752 + ] 753 + 754 + [[package]] 755 + name = "atrium-common" 756 + version = "0.1.2" 757 + source = "registry+https://github.com/rust-lang/crates.io-index" 758 + checksum = "9ed5610654043faa396a5a15afac0ac646d76aebe45aebd7cef4f8b96b0ab7f4" 759 + dependencies = [ 760 + "dashmap", 761 + "lru", 762 + "moka", 763 + "thiserror 1.0.69", 764 + "tokio", 765 + "trait-variant", 766 + "web-time", 767 + ] 768 + 769 + [[package]] 770 + name = "atrium-xrpc" 771 + version = "0.12.3" 772 + source = "registry+https://github.com/rust-lang/crates.io-index" 773 + checksum = "0216ad50ce34e9ff982e171c3659e65dedaa2ed5ac2994524debdc9a9647ffa8" 774 + dependencies = [ 775 + "http 1.3.1", 776 + "serde", 777 + "serde_html_form", 778 + "serde_json", 779 + "thiserror 1.0.69", 780 + "trait-variant", 781 + ] 782 + 783 + [[package]] 784 + name = "atrium-xrpc-client" 785 + version = "0.5.14" 786 + source = "registry+https://github.com/rust-lang/crates.io-index" 787 + checksum = "e099e5171f79faef52364ef0657a4cab086a71b384a779a29597a91b780de0d5" 788 + dependencies = [ 789 + "atrium-xrpc", 790 + "reqwest", 791 + ] 792 + 793 + [[package]] 710 794 name = "attohttpc" 711 795 version = "0.28.5" 712 796 ··· 769 853 ] 770 854 771 855 [[package]] 856 + name = "base-x" 857 + version = "0.2.11" 858 + source = "registry+https://github.com/rust-lang/crates.io-index" 859 + checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" 860 + 861 + [[package]] 772 862 name = "base64" 773 863 version = "0.20.0" 774 864 ··· 1120 1210 ] 1121 1211 1122 1212 [[package]] 1213 + name = "cid" 1214 + version = "0.11.1" 1215 + source = "registry+https://github.com/rust-lang/crates.io-index" 1216 + checksum = "3147d8272e8fa0ccd29ce51194dd98f79ddfb8191ba9e3409884e751798acf3a" 1217 + dependencies = [ 1218 + "core2", 1219 + "multibase", 1220 + "multihash", 1221 + "serde", 1222 + "serde_bytes", 1223 + "unsigned-varint", 1224 + ] 1225 + 1226 + [[package]] 1123 1227 name = "cipher" 1124 1228 version = "0.4.4" 1125 1229 ··· 1247 1351 ] 1248 1352 1249 1353 [[package]] 1354 + name = "compression-codecs" 1355 + version = "0.4.30" 1356 + source = "registry+https://github.com/rust-lang/crates.io-index" 1357 + checksum = "485abf41ac0c8047c07c87c72c8fb3eb5197f6e9d7ded615dfd1a00ae00a0f64" 1358 + dependencies = [ 1359 + "compression-core", 1360 + "flate2", 1361 + "memchr", 1362 + ] 1363 + 1364 + [[package]] 1365 + name = "compression-core" 1366 + version = "0.4.29" 1367 + source = "registry+https://github.com/rust-lang/crates.io-index" 1368 + checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb" 1369 + 1370 + [[package]] 1250 1371 name = "concurrent-queue" 1251 1372 version = "2.5.0" 1252 1373 ··· 1341 1462 checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 1342 1463 1343 1464 [[package]] 1465 + name = "core2" 1466 + version = "0.4.0" 1467 + source = "registry+https://github.com/rust-lang/crates.io-index" 1468 + checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" 1469 + dependencies = [ 1470 + "memchr", 1471 + ] 1472 + 1473 + [[package]] 1344 1474 name = "cpufeatures" 1345 1475 version = "0.2.17" 1346 1476 ··· 1491 1621 ] 1492 1622 1493 1623 [[package]] 1624 + name = "dashmap" 1625 + version = "6.1.0" 1626 + source = "registry+https://github.com/rust-lang/crates.io-index" 1627 + checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" 1628 + dependencies = [ 1629 + "cfg-if", 1630 + "crossbeam-utils", 1631 + "hashbrown 0.14.5", 1632 + "lock_api", 1633 + "once_cell", 1634 + "parking_lot_core", 1635 + ] 1636 + 1637 + [[package]] 1494 1638 name = "data-encoding" 1495 1639 version = "2.9.0" 1496 1640 source = "registry+https://github.com/rust-lang/crates.io-index" 1497 1641 checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" 1498 1642 1499 1643 [[package]] 1644 + name = "data-encoding-macro" 1645 + version = "0.1.18" 1646 + source = "registry+https://github.com/rust-lang/crates.io-index" 1647 + checksum = "47ce6c96ea0102f01122a185683611bd5ac8d99e62bc59dd12e6bda344ee673d" 1648 + dependencies = [ 1649 + "data-encoding", 1650 + "data-encoding-macro-internal", 1651 + ] 1652 + 1653 + [[package]] 1654 + name = "data-encoding-macro-internal" 1655 + version = "0.1.16" 1656 + source = "registry+https://github.com/rust-lang/crates.io-index" 1657 + checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" 1658 + dependencies = [ 1659 + "data-encoding", 1660 + "syn 2.0.101", 1661 + ] 1662 + 1663 + [[package]] 1500 1664 name = "der" 1501 1665 version = "0.7.10" 1502 1666 ··· 1780 1944 ] 1781 1945 1782 1946 [[package]] 1947 + name = "event-listener-strategy" 1948 + version = "0.5.4" 1949 + source = "registry+https://github.com/rust-lang/crates.io-index" 1950 + checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" 1951 + dependencies = [ 1952 + "event-listener", 1953 + "pin-project-lite", 1954 + ] 1955 + 1956 + [[package]] 1783 1957 name = "extended" 1784 1958 version = "0.1.0" 1785 1959 ··· 1867 2041 dependencies = [ 1868 2042 "futures-core", 1869 2043 "futures-sink", 2044 + "nanorand", 1870 2045 "spin", 1871 2046 ] 1872 2047 ··· 1883 2058 checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" 1884 2059 1885 2060 [[package]] 2061 + name = "foreign-types" 2062 + version = "0.3.2" 2063 + source = "registry+https://github.com/rust-lang/crates.io-index" 2064 + checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 2065 + dependencies = [ 2066 + "foreign-types-shared", 2067 + ] 2068 + 2069 + [[package]] 2070 + name = "foreign-types-shared" 2071 + version = "0.1.1" 2072 + source = "registry+https://github.com/rust-lang/crates.io-index" 2073 + checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 2074 + 2075 + [[package]] 1886 2076 name = "form_urlencoded" 1887 2077 version = "1.2.1" 1888 2078 ··· 2229 2419 ] 2230 2420 2231 2421 [[package]] 2422 + name = "headers" 2423 + version = "0.3.9" 2424 + source = "registry+https://github.com/rust-lang/crates.io-index" 2425 + checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" 2426 + dependencies = [ 2427 + "base64 0.21.7", 2428 + "bytes", 2429 + "headers-core", 2430 + "http 0.2.12", 2431 + "httpdate", 2432 + "mime", 2433 + "sha1", 2434 + ] 2435 + 2436 + [[package]] 2437 + name = "headers-core" 2438 + version = "0.2.0" 2439 + source = "registry+https://github.com/rust-lang/crates.io-index" 2440 + checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" 2441 + dependencies = [ 2442 + "http 0.2.12", 2443 + ] 2444 + 2445 + [[package]] 2232 2446 name = "heapless" 2233 2447 version = "0.8.0" 2234 2448 ··· 2378 2592 "futures-channel", 2379 2593 "futures-core", 2380 2594 "futures-util", 2595 + "h2 0.3.26", 2381 2596 "http 0.2.12", 2382 2597 "http-body 0.4.6", 2383 2598 "httparse", ··· 2444 2659 ] 2445 2660 2446 2661 [[package]] 2662 + name = "hyper-tls" 2663 + version = "0.6.0" 2664 + source = "registry+https://github.com/rust-lang/crates.io-index" 2665 + checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 2666 + dependencies = [ 2667 + "bytes", 2668 + "http-body-util", 2669 + "hyper 1.6.0", 2670 + "hyper-util", 2671 + "native-tls", 2672 + "tokio", 2673 + "tokio-native-tls", 2674 + "tower-service", 2675 + ] 2676 + 2677 + [[package]] 2447 2678 name = "hyper-util" 2448 2679 version = "0.1.12" 2449 2680 ··· 2627 2858 ] 2628 2859 2629 2860 [[package]] 2861 + name = "ipld-core" 2862 + version = "0.4.2" 2863 + source = "registry+https://github.com/rust-lang/crates.io-index" 2864 + checksum = "104718b1cc124d92a6d01ca9c9258a7df311405debb3408c445a36452f9bf8db" 2865 + dependencies = [ 2866 + "cid", 2867 + "serde", 2868 + "serde_bytes", 2869 + ] 2870 + 2871 + [[package]] 2630 2872 name = "ipnet" 2631 2873 version = "2.11.0" 2632 2874 ··· 2671 2913 checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 2672 2914 2673 2915 [[package]] 2916 + name = "jetstream-oxide" 2917 + version = "0.1.2" 2918 + source = "registry+https://github.com/rust-lang/crates.io-index" 2919 + checksum = "a267b4f381f1db945e9eb6b9ff0f3070950cc01521fef6265556b6a683e41e13" 2920 + dependencies = [ 2921 + "async-trait", 2922 + "atrium-api", 2923 + "chrono", 2924 + "flume", 2925 + "futures-util", 2926 + "log", 2927 + "serde", 2928 + "serde_json", 2929 + "thiserror 2.0.12", 2930 + "tokio", 2931 + "tokio-tungstenite 0.24.0", 2932 + "tokio-util", 2933 + "url", 2934 + "zstd", 2935 + ] 2936 + 2937 + [[package]] 2674 2938 name = "jni" 2675 2939 version = "0.21.1" 2676 2940 ··· 2855 3119 ] 2856 3120 2857 3121 [[package]] 3122 + name = "langtag" 3123 + version = "0.3.4" 3124 + source = "registry+https://github.com/rust-lang/crates.io-index" 3125 + checksum = "ed60c85f254d6ae8450cec15eedd921efbc4d1bdf6fcf6202b9a58b403f6f805" 3126 + dependencies = [ 3127 + "serde", 3128 + ] 3129 + 3130 + [[package]] 2858 3131 name = "language-tags" 2859 3132 version = "0.3.2" 2860 3133 ··· 3069 3342 checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 3070 3343 3071 3344 [[package]] 3345 + name = "lru" 3346 + version = "0.12.5" 3347 + source = "registry+https://github.com/rust-lang/crates.io-index" 3348 + checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" 3349 + dependencies = [ 3350 + "hashbrown 0.15.3", 3351 + ] 3352 + 3353 + [[package]] 3072 3354 name = "lru-slab" 3073 3355 version = "0.1.2" 3074 3356 ··· 3181 3463 3182 3464 3183 3465 3466 + "windows-sys 0.59.0", 3467 + ] 3184 3468 3469 + [[package]] 3470 + name = "moka" 3471 + version = "0.12.11" 3472 + source = "registry+https://github.com/rust-lang/crates.io-index" 3473 + checksum = "8261cd88c312e0004c1d51baad2980c66528dfdb2bee62003e643a4d8f86b077" 3474 + dependencies = [ 3475 + "async-lock", 3476 + "crossbeam-channel", 3477 + "crossbeam-epoch", 3478 + "crossbeam-utils", 3479 + "equivalent", 3480 + "event-listener", 3481 + "futures-util", 3482 + "parking_lot", 3483 + "portable-atomic", 3484 + "rustc_version", 3485 + "smallvec", 3486 + "tagptr", 3487 + "uuid", 3488 + ] 3185 3489 3490 + [[package]] 3491 + name = "multer" 3492 + version = "2.1.0" 3493 + source = "registry+https://github.com/rust-lang/crates.io-index" 3494 + checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" 3495 + dependencies = [ 3496 + "bytes", 3497 + "encoding_rs", 3498 + "futures-util", 3499 + "http 0.2.12", 3500 + "httparse", 3501 + "log", 3502 + "memchr", 3503 + "mime", 3504 + "spin", 3505 + "version_check", 3506 + ] 3186 3507 3508 + [[package]] 3509 + name = "multibase" 3510 + version = "0.9.1" 3511 + source = "registry+https://github.com/rust-lang/crates.io-index" 3512 + checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" 3513 + dependencies = [ 3514 + "base-x", 3515 + "data-encoding", 3516 + "data-encoding-macro", 3517 + ] 3187 3518 3519 + [[package]] 3520 + name = "multihash" 3521 + version = "0.19.3" 3522 + source = "registry+https://github.com/rust-lang/crates.io-index" 3523 + checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" 3524 + dependencies = [ 3525 + "core2", 3526 + "serde", 3527 + "unsigned-varint", 3528 + ] 3188 3529 3530 + [[package]] 3531 + name = "nanoid" 3532 + version = "0.4.0" 3189 3533 3190 3534 3191 3535 3536 + "rand 0.8.5", 3537 + ] 3192 3538 3539 + [[package]] 3540 + name = "nanorand" 3541 + version = "0.7.0" 3542 + source = "registry+https://github.com/rust-lang/crates.io-index" 3543 + checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" 3544 + dependencies = [ 3545 + "getrandom 0.2.16", 3546 + ] 3193 3547 3548 + [[package]] 3549 + name = "native-tls" 3550 + version = "0.2.14" 3551 + source = "registry+https://github.com/rust-lang/crates.io-index" 3552 + checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" 3553 + dependencies = [ 3554 + "libc", 3555 + "log", 3556 + "openssl", 3557 + "openssl-probe", 3558 + "openssl-sys", 3559 + "schannel", 3560 + "security-framework 2.11.1", 3561 + "security-framework-sys", 3562 + "tempfile", 3563 + ] 3194 3564 3565 + [[package]] 3566 + name = "nkeys" 3567 + version = "0.4.4" 3195 3568 3196 3569 3197 3570 ··· 3390 3763 3391 3764 3392 3765 3766 + checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" 3393 3767 3768 + [[package]] 3769 + name = "openssl" 3770 + version = "0.10.73" 3771 + source = "registry+https://github.com/rust-lang/crates.io-index" 3772 + checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" 3773 + dependencies = [ 3774 + "bitflags 2.9.1", 3775 + "cfg-if", 3776 + "foreign-types", 3777 + "libc", 3778 + "once_cell", 3779 + "openssl-macros", 3780 + "openssl-sys", 3781 + ] 3394 3782 3783 + [[package]] 3784 + name = "openssl-macros" 3785 + version = "0.1.1" 3786 + source = "registry+https://github.com/rust-lang/crates.io-index" 3787 + checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 3788 + dependencies = [ 3789 + "proc-macro2", 3790 + "quote", 3791 + "syn 2.0.101", 3792 + ] 3395 3793 3396 - 3397 - checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" 3398 - 3399 3794 [[package]] 3400 3795 name = "openssl-probe" 3401 3796 version = "0.1.6" ··· 3403 3798 checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 3404 3799 3405 3800 [[package]] 3801 + name = "openssl-src" 3802 + version = "300.5.2+3.5.2" 3803 + source = "registry+https://github.com/rust-lang/crates.io-index" 3804 + checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" 3805 + dependencies = [ 3806 + "cc", 3807 + ] 3808 + 3809 + [[package]] 3810 + name = "openssl-sys" 3811 + version = "0.9.109" 3812 + source = "registry+https://github.com/rust-lang/crates.io-index" 3813 + checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" 3814 + dependencies = [ 3815 + "cc", 3816 + "libc", 3817 + "openssl-src", 3818 + "pkg-config", 3819 + "vcpkg", 3820 + ] 3821 + 3822 + [[package]] 3406 3823 name = "option-ext" 3407 3824 version = "0.2.0" 3408 3825 ··· 4754 5171 source = "registry+https://github.com/rust-lang/crates.io-index" 4755 5172 checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" 4756 5173 dependencies = [ 5174 + "async-compression", 4757 5175 "base64 0.22.1", 4758 5176 "bytes", 4759 5177 "futures-core", ··· 4763 5181 "http-body-util", 4764 5182 "hyper 1.6.0", 4765 5183 "hyper-rustls 0.27.6", 5184 + "hyper-tls", 4766 5185 "hyper-util", 4767 5186 "ipnet", 4768 5187 "js-sys", 4769 5188 "log", 4770 5189 "mime", 4771 5190 "mime_guess", 5191 + "native-tls", 4772 5192 "once_cell", 4773 5193 "percent-encoding", 4774 5194 "pin-project-lite", ··· 4781 5201 "serde_urlencoded", 4782 5202 "sync_wrapper", 4783 5203 "tokio", 5204 + "tokio-native-tls", 4784 5205 "tokio-rustls 0.26.2", 4785 5206 "tokio-util", 4786 5207 "tower", ··· 4875 5296 "serde_json", 4876 5297 "tokio", 4877 5298 "tokio-stream", 4878 - "tokio-tungstenite", 4879 - "tungstenite", 5299 + "tokio-tungstenite 0.26.2", 5300 + "tungstenite 0.26.2", 4880 5301 ] 4881 5302 4882 5303 [[package]] ··· 4911 5332 ] 4912 5333 4913 5334 [[package]] 5335 + name = "rocksky-feed" 5336 + version = "0.1.0" 5337 + dependencies = [ 5338 + "anyhow", 5339 + "atrium-api", 5340 + "atrium-xrpc-client", 5341 + "chrono", 5342 + "dotenv", 5343 + "duckdb", 5344 + "jetstream-oxide", 5345 + "owo-colors", 5346 + "reqwest", 5347 + "serde", 5348 + "serde_json", 5349 + "sqlx", 5350 + "tokio", 5351 + "tracing", 5352 + "warp", 5353 + ] 5354 + 5355 + [[package]] 4914 5356 name = "rocksky-googledrive" 4915 5357 version = "0.1.0" 4916 5358 ··· 4961 5403 "time", 4962 5404 "tokio", 4963 5405 "tokio-stream", 4964 - "tokio-tungstenite", 5406 + "tokio-tungstenite 0.26.2", 4965 5407 "tracing", 4966 - "tungstenite", 5408 + "tungstenite 0.26.2", 4967 5409 "url", 4968 5410 ] 4969 5411 ··· 5121 5563 5122 5564 5123 5565 5566 + "owo-colors", 5567 + "rocksky-analytics", 5568 + "rocksky-dropbox", 5569 + "rocksky-feed", 5570 + "rocksky-googledrive", 5571 + "rocksky-jetstream", 5572 + "rocksky-playlists", 5124 5573 5125 5574 5126 5575 ··· 5460 5909 5461 5910 5462 5911 5463 - 5464 - 5465 - 5466 - 5467 - 5468 - 5469 5912 "windows-sys 0.59.0", 5470 5913 ] 5471 5914 5472 5915 [[package]] 5916 + name = "scoped-tls" 5917 + version = "1.0.1" 5918 + source = "registry+https://github.com/rust-lang/crates.io-index" 5919 + checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 5920 + 5921 + [[package]] 5473 5922 name = "scopeguard" 5474 5923 version = "1.2.0" 5475 5924 ··· 5550 5999 5551 6000 [[package]] 5552 6001 name = "serde" 5553 - version = "1.0.219" 6002 + version = "1.0.227" 5554 6003 source = "registry+https://github.com/rust-lang/crates.io-index" 5555 - checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 6004 + checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" 5556 6005 dependencies = [ 6006 + "serde_core", 5557 6007 "serde_derive", 5558 6008 ] 5559 6009 5560 6010 [[package]] 6011 + name = "serde_bytes" 6012 + version = "0.11.19" 6013 + source = "registry+https://github.com/rust-lang/crates.io-index" 6014 + checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" 6015 + dependencies = [ 6016 + "serde", 6017 + "serde_core", 6018 + ] 6019 + 6020 + [[package]] 5561 6021 name = "serde_cbor" 5562 6022 version = "0.11.2" 5563 6023 ··· 5568 6028 ] 5569 6029 5570 6030 [[package]] 6031 + name = "serde_core" 6032 + version = "1.0.227" 6033 + source = "registry+https://github.com/rust-lang/crates.io-index" 6034 + checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" 6035 + dependencies = [ 6036 + "serde_derive", 6037 + ] 6038 + 6039 + [[package]] 5571 6040 name = "serde_derive" 5572 - version = "1.0.219" 6041 + version = "1.0.227" 5573 6042 source = "registry+https://github.com/rust-lang/crates.io-index" 5574 - checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 6043 + checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" 5575 6044 dependencies = [ 5576 6045 "proc-macro2", 5577 6046 "quote", ··· 5579 6048 ] 5580 6049 5581 6050 [[package]] 6051 + name = "serde_html_form" 6052 + version = "0.2.8" 6053 + source = "registry+https://github.com/rust-lang/crates.io-index" 6054 + checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f" 6055 + dependencies = [ 6056 + "form_urlencoded", 6057 + "indexmap", 6058 + "itoa", 6059 + "ryu", 6060 + "serde_core", 6061 + ] 6062 + 6063 + [[package]] 5582 6064 name = "serde_json" 5583 - version = "1.0.140" 6065 + version = "1.0.145" 5584 6066 source = "registry+https://github.com/rust-lang/crates.io-index" 5585 - checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 6067 + checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" 5586 6068 dependencies = [ 5587 6069 "itoa", 5588 6070 "memchr", 5589 6071 "ryu", 5590 6072 "serde", 6073 + "serde_core", 5591 6074 ] 5592 6075 5593 6076 [[package]] ··· 6456 6939 ] 6457 6940 6458 6941 [[package]] 6942 + name = "tagptr" 6943 + version = "0.2.0" 6944 + source = "registry+https://github.com/rust-lang/crates.io-index" 6945 + checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" 6946 + 6947 + [[package]] 6459 6948 name = "tap" 6460 6949 version = "1.0.1" 6461 6950 ··· 6629 7118 ] 6630 7119 6631 7120 [[package]] 7121 + name = "tokio-native-tls" 7122 + version = "0.3.1" 7123 + source = "registry+https://github.com/rust-lang/crates.io-index" 7124 + checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 7125 + dependencies = [ 7126 + "native-tls", 7127 + "tokio", 7128 + ] 7129 + 7130 + [[package]] 6632 7131 name = "tokio-postgres" 6633 7132 version = "0.7.13" 6634 7133 ··· 6688 7187 6689 7188 [[package]] 6690 7189 name = "tokio-tungstenite" 7190 + version = "0.21.0" 7191 + source = "registry+https://github.com/rust-lang/crates.io-index" 7192 + checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" 7193 + dependencies = [ 7194 + "futures-util", 7195 + "log", 7196 + "tokio", 7197 + "tungstenite 0.21.0", 7198 + ] 7199 + 7200 + [[package]] 7201 + name = "tokio-tungstenite" 7202 + version = "0.24.0" 7203 + source = "registry+https://github.com/rust-lang/crates.io-index" 7204 + checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" 7205 + dependencies = [ 7206 + "futures-util", 7207 + "log", 7208 + "native-tls", 7209 + "tokio", 7210 + "tokio-native-tls", 7211 + "tungstenite 0.24.0", 7212 + ] 7213 + 7214 + [[package]] 7215 + name = "tokio-tungstenite" 6691 7216 version = "0.26.2" 6692 7217 6693 7218 ··· 6698 7223 "rustls-pki-types", 6699 7224 "tokio", 6700 7225 "tokio-rustls 0.26.2", 6701 - "tungstenite", 7226 + "tungstenite 0.26.2", 6702 7227 "webpki-roots 0.26.11", 6703 7228 ] 6704 7229 ··· 6903 7428 ] 6904 7429 6905 7430 [[package]] 7431 + name = "trait-variant" 7432 + version = "0.1.2" 7433 + source = "registry+https://github.com/rust-lang/crates.io-index" 7434 + checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" 7435 + dependencies = [ 7436 + "proc-macro2", 7437 + "quote", 7438 + "syn 2.0.101", 7439 + ] 7440 + 7441 + [[package]] 6906 7442 name = "trim-in-place" 6907 7443 version = "0.1.7" 6908 7444 ··· 6927 7463 6928 7464 [[package]] 6929 7465 name = "tungstenite" 7466 + version = "0.21.0" 7467 + source = "registry+https://github.com/rust-lang/crates.io-index" 7468 + checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" 7469 + dependencies = [ 7470 + "byteorder", 7471 + "bytes", 7472 + "data-encoding", 7473 + "http 1.3.1", 7474 + "httparse", 7475 + "log", 7476 + "rand 0.8.5", 7477 + "sha1", 7478 + "thiserror 1.0.69", 7479 + "url", 7480 + "utf-8", 7481 + ] 7482 + 7483 + [[package]] 7484 + name = "tungstenite" 7485 + version = "0.24.0" 7486 + source = "registry+https://github.com/rust-lang/crates.io-index" 7487 + checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" 7488 + dependencies = [ 7489 + "byteorder", 7490 + "bytes", 7491 + "data-encoding", 7492 + "http 1.3.1", 7493 + "httparse", 7494 + "log", 7495 + "native-tls", 7496 + "rand 0.8.5", 7497 + "sha1", 7498 + "thiserror 1.0.69", 7499 + "url", 7500 + "utf-8", 7501 + ] 7502 + 7503 + [[package]] 7504 + name = "tungstenite" 6930 7505 version = "0.26.2" 6931 7506 6932 7507 ··· 7033 7608 ] 7034 7609 7035 7610 [[package]] 7611 + name = "unsigned-varint" 7612 + version = "0.8.0" 7613 + source = "registry+https://github.com/rust-lang/crates.io-index" 7614 + checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" 7615 + 7616 + [[package]] 7036 7617 name = "untrusted" 7037 7618 version = "0.9.0" 7038 7619 ··· 7122 7703 7123 7704 7124 7705 "try-lock", 7706 + ] 7707 + 7708 + [[package]] 7709 + name = "warp" 7710 + version = "0.3.7" 7711 + source = "registry+https://github.com/rust-lang/crates.io-index" 7712 + checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" 7713 + dependencies = [ 7714 + "bytes", 7715 + "futures-channel", 7716 + "futures-util", 7717 + "headers", 7718 + "http 0.2.12", 7719 + "hyper 0.14.32", 7720 + "log", 7721 + "mime", 7722 + "mime_guess", 7723 + "multer", 7724 + "percent-encoding", 7725 + "pin-project", 7726 + "scoped-tls", 7727 + "serde", 7728 + "serde_json", 7729 + "serde_urlencoded", 7730 + "tokio", 7731 + "tokio-tungstenite 0.21.0", 7732 + "tokio-util", 7733 + "tower-service", 7734 + "tracing", 7125 7735 ] 7126 7736 7127 7737 [[package]]
+35
crates/feed/Cargo.toml
··· 1 + [package] 2 + name = "rocksky-feed" 3 + version = "0.1.0" 4 + authors.workspace = true 5 + edition.workspace = true 6 + license.workspace = true 7 + repository.workspace = true 8 + 9 + [dependencies] 10 + warp = "0.3.7" 11 + owo-colors = "4.1.0" 12 + anyhow = "1.0.100" 13 + atrium-api = "0.25.5" 14 + atrium-xrpc-client = "0.5.14" 15 + chrono = { version = "= 0.4.39", features = ["serde"] } 16 + duckdb = { version = "1.2.0", features = ["chrono"] } 17 + jetstream-oxide = "=0.1.2" 18 + reqwest = { version = "0.12.12", features = [ 19 + "rustls-tls", 20 + "json", 21 + "multipart", 22 + ], default-features = false } 23 + serde = "1.0.227" 24 + serde_json = "1.0.145" 25 + tokio = { version = "1.43.0", features = ["full"] } 26 + tracing = "0.1.41" 27 + dotenv = "0.15.0" 28 + sqlx = { version = "0.8.3", features = [ 29 + "runtime-tokio", 30 + "tls-rustls", 31 + "postgres", 32 + "chrono", 33 + "derive", 34 + "macros", 35 + ] }
+35
crates/feed/src/config.rs
··· 1 + use std::env; 2 + 3 + use dotenv::dotenv; 4 + 5 + #[derive(Debug, Clone)] 6 + /// Configuration values for a Feed service 7 + pub struct Config { 8 + /// Your account's decentralized identifier (DID) 9 + /// A DID is a persistent, long-term identifier for every account. Usually look like did:plc:ewvi7nxzyoun6zhxrhs64oiz. 10 + pub publisher_did: String, 11 + /// The host name for your feed generator. 12 + /// 13 + /// For example: if github were to host a feed generator service at their domain they would set this value to `github.com` 14 + /// 15 + /// You can develop your feed locally without setting this to a real value. However, when publishing, this value must be a domain that: 16 + /// - Points to your service. 17 + /// - Is secured with SSL (HTTPS). 18 + /// - Is accessible on the public internet. 19 + pub feed_generator_hostname: String, 20 + } 21 + 22 + impl Config { 23 + /// Loads the config from a local .env file containing these variables 24 + /// PUBLISHER_DID 25 + /// FEED_GENERATOR_HOSTNAME 26 + pub fn load_env_config() -> Self { 27 + dotenv().expect("Missing .env"); 28 + Config { 29 + publisher_did: env::var("PUBLISHER_DID") 30 + .expect(".env file is missing an entry for PUBLISHER_DID"), 31 + feed_generator_hostname: env::var("FEED_GENERATOR_HOSTNAME") 32 + .expect(".env file is missing an entry for FEED_GENERATOR_HOSTNAME"), 33 + } 34 + } 35 + }
+148
crates/feed/src/feed.rs
··· 1 + use crate::config::Config; 2 + use crate::types::{DidDocument, FeedSkeletonParameters, Service}; 3 + use crate::{feed_handler::FeedHandler, types::FeedSkeletonQuery}; 4 + use anyhow::Error; 5 + use sqlx::postgres::PgPoolOptions; 6 + use sqlx::{Pool, Postgres}; 7 + use std::env; 8 + use std::fmt::Debug; 9 + use std::net::SocketAddr; 10 + use std::sync::Arc; 11 + use warp::Filter; 12 + 13 + /// A `Feed` stores a `FeedHandler`, handles feed server endpoints & connects to the Firehose using the `start` methods. 14 + pub trait Feed<Handler: FeedHandler + Clone + Send + Sync + 'static> { 15 + fn handler(&mut self) -> Handler; 16 + /// Starts the feed generator server & connects to the firehose. 17 + /// 18 + /// 19 + /// - name: The identifying name of your feed. This value is used in the feed URL & when identifying which feed to *unpublish*. This is a separate value from the display name. 20 + /// - address: The address to bind the server to 21 + /// 22 + /// # Panics 23 + /// 24 + /// Panics if unable to bind to the provided address. 25 + fn start( 26 + &mut self, 27 + name: impl AsRef<str>, 28 + address: impl Into<SocketAddr> + Debug + Clone + Send, 29 + ) -> impl std::future::Future<Output = Result<(), Error>> + Send { 30 + self.start_with_config(name, Config::load_env_config(), address) 31 + } 32 + 33 + /// Starts the feed generator server & connects to the firehose. 34 + /// 35 + /// - name: The identifying name of your feed. This value is used in the feed URL & when identifying which feed to *unpublish*. This is a separate value from the display name. 36 + /// - config: Configuration values, see `Config` 37 + /// - address: The address to bind the server to 38 + /// 39 + /// # Panics 40 + /// 41 + /// Panics if unable to bind to the provided address. 42 + fn start_with_config( 43 + &mut self, 44 + name: impl AsRef<str>, 45 + config: Config, 46 + address: impl Into<SocketAddr> + Debug + Clone + Send, 47 + ) -> impl std::future::Future<Output = Result<(), Error>> + Send { 48 + let handler = self.handler(); 49 + let address = address.clone(); 50 + let feed_name = name.as_ref().to_string(); 51 + 52 + async move { 53 + let config = config; 54 + let pool = PgPoolOptions::new() 55 + .max_connections(5) 56 + .connect(&env::var("XATA_POSTGRES_URL")?) 57 + .await?; 58 + let pool = Arc::new(pool); 59 + let db_filter = warp::any().map(move || pool.clone()); 60 + 61 + let did_config = config.clone(); 62 + let did_json = warp::path(".well-known") 63 + .and(warp::path("did.json")) 64 + .and(warp::get()) 65 + .and_then(move || did_json(did_config.clone())); 66 + 67 + let describe_feed_generator = warp::path("xrpc") 68 + .and(warp::path("app.rocksky.feed.describeFeedGenerator")) 69 + .and(warp::get()) 70 + .and(db_filter.clone()) 71 + .and_then(move |_pool: Arc<Pool<Postgres>>| { 72 + describe_feed_generator(feed_name.clone()) 73 + }); 74 + 75 + let get_feed_handler = handler.clone(); 76 + let get_feed_skeleton = warp::path("xrpc") 77 + .and(warp::path("app.rocksky.feed.getFeedSkeleton")) 78 + .and(warp::get()) 79 + .and(warp::query::<FeedSkeletonParameters>()) 80 + .and(db_filter.clone()) 81 + .and_then( 82 + move |query: FeedSkeletonParameters, _pool: Arc<Pool<Postgres>>| { 83 + get_feed_skeleton::<Handler>(query.into(), get_feed_handler.clone()) 84 + }, 85 + ); 86 + 87 + let api = did_json.or(describe_feed_generator).or(get_feed_skeleton); 88 + 89 + tracing::info!("Serving feed on {}", format!("{:?}", address)); 90 + 91 + let routes = api.with(warp::log::custom(|info| { 92 + let method = info.method(); 93 + let path = info.path(); 94 + let status = info.status(); 95 + let elapsed = info.elapsed().as_millis(); 96 + 97 + if status.is_success() { 98 + tracing::info!( 99 + "Method: {}, Path: {}, Status: {}, Elapsed Time: {}ms", 100 + method, 101 + path, 102 + status, 103 + elapsed 104 + ); 105 + } else { 106 + tracing::error!( 107 + "Method: {}, Path: {}, Status: {}, Elapsed Time: {}ms", 108 + method, 109 + path, 110 + status, 111 + elapsed, 112 + ); 113 + } 114 + })); 115 + let feed_server = warp::serve(routes); 116 + let firehose_listener = tokio::spawn(async move {}); 117 + 118 + tokio::join!(feed_server.run(address), firehose_listener) 119 + .1 120 + .expect("Couldn't await tasks"); 121 + 122 + Ok::<(), Error>(()) 123 + } 124 + } 125 + } 126 + 127 + async fn did_json(config: Config) -> Result<impl warp::Reply, warp::Rejection> { 128 + Ok(warp::reply::json(&DidDocument { 129 + context: vec!["https://www.w3.org/ns/did/v1".to_owned()], 130 + id: format!("did:web:{}", config.feed_generator_hostname), 131 + service: vec![Service { 132 + id: "#rocksky_fg".to_owned(), 133 + type_: "RockskyFeedGenerator".to_owned(), 134 + service_endpoint: format!("https://{}", config.feed_generator_hostname), 135 + }], 136 + })) 137 + } 138 + 139 + async fn describe_feed_generator(feed_name: String) -> Result<impl warp::Reply, warp::Rejection> { 140 + Ok(warp::reply::json(&serde_json::json!({}))) 141 + } 142 + 143 + async fn get_feed_skeleton<Handler: FeedHandler>( 144 + query: FeedSkeletonQuery, 145 + handler: Handler, 146 + ) -> Result<impl warp::Reply, warp::Rejection> { 147 + Ok(warp::reply::json(&serde_json::json!({}))) 148 + }
+10
crates/feed/src/feed_handler.rs
··· 1 + use crate::types::{FeedResult, Request, Scrobble, Uri}; 2 + 3 + /// A feed handler is responsible for 4 + /// - Storing and managing firehose input. 5 + /// - Serving responses to feed requests with `serve_feed` 6 + pub trait FeedHandler { 7 + fn insert_scrobble(&self, scrobble: Scrobble) -> impl std::future::Future<Output = ()> + Send; 8 + fn delete_scrobble(&self, uri: Uri) -> impl std::future::Future<Output = ()> + Send; 9 + fn serve_feed(&self, request: Request) -> impl std::future::Future<Output = FeedResult> + Send; 10 + }
+58
crates/feed/src/lib.rs
··· 1 + use anyhow::Error; 2 + use std::{env, net::SocketAddr, sync::Arc}; 3 + use tokio::sync::Mutex; 4 + 5 + use crate::{ 6 + feed::Feed, 7 + feed_handler::FeedHandler, 8 + types::{FeedResult, Scrobble}, 9 + }; 10 + 11 + pub mod config; 12 + pub mod feed; 13 + pub mod feed_handler; 14 + pub mod types; 15 + 16 + pub struct RecentlyPlayedFeed { 17 + handler: RecentlyPlayedFeedHandler, 18 + } 19 + 20 + impl Feed<RecentlyPlayedFeedHandler> for RecentlyPlayedFeed { 21 + fn handler(&mut self) -> RecentlyPlayedFeedHandler { 22 + self.handler.clone() 23 + } 24 + } 25 + 26 + #[derive(Clone)] 27 + pub struct RecentlyPlayedFeedHandler { 28 + pub scrobbles: Arc<Mutex<Vec<Scrobble>>>, 29 + } 30 + 31 + impl FeedHandler for RecentlyPlayedFeedHandler { 32 + async fn insert_scrobble(&self, scrobble: Scrobble) { 33 + todo!() 34 + } 35 + 36 + async fn delete_scrobble(&self, uri: types::Uri) { 37 + todo!() 38 + } 39 + 40 + async fn serve_feed(&self, request: types::Request) -> FeedResult { 41 + todo!() 42 + } 43 + } 44 + 45 + pub async fn run() -> Result<(), Error> { 46 + let mut feed = RecentlyPlayedFeed { 47 + handler: RecentlyPlayedFeedHandler { 48 + scrobbles: Arc::new(Mutex::new(Vec::new())), 49 + }, 50 + }; 51 + let host = env::var("FEED_HOST").unwrap_or_else(|_| "127.0.0.1".to_string()); 52 + let port = env::var("FEED_PORT").unwrap_or_else(|_| "7885".to_string()); 53 + let addr_str = format!("{}:{}", host, port); 54 + let addr: SocketAddr = addr_str.parse().expect("Invalid address format"); 55 + 56 + feed.start("RecentlyPlayed", addr).await?; 57 + Ok(()) 58 + }
+54
crates/feed/src/types.rs
··· 1 + #[derive(Debug, Clone)] 2 + pub struct Request { 3 + pub cursor: Option<String>, 4 + pub feed: String, 5 + pub limit: Option<u8>, 6 + } 7 + 8 + #[derive(Debug, Clone)] 9 + pub struct Cid(pub String); 10 + 11 + #[derive(Debug, Clone)] 12 + pub struct Did(pub String); 13 + 14 + #[derive(Debug, Clone, Hash, PartialEq, Eq)] 15 + pub struct Uri(pub String); 16 + 17 + #[derive(Debug, Clone)] 18 + pub struct FeedResult { 19 + pub cursor: Option<String>, 20 + pub feed: Vec<Uri>, 21 + } 22 + 23 + pub struct FeedSkeletonQuery {} 24 + 25 + #[derive(Deserialize)] 26 + pub struct FeedSkeletonParameters {} 27 + 28 + impl Into<FeedSkeletonQuery> for FeedSkeletonParameters { 29 + fn into(self) -> FeedSkeletonQuery { 30 + FeedSkeletonQuery {} 31 + } 32 + } 33 + 34 + #[derive(Debug, Clone)] 35 + pub struct Scrobble {} 36 + 37 + use serde::{Deserialize, Serialize}; 38 + 39 + #[derive(Serialize)] 40 + pub(crate) struct DidDocument { 41 + #[serde(rename = "@context")] 42 + pub(crate) context: Vec<String>, 43 + pub(crate) id: String, 44 + pub(crate) service: Vec<Service>, 45 + } 46 + 47 + #[derive(Serialize)] 48 + pub(crate) struct Service { 49 + pub(crate) id: String, 50 + #[serde(rename = "type")] 51 + pub(crate) type_: String, 52 + #[serde(rename = "serviceEndpoint")] 53 + pub(crate) service_endpoint: String, 54 + }
+1
crates/rockskyd/Cargo.toml
··· 20 20 rocksky-spotify = { path = "../spotify" } 21 21 rocksky-tracklist = { path = "../tracklist" } 22 22 rocksky-webscrobbler = { path = "../webscrobbler" } 23 + rocksky-feed = { path = "../feed" } 23 24 tracing = "0.1.41" 24 25 tracing-subscriber = "0.3.20" 25 26 tracing-log = "0.2.0"
+6
crates/rockskyd/src/cmd/feed.rs
··· 1 + use anyhow::Error; 2 + 3 + pub async fn serve() -> Result<(), Error> { 4 + rocksky_feed::run().await?; 5 + Ok(()) 6 + }
+1
crates/rockskyd/src/cmd/mod.rs
··· 1 1 pub mod analytics; 2 2 pub mod dropbox; 3 + pub mod feed; 3 4 pub mod googledrive; 4 5 pub mod jetstream; 5 6 pub mod playlist;
+9
crates/rockskyd/src/main.rs
··· 32 32 .subcommand(Command::new("spotify").about("Start Spotify Listener Service")) 33 33 .subcommand(Command::new("tracklist").about("Start User Current Track Queue Service")) 34 34 .subcommand(Command::new("webscrobbler").about("Start Webscrobbler API")) 35 + .subcommand( 36 + Command::new("feed") 37 + .about("Feed related commands") 38 + .subcommand(Command::new("serve").about("Serve the Rocksky Feed API")), 39 + ) 35 40 } 36 41 37 42 #[tokio::main] ··· 85 90 Some(("webscrobbler", _)) => { 86 91 cmd::webscrobbler::start_webscrobbler_service().await?; 87 92 } 93 + Some(("feed", sub_m)) => match sub_m.subcommand() { 94 + Some(("serve", _)) => cmd::feed::serve().await?, 95 + _ => println!("Unknown feed command"), 96 + }, 88 97 _ => { 89 98 println!("No valid subcommand was used. Use --help to see available commands."); 90 99 }

History

2 rounds 0 comments
sign up or login to add to the discussion
4 commits
expand
feat(feed): implement feed service with configuration and handler
feat(feed): add feed command with serve subcommand and integrate feed module
fix: update feed and lib modules to return Result types for better error handling
feat: add new dependencies for moka, multer, multibase, multihash, nanorand, and native-tls
expand 0 comments
closed without merging
2 commits
expand
feat(feed): implement feed service with configuration and handler
feat(feed): add feed command with serve subcommand and integrate feed module
expand 0 comments