Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix feature conflicts #222

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
run: cargo install cargo-deadlinks

- name: Build and Check
run: RUSTDOCFLAGS='-D warnings' cargo doc --features=cli,env-file
run: RUSTDOCFLAGS='-D warnings' cargo doc --all-features

- name: Look for Dead Links
run: |
Expand All @@ -59,11 +59,6 @@ jobs:
test:
name: Test and Lint for each Client
runs-on: ubuntu-latest
strategy:
matrix:
features:
- rspotify/cli,rspotify/env-file,rspotify/client-ureq,rspotify/ureq-rustls-tls,rspotify-http/client-ureq,rspotify-http/ureq-rustls-tls
- rspotify/cli,rspotify/env-file,rspotify/client-reqwest,rspotify/reqwest-rustls-tls,rspotify-http/client-reqwest,rspotify-http/reqwest-rustls-tls
steps:
- name: Checkout sources
uses: actions/checkout@v2
Expand All @@ -80,10 +75,10 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: clippy
args: -p rspotify -p rspotify-http -p rspotify-model -p rspotify-macros --no-default-features --features=${{ matrix.features }} -- -D warnings
args: --workspace --all-features -- -D warnings

- name: Run cargo test
uses: actions-rs/cargo@v1
with:
command: test
args: -p rspotify -p rspotify-http -p rspotify-model -p rspotify-macros --no-default-features --features=${{ matrix.features }}
args: --workspace --all-features
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ __sync = ["maybe-async/is_sync"]
# Documenting the CLI methods, and working links for `dotenv`
features = ["cli", "env-file"]

[[example]]
name = "http_clients"
required-features = ["env-file", "cli", "client-reqwest", "client-ureq"]
path = "examples/http_clients.rs"

[[example]]
name = "client_creds"
required-features = ["env-file", "cli", "client-reqwest"]
Expand Down
4 changes: 2 additions & 2 deletions examples/client_creds.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rspotify::{model::Id, prelude::*, ClientCredsSpotify, Credentials};
use rspotify::{http::ReqwestClient, model::Id, prelude::*, ClientCredsSpotify, Credentials};

