twitch-rs/twitch_api

implementation of `twitch_oauth2::client::Client` is not general enough

Fr33maan opened this issue · 7 comments

I'm trying to use the client in a tokio::spawn context but I get the following error.

async fn get_auth_token_request() -> Result<AppAccessToken, AppError> {
    let config = get_config();

    let client_id = ClientId::new(config.twitch.api.id.clone());
    let client_secret = ClientSecret::new(config.twitch.api.secret.clone());
    let client: TwitchClient<reqwest::Client> = TwitchClient::default();

    let token =
        AppAccessToken::get_app_access_token(&client, client_id, client_secret, Scope::all())
            .await
            .unwrap();

    Ok(token)
}

fn spawn_followers_poll(pool: Pool) {
    tokio::spawn({ // <---- here is the error
        async move {
            get_auth_token_request().await.unwrap();
        }
    });
}
implementation of `twitch_oauth2::client::Client` is not general enough
`twitch_oauth2::client::Client<'1>` would have to be implemented for the type `TwitchClient<'0, reqwest::Client>`, for any two lifetimes `'0` and `'1`...
...but `twitch_oauth2::client::Client<'2>` is actually implemented for the type `TwitchClient<'2, reqwest::Client>`, for some specific lifetime `'2`rustc

Following the exemple, I can see that we must explicit some lifetimes but I don't really understand what should be done.

Can you provide some help please ?

real error is

/// [dependencies]
/// twitch_api2 = {version= "0.6.0-rc.3", features = ["client", "helix", "reqwest_client"]}
/// tokio = {version = "*", features=["full"]}
/// reqwest = "*"

use twitch_api2::{twitch_oauth2::*, *};

async fn get_auth_token_request(client: &TwitchClient<'static, reqwest::Client>) -> Result<AppAccessToken, ()> {

    let client_id = ClientId::new("aaa");
    let client_secret = ClientSecret::new("aaaa");

    let token =
        AppAccessToken::get_app_access_token(&client, client_id, client_secret, Scope::all())
            .await
            .unwrap();

    Ok(token)
}

fn spawn_followers_poll() {
    let client: TwitchClient<'static, reqwest::Client> = TwitchClient::new();

    tokio::spawn({
        // <---- here is the error
        async move {
            get_auth_token_request(&client).await.unwrap();
        }
    });
}
❯ cargo check
    Checking aaa v0.1.0 (G:\workspace\small dev space\aaa)
error[E0277]: the trait bound `&twitch_api2::TwitchClient<'_, reqwest::Client>: twitch_api2::twitch_oauth2::client::Client<'_>` is not satisfied
   --> src\lib.rs:9:9
    |
9   |         AppAccessToken::get_app_access_token(&client, client_id, client_secret, Scope::all())
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `twitch_api2::twitch_oauth2::client::Client<'_>` is not implemented for `&twitch_api2::TwitchClient<'_, reqwest::Client>`
    |
    = help: the following implementations were found:
              <twitch_api2::TwitchClient<'a, C> as twitch_api2::twitch_oauth2::client::Client<'a>>
note: required by a bound in `twitch_api2::twitch_oauth2::AppAccessToken::get_app_access_token`
   --> G:\workspace\twitch_api2\twitch_oauth2\src\tokens\app_access_token.rs:136:12
