Browse and listen to thousands of radio stations across the globe right from your terminal ๐ŸŒŽ ๐Ÿ“ป ๐ŸŽตโœจ
radio rust tokio web-radio command-line-tool tui

feat(api): call a generic radio provider

+710 -397
+312 -151
Cargo.lock
··· 3 3 version = 4 4 4 5 5 [[package]] 6 + name = "addr2line" 7 + version = "0.24.2" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 + dependencies = [ 11 + "gimli", 12 + ] 13 + 14 + [[package]] 15 + name = "adler2" 16 + version = "2.0.0" 17 + source = "registry+https://github.com/rust-lang/crates.io-index" 18 + checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 + 20 + [[package]] 6 21 name = "aead" 7 22 version = "0.3.2" 8 23 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 383 398 384 399 [[package]] 385 400 name = "axum" 386 - version = "0.6.8" 401 + version = "0.7.5" 387 402 source = "registry+https://github.com/rust-lang/crates.io-index" 388 - checksum = "2bd379e511536bad07447f899300aa526e9bae8e6f66dc5e5ca45d7587b7c1ec" 403 + checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" 389 404 dependencies = [ 390 405 "async-trait", 391 406 "axum-core", 392 - "bitflags 1.3.2", 393 407 "bytes", 394 408 "futures-util", 395 - "http", 396 - "http-body", 397 - "hyper", 409 + "http 1.2.0", 410 + "http-body 1.0.1", 411 + "http-body-util", 398 412 "itoa", 399 413 "matchit", 400 414 "memchr", ··· 403 417 "pin-project-lite", 404 418 "rustversion", 405 419 "serde", 406 - "sync_wrapper", 420 + "sync_wrapper 1.0.2", 407 421 "tower", 408 - "tower-http", 409 422 "tower-layer", 410 423 "tower-service", 411 424 ] 412 425 413 426 [[package]] 414 427 name = "axum-core" 415 - version = "0.3.2" 428 + version = "0.4.5" 416 429 source = "registry+https://github.com/rust-lang/crates.io-index" 417 - checksum = "1cae3e661676ffbacb30f1a824089a8c9150e71017f7e1e38f2aa32009188d34" 430 + checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" 418 431 dependencies = [ 419 432 "async-trait", 420 433 "bytes", 421 434 "futures-util", 422 - "http", 423 - "http-body", 435 + "http 1.2.0", 436 + "http-body 1.0.1", 437 + "http-body-util", 424 438 "mime", 439 + "pin-project-lite", 425 440 "rustversion", 441 + "sync_wrapper 1.0.2", 426 442 "tower-layer", 427 443 "tower-service", 444 + ] 445 + 446 + [[package]] 447 + name = "backtrace" 448 + version = "0.3.74" 449 + source = "registry+https://github.com/rust-lang/crates.io-index" 450 + checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 451 + dependencies = [ 452 + "addr2line", 453 + "cfg-if", 454 + "libc", 455 + "miniz_oxide", 456 + "object", 457 + "rustc-demangle", 458 + "windows-targets 0.52.6", 428 459 ] 429 460 430 461 [[package]] ··· 452 483 checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" 453 484 454 485 [[package]] 486 + name = "base64" 487 + version = "0.22.1" 488 + source = "registry+https://github.com/rust-lang/crates.io-index" 489 + checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 490 + 491 + [[package]] 455 492 name = "bindgen" 456 493 version = "0.61.0" 457 494 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 526 563 527 564 [[package]] 528 565 name = "bytes" 529 - version = "1.4.0" 566 + version = "1.9.0" 530 567 source = "registry+https://github.com/rust-lang/crates.io-index" 531 - checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" 568 + checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 532 569 533 570 [[package]] 534 571 name = "cassowary" ··· 619 656 "atty", 620 657 "bitflags 1.3.2", 621 658 "clap_lex", 622 - "indexmap", 659 + "indexmap 1.9.2", 623 660 "strsim", 624 661 "termcolor", 625 662 "textwrap", ··· 814 851 "bitflags 2.4.2", 815 852 "crossterm_winapi", 816 853 "libc", 817 - "mio", 854 + "mio 0.8.6", 818 855 "parking_lot", 819 856 "signal-hook", 820 857 "signal-hook-mio", ··· 955 992 ] 956 993 957 994 [[package]] 995 + name = "equivalent" 996 + version = "1.0.1" 997 + source = "registry+https://github.com/rust-lang/crates.io-index" 998 + checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 999 + 1000 + [[package]] 958 1001 name = "errno" 959 1002 version = "0.3.10" 960 1003 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1147 1190 ] 1148 1191 1149 1192 [[package]] 1193 + name = "gimli" 1194 + version = "0.31.1" 1195 + source = "registry+https://github.com/rust-lang/crates.io-index" 1196 + checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 1197 + 1198 + [[package]] 1150 1199 name = "glob" 1151 1200 version = "0.3.1" 1152 1201 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1175 1224 "futures-core", 1176 1225 "futures-sink", 1177 1226 "futures-util", 1178 - "http", 1179 - "indexmap", 1227 + "http 0.2.9", 1228 + "indexmap 1.9.2", 1229 + "slab", 1230 + "tokio", 1231 + "tokio-util", 1232 + "tracing", 1233 + ] 1234 + 1235 + [[package]] 1236 + name = "h2" 1237 + version = "0.4.7" 1238 + source = "registry+https://github.com/rust-lang/crates.io-index" 1239 + checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" 1240 + dependencies = [ 1241 + "atomic-waker", 1242 + "bytes", 1243 + "fnv", 1244 + "futures-core", 1245 + "futures-sink", 1246 + "http 1.2.0", 1247 + "indexmap 2.7.1", 1180 1248 "slab", 1181 1249 "tokio", 1182 1250 "tokio-util", ··· 1198 1266 "ahash", 1199 1267 "allocator-api2", 1200 1268 ] 1269 + 1270 + [[package]] 1271 + name = "hashbrown" 1272 + version = "0.15.2" 1273 + source = "registry+https://github.com/rust-lang/crates.io-index" 1274 + checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 1201 1275 1202 1276 [[package]] 1203 1277 name = "heck" ··· 1327 1401 ] 1328 1402 1329 1403 [[package]] 1404 + name = "http" 1405 + version = "1.2.0" 1406 + source = "registry+https://github.com/rust-lang/crates.io-index" 1407 + checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" 1408 + dependencies = [ 1409 + "bytes", 1410 + "fnv", 1411 + "itoa", 1412 + ] 1413 + 1414 + [[package]] 1330 1415 name = "http-body" 1331 1416 version = "0.4.5" 1332 1417 source = "registry+https://github.com/rust-lang/crates.io-index" 1333 1418 checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 1334 1419 dependencies = [ 1335 1420 "bytes", 1336 - "http", 1421 + "http 0.2.9", 1422 + "pin-project-lite", 1423 + ] 1424 + 1425 + [[package]] 1426 + name = "http-body" 1427 + version = "1.0.1" 1428 + source = "registry+https://github.com/rust-lang/crates.io-index" 1429 + checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 1430 + dependencies = [ 1431 + "bytes", 1432 + "http 1.2.0", 1433 + ] 1434 + 1435 + [[package]] 1436 + name = "http-body-util" 1437 + version = "0.1.2" 1438 + source = "registry+https://github.com/rust-lang/crates.io-index" 1439 + checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 1440 + dependencies = [ 1441 + "bytes", 1442 + "futures-util", 1443 + "http 1.2.0", 1444 + "http-body 1.0.1", 1337 1445 "pin-project-lite", 1338 1446 ] 1339 1447 ··· 1355 1463 "log", 1356 1464 "rustls 0.18.1", 1357 1465 ] 1358 - 1359 - [[package]] 1360 - name = "http-range-header" 1361 - version = "0.3.0" 1362 - source = "registry+https://github.com/rust-lang/crates.io-index" 1363 - checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" 1364 1466 1365 1467 [[package]] 1366 1468 name = "http-types" ··· 1406 1508 "futures-channel", 1407 1509 "futures-core", 1408 1510 "futures-util", 1409 - "h2", 1410 - "http", 1411 - "http-body", 1511 + "h2 0.3.15", 1512 + "http 0.2.9", 1513 + "http-body 0.4.5", 1412 1514 "httparse", 1413 1515 "httpdate", 1414 1516 "itoa", ··· 1421 1523 ] 1422 1524 1423 1525 [[package]] 1526 + name = "hyper" 1527 + version = "1.5.2" 1528 + source = "registry+https://github.com/rust-lang/crates.io-index" 1529 + checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" 1530 + dependencies = [ 1531 + "bytes", 1532 + "futures-channel", 1533 + "futures-util", 1534 + "h2 0.4.7", 1535 + "http 1.2.0", 1536 + "http-body 1.0.1", 1537 + "httparse", 1538 + "httpdate", 1539 + "itoa", 1540 + "pin-project-lite", 1541 + "smallvec", 1542 + "tokio", 1543 + "want", 1544 + ] 1545 + 1546 + [[package]] 1424 1547 name = "hyper-rustls" 1425 1548 version = "0.24.2" 1426 1549 source = "registry+https://github.com/rust-lang/crates.io-index" 1427 1550 checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" 1428 1551 dependencies = [ 1429 1552 "futures-util", 1430 - "http", 1431 - "hyper", 1553 + "http 0.2.9", 1554 + "hyper 0.14.24", 1432 1555 "rustls 0.21.12", 1433 1556 "tokio", 1434 1557 "tokio-rustls", ··· 1436 1559 1437 1560 [[package]] 1438 1561 name = "hyper-timeout" 1439 - version = "0.4.1" 1562 + version = "0.5.2" 1440 1563 source = "registry+https://github.com/rust-lang/crates.io-index" 1441 - checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" 1564 + checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" 1442 1565 dependencies = [ 1443 - "hyper", 1566 + "hyper 1.5.2", 1567 + "hyper-util", 1444 1568 "pin-project-lite", 1445 1569 "tokio", 1446 - "tokio-io-timeout", 1570 + "tower-service", 1571 + ] 1572 + 1573 + [[package]] 1574 + name = "hyper-util" 1575 + version = "0.1.10" 1576 + source = "registry+https://github.com/rust-lang/crates.io-index" 1577 + checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" 1578 + dependencies = [ 1579 + "bytes", 1580 + "futures-channel", 1581 + "futures-util", 1582 + "http 1.2.0", 1583 + "http-body 1.0.1", 1584 + "hyper 1.5.2", 1585 + "pin-project-lite", 1586 + "socket2 0.5.8", 1587 + "tokio", 1588 + "tower-service", 1589 + "tracing", 1447 1590 ] 1448 1591 1449 1592 [[package]] ··· 1630 1773 ] 1631 1774 1632 1775 [[package]] 1776 + name = "indexmap" 1777 + version = "2.7.1" 1778 + source = "registry+https://github.com/rust-lang/crates.io-index" 1779 + checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" 1780 + dependencies = [ 1781 + "equivalent", 1782 + "hashbrown 0.15.2", 1783 + ] 1784 + 1785 + [[package]] 1633 1786 name = "indoc" 1634 1787 version = "2.0.4" 1635 1788 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1678 1831 version = "2.7.1" 1679 1832 source = "registry+https://github.com/rust-lang/crates.io-index" 1680 1833 checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" 1681 - 1682 - [[package]] 1683 - name = "itertools" 1684 - version = "0.10.5" 1685 - source = "registry+https://github.com/rust-lang/crates.io-index" 1686 - checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 1687 - dependencies = [ 1688 - "either", 1689 - ] 1690 1834 1691 1835 [[package]] 1692 1836 name = "itertools" ··· 1952 2096 ] 1953 2097 1954 2098 [[package]] 2099 + name = "miniz_oxide" 2100 + version = "0.8.3" 2101 + source = "registry+https://github.com/rust-lang/crates.io-index" 2102 + checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" 2103 + dependencies = [ 2104 + "adler2", 2105 + ] 2106 + 2107 + [[package]] 1955 2108 name = "mio" 1956 2109 version = "0.8.6" 1957 2110 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1961 2114 "log", 1962 2115 "wasi 0.11.0+wasi-snapshot-preview1", 1963 2116 "windows-sys 0.45.0", 2117 + ] 2118 + 2119 + [[package]] 2120 + name = "mio" 2121 + version = "1.0.3" 2122 + source = "registry+https://github.com/rust-lang/crates.io-index" 2123 + checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 2124 + dependencies = [ 2125 + "libc", 2126 + "wasi 0.11.0+wasi-snapshot-preview1", 2127 + "windows-sys 0.52.0", 1964 2128 ] 1965 2129 1966 2130 [[package]] ··· 2139 2303 checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" 2140 2304 2141 2305 [[package]] 2306 + name = "object" 2307 + version = "0.36.7" 2308 + source = "registry+https://github.com/rust-lang/crates.io-index" 2309 + checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 2310 + dependencies = [ 2311 + "memchr", 2312 + ] 2313 + 2314 + [[package]] 2142 2315 name = "oboe" 2143 2316 version = "0.4.6" 2144 2317 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2254 2427 checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" 2255 2428 dependencies = [ 2256 2429 "fixedbitset", 2257 - "indexmap", 2430 + "indexmap 1.9.2", 2258 2431 ] 2259 2432 2260 2433 [[package]] ··· 2279 2452 2280 2453 [[package]] 2281 2454 name = "pin-project-lite" 2282 - version = "0.2.9" 2455 + version = "0.2.16" 2283 2456 source = "registry+https://github.com/rust-lang/crates.io-index" 2284 - checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 2457 + checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 2285 2458 2286 2459 [[package]] 2287 2460 name = "pin-utils" ··· 2337 2510 2338 2511 [[package]] 2339 2512 name = "prettyplease" 2340 - version = "0.1.23" 2513 + version = "0.2.17" 2341 2514 source = "registry+https://github.com/rust-lang/crates.io-index" 2342 - checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" 2515 + checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" 2343 2516 dependencies = [ 2344 2517 "proc-macro2", 2345 - "syn 1.0.107", 2518 + "syn 2.0.51", 2346 2519 ] 2347 2520 2348 2521 [[package]] ··· 2381 2554 2382 2555 [[package]] 2383 2556 name = "prost" 2384 - version = "0.11.8" 2557 + version = "0.13.4" 2385 2558 source = "registry+https://github.com/rust-lang/crates.io-index" 2386 - checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" 2559 + checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec" 2387 2560 dependencies = [ 2388 2561 "bytes", 2389 2562 "prost-derive", ··· 2391 2564 2392 2565 [[package]] 2393 2566 name = "prost-build" 2394 - version = "0.11.8" 2567 + version = "0.13.4" 2395 2568 source = "registry+https://github.com/rust-lang/crates.io-index" 2396 - checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12" 2569 + checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b" 2397 2570 dependencies = [ 2398 - "bytes", 2399 - "heck 0.4.1", 2400 - "itertools 0.10.5", 2401 - "lazy_static", 2571 + "heck 0.5.0", 2572 + "itertools", 2402 2573 "log", 2403 2574 "multimap", 2575 + "once_cell", 2404 2576 "petgraph", 2405 2577 "prettyplease", 2406 2578 "prost", 2407 2579 "prost-types", 2408 2580 "regex", 2409 - "syn 1.0.107", 2581 + "syn 2.0.51", 2410 2582 "tempfile", 2411 - "which", 2412 2583 ] 2413 2584 2414 2585 [[package]] 2415 2586 name = "prost-derive" 2416 - version = "0.11.8" 2587 + version = "0.13.4" 2417 2588 source = "registry+https://github.com/rust-lang/crates.io-index" 2418 - checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" 2589 + checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" 2419 2590 dependencies = [ 2420 2591 "anyhow", 2421 - "itertools 0.10.5", 2592 + "itertools", 2422 2593 "proc-macro2", 2423 2594 "quote", 2424 - "syn 1.0.107", 2595 + "syn 2.0.51", 2425 2596 ] 2426 2597 2427 2598 [[package]] 2428 2599 name = "prost-types" 2429 - version = "0.11.8" 2600 + version = "0.13.4" 2430 2601 source = "registry+https://github.com/rust-lang/crates.io-index" 2431 - checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" 2602 + checksum = "cc2f1e56baa61e93533aebc21af4d2134b70f66275e0fcdf3cbe43d77ff7e8fc" 2432 2603 dependencies = [ 2433 2604 "prost", 2434 2605 ] ··· 2545 2716 "compact_str", 2546 2717 "crossterm", 2547 2718 "indoc", 2548 - "itertools 0.12.1", 2719 + "itertools", 2549 2720 "lru", 2550 2721 "paste", 2551 2722 "stability", ··· 2630 2801 "encoding_rs", 2631 2802 "futures-core", 2632 2803 "futures-util", 2633 - "h2", 2634 - "http", 2635 - "http-body", 2636 - "hyper", 2804 + "h2 0.3.15", 2805 + "http 0.2.9", 2806 + "http-body 0.4.5", 2807 + "hyper 0.14.24", 2637 2808 "hyper-rustls", 2638 2809 "ipnet", 2639 2810 "js-sys", ··· 2647 2818 "serde", 2648 2819 "serde_json", 2649 2820 "serde_urlencoded", 2650 - "sync_wrapper", 2821 + "sync_wrapper 0.1.2", 2651 2822 "system-configuration", 2652 2823 "tokio", 2653 2824 "tokio-rustls", ··· 2717 2888 version = "0.10.3" 2718 2889 source = "registry+https://github.com/rust-lang/crates.io-index" 2719 2890 checksum = "8a654c5bda722c699be6b0fe4c0d90de218928da5b724c3e467fc48865c37263" 2891 + 2892 + [[package]] 2893 + name = "rustc-demangle" 2894 + version = "0.1.24" 2895 + source = "registry+https://github.com/rust-lang/crates.io-index" 2896 + checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 2720 2897 2721 2898 [[package]] 2722 2899 name = "rustc-hash" ··· 2988 3165 checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" 2989 3166 dependencies = [ 2990 3167 "libc", 2991 - "mio", 3168 + "mio 0.8.6", 2992 3169 "signal-hook", 2993 3170 ] 2994 3171 ··· 3422 3599 checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 3423 3600 3424 3601 [[package]] 3602 + name = "sync_wrapper" 3603 + version = "1.0.2" 3604 + source = "registry+https://github.com/rust-lang/crates.io-index" 3605 + checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 3606 + 3607 + [[package]] 3425 3608 name = "synstructure" 3426 3609 version = "0.13.1" 3427 3610 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3579 3762 3580 3763 [[package]] 3581 3764 name = "tokio" 3582 - version = "1.25.0" 3765 + version = "1.43.0" 3583 3766 source = "registry+https://github.com/rust-lang/crates.io-index" 3584 - checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" 3767 + checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" 3585 3768 dependencies = [ 3586 - "autocfg", 3769 + "backtrace", 3587 3770 "bytes", 3588 3771 "libc", 3589 - "memchr", 3590 - "mio", 3591 - "num_cpus", 3772 + "mio 1.0.3", 3592 3773 "pin-project-lite", 3593 - "socket2 0.4.7", 3774 + "socket2 0.5.8", 3594 3775 "tokio-macros", 3595 - "windows-sys 0.42.0", 3596 - ] 3597 - 3598 - [[package]] 3599 - name = "tokio-io-timeout" 3600 - version = "1.2.0" 3601 - source = "registry+https://github.com/rust-lang/crates.io-index" 3602 - checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" 3603 - dependencies = [ 3604 - "pin-project-lite", 3605 - "tokio", 3776 + "windows-sys 0.52.0", 3606 3777 ] 3607 3778 3608 3779 [[package]] 3609 3780 name = "tokio-macros" 3610 - version = "1.8.2" 3781 + version = "2.5.0" 3611 3782 source = "registry+https://github.com/rust-lang/crates.io-index" 3612 - checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" 3783 + checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 3613 3784 dependencies = [ 3614 3785 "proc-macro2", 3615 3786 "quote", 3616 - "syn 1.0.107", 3787 + "syn 2.0.51", 3617 3788 ] 3618 3789 3619 3790 [[package]] ··· 3628 3799 3629 3800 [[package]] 3630 3801 name = "tokio-stream" 3631 - version = "0.1.12" 3802 + version = "0.1.17" 3632 3803 source = "registry+https://github.com/rust-lang/crates.io-index" 3633 - checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" 3804 + checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" 3634 3805 dependencies = [ 3635 3806 "futures-core", 3636 3807 "pin-project-lite", ··· 3663 3834 source = "registry+https://github.com/rust-lang/crates.io-index" 3664 3835 checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" 3665 3836 dependencies = [ 3666 - "indexmap", 3837 + "indexmap 1.9.2", 3667 3838 "nom8", 3668 3839 "toml_datetime", 3669 3840 ] 3670 3841 3671 3842 [[package]] 3672 3843 name = "tonic" 3673 - version = "0.8.3" 3844 + version = "0.12.3" 3674 3845 source = "registry+https://github.com/rust-lang/crates.io-index" 3675 - checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" 3846 + checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" 3676 3847 dependencies = [ 3677 3848 "async-stream", 3678 3849 "async-trait", 3679 3850 "axum", 3680 - "base64 0.13.1", 3851 + "base64 0.22.1", 3681 3852 "bytes", 3682 - "futures-core", 3683 - "futures-util", 3684 - "h2", 3685 - "http", 3686 - "http-body", 3687 - "hyper", 3853 + "h2 0.4.7", 3854 + "http 1.2.0", 3855 + "http-body 1.0.1", 3856 + "http-body-util", 3857 + "hyper 1.5.2", 3688 3858 "hyper-timeout", 3859 + "hyper-util", 3689 3860 "percent-encoding 2.3.1", 3690 3861 "pin-project", 3691 3862 "prost", 3692 - "prost-derive", 3863 + "socket2 0.5.8", 3693 3864 "tokio", 3694 3865 "tokio-stream", 3695 - "tokio-util", 3696 3866 "tower", 3697 3867 "tower-layer", 3698 3868 "tower-service", 3699 3869 "tracing", 3700 - "tracing-futures", 3701 3870 ] 3702 3871 3703 3872 [[package]] 3704 3873 name = "tonic-build" 3705 - version = "0.8.4" 3874 + version = "0.12.3" 3706 3875 source = "registry+https://github.com/rust-lang/crates.io-index" 3707 - checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" 3876 + checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" 3708 3877 dependencies = [ 3709 3878 "prettyplease", 3710 3879 "proc-macro2", 3711 3880 "prost-build", 3881 + "prost-types", 3712 3882 "quote", 3713 - "syn 1.0.107", 3883 + "syn 2.0.51", 3884 + ] 3885 + 3886 + [[package]] 3887 + name = "tonic-reflection" 3888 + version = "0.12.3" 3889 + source = "registry+https://github.com/rust-lang/crates.io-index" 3890 + checksum = "878d81f52e7fcfd80026b7fdb6a9b578b3c3653ba987f87f0dce4b64043cba27" 3891 + dependencies = [ 3892 + "prost", 3893 + "prost-types", 3894 + "tokio", 3895 + "tokio-stream", 3896 + "tonic", 3714 3897 ] 3715 3898 3716 3899 [[package]] 3717 3900 name = "tonic-web" 3718 - version = "0.4.0" 3901 + version = "0.12.3" 3719 3902 source = "registry+https://github.com/rust-lang/crates.io-index" 3720 - checksum = "e392f7556972523aa87ddb0fc7f2d2ce530559956706aa081bb0bd8fed158559" 3903 + checksum = "5299dd20801ad736dccb4a5ea0da7376e59cd98f213bf1c3d478cf53f4834b58" 3721 3904 dependencies = [ 3722 - "base64 0.13.1", 3905 + "base64 0.22.1", 3723 3906 "bytes", 3724 - "futures-core", 3725 - "http", 3726 - "http-body", 3727 - "hyper", 3907 + "http 1.2.0", 3908 + "http-body 1.0.1", 3909 + "http-body-util", 3728 3910 "pin-project", 3911 + "tokio-stream", 3729 3912 "tonic", 3913 + "tower-http", 3914 + "tower-layer", 3730 3915 "tower-service", 3731 3916 "tracing", 3732 3917 ] ··· 3739 3924 dependencies = [ 3740 3925 "futures-core", 3741 3926 "futures-util", 3742 - "indexmap", 3927 + "indexmap 1.9.2", 3743 3928 "pin-project", 3744 3929 "pin-project-lite", 3745 3930 "rand 0.8.5", ··· 3753 3938 3754 3939 [[package]] 3755 3940 name = "tower-http" 3756 - version = "0.3.5" 3941 + version = "0.5.2" 3757 3942 source = "registry+https://github.com/rust-lang/crates.io-index" 3758 - checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" 3943 + checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" 3759 3944 dependencies = [ 3760 - "bitflags 1.3.2", 3945 + "bitflags 2.4.2", 3761 3946 "bytes", 3762 - "futures-core", 3763 - "futures-util", 3764 - "http", 3765 - "http-body", 3766 - "http-range-header", 3947 + "http 1.2.0", 3948 + "http-body 1.0.1", 3949 + "http-body-util", 3767 3950 "pin-project-lite", 3768 - "tower", 3769 3951 "tower-layer", 3770 3952 "tower-service", 3771 3953 ] ··· 3789 3971 checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 3790 3972 dependencies = [ 3791 3973 "cfg-if", 3792 - "log", 3793 3974 "pin-project-lite", 3794 3975 "tracing-attributes", 3795 3976 "tracing-core", ··· 3816 3997 ] 3817 3998 3818 3999 [[package]] 3819 - name = "tracing-futures" 3820 - version = "0.2.5" 3821 - source = "registry+https://github.com/rust-lang/crates.io-index" 3822 - checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" 3823 - dependencies = [ 3824 - "pin-project", 3825 - "tracing", 3826 - ] 3827 - 3828 - [[package]] 3829 4000 name = "transpose" 3830 4001 version = "0.2.3" 3831 4002 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3868 4039 "derive_more", 3869 4040 "futures", 3870 4041 "futures-util", 3871 - "hyper", 4042 + "hyper 0.14.24", 3872 4043 "m3u", 3873 4044 "minimp3", 3874 4045 "owo-colors", ··· 3888 4059 "tokio", 3889 4060 "tonic", 3890 4061 "tonic-build", 4062 + "tonic-reflection", 3891 4063 "tonic-web", 3892 4064 "tunein", 3893 4065 "url 2.5.4", ··· 4161 4333 checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" 4162 4334 dependencies = [ 4163 4335 "cc", 4164 - ] 4165 - 4166 - [[package]] 4167 - name = "which" 4168 - version = "4.4.0" 4169 - source = "registry+https://github.com/rust-lang/crates.io-index" 4170 - checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" 4171 - dependencies = [ 4172 - "either", 4173 - "libc", 4174 - "once_cell", 4175 4336 ] 4176 4337 4177 4338 [[package]]
+6 -5
Cargo.toml
··· 36 36 minimp3 = "0.5.1" 37 37 owo-colors = "3.5.0" 38 38 pls = "0.2.2" 39 - prost = "0.11.8" 39 + prost = "0.13.2" 40 40 radiobrowser = { version = "0.6.1", features = ["default-rustls"], default-features = false } 41 41 ratatui = "0.26.1" 42 42 regex = "1.11.1" ··· 48 48 symphonia = {version = "0.5.1", features = ["aac", "alac", "mp3", "isomp4", "flac"]} 49 49 termion = "2.0.1" 50 50 thiserror = "1.0.58" 51 - tokio = {version = "1.24.2", features = ["tokio-macros", "macros", "rt", "rt-multi-thread"]} 52 - tonic = "0.8.3" 53 - tonic-web = "0.4.0" 51 + tokio = {version = "1.36.0", features = ["tokio-macros", "macros", "rt", "rt-multi-thread"]} 52 + tonic = "0.12.3" 53 + tonic-reflection = "0.12.3" 54 + tonic-web = "0.12.3" 54 55 tunein = "0.1.3" 55 56 url = "2.3.1" 56 57 57 58 [build-dependencies] 58 - tonic-build = "0.8" 59 + tonic-build = "0.12.3"
+12 -9
build.rs
··· 1 1 fn main() -> Result<(), Box<dyn std::error::Error>> { 2 - tonic_build::configure().out_dir("src/api").compile( 3 - &[ 4 - "proto/objects/v1alpha1/category.proto", 5 - "proto/objects/v1alpha1/station.proto", 6 - "proto/tunein/v1alpha1/browse.proto", 7 - "proto/tunein/v1alpha1/playback.proto", 8 - ], 9 - &["proto"], 10 - )?; 2 + tonic_build::configure() 3 + .out_dir("src/api") 4 + .file_descriptor_set_path("src/api/descriptor.bin") 5 + .compile_protos( 6 + &[ 7 + "proto/objects/v1alpha1/category.proto", 8 + "proto/objects/v1alpha1/station.proto", 9 + "proto/tunein/v1alpha1/browse.proto", 10 + "proto/tunein/v1alpha1/playback.proto", 11 + ], 12 + &["proto"], 13 + )?; 11 14 Ok(()) 12 15 }
src/api/descriptor.bin

