mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 10:06:32 +08:00 
			
		
		
		
	refactor(access_token): use merchant_connector_id for storing access token (#4462)
				
					
				
			This commit is contained in:
		
							
								
								
									
										11
									
								
								crates/common_utils/src/access_token.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								crates/common_utils/src/access_token.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | //! Commonly used utilities for access token | ||||||
|  |  | ||||||
|  | use std::fmt::Display; | ||||||
|  |  | ||||||
|  | /// Create a key for fetching the access token from redis | ||||||
|  | pub fn create_access_token_key( | ||||||
|  |     merchant_id: impl Display, | ||||||
|  |     merchant_connector_id: impl Display, | ||||||
|  | ) -> String { | ||||||
|  |     format!("access_token_{merchant_id}_{merchant_connector_id}") | ||||||
|  | } | ||||||
| @ -2,6 +2,7 @@ | |||||||
| #![warn(missing_docs, missing_debug_implementations)] | #![warn(missing_docs, missing_debug_implementations)] | ||||||
| #![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR" ), "/", "README.md"))] | #![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR" ), "/", "README.md"))] | ||||||
|  |  | ||||||
|  | pub mod access_token; | ||||||
| pub mod consts; | pub mod consts; | ||||||
| pub mod crypto; | pub mod crypto; | ||||||
| pub mod custom_serde; | pub mod custom_serde; | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ use crate::{ | |||||||
|         payments, |         payments, | ||||||
|     }, |     }, | ||||||
|     routes::{metrics, AppState}, |     routes::{metrics, AppState}, | ||||||
|     services, |     services::{self, logger}, | ||||||
|     types::{self, api as api_types, domain}, |     types::{self, api as api_types, domain}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @ -64,8 +64,14 @@ pub async fn add_access_token< | |||||||
|     { |     { | ||||||
|         let merchant_id = &merchant_account.merchant_id; |         let merchant_id = &merchant_account.merchant_id; | ||||||
|         let store = &*state.store; |         let store = &*state.store; | ||||||
|  |         let merchant_connector_id = connector | ||||||
|  |             .merchant_connector_id | ||||||
|  |             .as_ref() | ||||||
|  |             .ok_or(errors::ApiErrorResponse::InternalServerError) | ||||||
|  |             .attach_printable("Missing merchant_connector_id in ConnectorData")?; | ||||||
|  |  | ||||||
|         let old_access_token = store |         let old_access_token = store | ||||||
|             .get_access_token(merchant_id, connector.connector.id()) |             .get_access_token(merchant_id, merchant_connector_id) | ||||||
|             .await |             .await | ||||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) |             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|             .attach_printable("DB error when accessing the access token")?; |             .attach_printable("DB error when accessing the access token")?; | ||||||
| @ -103,19 +109,24 @@ pub async fn add_access_token< | |||||||
|                 ) |                 ) | ||||||
|                 .await? |                 .await? | ||||||
|                 .async_map(|access_token| async { |                 .async_map(|access_token| async { | ||||||
|                     //Store the access token in db |                     // Store the access token in redis with expiry | ||||||
|  |                     // The expiry should be adjusted for network delays from the connector | ||||||
|                     let store = &*state.store; |                     let store = &*state.store; | ||||||
|                     // This error should not be propagated, we don't want payments to fail once we have |                     if let Err(access_token_set_error) = store | ||||||
|                     // the access token, the next request will create new access token |  | ||||||
|                     let _ = store |  | ||||||
|                         .set_access_token( |                         .set_access_token( | ||||||
|                             merchant_id, |                             merchant_id, | ||||||
|                             connector.connector.id(), |                             merchant_connector_id.as_str(), | ||||||
|                             access_token.clone(), |                             access_token.clone(), | ||||||
|                         ) |                         ) | ||||||
|                         .await |                         .await | ||||||
|                         .change_context(errors::ApiErrorResponse::InternalServerError) |                         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|                         .attach_printable("DB error when setting the access token"); |                         .attach_printable("DB error when setting the access token") | ||||||
|  |                     { | ||||||
|  |                         // If we are not able to set the access token in redis, the error should just be logged and proceed with the payment | ||||||
|  |                         // Payments should not fail, once the access token is successfully created | ||||||
|  |                         // The next request will create new access token, if required | ||||||
|  |                         logger::error!(access_token_set_error=?access_token_set_error); | ||||||
|  |                     } | ||||||
|                     Some(access_token) |                     Some(access_token) | ||||||
|                 }) |                 }) | ||||||
|                 .await |                 .await | ||||||
|  | |||||||
| @ -859,21 +859,21 @@ impl ConnectorAccessToken for KafkaStore { | |||||||
|     async fn get_access_token( |     async fn get_access_token( | ||||||
|         &self, |         &self, | ||||||
|         merchant_id: &str, |         merchant_id: &str, | ||||||
|         connector_name: &str, |         merchant_connector_id: &str, | ||||||
|     ) -> CustomResult<Option<AccessToken>, errors::StorageError> { |     ) -> CustomResult<Option<AccessToken>, errors::StorageError> { | ||||||
|         self.diesel_store |         self.diesel_store | ||||||
|             .get_access_token(merchant_id, connector_name) |             .get_access_token(merchant_id, merchant_connector_id) | ||||||
|             .await |             .await | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async fn set_access_token( |     async fn set_access_token( | ||||||
|         &self, |         &self, | ||||||
|         merchant_id: &str, |         merchant_id: &str, | ||||||
|         connector_name: &str, |         merchant_connector_id: &str, | ||||||
|         access_token: AccessToken, |         access_token: AccessToken, | ||||||
|     ) -> CustomResult<(), errors::StorageError> { |     ) -> CustomResult<(), errors::StorageError> { | ||||||
|         self.diesel_store |         self.diesel_store | ||||||
|             .set_access_token(merchant_id, connector_name, access_token) |             .set_access_token(merchant_id, merchant_connector_id, access_token) | ||||||
|             .await |             .await | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,13 +24,13 @@ pub trait ConnectorAccessToken { | |||||||
|     async fn get_access_token( |     async fn get_access_token( | ||||||
|         &self, |         &self, | ||||||
|         merchant_id: &str, |         merchant_id: &str, | ||||||
|         connector_name: &str, |         merchant_connector_id: &str, | ||||||
|     ) -> CustomResult<Option<types::AccessToken>, errors::StorageError>; |     ) -> CustomResult<Option<types::AccessToken>, errors::StorageError>; | ||||||
|  |  | ||||||
|     async fn set_access_token( |     async fn set_access_token( | ||||||
|         &self, |         &self, | ||||||
|         merchant_id: &str, |         merchant_id: &str, | ||||||
|         connector_name: &str, |         merchant_connector_id: &str, | ||||||
|         access_token: types::AccessToken, |         access_token: types::AccessToken, | ||||||
|     ) -> CustomResult<(), errors::StorageError>; |     ) -> CustomResult<(), errors::StorageError>; | ||||||
| } | } | ||||||
| @ -41,12 +41,14 @@ impl ConnectorAccessToken for Store { | |||||||
|     async fn get_access_token( |     async fn get_access_token( | ||||||
|         &self, |         &self, | ||||||
|         merchant_id: &str, |         merchant_id: &str, | ||||||
|         connector_name: &str, |         merchant_connector_id: &str, | ||||||
|     ) -> CustomResult<Option<types::AccessToken>, errors::StorageError> { |     ) -> CustomResult<Option<types::AccessToken>, errors::StorageError> { | ||||||
|         //TODO: Handle race condition |         //TODO: Handle race condition | ||||||
|         // This function should acquire a global lock on some resource, if access token is already |         // This function should acquire a global lock on some resource, if access token is already | ||||||
|         // being refreshed by other request then wait till it finishes and use the same access token |         // being refreshed by other request then wait till it finishes and use the same access token | ||||||
|         let key = format!("access_token_{merchant_id}_{connector_name}"); |         let key = | ||||||
|  |             common_utils::access_token::create_access_token_key(merchant_id, merchant_connector_id); | ||||||
|  |  | ||||||
|         let maybe_token = self |         let maybe_token = self | ||||||
|             .get_redis_conn() |             .get_redis_conn() | ||||||
|             .map_err(Into::<errors::StorageError>::into)? |             .map_err(Into::<errors::StorageError>::into)? | ||||||
| @ -55,10 +57,9 @@ impl ConnectorAccessToken for Store { | |||||||
|             .change_context(errors::StorageError::KVError) |             .change_context(errors::StorageError::KVError) | ||||||
|             .attach_printable("DB error when getting access token")?; |             .attach_printable("DB error when getting access token")?; | ||||||
|  |  | ||||||
|         let access_token: Option<types::AccessToken> = maybe_token |         let access_token = maybe_token | ||||||
|             .map(|token| token.parse_struct("AccessToken")) |             .map(|token| token.parse_struct::<types::AccessToken>("AccessToken")) | ||||||
|             .transpose() |             .transpose() | ||||||
|             .change_context(errors::ParsingError::UnknownError) |  | ||||||
|             .change_context(errors::StorageError::DeserializationFailed)?; |             .change_context(errors::StorageError::DeserializationFailed)?; | ||||||
|  |  | ||||||
|         Ok(access_token) |         Ok(access_token) | ||||||
| @ -68,10 +69,11 @@ impl ConnectorAccessToken for Store { | |||||||
|     async fn set_access_token( |     async fn set_access_token( | ||||||
|         &self, |         &self, | ||||||
|         merchant_id: &str, |         merchant_id: &str, | ||||||
|         connector_name: &str, |         merchant_connector_id: &str, | ||||||
|         access_token: types::AccessToken, |         access_token: types::AccessToken, | ||||||
|     ) -> CustomResult<(), errors::StorageError> { |     ) -> CustomResult<(), errors::StorageError> { | ||||||
|         let key = format!("access_token_{merchant_id}_{connector_name}"); |         let key = | ||||||
|  |             common_utils::access_token::create_access_token_key(merchant_id, merchant_connector_id); | ||||||
|         let serialized_access_token = access_token |         let serialized_access_token = access_token | ||||||
|             .encode_to_string_of_json() |             .encode_to_string_of_json() | ||||||
|             .change_context(errors::StorageError::SerializationFailed)?; |             .change_context(errors::StorageError::SerializationFailed)?; | ||||||
| @ -88,7 +90,7 @@ impl ConnectorAccessToken for MockDb { | |||||||
|     async fn get_access_token( |     async fn get_access_token( | ||||||
|         &self, |         &self, | ||||||
|         _merchant_id: &str, |         _merchant_id: &str, | ||||||
|         _connector_name: &str, |         _merchant_connector_id: &str, | ||||||
|     ) -> CustomResult<Option<types::AccessToken>, errors::StorageError> { |     ) -> CustomResult<Option<types::AccessToken>, errors::StorageError> { | ||||||
|         Ok(None) |         Ok(None) | ||||||
|     } |     } | ||||||
| @ -96,7 +98,7 @@ impl ConnectorAccessToken for MockDb { | |||||||
|     async fn set_access_token( |     async fn set_access_token( | ||||||
|         &self, |         &self, | ||||||
|         _merchant_id: &str, |         _merchant_id: &str, | ||||||
|         _connector_name: &str, |         _merchant_connector_id: &str, | ||||||
|         _access_token: types::AccessToken, |         _access_token: types::AccessToken, | ||||||
|     ) -> CustomResult<(), errors::StorageError> { |     ) -> CustomResult<(), errors::StorageError> { | ||||||
|         Ok(()) |         Ok(()) | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Narayan Bhat
					Narayan Bhat