From 794aa513ee8b66f2889514dc4b2c7dc2692c0c23 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 26 Apr 2022 22:26:46 +0200 Subject: [PATCH] added blocking interface --- Cargo.toml | 9 +- src/api.rs | 20 ++-- src/bin/test.rs | 16 +++ src/blocking/api.rs | 50 +++++++++ src/blocking/countrysearchbuilder.rs | 54 +++++++++ src/blocking/languagesearchbuilder.rs | 54 +++++++++ src/blocking/mod.rs | 10 ++ src/blocking/stationsearchbuilder.rs | 154 ++++++++++++++++++++++++++ src/blocking/tagsearchbuilder.rs | 54 +++++++++ src/lib.rs | 26 ++++- 10 files changed, 430 insertions(+), 17 deletions(-) create mode 100644 src/blocking/api.rs create mode 100644 src/blocking/countrysearchbuilder.rs create mode 100644 src/blocking/languagesearchbuilder.rs create mode 100644 src/blocking/mod.rs create mode 100644 src/blocking/stationsearchbuilder.rs create mode 100644 src/blocking/tagsearchbuilder.rs diff --git a/Cargo.toml b/Cargo.toml index c70e1cd..7b13dde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "radiobrowser" -version = "0.1.0" +version = "0.2.0" authors = ["segler_alex "] edition = "2021" license = "MIT" @@ -15,11 +15,16 @@ repository = "https://gitlab.com/radiobrowser/radiobrowser-lib-rust" async-std = { version = "1.11.0", features = ["attributes", "tokio1"] } async-std-resolver = "0.21.2" chrono = { version = "0.4.19", features = ["serde"] } -futures = { version = "0.3.21" } +futures = { version = "0.3.21" } +log = { version = "0.4.16" } rand = { version = "0.8.5" } reqwest = { version = "0.11.10", features = ["json"] } serde = { version = "1.0.136", features = ["derive"] } +[features] +default = ["blocking"] +blocking = [] + [badges] # The `maintenance` table indicates the status of the maintenance of # the crate. This may be used by a registry, but is currently not diff --git a/src/api.rs b/src/api.rs index cef665c..5660a56 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,6 +1,5 @@ use crate::external::post_api; use crate::ApiConfig; -use crate::ApiCountry; use crate::CountrySearchBuilder; use crate::LanguageSearchBuilder; use crate::StationSearchBuilder; @@ -13,6 +12,8 @@ use std::error::Error; use rand::seq::SliceRandom; use rand::thread_rng; +use log::trace; + use async_std_resolver::proto::rr::RecordType; use async_std_resolver::proto::xfer::DnsRequestOptions; use async_std_resolver::{config, resolver}; @@ -31,7 +32,8 @@ impl RadioBrowserAPI { }) } - pub fn get_current_server(&mut self) -> String { + fn get_current_server(&mut self) -> String { + trace!("get_current_server()"); if self.servers.len() > 0 { self.current = self.current % self.servers.len(); format!("https://{}", self.servers[self.current]) @@ -40,7 +42,7 @@ impl RadioBrowserAPI { } } - pub async fn post_api>( + async fn post_api>( &mut self, endpoint: A, ) -> Result> { @@ -76,16 +78,8 @@ impl RadioBrowserAPI { post_api(self.get_current_server(), endpoint, mapjson).await } - pub async fn get_countries_filtered>( - &mut self, - filter: P, - ) -> Result, Box> { - Ok(self - .post_api(format!("/json/countries/{}", filter.as_ref())) - .await?) - } - pub async fn get_servers() -> Result, Box> { + trace!("get_servers()"); let resolver = resolver( config::ResolverConfig::default(), config::ResolverOpts::default(), @@ -105,7 +99,7 @@ impl RadioBrowserAPI { .collect(); list.shuffle(&mut thread_rng()); - println!("Servers: {:?}", list); + trace!("Servers: {:?}", list); Ok(list) } } diff --git a/src/bin/test.rs b/src/bin/test.rs index b35165b..2cb3807 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -1,3 +1,4 @@ +/* use futures::join; use radiobrowser::RadioBrowserAPI; use radiobrowser::StationOrder; @@ -27,3 +28,18 @@ async fn main() -> Result<(), Box> { println!("Stations found: {}", stations?.len()); Ok(()) } +*/ + +use radiobrowser::blocking::RadioBrowserAPI; +use std::error::Error; + +fn main() -> Result<(), Box> { + let api = RadioBrowserAPI::new()?; + let servers = RadioBrowserAPI::get_servers()?; + println!("Servers: {:?}", servers); + let countries = api.get_countries().send()?; + println!("Countries: {:?}", countries); + let stations = api.get_stations().name("jazz").send()?; + println!("Stations: {:?}", stations); + Ok(()) +} \ No newline at end of file diff --git a/src/blocking/api.rs b/src/blocking/api.rs new file mode 100644 index 0000000..4f5355d --- /dev/null +++ b/src/blocking/api.rs @@ -0,0 +1,50 @@ +use crate::blocking::stationsearchbuilder::StationSearchBuilder; +use crate::blocking::CountrySearchBuilder; +use crate::blocking::LanguageSearchBuilder; +use crate::blocking::TagSearchBuilder; + +use serde::de::DeserializeOwned; +use std::collections::HashMap; +use std::error::Error; + +#[derive(Clone, Debug)] +pub struct RadioBrowserAPI { + api: crate::RadioBrowserAPI, +} + +use async_std::task; + +impl RadioBrowserAPI { + pub fn new() -> Result> { + task::block_on(async { crate::RadioBrowserAPI::new().await }) + .map(|api| RadioBrowserAPI { api }) + } + + pub fn get_stations(&self) -> StationSearchBuilder { + StationSearchBuilder::new(self.api.get_stations()) + } + + pub fn get_countries(&self) -> CountrySearchBuilder { + CountrySearchBuilder::new(self.api.get_countries()) + } + + pub fn get_languages(&self) -> LanguageSearchBuilder { + LanguageSearchBuilder::new(self.api.get_languages()) + } + + pub fn get_tags(&self) -> TagSearchBuilder { + TagSearchBuilder::new(self.api.get_tags()) + } + + pub fn send, Q: DeserializeOwned>( + &mut self, + endpoint: P, + mapjson: HashMap, + ) -> Result> { + task::block_on(async { self.api.send(endpoint, mapjson).await }) + } + + pub fn get_servers() -> Result, Box> { + task::block_on(async { crate::RadioBrowserAPI::get_servers().await }) + } +} diff --git a/src/blocking/countrysearchbuilder.rs b/src/blocking/countrysearchbuilder.rs new file mode 100644 index 0000000..22366b0 --- /dev/null +++ b/src/blocking/countrysearchbuilder.rs @@ -0,0 +1,54 @@ +use crate::ApiCountry; +use async_std::task; +use std::error::Error; + +#[derive(Clone, Debug)] +pub struct CountrySearchBuilder { + builder: crate::CountrySearchBuilder, +} + +impl CountrySearchBuilder { + pub fn new(builder: crate::CountrySearchBuilder) -> Self { + CountrySearchBuilder { builder } + } + + pub fn filter>(self, filter: P) -> Self { + CountrySearchBuilder { + builder: self.builder.filter(filter.as_ref().to_string()), + } + } + + pub fn order(self, order: crate::CountryOrder) -> Self { + CountrySearchBuilder { + builder: self.builder.order(order), + } + } + + pub fn reverse(self, reverse: bool) -> Self { + CountrySearchBuilder { + builder: self.builder.reverse(reverse), + } + } + + pub fn offset>(self, offset: P) -> Self { + CountrySearchBuilder { + builder: self.builder.offset(offset), + } + } + + pub fn limit>(self, limit: P) -> Self { + CountrySearchBuilder { + builder: self.builder.limit(limit), + } + } + + pub fn hidebroken(self, hidebroken: bool) -> Self { + CountrySearchBuilder { + builder: self.builder.hidebroken(hidebroken), + } + } + + pub fn send(self) -> Result, Box> { + task::block_on(async { self.builder.send().await }) + } +} diff --git a/src/blocking/languagesearchbuilder.rs b/src/blocking/languagesearchbuilder.rs new file mode 100644 index 0000000..2ac25eb --- /dev/null +++ b/src/blocking/languagesearchbuilder.rs @@ -0,0 +1,54 @@ +use crate::ApiLanguage; +use async_std::task; +use std::error::Error; + +#[derive(Clone, Debug)] +pub struct LanguageSearchBuilder { + builder: crate::LanguageSearchBuilder, +} + +impl LanguageSearchBuilder { + pub fn new(builder: crate::LanguageSearchBuilder) -> Self { + LanguageSearchBuilder { builder } + } + + pub fn filter>(self, filter: P) -> Self { + LanguageSearchBuilder { + builder: self.builder.filter(filter.as_ref().to_string()), + } + } + + pub fn order(self, order: crate::LanguageOrder) -> Self { + LanguageSearchBuilder { + builder: self.builder.order(order), + } + } + + pub fn reverse(self, reverse: bool) -> Self { + LanguageSearchBuilder { + builder: self.builder.reverse(reverse), + } + } + + pub fn offset>(self, offset: P) -> Self { + LanguageSearchBuilder { + builder: self.builder.offset(offset), + } + } + + pub fn limit>(self, limit: P) -> Self { + LanguageSearchBuilder { + builder: self.builder.limit(limit), + } + } + + pub fn hidebroken(self, hidebroken: bool) -> Self { + LanguageSearchBuilder { + builder: self.builder.hidebroken(hidebroken), + } + } + + pub fn send(self) -> Result, Box> { + task::block_on(async { self.builder.send().await }) + } +} diff --git a/src/blocking/mod.rs b/src/blocking/mod.rs new file mode 100644 index 0000000..acea445 --- /dev/null +++ b/src/blocking/mod.rs @@ -0,0 +1,10 @@ +pub mod api; +pub mod countrysearchbuilder; +pub mod languagesearchbuilder; +pub mod stationsearchbuilder; +pub mod tagsearchbuilder; + +pub use api::RadioBrowserAPI; +pub use countrysearchbuilder::CountrySearchBuilder; +pub use languagesearchbuilder::LanguageSearchBuilder; +pub use tagsearchbuilder::TagSearchBuilder; diff --git a/src/blocking/stationsearchbuilder.rs b/src/blocking/stationsearchbuilder.rs new file mode 100644 index 0000000..75a137f --- /dev/null +++ b/src/blocking/stationsearchbuilder.rs @@ -0,0 +1,154 @@ +use crate::structs::ApiStation; +use crate::StationOrder; +use async_std::task; +use std::error::Error; + +#[derive(Clone, Debug)] +pub struct StationSearchBuilder { + builder: crate::StationSearchBuilder, +} + +impl StationSearchBuilder { + pub fn new(builder: crate::StationSearchBuilder) -> Self { + StationSearchBuilder { builder } + } + + pub fn name>(self, name: P) -> Self { + StationSearchBuilder { + builder: self.builder.name(name), + } + } + + pub fn name_exact(self, name_exact: bool) -> Self { + StationSearchBuilder { + builder: self.builder.name_exact(name_exact), + } + } + + pub fn country>(self, country: P) -> Self { + StationSearchBuilder { + builder: self.builder.country(country), + } + } + + pub fn country_exact(self, country_exact: bool) -> Self { + StationSearchBuilder { + builder: self.builder.country_exact(country_exact), + } + } + + pub fn countrycode>(self, countrycode: P) -> Self { + StationSearchBuilder { + builder: self.builder.countrycode(countrycode), + } + } + + pub fn state>(self, state: P) -> Self { + StationSearchBuilder { + builder: self.builder.state(state), + } + } + + pub fn state_exact(self, state_exact: bool) -> Self { + StationSearchBuilder { + builder: self.builder.state_exact(state_exact), + } + } + + pub fn language>(self, language: P) -> Self { + StationSearchBuilder { + builder: self.builder.language(language), + } + } + + pub fn language_exact(self, language_exact: bool) -> Self { + StationSearchBuilder { + builder: self.builder.language_exact(language_exact), + } + } + + pub fn tag>(self, tag: P) -> Self { + StationSearchBuilder { + builder: self.builder.tag(tag), + } + } + + pub fn tag_exact(self, tag_exact: bool) -> Self { + StationSearchBuilder { + builder: self.builder.tag_exact(tag_exact), + } + } + + /* + tagList STRING, STRING, ... OPTIONAL. , a comma-separated list of tag. It can also be an array of string in JSON HTTP POST parameters. All tags in list have to match. + */ + + pub fn codec>(self, codec: P) -> Self { + StationSearchBuilder { + builder: self.builder.codec(codec), + } + } + + pub fn bitrate_min>(self, bitrate_min: P) -> Self { + StationSearchBuilder { + builder: self.builder.bitrate_min(bitrate_min), + } + } + pub fn bitrate_max>(self, bitrate_max: P) -> Self { + StationSearchBuilder { + builder: self.builder.bitrate_max(bitrate_max), + } + } + + pub fn has_geo_info(self, has_geo_info: bool) -> Self { + StationSearchBuilder { + builder: self.builder.has_geo_info(has_geo_info), + } + } + + pub fn has_extended_info(self, has_extended_info: bool) -> Self { + StationSearchBuilder { + builder: self.builder.has_extended_info(has_extended_info), + } + } + + pub fn is_https(self, is_https: bool) -> Self { + StationSearchBuilder { + builder: self.builder.is_https(is_https), + } + } + + pub fn order(self, order: StationOrder) -> Self { + StationSearchBuilder { + builder: self.builder.order(order), + } + } + + pub fn reverse(self, reverse: bool) -> Self { + StationSearchBuilder { + builder: self.builder.reverse(reverse), + } + } + + pub fn offset>(self, offset: P) -> Self { + StationSearchBuilder { + builder: self.builder.offset(offset), + } + } + + pub fn limit>(self, limit: P) -> Self { + StationSearchBuilder { + builder: self.builder.limit(limit), + } + } + + pub fn hidebroken(self, hidebroken: bool) -> Self { + StationSearchBuilder { + builder: self.builder.hidebroken(hidebroken), + } + } + + pub fn send(self) -> Result, Box> { + task::block_on(async { self.builder.send().await }) + } +} diff --git a/src/blocking/tagsearchbuilder.rs b/src/blocking/tagsearchbuilder.rs new file mode 100644 index 0000000..367b382 --- /dev/null +++ b/src/blocking/tagsearchbuilder.rs @@ -0,0 +1,54 @@ +use crate::ApiTag; +use async_std::task; +use std::error::Error; + +#[derive(Clone, Debug)] +pub struct TagSearchBuilder { + builder: crate::TagSearchBuilder, +} + +impl TagSearchBuilder { + pub fn new(builder: crate::TagSearchBuilder) -> Self { + TagSearchBuilder { builder } + } + + pub fn filter>(self, filter: P) -> Self { + TagSearchBuilder { + builder: self.builder.filter(filter.as_ref().to_string()), + } + } + + pub fn order(self, order: crate::TagOrder) -> Self { + TagSearchBuilder { + builder: self.builder.order(order), + } + } + + pub fn reverse(self, reverse: bool) -> Self { + TagSearchBuilder { + builder: self.builder.reverse(reverse), + } + } + + pub fn offset>(self, offset: P) -> Self { + TagSearchBuilder { + builder: self.builder.offset(offset), + } + } + + pub fn limit>(self, limit: P) -> Self { + TagSearchBuilder { + builder: self.builder.limit(limit), + } + } + + pub fn hidebroken(self, hidebroken: bool) -> Self { + TagSearchBuilder { + builder: self.builder.hidebroken(hidebroken), + } + } + + pub fn send(self) -> Result, Box> { + task::block_on(async { self.builder.send().await }) + } +} diff --git a/src/lib.rs b/src/lib.rs index 7951b24..81d9c50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,23 @@ //! //! -//! # Example +//! # Example blocking +//! ```rust +//! use radiobrowser::blocking::RadioBrowserAPI; +//! use std::error::Error; +//! +//! fn main() -> Result<(), Box> { +//! let api = RadioBrowserAPI::new()?; +//! let servers = RadioBrowserAPI::get_servers()?; +//! println!("Servers: {:?}", servers); +//! let countries = api.get_countries().send()?; +//! println!("Countries: {:?}", countries); +//! let stations = api.get_stations().name("jazz").send()?; +//! println!("Stations: {:?}", stations); +//! Ok(()) +//! } +//! ``` +//! +//! # Example async //! ```rust //! use std::error::Error; //! use futures::join; @@ -30,6 +47,8 @@ //! ``` mod api; +#[cfg(feature = "blocking")] +pub mod blocking; mod external; mod stationsearchbuilder; mod countrysearchbuilder; @@ -47,5 +66,8 @@ pub use structs::ApiTag; pub use stationsearchbuilder::StationSearchBuilder; pub use stationsearchbuilder::StationOrder; pub use countrysearchbuilder::CountrySearchBuilder; +pub use countrysearchbuilder::CountryOrder; pub use languagesearchbuilder::LanguageSearchBuilder; -pub use tagsearchbuilder::TagSearchBuilder; \ No newline at end of file +pub use languagesearchbuilder::LanguageOrder; +pub use tagsearchbuilder::TagSearchBuilder; +pub use tagsearchbuilder::TagOrder; \ No newline at end of file