This is a binary file and will not be displayed.

+1 -3
src/api/objects.v1alpha1.rs
··· 1 - #[allow(clippy::derive_partial_eq_without_eq)] 1 + // This file is @generated by prost-build. 2 2 #[derive(Clone, PartialEq, ::prost::Message)] 3 3 pub struct Station { 4 4 #[prost(string, tag = "1")] ··· 8 8 #[prost(string, tag = "3")] 9 9 pub playing: ::prost::alloc::string::String, 10 10 } 11 - #[allow(clippy::derive_partial_eq_without_eq)] 12 11 #[derive(Clone, PartialEq, ::prost::Message)] 13 12 pub struct StationLinkDetails { 14 13 #[prost(uint32, tag = "1")] ··· 38 37 #[prost(string, tag = "13")] 39 38 pub url: ::prost::alloc::string::String, 40 39 } 41 - #[allow(clippy::derive_partial_eq_without_eq)] 42 40 #[derive(Clone, PartialEq, ::prost::Message)] 43 41 pub struct Category { 44 42 #[prost(string, tag = "1")]
+296 -140
src/api/tunein.v1alpha1.rs
··· 1 - #[allow(clippy::derive_partial_eq_without_eq)] 2 - #[derive(Clone, PartialEq, ::prost::Message)] 1 + // This file is @generated by prost-build. 2 + #[derive(Clone, Copy, PartialEq, ::prost::Message)] 3 3 pub struct GetCategoriesRequest {} 4 - #[allow(clippy::derive_partial_eq_without_eq)] 5 4 #[derive(Clone, PartialEq, ::prost::Message)] 6 5 pub struct GetCategoriesResponse { 7 6 #[prost(message, repeated, tag = "1")] 8 7 pub categories: ::prost::alloc::vec::Vec<super::super::objects::v1alpha1::Category>, 9 8 } 10 - #[allow(clippy::derive_partial_eq_without_eq)] 11 9 #[derive(Clone, PartialEq, ::prost::Message)] 12 10 pub struct BrowseCategoryRequest { 13 11 #[prost(string, tag = "1")] 14 12 pub category_id: ::prost::alloc::string::String, 15 13 } 16 - #[allow(clippy::derive_partial_eq_without_eq)] 17 14 #[derive(Clone, PartialEq, ::prost::Message)] 18 15 pub struct BrowseCategoryResponse { 19 16 #[prost(message, repeated, tag = "1")] 20 17 pub categories: ::prost::alloc::vec::Vec<super::super::objects::v1alpha1::Category>, 21 18 } 22 - #[allow(clippy::derive_partial_eq_without_eq)] 23 19 #[derive(Clone, PartialEq, ::prost::Message)] 24 20 pub struct GetStationDetailsRequest { 25 21 #[prost(string, tag = "1")] 26 22 pub id: ::prost::alloc::string::String, 27 23 } 28 - #[allow(clippy::derive_partial_eq_without_eq)] 29 24 #[derive(Clone, PartialEq, ::prost::Message)] 30 25 pub struct GetStationDetailsResponse { 31 26 #[prost(message, repeated, tag = "1")] ··· 35 30 } 36 31 /// Generated client implementations. 37 32 pub mod browse_service_client { 38 - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] 33 + #![allow( 34 + unused_variables, 35 + dead_code, 36 + missing_docs, 37 + clippy::wildcard_imports, 38 + clippy::let_unit_value, 39 + )] 39 40 use tonic::codegen::*; 40 41 use tonic::codegen::http::Uri; 41 42 #[derive(Debug, Clone)] ··· 46 47 /// Attempt to create a new client by connecting to a given endpoint. 47 48 pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error> 48 49 where 49 - D: std::convert::TryInto<tonic::transport::Endpoint>, 50 + D: TryInto<tonic::transport::Endpoint>, 50 51 D::Error: Into<StdError>, 51 52 { 52 53 let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; ··· 57 58 where 58 59 T: tonic::client::GrpcService<tonic::body::BoxBody>, 59 60 T::Error: Into<StdError>, 60 - T::ResponseBody: Body<Data = Bytes> + Send + 'static, 61 - <T::ResponseBody as Body>::Error: Into<StdError> + Send, 61 + T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static, 62 + <T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send, 62 63 { 63 64 pub fn new(inner: T) -> Self { 64 65 let inner = tonic::client::Grpc::new(inner); ··· 83 84 >, 84 85 <T as tonic::codegen::Service< 85 86 http::Request<tonic::body::BoxBody>, 86 - >>::Error: Into<StdError> + Send + Sync, 87 + >>::Error: Into<StdError> + std::marker::Send + std::marker::Sync, 87 88 { 88 89 BrowseServiceClient::new(InterceptedService::new(inner, interceptor)) 89 90 } ··· 102 103 self.inner = self.inner.accept_compressed(encoding); 103 104 self 104 105 } 106 + /// Limits the maximum size of a decoded message. 107 + /// 108 + /// Default: `4MB` 109 + #[must_use] 110 + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { 111 + self.inner = self.inner.max_decoding_message_size(limit); 112 + self 113 + } 114 + /// Limits the maximum size of an encoded message. 115 + /// 116 + /// Default: `usize::MAX` 117 + #[must_use] 118 + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { 119 + self.inner = self.inner.max_encoding_message_size(limit); 120 + self 121 + } 105 122 pub async fn get_categories( 106 123 &mut self, 107 124 request: impl tonic::IntoRequest<super::GetCategoriesRequest>, 108 - ) -> Result<tonic::Response<super::GetCategoriesResponse>, tonic::Status> { 125 + ) -> std::result::Result< 126 + tonic::Response<super::GetCategoriesResponse>, 127 + tonic::Status, 128 + > { 109 129 self.inner 110 130 .ready() 111 131 .await 112 132 .map_err(|e| { 113 - tonic::Status::new( 114 - tonic::Code::Unknown, 133 + tonic::Status::unknown( 115 134 format!("Service was not ready: {}", e.into()), 116 135 ) 117 136 })?; ··· 119 138 let path = http::uri::PathAndQuery::from_static( 120 139 "/tunein.v1alpha1.BrowseService/GetCategories", 121 140 ); 122 - self.inner.unary(request.into_request(), path, codec).await 141 + let mut req = request.into_request(); 142 + req.extensions_mut() 143 + .insert( 144 + GrpcMethod::new("tunein.v1alpha1.BrowseService", "GetCategories"), 145 + ); 146 + self.inner.unary(req, path, codec).await 123 147 } 124 148 pub async fn browse_category( 125 149 &mut self, 126 150 request: impl tonic::IntoRequest<super::BrowseCategoryRequest>, 127 - ) -> Result<tonic::Response<super::BrowseCategoryResponse>, tonic::Status> { 151 + ) -> std::result::Result< 152 + tonic::Response<super::BrowseCategoryResponse>, 153 + tonic::Status, 154 + > { 128 155 self.inner 129 156 .ready() 130 157 .await 131 158 .map_err(|e| { 132 - tonic::Status::new( 133 - tonic::Code::Unknown, 159 + tonic::Status::unknown( 134 160 format!("Service was not ready: {}", e.into()), 135 161 ) 136 162 })?; ··· 138 164 let path = http::uri::PathAndQuery::from_static( 139 165 "/tunein.v1alpha1.BrowseService/BrowseCategory", 140 166 ); 141 - self.inner.unary(request.into_request(), path, codec).await 167 + let mut req = request.into_request(); 168 + req.extensions_mut() 169 + .insert( 170 + GrpcMethod::new("tunein.v1alpha1.BrowseService", "BrowseCategory"), 171 + ); 172 + self.inner.unary(req, path, codec).await 142 173 } 143 174 pub async fn get_station_details( 144 175 &mut self, 145 176 request: impl tonic::IntoRequest<super::GetStationDetailsRequest>, 146 - ) -> Result<tonic::Response<super::GetStationDetailsResponse>, tonic::Status> { 177 + ) -> std::result::Result< 178 + tonic::Response<super::GetStationDetailsResponse>, 179 + tonic::Status, 180 + > { 147 181 self.inner 148 182 .ready() 149 183 .await 150 184 .map_err(|e| { 151 - tonic::Status::new( 152 - tonic::Code::Unknown, 185 + tonic::Status::unknown( 153 186 format!("Service was not ready: {}", e.into()), 154 187 ) 155 188 })?; ··· 157 190 let path = http::uri::PathAndQuery::from_static( 158 191 "/tunein.v1alpha1.BrowseService/GetStationDetails", 159 192 ); 160 - self.inner.unary(request.into_request(), path, codec).await 193 + let mut req = request.into_request(); 194 + req.extensions_mut() 195 + .insert( 196 + GrpcMethod::new("tunein.v1alpha1.BrowseService", "GetStationDetails"), 197 + ); 198 + self.inner.unary(req, path, codec).await 161 199 } 162 200 } 163 201 } 164 202 /// Generated server implementations. 165 203 pub mod browse_service_server { 166 - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] 204 + #![allow( 205 + unused_variables, 206 + dead_code, 207 + missing_docs, 208 + clippy::wildcard_imports, 209 + clippy::let_unit_value, 210 + )] 167 211 use tonic::codegen::*; 168 212 /// Generated trait containing gRPC methods that should be implemented for use with BrowseServiceServer. 169 213 #[async_trait] 170 - pub trait BrowseService: Send + Sync + 'static { 214 + pub trait BrowseService: std::marker::Send + std::marker::Sync + 'static { 171 215 async fn get_categories( 172 216 &self, 173 217 request: tonic::Request<super::GetCategoriesRequest>, 174 - ) -> Result<tonic::Response<super::GetCategoriesResponse>, tonic::Status>; 218 + ) -> std::result::Result< 219 + tonic::Response<super::GetCategoriesResponse>, 220 + tonic::Status, 221 + >; 175 222 async fn browse_category( 176 223 &self, 177 224 request: tonic::Request<super::BrowseCategoryRequest>, 178 - ) -> Result<tonic::Response<super::BrowseCategoryResponse>, tonic::Status>; 225 + ) -> std::result::Result< 226 + tonic::Response<super::BrowseCategoryResponse>, 227 + tonic::Status, 228 + >; 179 229 async fn get_station_details( 180 230 &self, 181 231 request: tonic::Request<super::GetStationDetailsRequest>, 182 - ) -> Result<tonic::Response<super::GetStationDetailsResponse>, tonic::Status>; 232 + ) -> std::result::Result< 233 + tonic::Response<super::GetStationDetailsResponse>, 234 + tonic::Status, 235 + >; 183 236 } 184 237 #[derive(Debug)] 185 - pub struct BrowseServiceServer<T: BrowseService> { 186 - inner: _Inner<T>, 238 + pub struct BrowseServiceServer<T> { 239 + inner: Arc<T>, 187 240 accept_compression_encodings: EnabledCompressionEncodings, 188 241 send_compression_encodings: EnabledCompressionEncodings, 242 + max_decoding_message_size: Option<usize>, 243 + max_encoding_message_size: Option<usize>, 189 244 } 190 - struct _Inner<T>(Arc<T>); 191 - impl<T: BrowseService> BrowseServiceServer<T> { 245 + impl<T> BrowseServiceServer<T> { 192 246 pub fn new(inner: T) -> Self { 193 247 Self::from_arc(Arc::new(inner)) 194 248 } 195 249 pub fn from_arc(inner: Arc<T>) -> Self { 196 - let inner = _Inner(inner); 197 250 Self { 198 251 inner, 199 252 accept_compression_encodings: Default::default(), 200 253 send_compression_encodings: Default::default(), 254 + max_decoding_message_size: None, 255 + max_encoding_message_size: None, 201 256 } 202 257 } 203 258 pub fn with_interceptor<F>( ··· 221 276 self.send_compression_encodings.enable(encoding); 222 277 self 223 278 } 279 + /// Limits the maximum size of a decoded message. 280 + /// 281 + /// Default: `4MB` 282 + #[must_use] 283 + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { 284 + self.max_decoding_message_size = Some(limit); 285 + self 286 + } 287 + /// Limits the maximum size of an encoded message. 288 + /// 289 + /// Default: `usize::MAX` 290 + #[must_use] 291 + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { 292 + self.max_encoding_message_size = Some(limit); 293 + self 294 + } 224 295 } 225 296 impl<T, B> tonic::codegen::Service<http::Request<B>> for BrowseServiceServer<T> 226 297 where 227 298 T: BrowseService, 228 - B: Body + Send + 'static, 229 - B::Error: Into<StdError> + Send + 'static, 299 + B: Body + std::marker::Send + 'static, 300 + B::Error: Into<StdError> + std::marker::Send + 'static, 230 301 { 231 302 type Response = http::Response<tonic::body::BoxBody>; 232 303 type Error = std::convert::Infallible; ··· 234 305 fn poll_ready( 235 306 &mut self, 236 307 _cx: &mut Context<'_>, 237 - ) -> Poll<Result<(), Self::Error>> { 308 + ) -> Poll<std::result::Result<(), Self::Error>> { 238 309 Poll::Ready(Ok(())) 239 310 } 240 311 fn call(&mut self, req: http::Request<B>) -> Self::Future { 241 - let inner = self.inner.clone(); 242 312 match req.uri().path() { 243 313 "/tunein.v1alpha1.BrowseService/GetCategories" => { 244 314 #[allow(non_camel_case_types)] ··· 256 326 &mut self, 257 327 request: tonic::Request<super::GetCategoriesRequest>, 258 328 ) -> Self::Future { 259 - let inner = self.0.clone(); 329 + let inner = Arc::clone(&self.0); 260 330 let fut = async move { 261 - (*inner).get_categories(request).await 331 + <T as BrowseService>::get_categories(&inner, request).await 262 332 }; 263 333 Box::pin(fut) 264 334 } 265 335 } 266 336 let accept_compression_encodings = self.accept_compression_encodings; 267 337 let send_compression_encodings = self.send_compression_encodings; 338 + let max_decoding_message_size = self.max_decoding_message_size; 339 + let max_encoding_message_size = self.max_encoding_message_size; 268 340 let inner = self.inner.clone(); 269 341 let fut = async move { 270 - let inner = inner.0; 271 342 let method = GetCategoriesSvc(inner); 272 343 let codec = tonic::codec::ProstCodec::default(); 273 344 let mut grpc = tonic::server::Grpc::new(codec) 274 345 .apply_compression_config( 275 346 accept_compression_encodings, 276 347 send_compression_encodings, 348 + ) 349 + .apply_max_message_size_config( 350 + max_decoding_message_size, 351 + max_encoding_message_size, 277 352 ); 278 353 let res = grpc.unary(method, req).await; 279 354 Ok(res) ··· 296 371 &mut self, 297 372 request: tonic::Request<super::BrowseCategoryRequest>, 298 373 ) -> Self::Future { 299 - let inner = self.0.clone(); 374 + let inner = Arc::clone(&self.0); 300 375 let fut = async move { 301 - (*inner).browse_category(request).await 376 + <T as BrowseService>::browse_category(&inner, request).await 302 377 }; 303 378 Box::pin(fut) 304 379 } 305 380 } 306 381 let accept_compression_encodings = self.accept_compression_encodings; 307 382 let send_compression_encodings = self.send_compression_encodings; 383 + let max_decoding_message_size = self.max_decoding_message_size; 384 + let max_encoding_message_size = self.max_encoding_message_size; 308 385 let inner = self.inner.clone(); 309 386 let fut = async move { 310 - let inner = inner.0; 311 387 let method = BrowseCategorySvc(inner); 312 388 let codec = tonic::codec::ProstCodec::default(); 313 389 let mut grpc = tonic::server::Grpc::new(codec) 314 390 .apply_compression_config( 315 391 accept_compression_encodings, 316 392 send_compression_encodings, 393 + ) 394 + .apply_max_message_size_config( 395 + max_decoding_message_size, 396 + max_encoding_message_size, 317 397 ); 318 398 let res = grpc.unary(method, req).await; 319 399 Ok(res) ··· 336 416 &mut self, 337 417 request: tonic::Request<super::GetStationDetailsRequest>, 338 418 ) -> Self::Future { 339 - let inner = self.0.clone(); 419 + let inner = Arc::clone(&self.0); 340 420 let fut = async move { 341 - (*inner).get_station_details(request).await 421 + <T as BrowseService>::get_station_details(&inner, request) 422 + .await 342 423 }; 343 424 Box::pin(fut) 344 425 } 345 426 } 346 427 let accept_compression_encodings = self.accept_compression_encodings; 347 428 let send_compression_encodings = self.send_compression_encodings; 429 + let max_decoding_message_size = self.max_decoding_message_size; 430 + let max_encoding_message_size = self.max_encoding_message_size; 348 431 let inner = self.inner.clone(); 349 432 let fut = async move { 350 - let inner = inner.0; 351 433 let method = GetStationDetailsSvc(inner); 352 434 let codec = tonic::codec::ProstCodec::default(); 353 435 let mut grpc = tonic::server::Grpc::new(codec) 354 436 .apply_compression_config( 355 437 accept_compression_encodings, 356 438 send_compression_encodings, 439 + ) 440 + .apply_max_message_size_config( 441 + max_decoding_message_size, 442 + max_encoding_message_size, 357 443 ); 358 444 let res = grpc.unary(method, req).await; 359 445 Ok(res) ··· 362 448 } 363 449 _ => { 364 450 Box::pin(async move { 365 - Ok( 366 - http::Response::builder() 367 - .status(200) 368 - .header("grpc-status", "12") 369 - .header("content-type", "application/grpc") 370 - .body(empty_body()) 371 - .unwrap(), 372 - ) 451 + let mut response = http::Response::new(empty_body()); 452 + let headers = response.headers_mut(); 453 + headers 454 + .insert( 455 + tonic::Status::GRPC_STATUS, 456 + (tonic::Code::Unimplemented as i32).into(), 457 + ); 458 + headers 459 + .insert( 460 + http::header::CONTENT_TYPE, 461 + tonic::metadata::GRPC_CONTENT_TYPE, 462 + ); 463 + Ok(response) 373 464 }) 374 465 } 375 466 } 376 467 } 377 468 } 378 - impl<T: BrowseService> Clone for BrowseServiceServer<T> { 469 + impl<T> Clone for BrowseServiceServer<T> { 379 470 fn clone(&self) -> Self { 380 471 let inner = self.inner.clone(); 381 472 Self { 382 473 inner, 383 474 accept_compression_encodings: self.accept_compression_encodings, 384 475 send_compression_encodings: self.send_compression_encodings, 476 + max_decoding_message_size: self.max_decoding_message_size, 477 + max_encoding_message_size: self.max_encoding_message_size, 385 478 } 386 479 } 387 480 } 388 - impl<T: BrowseService> Clone for _Inner<T> { 389 - fn clone(&self) -> Self { 390 - Self(self.0.clone()) 391 - } 392 - } 393 - impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> { 394 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 395 - write!(f, "{:?}", self.0) 396 - } 397 - } 398 - impl<T: BrowseService> tonic::server::NamedService for BrowseServiceServer<T> { 399 - const NAME: &'static str = "tunein.v1alpha1.BrowseService"; 481 + /// Generated gRPC service name 482 + pub const SERVICE_NAME: &str = "tunein.v1alpha1.BrowseService"; 483 + impl<T> tonic::server::NamedService for BrowseServiceServer<T> { 484 + const NAME: &'static str = SERVICE_NAME; 400 485 } 401 486 } 402 - #[allow(clippy::derive_partial_eq_without_eq)] 403 - #[derive(Clone, PartialEq, ::prost::Message)] 487 + #[derive(Clone, Copy, PartialEq, ::prost::Message)] 404 488 pub struct PlayOrPauseRequest {} 405 - #[allow(clippy::derive_partial_eq_without_eq)] 406 - #[derive(Clone, PartialEq, ::prost::Message)] 489 + #[derive(Clone, Copy, PartialEq, ::prost::Message)] 407 490 pub struct PlayOrPauseResponse {} 408 - #[allow(clippy::derive_partial_eq_without_eq)] 409 - #[derive(Clone, PartialEq, ::prost::Message)] 491 + #[derive(Clone, Copy, PartialEq, ::prost::Message)] 410 492 pub struct StopRequest {} 411 - #[allow(clippy::derive_partial_eq_without_eq)] 412 - #[derive(Clone, PartialEq, ::prost::Message)] 493 + #[derive(Clone, Copy, PartialEq, ::prost::Message)] 413 494 pub struct StopResponse {} 414 - #[allow(clippy::derive_partial_eq_without_eq)] 415 495 #[derive(Clone, PartialEq, ::prost::Message)] 416 496 pub struct PlayRequest { 417 497 #[prost(string, tag = "1")] 418 498 pub station_name_or_id: ::prost::alloc::string::String, 419 499 } 420 - #[allow(clippy::derive_partial_eq_without_eq)] 421 - #[derive(Clone, PartialEq, ::prost::Message)] 500 + #[derive(Clone, Copy, PartialEq, ::prost::Message)] 422 501 pub struct PlayResponse {} 423 502 /// Generated client implementations. 424 503 pub mod playback_service_client { 425 - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] 504 + #![allow( 505 + unused_variables, 506 + dead_code, 507 + missing_docs, 508 + clippy::wildcard_imports, 509 + clippy::let_unit_value, 510 + )] 426 511 use tonic::codegen::*; 427 512 use tonic::codegen::http::Uri; 428 513 #[derive(Debug, Clone)] ··· 433 518 /// Attempt to create a new client by connecting to a given endpoint. 434 519 pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error> 435 520 where 436 - D: std::convert::TryInto<tonic::transport::Endpoint>, 521 + D: TryInto<tonic::transport::Endpoint>, 437 522 D::Error: Into<StdError>, 438 523 { 439 524 let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; ··· 444 529 where 445 530 T: tonic::client::GrpcService<tonic::body::BoxBody>, 446 531 T::Error: Into<StdError>, 447 - T::ResponseBody: Body<Data = Bytes> + Send + 'static, 448 - <T::ResponseBody as Body>::Error: Into<StdError> + Send, 532 + T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static, 533 + <T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send, 449 534 { 450 535 pub fn new(inner: T) -> Self { 451 536 let inner = tonic::client::Grpc::new(inner); ··· 470 555 >, 471 556 <T as tonic::codegen::Service< 472 557 http::Request<tonic::body::BoxBody>, 473 - >>::Error: Into<StdError> + Send + Sync, 558 + >>::Error: Into<StdError> + std::marker::Send + std::marker::Sync, 474 559 { 475 560 PlaybackServiceClient::new(InterceptedService::new(inner, interceptor)) 476 561 } ··· 489 574 self.inner = self.inner.accept_compressed(encoding); 490 575 self 491 576 } 577 + /// Limits the maximum size of a decoded message. 578 + /// 579 + /// Default: `4MB` 580 + #[must_use] 581 + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { 582 + self.inner = self.inner.max_decoding_message_size(limit); 583 + self 584 + } 585 + /// Limits the maximum size of an encoded message. 586 + /// 587 + /// Default: `usize::MAX` 588 + #[must_use] 589 + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { 590 + self.inner = self.inner.max_encoding_message_size(limit); 591 + self 592 + } 492 593 pub async fn play( 493 594 &mut self, 494 595 request: impl tonic::IntoRequest<super::PlayRequest>, 495 - ) -> Result<tonic::Response<super::PlayResponse>, tonic::Status> { 596 + ) -> std::result::Result<tonic::Response<super::PlayResponse>, tonic::Status> { 496 597 self.inner 497 598 .ready() 498 599 .await 499 600 .map_err(|e| { 500 - tonic::Status::new( 501 - tonic::Code::Unknown, 601 + tonic::Status::unknown( 502 602 format!("Service was not ready: {}", e.into()), 503 603 ) 504 604 })?; ··· 506 606 let path = http::uri::PathAndQuery::from_static( 507 607 "/tunein.v1alpha1.PlaybackService/Play", 508 608 ); 509 - self.inner.unary(request.into_request(), path, codec).await 609 + let mut req = request.into_request(); 610 + req.extensions_mut() 611 + .insert(GrpcMethod::new("tunein.v1alpha1.PlaybackService", "Play")); 612 + self.inner.unary(req, path, codec).await 510 613 } 511 614 pub async fn stop( 512 615 &mut self, 513 616 request: impl tonic::IntoRequest<super::StopRequest>, 514 - ) -> Result<tonic::Response<super::StopResponse>, tonic::Status> { 617 + ) -> std::result::Result<tonic::Response<super::StopResponse>, tonic::Status> { 515 618 self.inner 516 619 .ready() 517 620 .await 518 621 .map_err(|e| { 519 - tonic::Status::new( 520 - tonic::Code::Unknown, 622 + tonic::Status::unknown( 521 623 format!("Service was not ready: {}", e.into()), 522 624 ) 523 625 })?; ··· 525 627 let path = http::uri::PathAndQuery::from_static( 526 628 "/tunein.v1alpha1.PlaybackService/Stop", 527 629 ); 528 - self.inner.unary(request.into_request(), path, codec).await 630 + let mut req = request.into_request(); 631 + req.extensions_mut() 632 + .insert(GrpcMethod::new("tunein.v1alpha1.PlaybackService", "Stop")); 633 + self.inner.unary(req, path, codec).await 529 634 } 530 635 pub async fn play_or_pause( 531 636 &mut self, 532 637 request: impl tonic::IntoRequest<super::PlayOrPauseRequest>, 533 - ) -> Result<tonic::Response<super::PlayOrPauseResponse>, tonic::Status> { 638 + ) -> std::result::Result< 639 + tonic::Response<super::PlayOrPauseResponse>, 640 + tonic::Status, 641 + > { 534 642 self.inner 535 643 .ready() 536 644 .await 537 645 .map_err(|e| { 538 - tonic::Status::new( 539 - tonic::Code::Unknown, 646 + tonic::Status::unknown( 540 647 format!("Service was not ready: {}", e.into()), 541 648 ) 542 649 })?; ··· 544 651 let path = http::uri::PathAndQuery::from_static( 545 652 "/tunein.v1alpha1.PlaybackService/PlayOrPause", 546 653 ); 547 - self.inner.unary(request.into_request(), path, codec).await 654 + let mut req = request.into_request(); 655 + req.extensions_mut() 656 + .insert( 657 + GrpcMethod::new("tunein.v1alpha1.PlaybackService", "PlayOrPause"), 658 + ); 659 + self.inner.unary(req, path, codec).await 548 660 } 549 661 } 550 662 } 551 663 /// Generated server implementations. 552 664 pub mod playback_service_server { 553 - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] 665 + #![allow( 666 + unused_variables, 667 + dead_code, 668 + missing_docs, 669 + clippy::wildcard_imports, 670 + clippy::let_unit_value, 671 + )] 554 672 use tonic::codegen::*; 555 673 /// Generated trait containing gRPC methods that should be implemented for use with PlaybackServiceServer. 556 674 #[async_trait] 557 - pub trait PlaybackService: Send + Sync + 'static { 675 + pub trait PlaybackService: std::marker::Send + std::marker::Sync + 'static { 558 676 async fn play( 559 677 &self, 560 678 request: tonic::Request<super::PlayRequest>, 561 - ) -> Result<tonic::Response<super::PlayResponse>, tonic::Status>; 679 + ) -> std::result::Result<tonic::Response<super::PlayResponse>, tonic::Status>; 562 680 async fn stop( 563 681 &self, 564 682 request: tonic::Request<super::StopRequest>, 565 - ) -> Result<tonic::Response<super::StopResponse>, tonic::Status>; 683 + ) -> std::result::Result<tonic::Response<super::StopResponse>, tonic::Status>; 566 684 async fn play_or_pause( 567 685 &self, 568 686 request: tonic::Request<super::PlayOrPauseRequest>, 569 - ) -> Result<tonic::Response<super::PlayOrPauseResponse>, tonic::Status>; 687 + ) -> std::result::Result< 688 + tonic::Response<super::PlayOrPauseResponse>, 689 + tonic::Status, 690 + >; 570 691 } 571 692 #[derive(Debug)] 572 - pub struct PlaybackServiceServer<T: PlaybackService> { 573 - inner: _Inner<T>, 693 + pub struct PlaybackServiceServer<T> { 694 + inner: Arc<T>, 574 695 accept_compression_encodings: EnabledCompressionEncodings, 575 696 send_compression_encodings: EnabledCompressionEncodings, 697 + max_decoding_message_size: Option<usize>, 698 + max_encoding_message_size: Option<usize>, 576 699 } 577 - struct _Inner<T>(Arc<T>); 578 - impl<T: PlaybackService> PlaybackServiceServer<T> { 700 + impl<T> PlaybackServiceServer<T> { 579 701 pub fn new(inner: T) -> Self { 580 702 Self::from_arc(Arc::new(inner)) 581 703 } 582 704 pub fn from_arc(inner: Arc<T>) -> Self { 583 - let inner = _Inner(inner); 584 705 Self { 585 706 inner, 586 707 accept_compression_encodings: Default::default(), 587 708 send_compression_encodings: Default::default(), 709 + max_decoding_message_size: None, 710 + max_encoding_message_size: None, 588 711 } 589 712 } 590 713 pub fn with_interceptor<F>( ··· 608 731 self.send_compression_encodings.enable(encoding); 609 732 self 610 733 } 734 + /// Limits the maximum size of a decoded message. 735 + /// 736 + /// Default: `4MB` 737 + #[must_use] 738 + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { 739 + self.max_decoding_message_size = Some(limit); 740 + self 741 + } 742 + /// Limits the maximum size of an encoded message. 743 + /// 744 + /// Default: `usize::MAX` 745 + #[must_use] 746 + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { 747 + self.max_encoding_message_size = Some(limit); 748 + self 749 + } 611 750 } 612 751 impl<T, B> tonic::codegen::Service<http::Request<B>> for PlaybackServiceServer<T> 613 752 where 614 753 T: PlaybackService, 615 - B: Body + Send + 'static, 616 - B::Error: Into<StdError> + Send + 'static, 754 + B: Body + std::marker::Send + 'static, 755 + B::Error: Into<StdError> + std::marker::Send + 'static, 617 756 { 618 757 type Response = http::Response<tonic::body::BoxBody>; 619 758 type Error = std::convert::Infallible; ··· 621 760 fn poll_ready( 622 761 &mut self, 623 762 _cx: &mut Context<'_>, 624 - ) -> Poll<Result<(), Self::Error>> { 763 + ) -> Poll<std::result::Result<(), Self::Error>> { 625 764 Poll::Ready(Ok(())) 626 765 } 627 766 fn call(&mut self, req: http::Request<B>) -> Self::Future { 628 - let inner = self.inner.clone(); 629 767 match req.uri().path() { 630 768 "/tunein.v1alpha1.PlaybackService/Play" => { 631 769 #[allow(non_camel_case_types)] ··· 642 780 &mut self, 643 781 request: tonic::Request<super::PlayRequest>, 644 782 ) -> Self::Future { 645 - let inner = self.0.clone(); 646 - let fut = async move { (*inner).play(request).await }; 783 + let inner = Arc::clone(&self.0); 784 + let fut = async move { 785 + <T as PlaybackService>::play(&inner, request).await 786 + }; 647 787 Box::pin(fut) 648 788 } 649 789 } 650 790 let accept_compression_encodings = self.accept_compression_encodings; 651 791 let send_compression_encodings = self.send_compression_encodings; 792 + let max_decoding_message_size = self.max_decoding_message_size; 793 + let max_encoding_message_size = self.max_encoding_message_size; 652 794 let inner = self.inner.clone(); 653 795 let fut = async move { 654 - let inner = inner.0; 655 796 let method = PlaySvc(inner); 656 797 let codec = tonic::codec::ProstCodec::default(); 657 798 let mut grpc = tonic::server::Grpc::new(codec) 658 799 .apply_compression_config( 659 800 accept_compression_encodings, 660 801 send_compression_encodings, 802 + ) 803 + .apply_max_message_size_config( 804 + max_decoding_message_size, 805 + max_encoding_message_size, 661 806 ); 662 807 let res = grpc.unary(method, req).await; 663 808 Ok(res) ··· 679 824 &mut self, 680 825 request: tonic::Request<super::StopRequest>, 681 826 ) -> Self::Future { 682 - let inner = self.0.clone(); 683 - let fut = async move { (*inner).stop(request).await }; 827 + let inner = Arc::clone(&self.0); 828 + let fut = async move { 829 + <T as PlaybackService>::stop(&inner, request).await 830 + }; 684 831 Box::pin(fut) 685 832 } 686 833 } 687 834 let accept_compression_encodings = self.accept_compression_encodings; 688 835 let send_compression_encodings = self.send_compression_encodings; 836 + let max_decoding_message_size = self.max_decoding_message_size; 837 + let max_encoding_message_size = self.max_encoding_message_size; 689 838 let inner = self.inner.clone(); 690 839 let fut = async move { 691 - let inner = inner.0; 692 840 let method = StopSvc(inner); 693 841 let codec = tonic::codec::ProstCodec::default(); 694 842 let mut grpc = tonic::server::Grpc::new(codec) 695 843 .apply_compression_config( 696 844 accept_compression_encodings, 697 845 send_compression_encodings, 846 + ) 847 + .apply_max_message_size_config( 848 + max_decoding_message_size, 849 + max_encoding_message_size, 698 850 ); 699 851 let res = grpc.unary(method, req).await; 700 852 Ok(res) ··· 717 869 &mut self, 718 870 request: tonic::Request<super::PlayOrPauseRequest>, 719 871 ) -> Self::Future { 720 - let inner = self.0.clone(); 872 + let inner = Arc::clone(&self.0); 721 873 let fut = async move { 722 - (*inner).play_or_pause(request).await 874 + <T as PlaybackService>::play_or_pause(&inner, request).await 723 875 }; 724 876 Box::pin(fut) 725 877 } 726 878 } 727 879 let accept_compression_encodings = self.accept_compression_encodings; 728 880 let send_compression_encodings = self.send_compression_encodings; 881 + let max_decoding_message_size = self.max_decoding_message_size; 882 + let max_encoding_message_size = self.max_encoding_message_size; 729 883 let inner = self.inner.clone(); 730 884 let fut = async move { 731 - let inner = inner.0; 732 885 let method = PlayOrPauseSvc(inner); 733 886 let codec = tonic::codec::ProstCodec::default(); 734 887 let mut grpc = tonic::server::Grpc::new(codec) 735 888 .apply_compression_config( 736 889 accept_compression_encodings, 737 890 send_compression_encodings, 891 + ) 892 + .apply_max_message_size_config( 893 + max_decoding_message_size, 894 + max_encoding_message_size, 738 895 ); 739 896 let res = grpc.unary(method, req).await; 740 897 Ok(res) ··· 743 900 } 744 901 _ => { 745 902 Box::pin(async move { 746 - Ok( 747 - http::Response::builder() 748 - .status(200) 749 - .header("grpc-status", "12") 750 - .header("content-type", "application/grpc") 751 - .body(empty_body()) 752 - .unwrap(), 753 - ) 903 + let mut response = http::Response::new(empty_body()); 904 + let headers = response.headers_mut(); 905 + headers 906 + .insert( 907 + tonic::Status::GRPC_STATUS, 908 + (tonic::Code::Unimplemented as i32).into(), 909 + ); 910 + headers 911 + .insert( 912 + http::header::CONTENT_TYPE, 913 + tonic::metadata::GRPC_CONTENT_TYPE, 914 + ); 915 + Ok(response) 754 916 }) 755 917 } 756 918 } 757 919 } 758 920 } 759 - impl<T: PlaybackService> Clone for PlaybackServiceServer<T> { 921 + impl<T> Clone for PlaybackServiceServer<T> { 760 922 fn clone(&self) -> Self { 761 923 let inner = self.inner.clone(); 762 924 Self { 763 925 inner, 764 926 accept_compression_encodings: self.accept_compression_encodings, 765 927 send_compression_encodings: self.send_compression_encodings, 928 + max_decoding_message_size: self.max_decoding_message_size, 929 + max_encoding_message_size: self.max_encoding_message_size, 766 930 } 767 931 } 768 932 } 769 - impl<T: PlaybackService> Clone for _Inner<T> { 770 - fn clone(&self) -> Self { 771 - Self(self.0.clone()) 772 - } 773 - } 774 - impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> { 775 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 776 - write!(f, "{:?}", self.0) 777 - } 778 - } 779 - impl<T: PlaybackService> tonic::server::NamedService for PlaybackServiceServer<T> { 780 - const NAME: &'static str = "tunein.v1alpha1.PlaybackService"; 933 + /// Generated gRPC service name 934 + pub const SERVICE_NAME: &str = "tunein.v1alpha1.PlaybackService"; 935 + impl<T> tonic::server::NamedService for PlaybackServiceServer<T> { 936 + const NAME: &'static str = SERVICE_NAME; 781 937 } 782 938 }
+38
src/lib.rs
··· 1 + pub mod extract; 2 + pub mod provider; 3 + pub mod types; 4 + 1 5 pub mod api { 2 6 #[path = ""] 3 7 pub mod tunein { 8 + use super::super::types; 4 9 use tunein::types::CategoryDetails; 5 10 6 11 use super::objects::v1alpha1::{Category, Station, StationLinkDetails}; 7 12 8 13 #[path = "tunein.v1alpha1.rs"] 9 14 pub mod v1alpha1; 15 + 16 + pub const FILE_DESCRIPTOR_SET: &[u8] = include_bytes!("api/descriptor.bin"); 17 + 18 + impl From<String> for Category { 19 + fn from(name: String) -> Self { 20 + Self { 21 + name, 22 + ..Default::default() 23 + } 24 + } 25 + } 26 + 27 + impl From<types::Station> for Category { 28 + fn from(st: crate::types::Station) -> Self { 29 + Self { 30 + id: st.id, 31 + name: st.name, 32 + ..Default::default() 33 + } 34 + } 35 + } 36 + 10 37 impl From<CategoryDetails> for Category { 11 38 fn from(category: CategoryDetails) -> Self { 12 39 Self { ··· 45 72 .collect() 46 73 }) 47 74 .unwrap_or(vec![]), 75 + } 76 + } 77 + } 78 + 79 + impl From<types::Station> for StationLinkDetails { 80 + fn from(s: types::Station) -> Self { 81 + Self { 82 + bitrate: s.bitrate, 83 + url: s.stream_url, 84 + media_type: s.codec, 85 + ..Default::default() 48 86 } 49 87 } 50 88 }
+27 -38
src/server/browse.rs
··· 1 - use std::str::FromStr; 2 - 3 - use tunein::{types, TuneInClient}; 4 1 use tunein_cli::api::{ 5 2 objects::v1alpha1::{Category, StationLinkDetails}, 6 3 tunein::v1alpha1::{ ··· 10 7 }, 11 8 }; 12 9 13 - pub struct Browse { 14 - client: TuneInClient, 15 - } 10 + use tunein_cli::provider::{tunein::Tunein, Provider}; 16 11 17 - impl Default for Browse { 18 - fn default() -> Self { 19 - Self { 20 - client: TuneInClient::new(), 21 - } 22 - } 23 - } 12 + #[derive(Default)] 13 + pub struct Browse; 24 14 25 15 #[tonic::async_trait] 26 16 impl BrowseService for Browse { ··· 28 18 &self, 29 19 _request: tonic::Request<GetCategoriesRequest>, 30 20 ) -> Result<tonic::Response<GetCategoriesResponse>, tonic::Status> { 31 - let result = self 32 - .client 33 - .browse(None) 21 + let client: Box<dyn Provider + Send + Sync> = Box::new(Tunein::new()); 22 + let offset = 0; 23 + let limit = 100; 24 + let result = client 25 + .categories(offset, limit) 34 26 .await 35 27 .map_err(|e| tonic::Status::internal(e.to_string()))?; 36 28 ··· 45 37 ) -> Result<tonic::Response<BrowseCategoryResponse>, tonic::Status> { 46 38 let req = request.into_inner(); 47 39 let category_id = req.category_id; 48 - let categories: Vec<Category> = match types::Category::from_str(&category_id) { 49 - Ok(category) => { 50 - let results = self 51 - .client 52 - .browse(Some(category)) 53 - .await 54 - .map_err(|e| tonic::Status::internal(e.to_string()))?; 55 - results.into_iter().map(Category::from).collect() 56 - } 57 - Err(_) => { 58 - let results = self 59 - .client 60 - .browse_by_id(&category_id) 61 - .await 62 - .map_err(|e| tonic::Status::internal(e.to_string()))?; 63 - results.into_iter().map(Category::from).collect() 64 - } 65 - }; 40 + 41 + let offset = 0; 42 + let limit = 100; 43 + 44 + let client: Box<dyn Provider + Send + Sync> = Box::new(Tunein::new()); 45 + let results = client 46 + .browse(category_id, offset, limit) 47 + .await 48 + .map_err(|e| tonic::Status::internal(e.to_string()))?; 49 + 50 + let categories = results.into_iter().map(Category::from).collect(); 66 51 Ok(tonic::Response::new(BrowseCategoryResponse { categories })) 67 52 } 68 53 ··· 72 57 ) -> Result<tonic::Response<GetStationDetailsResponse>, tonic::Status> { 73 58 let req = request.into_inner(); 74 59 let station_id = req.id; 75 - let station = self 76 - .client 77 - .get_station(&station_id) 60 + let client: Box<dyn Provider + Send + Sync> = Box::new(Tunein::new()); 61 + let result = client 62 + .get_station(station_id) 78 63 .await 79 64 .map_err(|e| tonic::Status::internal(e.to_string()))?; 80 65 66 + let station = match result { 67 + Some(station) => station, 68 + None => return Err(tonic::Status::internal("No station found")), 69 + }; 81 70 Ok(tonic::Response::new(GetStationDetailsResponse { 82 - station_link_details: station.into_iter().map(StationLinkDetails::from).collect(), 71 + station_link_details: vec![StationLinkDetails::from(station)], 83 72 })) 84 73 } 85 74 }
+6
src/server/mod.rs
··· 6 6 use tunein_cli::api::tunein::v1alpha1::{ 7 7 browse_service_server::BrowseServiceServer, playback_service_server::PlaybackServiceServer, 8 8 }; 9 + use tunein_cli::api::tunein::FILE_DESCRIPTOR_SET; 9 10 10 11 use self::{browse::Browse, playback::Playback}; 11 12 ··· 17 18 println!("Listening on {}", addr.cyan()); 18 19 Server::builder() 19 20 .accept_http1(true) 21 + .add_service( 22 + tonic_reflection::server::Builder::configure() 23 + .register_encoded_file_descriptor_set(FILE_DESCRIPTOR_SET) 24 + .build_v1alpha()?, 25 + ) 20 26 .add_service(tonic_web::enable(BrowseServiceServer::new( 21 27 Browse::default(), 22 28 )))
+12 -51
src/server/playback.rs
··· 1 1 use std::sync::{Arc, Mutex}; 2 2 3 3 use tokio::sync::mpsc; 4 - use tunein::TuneInClient; 5 4 use tunein_cli::api::tunein::v1alpha1::{ 6 5 playback_service_server::PlaybackService, PlayOrPauseRequest, PlayOrPauseResponse, PlayRequest, 7 6 PlayResponse, StopRequest, StopResponse, 8 7 }; 9 8 10 9 use crate::{ 11 - extract::extract_stream_url, 12 10 player::{Player, PlayerCommand}, 11 + provider::{tunein::Tunein, Provider}, 13 12 }; 14 13 15 14 pub struct Playback { 16 - client: TuneInClient, 17 15 player: Player, 18 16 cmd_tx: mpsc::UnboundedSender<PlayerCommand>, 19 17 } ··· 23 21 let (cmd_tx, cmd_rx) = mpsc::unbounded_channel::<PlayerCommand>(); 24 22 let cmd_rx = Arc::new(Mutex::new(cmd_rx)); 25 23 let player = Player::new(cmd_rx); 26 - Self { 27 - client: TuneInClient::new(), 28 - player, 29 - cmd_tx, 30 - } 24 + Self { player, cmd_tx } 31 25 } 32 26 } 33 27 ··· 39 33 ) -> Result<tonic::Response<PlayResponse>, tonic::Status> { 40 34 let req = request.into_inner(); 41 35 42 - let results = self 43 - .client 44 - .get_station(&req.station_name_or_id) 36 + let client: Box<dyn Provider + Send + Sync> = Box::new(Tunein::new()); 37 + let station = client 38 + .get_station(req.station_name_or_id.clone()) 45 39 .await 46 40 .map_err(|e| tonic::Status::internal(e.to_string()))?; 47 - let (url, playlist_type, _) = match results.is_empty() { 48 - true => { 49 - let results = self 50 - .client 51 - .search(&req.station_name_or_id) 52 - .await 53 - .map_err(|e| tonic::Status::internal(e.to_string()))?; 54 - match results.first() { 55 - Some(result) => { 56 - if result.r#type != Some("audio".to_string()) { 57 - return Err(tonic::Status::internal("No station found")); 58 - } 59 - let id = result.guide_id.as_ref().unwrap(); 60 - let station = self 61 - .client 62 - .get_station(id) 63 - .await 64 - .map_err(|e| tonic::Status::internal(e.to_string()))?; 65 - let station = station.first().unwrap(); 66 - ( 67 - station.url.clone(), 68 - station.playlist_type.clone(), 69 - station.media_type.clone(), 70 - ) 71 - } 72 - None => ("".to_string(), None, "".to_string()), 73 - } 74 - } 75 - false => { 76 - let result = results.first().unwrap(); 77 - ( 78 - result.url.clone(), 79 - result.playlist_type.clone(), 80 - result.media_type.clone(), 81 - ) 82 - } 83 - }; 84 - let stream_url = extract_stream_url(&url, playlist_type) 85 - .await 86 - .map_err(|e| tonic::Status::internal(e.to_string()))?; 41 + 42 + if station.is_none() { 43 + return Err(tonic::Status::internal("No station found")); 44 + } 45 + 46 + let station = station.unwrap(); 47 + let stream_url = station.stream_url.clone(); 87 48 println!("{}", stream_url); 88 49 89 50 self.cmd_tx.send(PlayerCommand::Play(stream_url)).unwrap();