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

configure a simple tonic gRPC server

+378
Cargo.lock
··· 219 219 ] 220 220 221 221 [[package]] 222 + name = "async-stream" 223 + version = "0.3.4" 224 + source = "registry+https://github.com/rust-lang/crates.io-index" 225 + checksum = "ad445822218ce64be7a341abfb0b1ea43b5c23aa83902542a4542e78309d8e5e" 226 + dependencies = [ 227 + "async-stream-impl", 228 + "futures-core", 229 + "pin-project-lite", 230 + ] 231 + 232 + [[package]] 233 + name = "async-stream-impl" 234 + version = "0.3.4" 235 + source = "registry+https://github.com/rust-lang/crates.io-index" 236 + checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965" 237 + dependencies = [ 238 + "proc-macro2", 239 + "quote", 240 + "syn", 241 + ] 242 + 243 + [[package]] 222 244 name = "async-task" 223 245 version = "4.3.0" 224 246 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 272 294 checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 273 295 274 296 [[package]] 297 + name = "axum" 298 + version = "0.6.8" 299 + source = "registry+https://github.com/rust-lang/crates.io-index" 300 + checksum = "2bd379e511536bad07447f899300aa526e9bae8e6f66dc5e5ca45d7587b7c1ec" 301 + dependencies = [ 302 + "async-trait", 303 + "axum-core", 304 + "bitflags", 305 + "bytes", 306 + "futures-util", 307 + "http", 308 + "http-body", 309 + "hyper", 310 + "itoa", 311 + "matchit", 312 + "memchr", 313 + "mime", 314 + "percent-encoding 2.2.0", 315 + "pin-project-lite", 316 + "rustversion", 317 + "serde", 318 + "sync_wrapper", 319 + "tower", 320 + "tower-http", 321 + "tower-layer", 322 + "tower-service", 323 + ] 324 + 325 + [[package]] 326 + name = "axum-core" 327 + version = "0.3.2" 328 + source = "registry+https://github.com/rust-lang/crates.io-index" 329 + checksum = "1cae3e661676ffbacb30f1a824089a8c9150e71017f7e1e38f2aa32009188d34" 330 + dependencies = [ 331 + "async-trait", 332 + "bytes", 333 + "futures-util", 334 + "http", 335 + "http-body", 336 + "mime", 337 + "rustversion", 338 + "tower-layer", 339 + "tower-service", 340 + ] 341 + 342 + [[package]] 275 343 name = "base-x" 276 344 version = "0.2.11" 277 345 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 672 740 checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" 673 741 674 742 [[package]] 743 + name = "either" 744 + version = "1.8.1" 745 + source = "registry+https://github.com/rust-lang/crates.io-index" 746 + checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" 747 + 748 + [[package]] 675 749 name = "encoding_rs" 676 750 version = "0.8.32" 677 751 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 694 768 dependencies = [ 695 769 "instant", 696 770 ] 771 + 772 + [[package]] 773 + name = "fixedbitset" 774 + version = "0.4.2" 775 + source = "registry+https://github.com/rust-lang/crates.io-index" 776 + checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" 697 777 698 778 [[package]] 699 779 name = "fnv" ··· 915 995 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 916 996 917 997 [[package]] 998 + name = "heck" 999 + version = "0.4.1" 1000 + source = "registry+https://github.com/rust-lang/crates.io-index" 1001 + checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 1002 + 1003 + [[package]] 918 1004 name = "hermit-abi" 919 1005 version = "0.1.19" 920 1006 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1000 1086 ] 1001 1087 1002 1088 [[package]] 1089 + name = "http-range-header" 1090 + version = "0.3.0" 1091 + source = "registry+https://github.com/rust-lang/crates.io-index" 1092 + checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" 1093 + 1094 + [[package]] 1003 1095 name = "http-types" 1004 1096 version = "2.12.0" 1005 1097 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1058 1150 ] 1059 1151 1060 1152 [[package]] 1153 + name = "hyper-timeout" 1154 + version = "0.4.1" 1155 + source = "registry+https://github.com/rust-lang/crates.io-index" 1156 + checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" 1157 + dependencies = [ 1158 + "hyper", 1159 + "pin-project-lite", 1160 + "tokio", 1161 + "tokio-io-timeout", 1162 + ] 1163 + 1164 + [[package]] 1061 1165 name = "hyper-tls" 1062 1166 version = "0.5.0" 1063 1167 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1121 1225 version = "2.7.1" 1122 1226 source = "registry+https://github.com/rust-lang/crates.io-index" 1123 1227 checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" 1228 + 1229 + [[package]] 1230 + name = "itertools" 1231 + version = "0.10.5" 1232 + source = "registry+https://github.com/rust-lang/crates.io-index" 1233 + checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 1234 + dependencies = [ 1235 + "either", 1236 + ] 1124 1237 1125 1238 [[package]] 1126 1239 name = "itoa" ··· 1270 1383 version = "0.1.10" 1271 1384 source = "registry+https://github.com/rust-lang/crates.io-index" 1272 1385 checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" 1386 + 1387 + [[package]] 1388 + name = "matchit" 1389 + version = "0.7.0" 1390 + source = "registry+https://github.com/rust-lang/crates.io-index" 1391 + checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" 1273 1392 1274 1393 [[package]] 1275 1394 name = "memchr" ··· 1341 1460 ] 1342 1461 1343 1462 [[package]] 1463 + name = "multimap" 1464 + version = "0.8.3" 1465 + source = "registry+https://github.com/rust-lang/crates.io-index" 1466 + checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" 1467 + 1468 + [[package]] 1344 1469 name = "native-tls" 1345 1470 version = "0.2.11" 1346 1471 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1652 1777 checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" 1653 1778 1654 1779 [[package]] 1780 + name = "petgraph" 1781 + version = "0.6.3" 1782 + source = "registry+https://github.com/rust-lang/crates.io-index" 1783 + checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" 1784 + dependencies = [ 1785 + "fixedbitset", 1786 + "indexmap", 1787 + ] 1788 + 1789 + [[package]] 1655 1790 name = "pin-project" 1656 1791 version = "1.0.12" 1657 1792 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1730 1865 checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1731 1866 1732 1867 [[package]] 1868 + name = "prettyplease" 1869 + version = "0.1.23" 1870 + source = "registry+https://github.com/rust-lang/crates.io-index" 1871 + checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" 1872 + dependencies = [ 1873 + "proc-macro2", 1874 + "syn", 1875 + ] 1876 + 1877 + [[package]] 1733 1878 name = "proc-macro-crate" 1734 1879 version = "1.3.0" 1735 1880 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1755 1900 ] 1756 1901 1757 1902 [[package]] 1903 + name = "prost" 1904 + version = "0.11.8" 1905 + source = "registry+https://github.com/rust-lang/crates.io-index" 1906 + checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" 1907 + dependencies = [ 1908 + "bytes", 1909 + "prost-derive", 1910 + ] 1911 + 1912 + [[package]] 1913 + name = "prost-build" 1914 + version = "0.11.8" 1915 + source = "registry+https://github.com/rust-lang/crates.io-index" 1916 + checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12" 1917 + dependencies = [ 1918 + "bytes", 1919 + "heck", 1920 + "itertools", 1921 + "lazy_static", 1922 + "log", 1923 + "multimap", 1924 + "petgraph", 1925 + "prettyplease", 1926 + "prost", 1927 + "prost-types", 1928 + "regex", 1929 + "syn", 1930 + "tempfile", 1931 + "which", 1932 + ] 1933 + 1934 + [[package]] 1935 + name = "prost-derive" 1936 + version = "0.11.8" 1937 + source = "registry+https://github.com/rust-lang/crates.io-index" 1938 + checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" 1939 + dependencies = [ 1940 + "anyhow", 1941 + "itertools", 1942 + "proc-macro2", 1943 + "quote", 1944 + "syn", 1945 + ] 1946 + 1947 + [[package]] 1948 + name = "prost-types" 1949 + version = "0.11.8" 1950 + source = "registry+https://github.com/rust-lang/crates.io-index" 1951 + checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" 1952 + dependencies = [ 1953 + "prost", 1954 + ] 1955 + 1956 + [[package]] 1758 1957 name = "quote" 1759 1958 version = "1.0.23" 1760 1959 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1974 2173 "sct", 1975 2174 "webpki", 1976 2175 ] 2176 + 2177 + [[package]] 2178 + name = "rustversion" 2179 + version = "1.0.11" 2180 + source = "registry+https://github.com/rust-lang/crates.io-index" 2181 + checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" 1977 2182 1978 2183 [[package]] 1979 2184 name = "ryu" ··· 2485 2690 ] 2486 2691 2487 2692 [[package]] 2693 + name = "sync_wrapper" 2694 + version = "0.1.2" 2695 + source = "registry+https://github.com/rust-lang/crates.io-index" 2696 + checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 2697 + 2698 + [[package]] 2488 2699 name = "tempfile" 2489 2700 version = "3.3.0" 2490 2701 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2605 2816 ] 2606 2817 2607 2818 [[package]] 2819 + name = "tokio-io-timeout" 2820 + version = "1.2.0" 2821 + source = "registry+https://github.com/rust-lang/crates.io-index" 2822 + checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" 2823 + dependencies = [ 2824 + "pin-project-lite", 2825 + "tokio", 2826 + ] 2827 + 2828 + [[package]] 2608 2829 name = "tokio-macros" 2609 2830 version = "1.8.2" 2610 2831 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2626 2847 ] 2627 2848 2628 2849 [[package]] 2850 + name = "tokio-stream" 2851 + version = "0.1.12" 2852 + source = "registry+https://github.com/rust-lang/crates.io-index" 2853 + checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" 2854 + dependencies = [ 2855 + "futures-core", 2856 + "pin-project-lite", 2857 + "tokio", 2858 + ] 2859 + 2860 + [[package]] 2629 2861 name = "tokio-util" 2630 2862 version = "0.7.7" 2631 2863 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2657 2889 ] 2658 2890 2659 2891 [[package]] 2892 + name = "tonic" 2893 + version = "0.8.3" 2894 + source = "registry+https://github.com/rust-lang/crates.io-index" 2895 + checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" 2896 + dependencies = [ 2897 + "async-stream", 2898 + "async-trait", 2899 + "axum", 2900 + "base64 0.13.1", 2901 + "bytes", 2902 + "futures-core", 2903 + "futures-util", 2904 + "h2", 2905 + "http", 2906 + "http-body", 2907 + "hyper", 2908 + "hyper-timeout", 2909 + "percent-encoding 2.2.0", 2910 + "pin-project", 2911 + "prost", 2912 + "prost-derive", 2913 + "tokio", 2914 + "tokio-stream", 2915 + "tokio-util", 2916 + "tower", 2917 + "tower-layer", 2918 + "tower-service", 2919 + "tracing", 2920 + "tracing-futures", 2921 + ] 2922 + 2923 + [[package]] 2924 + name = "tonic-build" 2925 + version = "0.8.4" 2926 + source = "registry+https://github.com/rust-lang/crates.io-index" 2927 + checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" 2928 + dependencies = [ 2929 + "prettyplease", 2930 + "proc-macro2", 2931 + "prost-build", 2932 + "quote", 2933 + "syn", 2934 + ] 2935 + 2936 + [[package]] 2937 + name = "tonic-web" 2938 + version = "0.4.0" 2939 + source = "registry+https://github.com/rust-lang/crates.io-index" 2940 + checksum = "e392f7556972523aa87ddb0fc7f2d2ce530559956706aa081bb0bd8fed158559" 2941 + dependencies = [ 2942 + "base64 0.13.1", 2943 + "bytes", 2944 + "futures-core", 2945 + "http", 2946 + "http-body", 2947 + "hyper", 2948 + "pin-project", 2949 + "tonic", 2950 + "tower-service", 2951 + "tracing", 2952 + ] 2953 + 2954 + [[package]] 2955 + name = "tower" 2956 + version = "0.4.13" 2957 + source = "registry+https://github.com/rust-lang/crates.io-index" 2958 + checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 2959 + dependencies = [ 2960 + "futures-core", 2961 + "futures-util", 2962 + "indexmap", 2963 + "pin-project", 2964 + "pin-project-lite", 2965 + "rand 0.8.5", 2966 + "slab", 2967 + "tokio", 2968 + "tokio-util", 2969 + "tower-layer", 2970 + "tower-service", 2971 + "tracing", 2972 + ] 2973 + 2974 + [[package]] 2975 + name = "tower-http" 2976 + version = "0.3.5" 2977 + source = "registry+https://github.com/rust-lang/crates.io-index" 2978 + checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" 2979 + dependencies = [ 2980 + "bitflags", 2981 + "bytes", 2982 + "futures-core", 2983 + "futures-util", 2984 + "http", 2985 + "http-body", 2986 + "http-range-header", 2987 + "pin-project-lite", 2988 + "tower", 2989 + "tower-layer", 2990 + "tower-service", 2991 + ] 2992 + 2993 + [[package]] 2994 + name = "tower-layer" 2995 + version = "0.3.2" 2996 + source = "registry+https://github.com/rust-lang/crates.io-index" 2997 + checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 2998 + 2999 + [[package]] 2660 3000 name = "tower-service" 2661 3001 version = "0.3.2" 2662 3002 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2669 3009 checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 2670 3010 dependencies = [ 2671 3011 "cfg-if", 3012 + "log", 2672 3013 "pin-project-lite", 3014 + "tracing-attributes", 2673 3015 "tracing-core", 2674 3016 ] 2675 3017 2676 3018 [[package]] 3019 + name = "tracing-attributes" 3020 + version = "0.1.23" 3021 + source = "registry+https://github.com/rust-lang/crates.io-index" 3022 + checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" 3023 + dependencies = [ 3024 + "proc-macro2", 3025 + "quote", 3026 + "syn", 3027 + ] 3028 + 3029 + [[package]] 2677 3030 name = "tracing-core" 2678 3031 version = "0.1.30" 2679 3032 source = "registry+https://github.com/rust-lang/crates.io-index" 2680 3033 checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" 2681 3034 dependencies = [ 2682 3035 "once_cell", 3036 + ] 3037 + 3038 + [[package]] 3039 + name = "tracing-futures" 3040 + version = "0.2.5" 3041 + source = "registry+https://github.com/rust-lang/crates.io-index" 3042 + checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" 3043 + dependencies = [ 3044 + "pin-project", 3045 + "tracing", 2683 3046 ] 2684 3047 2685 3048 [[package]] ··· 2716 3079 "minimp3", 2717 3080 "owo-colors", 2718 3081 "pls", 3082 + "prost", 2719 3083 "reqwest", 2720 3084 "rodio", 2721 3085 "surf", 2722 3086 "symphonia", 2723 3087 "tokio", 3088 + "tonic", 3089 + "tonic-build", 3090 + "tonic-web", 2724 3091 "tunein", 2725 3092 "url 2.3.1", 2726 3093 ] ··· 2963 3330 checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" 2964 3331 dependencies = [ 2965 3332 "cc", 3333 + ] 3334 + 3335 + [[package]] 3336 + name = "which" 3337 + version = "4.4.0" 3338 + source = "registry+https://github.com/rust-lang/crates.io-index" 3339 + checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" 3340 + dependencies = [ 3341 + "either", 3342 + "libc", 3343 + "once_cell", 2966 3344 ] 2967 3345 2968 3346 [[package]]
+7
Cargo.toml
··· 33 33 rodio = { version = "0.16" } 34 34 reqwest = { version = "0.11.14", features = ["blocking"] } 35 35 minimp3 = "0.5.1" 36 + tonic = "0.8.3" 37 + prost = "0.11.8" 38 + tonic-web = "0.4.0" 39 + 40 + 41 + [build-dependencies] 42 + tonic-build = "0.8"
+12
build.rs
··· 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 + )?; 11 + Ok(()) 12 + }
+7
proto/buf.lock
··· 1 + # Generated by buf. DO NOT EDIT. 2 + version: v1 3 + deps: 4 + - remote: buf.build 5 + owner: googleapis 6 + repository: googleapis 7 + commit: 75b4300737fb4efca0831636be94e517
+3
proto/buf.md
··· 1 + ## TuneinServerAPIs 2 + 3 + This module contains all of APIs required to interact with the `TuneIn CLI` Server.
+10
proto/buf.yaml
··· 1 + version: v1 2 + name: buf.build/tsiry/tuneinserverapis 3 + deps: 4 + - buf.build/googleapis/googleapis 5 + lint: 6 + use: 7 + - DEFAULT 8 + breaking: 9 + use: 10 + - FILE
+7
proto/objects/v1alpha1/category.proto
··· 1 + syntax = "proto3"; 2 + 3 + package objects.v1alpha1; 4 + 5 + message Category { 6 + 7 + }
+7
proto/objects/v1alpha1/station.proto
··· 1 + syntax = "proto3"; 2 + 3 + package objects.v1alpha1; 4 + 5 + message Station { 6 + 7 + }
+25
proto/tunein/v1alpha1/browse.proto
··· 1 + syntax = "proto3"; 2 + 3 + package tunein.v1alpha1; 4 + 5 + message GetCategoriesRequest {} 6 + 7 + message GetCategoriesResponse {} 8 + 9 + message BrowseCategoryRequest { 10 + string category_id = 1; 11 + } 12 + 13 + message BrowseCategoryResponse {} 14 + 15 + message GetStationDetailsRequest { 16 + string id = 1; 17 + } 18 + 19 + message GetStationDetailsResponse {} 20 + 21 + service BrowseService { 22 + rpc GetCategories(GetCategoriesRequest) returns (GetCategoriesResponse) {} 23 + rpc BrowseCategory(BrowseCategoryRequest) returns (BrowseCategoryResponse) {} 24 + rpc GetStationDetails(GetStationDetailsRequest) returns (GetStationDetailsResponse) {} 25 + }
+23
proto/tunein/v1alpha1/playback.proto
··· 1 + syntax = "proto3"; 2 + 3 + package tunein.v1alpha1; 4 + 5 + message PlayOrPauseRequest {} 6 + 7 + message PlayOrPauseResponse {} 8 + 9 + message StopRequest {} 10 + 11 + message StopResponse {} 12 + 13 + message PlayRequest { 14 + string station_name_or_id = 1; 15 + } 16 + 17 + message PlayResponse {} 18 + 19 + service PlaybackService { 20 + rpc Play(PlayRequest) returns (PlayResponse) {} 21 + rpc Stop(StopRequest) returns (StopResponse) {} 22 + rpc PlayOrPause(PlayOrPauseRequest) returns (PlayOrPauseResponse) {} 23 + }
+6
src/api/objects.v1alpha1.rs
··· 1 + #[allow(clippy::derive_partial_eq_without_eq)] 2 + #[derive(Clone, PartialEq, ::prost::Message)] 3 + pub struct Category {} 4 + #[allow(clippy::derive_partial_eq_without_eq)] 5 + #[derive(Clone, PartialEq, ::prost::Message)] 6 + pub struct Station {}
+771
src/api/tunein.v1alpha1.rs
··· 1 + #[allow(clippy::derive_partial_eq_without_eq)] 2 + #[derive(Clone, PartialEq, ::prost::Message)] 3 + pub struct GetCategoriesRequest {} 4 + #[allow(clippy::derive_partial_eq_without_eq)] 5 + #[derive(Clone, PartialEq, ::prost::Message)] 6 + pub struct GetCategoriesResponse {} 7 + #[allow(clippy::derive_partial_eq_without_eq)] 8 + #[derive(Clone, PartialEq, ::prost::Message)] 9 + pub struct BrowseCategoryRequest { 10 + #[prost(string, tag = "1")] 11 + pub category_id: ::prost::alloc::string::String, 12 + } 13 + #[allow(clippy::derive_partial_eq_without_eq)] 14 + #[derive(Clone, PartialEq, ::prost::Message)] 15 + pub struct BrowseCategoryResponse {} 16 + #[allow(clippy::derive_partial_eq_without_eq)] 17 + #[derive(Clone, PartialEq, ::prost::Message)] 18 + pub struct GetStationDetailsRequest { 19 + #[prost(string, tag = "1")] 20 + pub id: ::prost::alloc::string::String, 21 + } 22 + #[allow(clippy::derive_partial_eq_without_eq)] 23 + #[derive(Clone, PartialEq, ::prost::Message)] 24 + pub struct GetStationDetailsResponse {} 25 + /// Generated client implementations. 26 + pub mod browse_service_client { 27 + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] 28 + use tonic::codegen::*; 29 + use tonic::codegen::http::Uri; 30 + #[derive(Debug, Clone)] 31 + pub struct BrowseServiceClient<T> { 32 + inner: tonic::client::Grpc<T>, 33 + } 34 + impl BrowseServiceClient<tonic::transport::Channel> { 35 + /// Attempt to create a new client by connecting to a given endpoint. 36 + pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error> 37 + where 38 + D: std::convert::TryInto<tonic::transport::Endpoint>, 39 + D::Error: Into<StdError>, 40 + { 41 + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; 42 + Ok(Self::new(conn)) 43 + } 44 + } 45 + impl<T> BrowseServiceClient<T> 46 + where 47 + T: tonic::client::GrpcService<tonic::body::BoxBody>, 48 + T::Error: Into<StdError>, 49 + T::ResponseBody: Body<Data = Bytes> + Send + 'static, 50 + <T::ResponseBody as Body>::Error: Into<StdError> + Send, 51 + { 52 + pub fn new(inner: T) -> Self { 53 + let inner = tonic::client::Grpc::new(inner); 54 + Self { inner } 55 + } 56 + pub fn with_origin(inner: T, origin: Uri) -> Self { 57 + let inner = tonic::client::Grpc::with_origin(inner, origin); 58 + Self { inner } 59 + } 60 + pub fn with_interceptor<F>( 61 + inner: T, 62 + interceptor: F, 63 + ) -> BrowseServiceClient<InterceptedService<T, F>> 64 + where 65 + F: tonic::service::Interceptor, 66 + T::ResponseBody: Default, 67 + T: tonic::codegen::Service< 68 + http::Request<tonic::body::BoxBody>, 69 + Response = http::Response< 70 + <T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody, 71 + >, 72 + >, 73 + <T as tonic::codegen::Service< 74 + http::Request<tonic::body::BoxBody>, 75 + >>::Error: Into<StdError> + Send + Sync, 76 + { 77 + BrowseServiceClient::new(InterceptedService::new(inner, interceptor)) 78 + } 79 + /// Compress requests with the given encoding. 80 + /// 81 + /// This requires the server to support it otherwise it might respond with an 82 + /// error. 83 + #[must_use] 84 + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { 85 + self.inner = self.inner.send_compressed(encoding); 86 + self 87 + } 88 + /// Enable decompressing responses. 89 + #[must_use] 90 + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { 91 + self.inner = self.inner.accept_compressed(encoding); 92 + self 93 + } 94 + pub async fn get_categories( 95 + &mut self, 96 + request: impl tonic::IntoRequest<super::GetCategoriesRequest>, 97 + ) -> Result<tonic::Response<super::GetCategoriesResponse>, tonic::Status> { 98 + self.inner 99 + .ready() 100 + .await 101 + .map_err(|e| { 102 + tonic::Status::new( 103 + tonic::Code::Unknown, 104 + format!("Service was not ready: {}", e.into()), 105 + ) 106 + })?; 107 + let codec = tonic::codec::ProstCodec::default(); 108 + let path = http::uri::PathAndQuery::from_static( 109 + "/tunein.v1alpha1.BrowseService/GetCategories", 110 + ); 111 + self.inner.unary(request.into_request(), path, codec).await 112 + } 113 + pub async fn browse_category( 114 + &mut self, 115 + request: impl tonic::IntoRequest<super::BrowseCategoryRequest>, 116 + ) -> Result<tonic::Response<super::BrowseCategoryResponse>, tonic::Status> { 117 + self.inner 118 + .ready() 119 + .await 120 + .map_err(|e| { 121 + tonic::Status::new( 122 + tonic::Code::Unknown, 123 + format!("Service was not ready: {}", e.into()), 124 + ) 125 + })?; 126 + let codec = tonic::codec::ProstCodec::default(); 127 + let path = http::uri::PathAndQuery::from_static( 128 + "/tunein.v1alpha1.BrowseService/BrowseCategory", 129 + ); 130 + self.inner.unary(request.into_request(), path, codec).await 131 + } 132 + pub async fn get_station_details( 133 + &mut self, 134 + request: impl tonic::IntoRequest<super::GetStationDetailsRequest>, 135 + ) -> Result<tonic::Response<super::GetStationDetailsResponse>, tonic::Status> { 136 + self.inner 137 + .ready() 138 + .await 139 + .map_err(|e| { 140 + tonic::Status::new( 141 + tonic::Code::Unknown, 142 + format!("Service was not ready: {}", e.into()), 143 + ) 144 + })?; 145 + let codec = tonic::codec::ProstCodec::default(); 146 + let path = http::uri::PathAndQuery::from_static( 147 + "/tunein.v1alpha1.BrowseService/GetStationDetails", 148 + ); 149 + self.inner.unary(request.into_request(), path, codec).await 150 + } 151 + } 152 + } 153 + /// Generated server implementations. 154 + pub mod browse_service_server { 155 + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] 156 + use tonic::codegen::*; 157 + /// Generated trait containing gRPC methods that should be implemented for use with BrowseServiceServer. 158 + #[async_trait] 159 + pub trait BrowseService: Send + Sync + 'static { 160 + async fn get_categories( 161 + &self, 162 + request: tonic::Request<super::GetCategoriesRequest>, 163 + ) -> Result<tonic::Response<super::GetCategoriesResponse>, tonic::Status>; 164 + async fn browse_category( 165 + &self, 166 + request: tonic::Request<super::BrowseCategoryRequest>, 167 + ) -> Result<tonic::Response<super::BrowseCategoryResponse>, tonic::Status>; 168 + async fn get_station_details( 169 + &self, 170 + request: tonic::Request<super::GetStationDetailsRequest>, 171 + ) -> Result<tonic::Response<super::GetStationDetailsResponse>, tonic::Status>; 172 + } 173 + #[derive(Debug)] 174 + pub struct BrowseServiceServer<T: BrowseService> { 175 + inner: _Inner<T>, 176 + accept_compression_encodings: EnabledCompressionEncodings, 177 + send_compression_encodings: EnabledCompressionEncodings, 178 + } 179 + struct _Inner<T>(Arc<T>); 180 + impl<T: BrowseService> BrowseServiceServer<T> { 181 + pub fn new(inner: T) -> Self { 182 + Self::from_arc(Arc::new(inner)) 183 + } 184 + pub fn from_arc(inner: Arc<T>) -> Self { 185 + let inner = _Inner(inner); 186 + Self { 187 + inner, 188 + accept_compression_encodings: Default::default(), 189 + send_compression_encodings: Default::default(), 190 + } 191 + } 192 + pub fn with_interceptor<F>( 193 + inner: T, 194 + interceptor: F, 195 + ) -> InterceptedService<Self, F> 196 + where 197 + F: tonic::service::Interceptor, 198 + { 199 + InterceptedService::new(Self::new(inner), interceptor) 200 + } 201 + /// Enable decompressing requests with the given encoding. 202 + #[must_use] 203 + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { 204 + self.accept_compression_encodings.enable(encoding); 205 + self 206 + } 207 + /// Compress responses with the given encoding, if the client supports it. 208 + #[must_use] 209 + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { 210 + self.send_compression_encodings.enable(encoding); 211 + self 212 + } 213 + } 214 + impl<T, B> tonic::codegen::Service<http::Request<B>> for BrowseServiceServer<T> 215 + where 216 + T: BrowseService, 217 + B: Body + Send + 'static, 218 + B::Error: Into<StdError> + Send + 'static, 219 + { 220 + type Response = http::Response<tonic::body::BoxBody>; 221 + type Error = std::convert::Infallible; 222 + type Future = BoxFuture<Self::Response, Self::Error>; 223 + fn poll_ready( 224 + &mut self, 225 + _cx: &mut Context<'_>, 226 + ) -> Poll<Result<(), Self::Error>> { 227 + Poll::Ready(Ok(())) 228 + } 229 + fn call(&mut self, req: http::Request<B>) -> Self::Future { 230 + let inner = self.inner.clone(); 231 + match req.uri().path() { 232 + "/tunein.v1alpha1.BrowseService/GetCategories" => { 233 + #[allow(non_camel_case_types)] 234 + struct GetCategoriesSvc<T: BrowseService>(pub Arc<T>); 235 + impl< 236 + T: BrowseService, 237 + > tonic::server::UnaryService<super::GetCategoriesRequest> 238 + for GetCategoriesSvc<T> { 239 + type Response = super::GetCategoriesResponse; 240 + type Future = BoxFuture< 241 + tonic::Response<Self::Response>, 242 + tonic::Status, 243 + >; 244 + fn call( 245 + &mut self, 246 + request: tonic::Request<super::GetCategoriesRequest>, 247 + ) -> Self::Future { 248 + let inner = self.0.clone(); 249 + let fut = async move { 250 + (*inner).get_categories(request).await 251 + }; 252 + Box::pin(fut) 253 + } 254 + } 255 + let accept_compression_encodings = self.accept_compression_encodings; 256 + let send_compression_encodings = self.send_compression_encodings; 257 + let inner = self.inner.clone(); 258 + let fut = async move { 259 + let inner = inner.0; 260 + let method = GetCategoriesSvc(inner); 261 + let codec = tonic::codec::ProstCodec::default(); 262 + let mut grpc = tonic::server::Grpc::new(codec) 263 + .apply_compression_config( 264 + accept_compression_encodings, 265 + send_compression_encodings, 266 + ); 267 + let res = grpc.unary(method, req).await; 268 + Ok(res) 269 + }; 270 + Box::pin(fut) 271 + } 272 + "/tunein.v1alpha1.BrowseService/BrowseCategory" => { 273 + #[allow(non_camel_case_types)] 274 + struct BrowseCategorySvc<T: BrowseService>(pub Arc<T>); 275 + impl< 276 + T: BrowseService, 277 + > tonic::server::UnaryService<super::BrowseCategoryRequest> 278 + for BrowseCategorySvc<T> { 279 + type Response = super::BrowseCategoryResponse; 280 + type Future = BoxFuture< 281 + tonic::Response<Self::Response>, 282 + tonic::Status, 283 + >; 284 + fn call( 285 + &mut self, 286 + request: tonic::Request<super::BrowseCategoryRequest>, 287 + ) -> Self::Future { 288 + let inner = self.0.clone(); 289 + let fut = async move { 290 + (*inner).browse_category(request).await 291 + }; 292 + Box::pin(fut) 293 + } 294 + } 295 + let accept_compression_encodings = self.accept_compression_encodings; 296 + let send_compression_encodings = self.send_compression_encodings; 297 + let inner = self.inner.clone(); 298 + let fut = async move { 299 + let inner = inner.0; 300 + let method = BrowseCategorySvc(inner); 301 + let codec = tonic::codec::ProstCodec::default(); 302 + let mut grpc = tonic::server::Grpc::new(codec) 303 + .apply_compression_config( 304 + accept_compression_encodings, 305 + send_compression_encodings, 306 + ); 307 + let res = grpc.unary(method, req).await; 308 + Ok(res) 309 + }; 310 + Box::pin(fut) 311 + } 312 + "/tunein.v1alpha1.BrowseService/GetStationDetails" => { 313 + #[allow(non_camel_case_types)] 314 + struct GetStationDetailsSvc<T: BrowseService>(pub Arc<T>); 315 + impl< 316 + T: BrowseService, 317 + > tonic::server::UnaryService<super::GetStationDetailsRequest> 318 + for GetStationDetailsSvc<T> { 319 + type Response = super::GetStationDetailsResponse; 320 + type Future = BoxFuture< 321 + tonic::Response<Self::Response>, 322 + tonic::Status, 323 + >; 324 + fn call( 325 + &mut self, 326 + request: tonic::Request<super::GetStationDetailsRequest>, 327 + ) -> Self::Future { 328 + let inner = self.0.clone(); 329 + let fut = async move { 330 + (*inner).get_station_details(request).await 331 + }; 332 + Box::pin(fut) 333 + } 334 + } 335 + let accept_compression_encodings = self.accept_compression_encodings; 336 + let send_compression_encodings = self.send_compression_encodings; 337 + let inner = self.inner.clone(); 338 + let fut = async move { 339 + let inner = inner.0; 340 + let method = GetStationDetailsSvc(inner); 341 + let codec = tonic::codec::ProstCodec::default(); 342 + let mut grpc = tonic::server::Grpc::new(codec) 343 + .apply_compression_config( 344 + accept_compression_encodings, 345 + send_compression_encodings, 346 + ); 347 + let res = grpc.unary(method, req).await; 348 + Ok(res) 349 + }; 350 + Box::pin(fut) 351 + } 352 + _ => { 353 + Box::pin(async move { 354 + Ok( 355 + http::Response::builder() 356 + .status(200) 357 + .header("grpc-status", "12") 358 + .header("content-type", "application/grpc") 359 + .body(empty_body()) 360 + .unwrap(), 361 + ) 362 + }) 363 + } 364 + } 365 + } 366 + } 367 + impl<T: BrowseService> Clone for BrowseServiceServer<T> { 368 + fn clone(&self) -> Self { 369 + let inner = self.inner.clone(); 370 + Self { 371 + inner, 372 + accept_compression_encodings: self.accept_compression_encodings, 373 + send_compression_encodings: self.send_compression_encodings, 374 + } 375 + } 376 + } 377 + impl<T: BrowseService> Clone for _Inner<T> { 378 + fn clone(&self) -> Self { 379 + Self(self.0.clone()) 380 + } 381 + } 382 + impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> { 383 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 384 + write!(f, "{:?}", self.0) 385 + } 386 + } 387 + impl<T: BrowseService> tonic::server::NamedService for BrowseServiceServer<T> { 388 + const NAME: &'static str = "tunein.v1alpha1.BrowseService"; 389 + } 390 + } 391 + #[allow(clippy::derive_partial_eq_without_eq)] 392 + #[derive(Clone, PartialEq, ::prost::Message)] 393 + pub struct PlayOrPauseRequest {} 394 + #[allow(clippy::derive_partial_eq_without_eq)] 395 + #[derive(Clone, PartialEq, ::prost::Message)] 396 + pub struct PlayOrPauseResponse {} 397 + #[allow(clippy::derive_partial_eq_without_eq)] 398 + #[derive(Clone, PartialEq, ::prost::Message)] 399 + pub struct StopRequest {} 400 + #[allow(clippy::derive_partial_eq_without_eq)] 401 + #[derive(Clone, PartialEq, ::prost::Message)] 402 + pub struct StopResponse {} 403 + #[allow(clippy::derive_partial_eq_without_eq)] 404 + #[derive(Clone, PartialEq, ::prost::Message)] 405 + pub struct PlayRequest { 406 + #[prost(string, tag = "1")] 407 + pub station_name_or_id: ::prost::alloc::string::String, 408 + } 409 + #[allow(clippy::derive_partial_eq_without_eq)] 410 + #[derive(Clone, PartialEq, ::prost::Message)] 411 + pub struct PlayResponse {} 412 + /// Generated client implementations. 413 + pub mod playback_service_client { 414 + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] 415 + use tonic::codegen::*; 416 + use tonic::codegen::http::Uri; 417 + #[derive(Debug, Clone)] 418 + pub struct PlaybackServiceClient<T> { 419 + inner: tonic::client::Grpc<T>, 420 + } 421 + impl PlaybackServiceClient<tonic::transport::Channel> { 422 + /// Attempt to create a new client by connecting to a given endpoint. 423 + pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error> 424 + where 425 + D: std::convert::TryInto<tonic::transport::Endpoint>, 426 + D::Error: Into<StdError>, 427 + { 428 + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; 429 + Ok(Self::new(conn)) 430 + } 431 + } 432 + impl<T> PlaybackServiceClient<T> 433 + where 434 + T: tonic::client::GrpcService<tonic::body::BoxBody>, 435 + T::Error: Into<StdError>, 436 + T::ResponseBody: Body<Data = Bytes> + Send + 'static, 437 + <T::ResponseBody as Body>::Error: Into<StdError> + Send, 438 + { 439 + pub fn new(inner: T) -> Self { 440 + let inner = tonic::client::Grpc::new(inner); 441 + Self { inner } 442 + } 443 + pub fn with_origin(inner: T, origin: Uri) -> Self { 444 + let inner = tonic::client::Grpc::with_origin(inner, origin); 445 + Self { inner } 446 + } 447 + pub fn with_interceptor<F>( 448 + inner: T, 449 + interceptor: F, 450 + ) -> PlaybackServiceClient<InterceptedService<T, F>> 451 + where 452 + F: tonic::service::Interceptor, 453 + T::ResponseBody: Default, 454 + T: tonic::codegen::Service< 455 + http::Request<tonic::body::BoxBody>, 456 + Response = http::Response< 457 + <T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody, 458 + >, 459 + >, 460 + <T as tonic::codegen::Service< 461 + http::Request<tonic::body::BoxBody>, 462 + >>::Error: Into<StdError> + Send + Sync, 463 + { 464 + PlaybackServiceClient::new(InterceptedService::new(inner, interceptor)) 465 + } 466 + /// Compress requests with the given encoding. 467 + /// 468 + /// This requires the server to support it otherwise it might respond with an 469 + /// error. 470 + #[must_use] 471 + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { 472 + self.inner = self.inner.send_compressed(encoding); 473 + self 474 + } 475 + /// Enable decompressing responses. 476 + #[must_use] 477 + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { 478 + self.inner = self.inner.accept_compressed(encoding); 479 + self 480 + } 481 + pub async fn play( 482 + &mut self, 483 + request: impl tonic::IntoRequest<super::PlayRequest>, 484 + ) -> Result<tonic::Response<super::PlayResponse>, tonic::Status> { 485 + self.inner 486 + .ready() 487 + .await 488 + .map_err(|e| { 489 + tonic::Status::new( 490 + tonic::Code::Unknown, 491 + format!("Service was not ready: {}", e.into()), 492 + ) 493 + })?; 494 + let codec = tonic::codec::ProstCodec::default(); 495 + let path = http::uri::PathAndQuery::from_static( 496 + "/tunein.v1alpha1.PlaybackService/Play", 497 + ); 498 + self.inner.unary(request.into_request(), path, codec).await 499 + } 500 + pub async fn stop( 501 + &mut self, 502 + request: impl tonic::IntoRequest<super::StopRequest>, 503 + ) -> Result<tonic::Response<super::StopResponse>, tonic::Status> { 504 + self.inner 505 + .ready() 506 + .await 507 + .map_err(|e| { 508 + tonic::Status::new( 509 + tonic::Code::Unknown, 510 + format!("Service was not ready: {}", e.into()), 511 + ) 512 + })?; 513 + let codec = tonic::codec::ProstCodec::default(); 514 + let path = http::uri::PathAndQuery::from_static( 515 + "/tunein.v1alpha1.PlaybackService/Stop", 516 + ); 517 + self.inner.unary(request.into_request(), path, codec).await 518 + } 519 + pub async fn play_or_pause( 520 + &mut self, 521 + request: impl tonic::IntoRequest<super::PlayOrPauseRequest>, 522 + ) -> Result<tonic::Response<super::PlayOrPauseResponse>, tonic::Status> { 523 + self.inner 524 + .ready() 525 + .await 526 + .map_err(|e| { 527 + tonic::Status::new( 528 + tonic::Code::Unknown, 529 + format!("Service was not ready: {}", e.into()), 530 + ) 531 + })?; 532 + let codec = tonic::codec::ProstCodec::default(); 533 + let path = http::uri::PathAndQuery::from_static( 534 + "/tunein.v1alpha1.PlaybackService/PlayOrPause", 535 + ); 536 + self.inner.unary(request.into_request(), path, codec).await 537 + } 538 + } 539 + } 540 + /// Generated server implementations. 541 + pub mod playback_service_server { 542 + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] 543 + use tonic::codegen::*; 544 + /// Generated trait containing gRPC methods that should be implemented for use with PlaybackServiceServer. 545 + #[async_trait] 546 + pub trait PlaybackService: Send + Sync + 'static { 547 + async fn play( 548 + &self, 549 + request: tonic::Request<super::PlayRequest>, 550 + ) -> Result<tonic::Response<super::PlayResponse>, tonic::Status>; 551 + async fn stop( 552 + &self, 553 + request: tonic::Request<super::StopRequest>, 554 + ) -> Result<tonic::Response<super::StopResponse>, tonic::Status>; 555 + async fn play_or_pause( 556 + &self, 557 + request: tonic::Request<super::PlayOrPauseRequest>, 558 + ) -> Result<tonic::Response<super::PlayOrPauseResponse>, tonic::Status>; 559 + } 560 + #[derive(Debug)] 561 + pub struct PlaybackServiceServer<T: PlaybackService> { 562 + inner: _Inner<T>, 563 + accept_compression_encodings: EnabledCompressionEncodings, 564 + send_compression_encodings: EnabledCompressionEncodings, 565 + } 566 + struct _Inner<T>(Arc<T>); 567 + impl<T: PlaybackService> PlaybackServiceServer<T> { 568 + pub fn new(inner: T) -> Self { 569 + Self::from_arc(Arc::new(inner)) 570 + } 571 + pub fn from_arc(inner: Arc<T>) -> Self { 572 + let inner = _Inner(inner); 573 + Self { 574 + inner, 575 + accept_compression_encodings: Default::default(), 576 + send_compression_encodings: Default::default(), 577 + } 578 + } 579 + pub fn with_interceptor<F>( 580 + inner: T, 581 + interceptor: F, 582 + ) -> InterceptedService<Self, F> 583 + where 584 + F: tonic::service::Interceptor, 585 + { 586 + InterceptedService::new(Self::new(inner), interceptor) 587 + } 588 + /// Enable decompressing requests with the given encoding. 589 + #[must_use] 590 + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { 591 + self.accept_compression_encodings.enable(encoding); 592 + self 593 + } 594 + /// Compress responses with the given encoding, if the client supports it. 595 + #[must_use] 596 + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { 597 + self.send_compression_encodings.enable(encoding); 598 + self 599 + } 600 + } 601 + impl<T, B> tonic::codegen::Service<http::Request<B>> for PlaybackServiceServer<T> 602 + where 603 + T: PlaybackService, 604 + B: Body + Send + 'static, 605 + B::Error: Into<StdError> + Send + 'static, 606 + { 607 + type Response = http::Response<tonic::body::BoxBody>; 608 + type Error = std::convert::Infallible; 609 + type Future = BoxFuture<Self::Response, Self::Error>; 610 + fn poll_ready( 611 + &mut self, 612 + _cx: &mut Context<'_>, 613 + ) -> Poll<Result<(), Self::Error>> { 614 + Poll::Ready(Ok(())) 615 + } 616 + fn call(&mut self, req: http::Request<B>) -> Self::Future { 617 + let inner = self.inner.clone(); 618 + match req.uri().path() { 619 + "/tunein.v1alpha1.PlaybackService/Play" => { 620 + #[allow(non_camel_case_types)] 621 + struct PlaySvc<T: PlaybackService>(pub Arc<T>); 622 + impl< 623 + T: PlaybackService, 624 + > tonic::server::UnaryService<super::PlayRequest> for PlaySvc<T> { 625 + type Response = super::PlayResponse; 626 + type Future = BoxFuture< 627 + tonic::Response<Self::Response>, 628 + tonic::Status, 629 + >; 630 + fn call( 631 + &mut self, 632 + request: tonic::Request<super::PlayRequest>, 633 + ) -> Self::Future { 634 + let inner = self.0.clone(); 635 + let fut = async move { (*inner).play(request).await }; 636 + Box::pin(fut) 637 + } 638 + } 639 + let accept_compression_encodings = self.accept_compression_encodings; 640 + let send_compression_encodings = self.send_compression_encodings; 641 + let inner = self.inner.clone(); 642 + let fut = async move { 643 + let inner = inner.0; 644 + let method = PlaySvc(inner); 645 + let codec = tonic::codec::ProstCodec::default(); 646 + let mut grpc = tonic::server::Grpc::new(codec) 647 + .apply_compression_config( 648 + accept_compression_encodings, 649 + send_compression_encodings, 650 + ); 651 + let res = grpc.unary(method, req).await; 652 + Ok(res) 653 + }; 654 + Box::pin(fut) 655 + } 656 + "/tunein.v1alpha1.PlaybackService/Stop" => { 657 + #[allow(non_camel_case_types)] 658 + struct StopSvc<T: PlaybackService>(pub Arc<T>); 659 + impl< 660 + T: PlaybackService, 661 + > tonic::server::UnaryService<super::StopRequest> for StopSvc<T> { 662 + type Response = super::StopResponse; 663 + type Future = BoxFuture< 664 + tonic::Response<Self::Response>, 665 + tonic::Status, 666 + >; 667 + fn call( 668 + &mut self, 669 + request: tonic::Request<super::StopRequest>, 670 + ) -> Self::Future { 671 + let inner = self.0.clone(); 672 + let fut = async move { (*inner).stop(request).await }; 673 + Box::pin(fut) 674 + } 675 + } 676 + let accept_compression_encodings = self.accept_compression_encodings; 677 + let send_compression_encodings = self.send_compression_encodings; 678 + let inner = self.inner.clone(); 679 + let fut = async move { 680 + let inner = inner.0; 681 + let method = StopSvc(inner); 682 + let codec = tonic::codec::ProstCodec::default(); 683 + let mut grpc = tonic::server::Grpc::new(codec) 684 + .apply_compression_config( 685 + accept_compression_encodings, 686 + send_compression_encodings, 687 + ); 688 + let res = grpc.unary(method, req).await; 689 + Ok(res) 690 + }; 691 + Box::pin(fut) 692 + } 693 + "/tunein.v1alpha1.PlaybackService/PlayOrPause" => { 694 + #[allow(non_camel_case_types)] 695 + struct PlayOrPauseSvc<T: PlaybackService>(pub Arc<T>); 696 + impl< 697 + T: PlaybackService, 698 + > tonic::server::UnaryService<super::PlayOrPauseRequest> 699 + for PlayOrPauseSvc<T> { 700 + type Response = super::PlayOrPauseResponse; 701 + type Future = BoxFuture< 702 + tonic::Response<Self::Response>, 703 + tonic::Status, 704 + >; 705 + fn call( 706 + &mut self, 707 + request: tonic::Request<super::PlayOrPauseRequest>, 708 + ) -> Self::Future { 709 + let inner = self.0.clone(); 710 + let fut = async move { 711 + (*inner).play_or_pause(request).await 712 + }; 713 + Box::pin(fut) 714 + } 715 + } 716 + let accept_compression_encodings = self.accept_compression_encodings; 717 + let send_compression_encodings = self.send_compression_encodings; 718 + let inner = self.inner.clone(); 719 + let fut = async move { 720 + let inner = inner.0; 721 + let method = PlayOrPauseSvc(inner); 722 + let codec = tonic::codec::ProstCodec::default(); 723 + let mut grpc = tonic::server::Grpc::new(codec) 724 + .apply_compression_config( 725 + accept_compression_encodings, 726 + send_compression_encodings, 727 + ); 728 + let res = grpc.unary(method, req).await; 729 + Ok(res) 730 + }; 731 + Box::pin(fut) 732 + } 733 + _ => { 734 + Box::pin(async move { 735 + Ok( 736 + http::Response::builder() 737 + .status(200) 738 + .header("grpc-status", "12") 739 + .header("content-type", "application/grpc") 740 + .body(empty_body()) 741 + .unwrap(), 742 + ) 743 + }) 744 + } 745 + } 746 + } 747 + } 748 + impl<T: PlaybackService> Clone for PlaybackServiceServer<T> { 749 + fn clone(&self) -> Self { 750 + let inner = self.inner.clone(); 751 + Self { 752 + inner, 753 + accept_compression_encodings: self.accept_compression_encodings, 754 + send_compression_encodings: self.send_compression_encodings, 755 + } 756 + } 757 + } 758 + impl<T: PlaybackService> Clone for _Inner<T> { 759 + fn clone(&self) -> Self { 760 + Self(self.0.clone()) 761 + } 762 + } 763 + impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> { 764 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 765 + write!(f, "{:?}", self.0) 766 + } 767 + } 768 + impl<T: PlaybackService> tonic::server::NamedService for PlaybackServiceServer<T> { 769 + const NAME: &'static str = "tunein.v1alpha1.PlaybackService"; 770 + } 771 + }
+13
src/lib.rs
··· 1 + pub mod api { 2 + #[path = ""] 3 + pub mod tunein { 4 + #[path = "tunein.v1alpha1.rs"] 5 + pub mod v1alpha1; 6 + } 7 + 8 + #[path = ""] 9 + pub mod objects { 10 + #[path = "objects.v1alpha1.rs"] 11 + pub mod v1alpha1; 12 + } 13 + }
+11
src/main.rs
··· 5 5 mod decoder; 6 6 mod play; 7 7 mod search; 8 + mod server; 8 9 9 10 fn cli() -> Command<'static> { 10 11 const VESRION: &str = env!("CARGO_PKG_VERSION"); ··· 36 37 .about("Browse radio stations") 37 38 .arg(arg!([category] "The category (category name or id) to browse")), 38 39 ) 40 + .subcommand( 41 + Command::new("server") 42 + .about("Start the server") 43 + .arg(arg!([port] "The port to listen on").default_value("8090")), 44 + ) 39 45 } 40 46 41 47 #[tokio::main] ··· 54 60 Some(("browse", args)) => { 55 61 let category = args.value_of("category"); 56 62 browse::exec(category).await?; 63 + } 64 + Some(("server", args)) => { 65 + let port = args.value_of("port").unwrap(); 66 + let port = port.parse::<u16>().unwrap(); 67 + server::exec(port).await?; 57 68 } 58 69 _ => unreachable!(), 59 70 }
+33
src/server/browse.rs
··· 1 + use tunein_cli::api::tunein::v1alpha1::{ 2 + browse_service_server::BrowseService, BrowseCategoryRequest, BrowseCategoryResponse, 3 + GetCategoriesRequest, GetCategoriesResponse, GetStationDetailsRequest, 4 + GetStationDetailsResponse, 5 + }; 6 + 7 + #[derive(Debug, Default)] 8 + pub struct Browse {} 9 + 10 + 11 + #[tonic::async_trait] 12 + impl BrowseService for Browse { 13 + async fn get_categories( 14 + &self, 15 + request: tonic::Request<GetCategoriesRequest>, 16 + ) -> Result<tonic::Response<GetCategoriesResponse>, tonic::Status> { 17 + todo!() 18 + } 19 + 20 + async fn browse_category( 21 + &self, 22 + request: tonic::Request<BrowseCategoryRequest>, 23 + ) -> Result<tonic::Response<BrowseCategoryResponse>, tonic::Status> { 24 + todo!() 25 + } 26 + 27 + async fn get_station_details( 28 + &self, 29 + request: tonic::Request<GetStationDetailsRequest>, 30 + ) -> Result<tonic::Response<GetStationDetailsResponse>, tonic::Status> { 31 + todo!() 32 + } 33 + }
+29
src/server/mod.rs
··· 1 + use std::net::SocketAddr; 2 + 3 + use anyhow::Error; 4 + use owo_colors::OwoColorize; 5 + use tonic::transport::Server; 6 + use tunein_cli::api::tunein::v1alpha1::{ 7 + browse_service_server::BrowseServiceServer, playback_service_server::PlaybackServiceServer, 8 + }; 9 + 10 + use self::{browse::Browse, playback::Playback}; 11 + 12 + pub mod browse; 13 + pub mod playback; 14 + 15 + pub async fn exec(port: u16) -> Result<(), Error> { 16 + let addr: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap(); 17 + println!("Listening on {}", addr.cyan()); 18 + Server::builder() 19 + .accept_http1(true) 20 + .add_service(tonic_web::enable(BrowseServiceServer::new( 21 + Browse::default(), 22 + ))) 23 + .add_service(tonic_web::enable(PlaybackServiceServer::new( 24 + Playback::default(), 25 + ))) 26 + .serve(addr) 27 + .await?; 28 + Ok(()) 29 + }
+31
src/server/playback.rs
··· 1 + use tunein_cli::api::tunein::v1alpha1::{ 2 + playback_service_server::PlaybackService, PlayOrPauseRequest, PlayOrPauseResponse, PlayRequest, 3 + PlayResponse, StopRequest, StopResponse, 4 + }; 5 + 6 + #[derive(Debug, Default)] 7 + pub struct Playback {} 8 + 9 + #[tonic::async_trait] 10 + impl PlaybackService for Playback { 11 + async fn play( 12 + &self, 13 + request: tonic::Request<PlayRequest>, 14 + ) -> Result<tonic::Response<PlayResponse>, tonic::Status> { 15 + todo!() 16 + } 17 + 18 + async fn stop( 19 + &self, 20 + request: tonic::Request<StopRequest>, 21 + ) -> Result<tonic::Response<StopResponse>, tonic::Status> { 22 + todo!() 23 + } 24 + 25 + async fn play_or_pause( 26 + &self, 27 + request: tonic::Request<PlayOrPauseRequest>, 28 + ) -> Result<tonic::Response<PlayOrPauseResponse>, tonic::Status> { 29 + todo!() 30 + } 31 + }