diff options
| author | HampusM <hampus@hampusmat.com> | 2022-09-08 21:08:48 +0200 | 
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2022-09-08 21:08:48 +0200 | 
| commit | 8a02d3386d4ce0b58de943fcf42bd072af1e0b42 (patch) | |
| tree | 6656b72ce309ae993029d8cdae26604098d92ba7 /src/client.rs | |
| parent | b44463d533ba9b789e3423d670e2ddcc32c1112c (diff) | |
refactor: move get access token to DeezerClient
Diffstat (limited to 'src/client.rs')
| -rw-r--r-- | src/client.rs | 113 | 
1 files changed, 99 insertions, 14 deletions
| diff --git a/src/client.rs b/src/client.rs index 0699545..179377f 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,11 +1,12 @@  //! Deezer client.  use std::fmt::Debug; +use std::time::Duration;  use hyper::client::{Client, HttpConnector};  use hyper::Uri;  use serde::Deserialize; -use crate::auth::AccessToken; +use crate::auth::{AccessToken, AuthCode};  use crate::errors::client::DeezerClientError;  use crate::playlist::Playlist;  use crate::user::{User, UserPlaylist, UserPlaylists}; @@ -31,24 +32,45 @@ struct ErrorResponseBody      error: DeezerError,  } +#[derive(Debug, Deserialize)] +struct AccessTokenResponse +{ +    pub access_token: String, +    pub expires: u64, +} + +impl From<AccessTokenResponse> for AccessToken +{ +    fn from(response: AccessTokenResponse) -> Self +    { +        Self { +            access_token: response.access_token, +            expires: Duration::from_secs(response.expires), +        } +    } +} +  /// Deezer client. +#[derive(Default)]  pub struct DeezerClient  {      client: Client<HttpConnector>, -    api_url: &'static str, -    access_token: AccessToken, +    api_uri_authority: &'static str, +    access_token_uri_authority: &'static str, +    access_token_uri_path: &'static str,  }  impl DeezerClient  {      /// Creates a new Deezer client.      #[must_use] -    pub fn new(access_token: AccessToken) -> Self +    pub fn new() -> Self      {          Self {              client: Client::new(), -            api_url: "api.deezer.com", -            access_token, +            api_uri_authority: "api.deezer.com", +            access_token_uri_authority: "connect.deezer.com", +            access_token_uri_path: "/oauth/access_token.php",          }      } @@ -56,11 +78,17 @@ impl DeezerClient      ///      /// # Errors      /// Will return Err if either sending the request or parsing the response fails. -    pub async fn get_me(&self) -> Result<User, DeezerClientError> +    pub async fn get_me( +        &self, +        access_token: AccessToken, +    ) -> Result<User, DeezerClientError>      {          let response = self              .client -            .get(self.build_endpoint_uri(&"user/me".to_string())?) +            .get(self.build_endpoint_uri( +                &"user/me".to_string(), +                &[("access_token", access_token.access_token)], +            )?)              .await?;          let body_buf = &*hyper::body::to_bytes(response).await?; @@ -82,11 +110,15 @@ impl DeezerClient      pub async fn get_user_playlists(          &self,          user_id: u64, +        access_token: AccessToken,      ) -> Result<Vec<UserPlaylist>, DeezerClientError>      {          let response = self              .client -            .get(self.build_endpoint_uri(&format!("user/{}/playlists", user_id))?) +            .get(self.build_endpoint_uri( +                &format!("user/{}/playlists", user_id), +                &[("access_token", access_token.access_token)], +            )?)              .await?;          let body_buf = &*hyper::body::to_bytes(response).await?; @@ -111,11 +143,15 @@ impl DeezerClient      pub async fn get_playlist(          &self,          playlist_id: u64, +        access_token: AccessToken,      ) -> Result<Playlist, DeezerClientError>      {          let response = self              .client -            .get(self.build_endpoint_uri(&format!("playlist/{}", playlist_id))?) +            .get(self.build_endpoint_uri( +                &format!("playlist/{}", playlist_id), +                &[("access_token", access_token.access_token)], +            )?)              .await?;          let body_buf = &*hyper::body::to_bytes(response).await?; @@ -130,14 +166,63 @@ impl DeezerClient          serde_json::from_slice(body_buf).map_err(DeezerClientError::ParseResponseFailed)      } -    fn build_endpoint_uri(&self, endpoint: &String) -> Result<Uri, DeezerClientError> +    /// Returns a access token. +    /// +    /// # Errors +    /// Will return Err if either sending the request or parsing the response fails. +    pub async fn get_access_token( +        &self, +        app_id: u32, +        secret_key: String, +        auth_code: AuthCode, +    ) -> Result<AccessToken, DeezerClientError> +    { +        let uri = Uri::builder() +            .scheme("http") +            .authority(self.access_token_uri_authority) +            .path_and_query(format!( +                "{}?app_id={}&secret={}&code={}&output=json", +                self.access_token_uri_path, app_id, secret_key, auth_code +            )) +            .build() +            .map_err(|_| DeezerClientError::BuildAPIEndpointURIFailed)?; + +        let response = self.client.get(uri).await?; + +        let body_buf = &*hyper::body::to_bytes(response).await?; + +        let err_body_result: Result<ErrorResponseBody, _> = +            serde_json::from_slice(body_buf); + +        if let Ok(err_body) = err_body_result { +            return Err(DeezerClientError::ReceivedErrorResponse(err_body.error)); +        } + +        let access_token_response: AccessTokenResponse = serde_json::from_slice(body_buf) +            .map_err(DeezerClientError::ParseResponseFailed)?; + +        Ok(access_token_response.into()) +    } + +    fn build_endpoint_uri( +        &self, +        endpoint: &String, +        query_params: &[(&'static str, String)], +    ) -> Result<Uri, DeezerClientError>      {          Uri::builder()              .scheme("http") -            .authority(self.api_url) +            .authority(self.api_uri_authority)              .path_and_query(format!( -                "/{}?access_token={}", -                endpoint, self.access_token.access_token +                "/{}?{}", +                endpoint, +                query_params +                    .iter() +                    .map(|(key, value)| format!("{}={}", key, value)) +                    .fold(String::new(), |acc, query_param| format!( +                        "{}&{}", +                        acc, query_param +                    ))              ))              .build()              .map_err(|_| DeezerClientError::BuildAPIEndpointURIFailed) | 