#[tokio::main]
async fn main() {
Expand All @@ -23,7 +23,7 @@ async fn main() {
// ```
let creds = Credentials::from_env().unwrap();

let mut spotify = ClientCredsSpotify::new(creds);
let mut spotify = ClientCredsSpotify::<ReqwestClient>::new(creds);

// Obtaining the access token. Requires to be mutable because the internal
// token will be modified. We don't need OAuth for this specific endpoint,
Expand Down
35 changes: 35 additions & 0 deletions examples/http_clients.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//! This example proves that you can use any HTTP client you like, as long as
//! it's available via its "feature".

use rspotify::{
http::{ReqwestClient, UreqClient},
model::Id,
prelude::*,
ClientCredsSpotify, Credentials,
};

#[tokio::main]
async fn main() {
// You can use any logger for debugging.
env_logger::init();

let creds = Credentials::from_env().unwrap();

// Spotify's clients are generic over the HTTP client; you have to specify
// which one you want to use. Since this example enables both
// `client-reqwest` and `client-ureq`, we can use either of them, even at
// the same time:
let mut spotify_reqwest = ClientCredsSpotify::<ReqwestClient>::new(creds);
let mut spotify_ureq = ClientCredsSpotify::<UreqClient>::new(creds);

spotify_reqwest.request_token().await.unwrap();
spotify_ureq.request_token().unwrap();

// Running the requests
let birdy_uri = Id::from_uri("spotify:album:0sNOF9WDwhWunNAHPD3Baj").unwrap();
let albums = spotify_reqwest.album(birdy_uri).await;
println!("Response with reqwest: {:#?}", albums);

let albums = spotify_ureq.album(birdy_uri).await;
println!("Response with ureq: {:#?}", albums);
}
4 changes: 2 additions & 2 deletions examples/oauth_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! an .env file or export them manually as environmental variables for this to
//! work.

use rspotify::{prelude::*, scopes, AuthCodeSpotify, Credentials, OAuth};
use rspotify::{http::ReqwestClient, prelude::*, scopes, AuthCodeSpotify, Credentials, OAuth};

#[tokio::main]
async fn main() {
Expand Down Expand Up @@ -38,7 +38,7 @@ async fn main() {
);
let oauth = OAuth::from_env(scopes).unwrap();

let mut spotify = AuthCodeSpotify::new(creds, oauth);
let mut spotify = AuthCodeSpotify::<ReqwestClient>::new(creds, oauth);

let url = spotify.get_authorize_url(false).unwrap();
spotify.prompt_for_token(&url).await.unwrap();
Expand Down
4 changes: 2 additions & 2 deletions examples/pagination_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use futures::stream::TryStreamExt;
use futures_util::pin_mut;
use rspotify::{prelude::*, scopes, AuthCodeSpotify, Credentials, OAuth};
use rspotify::{http::ReqwestClient, prelude::*, scopes, AuthCodeSpotify, Credentials, OAuth};

#[tokio::main]
async fn main() {
Expand All @@ -18,7 +18,7 @@ async fn main() {
let creds = Credentials::from_env().unwrap();
let oauth = OAuth::from_env(scopes!("user-library-read")).unwrap();

let mut spotify = AuthCodeSpotify::new(creds, oauth);
let mut spotify = AuthCodeSpotify::<ReqwestClient>::new(creds, oauth);

// Obtaining the access token
let url = spotify.get_authorize_url(false).unwrap();
Expand Down
24 changes: 2 additions & 22 deletions rspotify-http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,18 @@
// confusing errors..

#[cfg(feature = "client-reqwest")]
#[cfg(not(all(feature = "client-reqwest", feature = "client-ureq")))]
mod reqwest;

#[cfg(feature = "client-ureq")]
#[cfg(not(all(feature = "client-reqwest", feature = "client-ureq")))]
mod ureq;

#[cfg(any(feature = "client-reqwest", feature = "client-ureq"))]
#[cfg(not(all(feature = "client-reqwest", feature = "client-ureq")))]
mod common;

#[cfg(feature = "client-reqwest")]
#[cfg(not(all(feature = "client-reqwest", feature = "client-ureq")))]
pub use self::reqwest::ReqwestClient as HttpClient;
pub use self::reqwest::ReqwestClient;

#[cfg(feature = "client-ureq")]
#[cfg(not(all(feature = "client-reqwest", feature = "client-ureq")))]
pub use self::ureq::UreqClient as HttpClient;
pub use self::ureq::UreqClient;

#[cfg(any(feature = "client-reqwest", feature = "client-ureq"))]
#[cfg(not(all(feature = "client-reqwest", feature = "client-ureq")))]
pub use common::{BaseHttpClient, Form, Headers, HttpError, HttpResult, Query};

#[cfg(all(feature = "client-reqwest", feature = "client-ureq"))]
compile_error!(
"`client-reqwest` and `client-ureq` features cannot both be enabled at \
the same time, if you want to use `client-ureq` you need to set \
`default-features = false`"
);

#[cfg(not(any(feature = "client-reqwest", feature = "client-ureq")))]
compile_error!(
"You have to enable at least one of the available clients with the \
`client-reqwest` or `client-ureq` features."
);
4 changes: 2 additions & 2 deletions rspotify-http/src/reqwest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rspotify_model::ApiError;
use serde_json::Value;

impl HttpError {
pub async fn from_response(response: reqwest::Response) -> Self {
pub async fn from_reqwest(response: reqwest::Response) -> Self {
match response.status() {
StatusCode::UNAUTHORIZED => Self::Unauthorized,
StatusCode::TOO_MANY_REQUESTS => Self::RateLimited(
Expand Down Expand Up @@ -88,7 +88,7 @@ impl ReqwestClient {
if response.status().is_success() {
response.text().await.map_err(Into::into)
} else {
Err(HttpError::from_response(response).await)
Err(HttpError::from_reqwest(response).await)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions rspotify-http/src/ureq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde_json::Value;
use ureq::{Request, Response};

impl HttpError {
pub fn from_response(r: ureq::Response) -> Self {
pub fn from_ureq(r: ureq::Response) -> Self {
HttpError::StatusCode(r.status(), r.status_text().to_string())
}
}
Expand Down Expand Up @@ -45,7 +45,7 @@ impl UreqClient {
// Successful request
Ok(response) => response.into_string().map_err(Into::into),
// HTTP status error
Err(ureq::Error::Status(_, response)) => Err(HttpError::from_response(response)),
Err(ureq::Error::Status(_, response)) => Err(HttpError::from_ureq(response)),
// Some kind of IO/transport error
Err(err) => Err(HttpError::Request(err.to_string())),
}
Expand Down
14 changes: 7 additions & 7 deletions src/auth_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
auth_urls,
clients::{BaseClient, OAuthClient},
headers,
http::{Form, HttpClient},
http::{BaseHttpClient, Form},
ClientResult, Config, Credentials, OAuth, Token,
};

Expand Down Expand Up @@ -61,18 +61,18 @@ use url::Url;
/// [example-webapp]: https://github.com/ramsayleung/rspotify/tree/master/examples/webapp
/// [example-refresh-token]: https://github.com/ramsayleung/rspotify/blob/master/examples/with_refresh_token.rs
#[derive(Clone, Debug, Default)]
pub struct AuthCodeSpotify {
pub struct AuthCodeSpotify<Http: BaseHttpClient> {
pub creds: Credentials,
pub oauth: OAuth,
pub config: Config,
pub token: Option<Token>,
pub(in crate) http: HttpClient,
pub(in crate) http: Http,
}

/// This client has access to the base methods.
#[maybe_async(?Send)]
impl BaseClient for AuthCodeSpotify {
fn get_http(&self) -> &HttpClient {
impl<Http: BaseHttpClient> BaseClient<Http> for AuthCodeSpotify<Http> {
fn get_http(&self) -> &Http {
&self.http
}

Expand All @@ -96,7 +96,7 @@ impl BaseClient for AuthCodeSpotify {
/// This client includes user authorization, so it has access to the user
/// private endpoints in [`OAuthClient`].
#[maybe_async(?Send)]
impl OAuthClient for AuthCodeSpotify {
impl<Http: BaseHttpClient> OAuthClient<Http> for AuthCodeSpotify<Http> {
fn get_oauth(&self) -> &OAuth {
&self.oauth
}
Expand Down Expand Up @@ -140,7 +140,7 @@ impl OAuthClient for AuthCodeSpotify {
}
}

impl AuthCodeSpotify {
impl<Http: BaseHttpClient> AuthCodeSpotify<Http> {
/// Builds a new [`AuthCodeSpotify`] given a pair of client credentials and
/// OAuth information.
pub fn new(creds: Credentials, oauth: OAuth) -> Self {
Expand Down
14 changes: 7 additions & 7 deletions src/auth_code_pkce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
auth_urls,
clients::{BaseClient, OAuthClient},
headers,
http::{Form, HttpClient},
http::{BaseHttpClient, Form},
ClientResult, Config, Credentials, OAuth, Token,
};

Expand All @@ -25,17 +25,17 @@ use url::Url;
/// [reference]: https://developer.spotify.com/documentation/general/guides/authorization-guide/#authorization-code-flow-with-proof-key-for-code-exchange-pkce
/// [example-main]: https://github.com/ramsayleung/rspotify/blob/master/examples/auth_code_pkce.rs
#[derive(Clone, Debug, Default)]
pub struct AuthCodePkceSpotify {
pub struct AuthCodePkceSpotify<Http: BaseHttpClient> {
pub creds: Credentials,
pub oauth: OAuth,
pub config: Config,
pub token: Option<Token>,
pub(in crate) http: HttpClient,
pub(in crate) http: Http,
}

/// This client has access to the base methods.
impl BaseClient for AuthCodePkceSpotify {
fn get_http(&self) -> &HttpClient {
impl<Http: BaseHttpClient> BaseClient<Http> for AuthCodePkceSpotify<Http> {
fn get_http(&self) -> &Http {
&self.http
}

Expand All @@ -59,7 +59,7 @@ impl BaseClient for AuthCodePkceSpotify {
/// This client includes user authorization, so it has access to the user
/// private endpoints in [`OAuthClient`].
#[maybe_async(?Send)]
impl OAuthClient for AuthCodePkceSpotify {
impl<Http: BaseHttpClient> OAuthClient<Http> for AuthCodePkceSpotify<Http> {
fn get_oauth(&self) -> &OAuth {
&self.oauth
}
Expand Down Expand Up @@ -100,7 +100,7 @@ impl OAuthClient for AuthCodePkceSpotify {
}
}

impl AuthCodePkceSpotify {
impl<Http: BaseHttpClient> AuthCodePkceSpotify<Http> {
/// Builds a new [`AuthCodePkceSpotify`] given a pair of client credentials
/// and OAuth information.
pub fn new(creds: Credentials, oauth: OAuth) -> Self {
Expand Down
12 changes: 6 additions & 6 deletions src/client_creds.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
clients::BaseClient,
headers,
http::{Form, HttpClient},
http::{BaseHttpClient, Form},
ClientResult, Config, Credentials, Token,
};

Expand All @@ -20,16 +20,16 @@ use maybe_async::maybe_async;
/// [reference]: https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow
/// [example-main]: https://github.com/ramsayleung/rspotify/blob/master/examples/client_creds.rs
#[derive(Clone, Debug, Default)]
pub struct ClientCredsSpotify {
pub struct ClientCredsSpotify<Http: BaseHttpClient> {
pub config: Config,
pub creds: Credentials,
pub token: Option<Token>,
pub(in crate) http: HttpClient,
pub(in crate) http: Http,
}

/// This client has access to the base methods.
impl BaseClient for ClientCredsSpotify {
fn get_http(&self) -> &HttpClient {
impl<Http: BaseHttpClient> BaseClient<Http> for ClientCredsSpotify<Http> {
fn get_http(&self) -> &Http {
&self.http
}

Expand All @@ -50,7 +50,7 @@ impl BaseClient for ClientCredsSpotify {
}
}

impl ClientCredsSpotify {
impl<Http: BaseHttpClient> ClientCredsSpotify<Http> {
/// Builds a new [`ClientCredsSpotify`] given a pair of client credentials
/// and OAuth information.
pub fn new(creds: Credentials) -> Self {
Expand Down
7 changes: 4 additions & 3 deletions src/clients/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
basic_auth, bearer_auth, convert_result, join_ids,
pagination::{paginate, Paginator},
},
http::{BaseHttpClient, Form, Headers, HttpClient, Query},
http::{BaseHttpClient, Form, Headers, Query},
macros::build_map,
model::*,
ClientResult, Config, Credentials, Token,
Expand All @@ -20,12 +20,13 @@ use serde_json::{Map, Value};
/// accessed without user authorization, including parts of the authentication
/// flow that are shared, and the endpoints.
#[maybe_async(?Send)]
pub trait BaseClient
pub trait BaseClient<Http>
where
Self: Default + Clone + fmt::Debug,
Http: BaseHttpClient,
{
fn get_config(&self) -> &Config;
fn get_http(&self) -> &HttpClient;
fn get_http(&self) -> &Http;
fn get_token(&self) -> Option<&Token>;
fn get_token_mut(&mut self) -> Option<&mut Token>;
fn get_creds(&self) -> &Credentials;
Expand Down
7 changes: 5 additions & 2 deletions src/clients/oauth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
pagination::{paginate, Paginator},
BaseClient,
},
http::Query,
http::{BaseHttpClient, Query},
macros::{build_json, build_map},
model::*,
ClientResult, OAuth, Token,
Expand All @@ -28,7 +28,10 @@ use url::Url;
/// only separates endpoints that *always* need authorization from the base
/// ones.
#[maybe_async(?Send)]
pub trait OAuthClient: BaseClient {
pub trait OAuthClient<Http>: BaseClient<Http>
where
Http: BaseHttpClient,
{
fn get_oauth(&self) -> &OAuth;

/// Obtains a user access token given a code, as part of the OAuth
Expand Down