p_access_token`

error[E0277]: the trait bound `&twitch_api2::TwitchClient<'_, reqwest::Client>: twitch_api2::twitch_oauth2::client::Client<'_>` is not satisfied
  --> src\lib.rs:9:9
   |
9  | /         AppAccessToken::get_app_access_token(&client, client_id, client_secret, Scope::all())
10 | |             .await
   | |__________________^ the trait `twitch_api2::twitch_oauth2::client::Client<'_>` is not implemented for `&twitch_api2::TwitchClient<'_, reqwest::Client>`      
   |
   = help: the following implementations were found:
             <twitch_api2::TwitchClient<'a, C> as twitch_api2::twitch_oauth2::client::Client<'a>>

For more information about this error, try `rustc --explain E0277`.
error: could not compile `aaa` due to 2 previous errors

scratch that, that's not the error...

minimal repro:

use twitch_api2::{twitch_oauth2::*, *};

async fn get_auth_token_request(client: &TwitchClient<'static, reqwest::Client>) -> Result<AppAccessToken, ()> {

    let client_id = ClientId::new("aaa");
    let client_secret = ClientSecret::new("aaaa");

    let token =
        AppAccessToken::get_app_access_token(client, client_id, client_secret, Scope::all())
            .await
            .unwrap();

    Ok(token)
}

fn spawn_followers_poll() {
    let client: TwitchClient<'static, reqwest::Client> = TwitchClient::new();

    tokio::spawn({
        // <---- here is the error
        async move {
            get_auth_token_request(&client).await.unwrap();
        }
    });
}

pub fn main() {

}

gives

error: implementation of `twitch_api2::twitch_oauth2::client::Client` is not general enough
  --> examples\waaah.rs:19:5
   |
19 |     tokio::spawn({
   |     ^^^^^^^^^^^^ implementation of `twitch_api2::twitch_oauth2::client::Client` is not general enough
   |
   = note: `twitch_api2::twitch_oauth2::client::Client<'1>` would have to be implemented for the type `twitch_api2::TwitchClient<'0, reqwest::Client>`, for any two lifetimes `'0` and `'1`...
   = note: ...but `twitch_api2::twitch_oauth2::client::Client<'2>` is actually implemented for the type `twitch_api2::TwitchClient<'2, reqwest::Client>`, for some specific lifetime `'2`

error: could not compile `twitch_api2` due to previous error

I'm not sure if this is a library issue, or if it's a rust bug.

I'm not 100% sure what this issue is, but to fix it there is a workaround.

Instead of giving the TwitchClient, give it the "real" client inside, this can be done with client.helix.clone_client()

so

AppAccessToken::get_app_access_token(&client.helix.clone_client(), ...)

I'm going to expose the client() fn to make this easier and not having to clone (although the clone is cheap). So it would become client.get_client() instead.

I need to do some minimization of this to see if this is the same as above mentioned issue or if it's something else.

Thanks ! I tried to implement the given solution like this:

async fn get_auth_token_request(config: &Config) -> Result<AppAccessToken, AppError> {
    let client_id = ClientId::new(config.twitch.api.id.clone());
    let client_secret = ClientSecret::new(config.twitch.api.secret.clone());
    let client: TwitchClient<'static, reqwest::Client> = TwitchClient::new();

    let token = AppAccessToken::get_app_access_token(  // <------ error here
        &client.helix.clone_client(),
        client_id,
        client_secret,
        Scope::all(),
    )
    .await
    .unwrap();

    Ok(token)
}

This brings the following issue:

the trait bound `reqwest::Client: twitch_oauth2::client::Client<'_>` is not satisfied
the trait `twitch_oauth2::client::Client<'_>` is not implemented for `reqwest::Client`rustcE0277
app_access_token.rs(136, 12): required by a bound in `twitch_oauth2::AppAccessToken::get_app_access_token`

Then I tried to replace the reqwest client with the twitch_oauth2 one, even if I'm not sure why I'm required too.

async fn get_auth_token_request(config: &Config) -> Result<AppAccessToken, AppError> {
    let client_id = ClientId::new(config.twitch.api.id.clone());
    let client_secret = ClientSecret::new(config.twitch.api.secret.clone());
    let client: TwitchClient<'static, dyn twitch_oauth2::client::Client> = TwitchClient::new(); // <----- error 1 here (I tried with and without dyn keyword)

    let token = AppAccessToken::get_app_access_token(
        &client.helix.clone_client(),  // <-----  error 2 here
        client_id,
        client_secret,
        Scope::all(),
    )
    .await
    .unwrap();

    Ok(token)
}
the size for values of type `dyn twitch_oauth2::client::Client<'_>` cannot be known at compilation time
the trait `Sized` is not implemented for `dyn twitch_oauth2::client::Client<'_>`rustcE0277
lib.rs(203, 29): required by a bound in `TwitchClient`
the method `clone_client` exists for struct `HelixClient<'static, dyn twitch_oauth2::client::Client<'_>>`, but its trait bounds were not satisfied
the following trait bounds were not satisfied:
`dyn twitch_oauth2::client::Client<'_>: Sized`
`dyn twitch_oauth2::client::Client<'_>: HttpClient`rustcE0599
client.rs(17, 1): doesn't satisfy `dyn twitch_oauth2::client::Client<'_>: HttpClient`
client.rs(17, 1): doesn't satisfy `dyn twitch_oauth2::client::Client<'_>: Sized`

Second way wont work. the error message after doing the workaround suggests that you dont have reqwest_client feature enabled in twitch_api2.

this just works™️ now