added blocking interface

This commit is contained in:
Alex 2022-04-26 22:26:46 +02:00
parent afe64b7795
commit 794aa513ee
10 changed files with 430 additions and 17 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "radiobrowser" name = "radiobrowser"
version = "0.1.0" version = "0.2.0"
authors = ["segler_alex <segler_alex@web.de>"] authors = ["segler_alex <segler_alex@web.de>"]
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
@ -16,10 +16,15 @@ async-std = { version = "1.11.0", features = ["attributes", "tokio1"] }
async-std-resolver = "0.21.2" async-std-resolver = "0.21.2"
chrono = { version = "0.4.19", features = ["serde"] } 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" } rand = { version = "0.8.5" }
reqwest = { version = "0.11.10", features = ["json"] } reqwest = { version = "0.11.10", features = ["json"] }
serde = { version = "1.0.136", features = ["derive"] } serde = { version = "1.0.136", features = ["derive"] }
[features]
default = ["blocking"]
blocking = []
[badges] [badges]
# The `maintenance` table indicates the status of the maintenance of # The `maintenance` table indicates the status of the maintenance of
# the crate. This may be used by a registry, but is currently not # the crate. This may be used by a registry, but is currently not

View file

@ -1,6 +1,5 @@
use crate::external::post_api; use crate::external::post_api;
use crate::ApiConfig; use crate::ApiConfig;
use crate::ApiCountry;
use crate::CountrySearchBuilder; use crate::CountrySearchBuilder;
use crate::LanguageSearchBuilder; use crate::LanguageSearchBuilder;
use crate::StationSearchBuilder; use crate::StationSearchBuilder;
@ -13,6 +12,8 @@ use std::error::Error;
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use rand::thread_rng; use rand::thread_rng;
use log::trace;
use async_std_resolver::proto::rr::RecordType; use async_std_resolver::proto::rr::RecordType;
use async_std_resolver::proto::xfer::DnsRequestOptions; use async_std_resolver::proto::xfer::DnsRequestOptions;
use async_std_resolver::{config, resolver}; 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 { if self.servers.len() > 0 {
self.current = self.current % self.servers.len(); self.current = self.current % self.servers.len();
format!("https://{}", self.servers[self.current]) format!("https://{}", self.servers[self.current])
@ -40,7 +42,7 @@ impl RadioBrowserAPI {
} }
} }
pub async fn post_api<P: DeserializeOwned, A: AsRef<str>>( async fn post_api<P: DeserializeOwned, A: AsRef<str>>(
&mut self, &mut self,
endpoint: A, endpoint: A,
) -> Result<P, Box<dyn Error>> { ) -> Result<P, Box<dyn Error>> {
@ -76,16 +78,8 @@ impl RadioBrowserAPI {
post_api(self.get_current_server(), endpoint, mapjson).await post_api(self.get_current_server(), endpoint, mapjson).await
} }
pub async fn get_countries_filtered<P: AsRef<str>>(
&mut self,
filter: P,
) -> Result<Vec<ApiCountry>, Box<dyn Error>> {
Ok(self
.post_api(format!("/json/countries/{}", filter.as_ref()))
.await?)
}
pub async fn get_servers() -> Result<Vec<String>, Box<dyn Error>> { pub async fn get_servers() -> Result<Vec<String>, Box<dyn Error>> {
trace!("get_servers()");
let resolver = resolver( let resolver = resolver(
config::ResolverConfig::default(), config::ResolverConfig::default(),
config::ResolverOpts::default(), config::ResolverOpts::default(),
@ -105,7 +99,7 @@ impl RadioBrowserAPI {
.collect(); .collect();
list.shuffle(&mut thread_rng()); list.shuffle(&mut thread_rng());
println!("Servers: {:?}", list); trace!("Servers: {:?}", list);
Ok(list) Ok(list)
} }
} }

View file

@ -1,3 +1,4 @@
/*
use futures::join; use futures::join;
use radiobrowser::RadioBrowserAPI; use radiobrowser::RadioBrowserAPI;
use radiobrowser::StationOrder; use radiobrowser::StationOrder;
@ -27,3 +28,18 @@ async fn main() -> Result<(), Box<dyn Error>> {
println!("Stations found: {}", stations?.len()); println!("Stations found: {}", stations?.len());
Ok(()) Ok(())
} }
*/
use radiobrowser::blocking::RadioBrowserAPI;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
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(())
}

50
src/blocking/api.rs Normal file
View file

@ -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<Self, Box<dyn Error>> {
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<P: AsRef<str>, Q: DeserializeOwned>(
&mut self,
endpoint: P,
mapjson: HashMap<String, String>,
) -> Result<Q, Box<dyn Error>> {
task::block_on(async { self.api.send(endpoint, mapjson).await })
}
pub fn get_servers() -> Result<Vec<String>, Box<dyn Error>> {
task::block_on(async { crate::RadioBrowserAPI::get_servers().await })
}
}

View file

@ -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<P: AsRef<str>>(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<P: AsRef<str>>(self, offset: P) -> Self {
CountrySearchBuilder {
builder: self.builder.offset(offset),
}
}
pub fn limit<P: AsRef<str>>(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<Vec<ApiCountry>, Box<dyn Error>> {
task::block_on(async { self.builder.send().await })
}
}

View file

@ -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<P: AsRef<str>>(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<P: AsRef<str>>(self, offset: P) -> Self {
LanguageSearchBuilder {
builder: self.builder.offset(offset),
}
}
pub fn limit<P: AsRef<str>>(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<Vec<ApiLanguage>, Box<dyn Error>> {
task::block_on(async { self.builder.send().await })
}
}

10
src/blocking/mod.rs Normal file
View file

@ -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;

View file

@ -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<P: AsRef<str>>(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<P: AsRef<str>>(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<P: AsRef<str>>(self, countrycode: P) -> Self {
StationSearchBuilder {
builder: self.builder.countrycode(countrycode),
}
}
pub fn state<P: AsRef<str>>(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<P: AsRef<str>>(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<P: AsRef<str>>(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<P: AsRef<str>>(self, codec: P) -> Self {
StationSearchBuilder {
builder: self.builder.codec(codec),
}
}
pub fn bitrate_min<P: AsRef<str>>(self, bitrate_min: P) -> Self {
StationSearchBuilder {
builder: self.builder.bitrate_min(bitrate_min),
}
}
pub fn bitrate_max<P: AsRef<str>>(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<P: AsRef<str>>(self, offset: P) -> Self {
StationSearchBuilder {
builder: self.builder.offset(offset),
}
}
pub fn limit<P: AsRef<str>>(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<Vec<ApiStation>, Box<dyn Error>> {
task::block_on(async { self.builder.send().await })
}
}

View file

@ -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<P: AsRef<str>>(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<P: AsRef<str>>(self, offset: P) -> Self {
TagSearchBuilder {
builder: self.builder.offset(offset),
}
}
pub fn limit<P: AsRef<str>>(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<Vec<ApiTag>, Box<dyn Error>> {
task::block_on(async { self.builder.send().await })
}
}

View file

@ -1,6 +1,23 @@
//! //!
//! //!
//! # Example //! # Example blocking
//! ```rust
//! use radiobrowser::blocking::RadioBrowserAPI;
//! use std::error::Error;
//!
//! fn main() -> Result<(), Box<dyn Error>> {
//! 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 //! ```rust
//! use std::error::Error; //! use std::error::Error;
//! use futures::join; //! use futures::join;
@ -30,6 +47,8 @@
//! ``` //! ```
mod api; mod api;
#[cfg(feature = "blocking")]
pub mod blocking;
mod external; mod external;
mod stationsearchbuilder; mod stationsearchbuilder;
mod countrysearchbuilder; mod countrysearchbuilder;
@ -47,5 +66,8 @@ pub use structs::ApiTag;
pub use stationsearchbuilder::StationSearchBuilder; pub use stationsearchbuilder::StationSearchBuilder;
pub use stationsearchbuilder::StationOrder; pub use stationsearchbuilder::StationOrder;
pub use countrysearchbuilder::CountrySearchBuilder; pub use countrysearchbuilder::CountrySearchBuilder;
pub use countrysearchbuilder::CountryOrder;
pub use languagesearchbuilder::LanguageSearchBuilder; pub use languagesearchbuilder::LanguageSearchBuilder;
pub use languagesearchbuilder::LanguageOrder;
pub use tagsearchbuilder::TagSearchBuilder; pub use tagsearchbuilder::TagSearchBuilder;
pub use tagsearchbuilder::TagOrder;