mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +08:00
Co-authored-by: Prajjwal kumar <write2prajjwal@gmail.com> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: Prajjwal Kumar <prajjwal.kumar@juspay.in>
835 lines
30 KiB
Rust
835 lines
30 KiB
Rust
use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId};
|
|
use common_enums::PaymentAction;
|
|
use common_utils::{crypto, errors::CustomResult, request::Request};
|
|
use hyperswitch_domain_models::{
|
|
api::ApplicationResponse,
|
|
connector_endpoints::Connectors,
|
|
errors::api_error_response::ApiErrorResponse,
|
|
payment_method_data::PaymentMethodData,
|
|
router_data::{ConnectorAuthType, ErrorResponse, RouterData},
|
|
router_data_v2::RouterDataV2,
|
|
router_response_types::{ConnectorInfo, SupportedPaymentMethods},
|
|
};
|
|
|
|
use crate::{
|
|
api,
|
|
api::{
|
|
BoxedConnectorIntegration, CaptureSyncMethod, Connector, ConnectorCommon,
|
|
ConnectorIntegration, ConnectorRedirectResponse, ConnectorSpecifications,
|
|
ConnectorValidation, CurrencyUnit,
|
|
},
|
|
authentication::ExternalAuthenticationPayload,
|
|
connector_integration_v2::{BoxedConnectorIntegrationV2, ConnectorIntegrationV2, ConnectorV2},
|
|
disputes, errors,
|
|
events::connector_api_logs::ConnectorEvent,
|
|
types,
|
|
webhooks::{IncomingWebhook, IncomingWebhookFlowError, IncomingWebhookRequestDetails},
|
|
};
|
|
|
|
/// RouterDataConversion trait
|
|
///
|
|
/// This trait must be implemented for conversion between Router data and RouterDataV2
|
|
pub trait RouterDataConversion<T, Req: Clone, Resp: Clone> {
|
|
/// Convert RouterData to RouterDataV2
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `old_router_data` - A reference to the old RouterData
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// A `CustomResult` containing the new RouterDataV2 or a ConnectorError
|
|
fn from_old_router_data(
|
|
old_router_data: &RouterData<T, Req, Resp>,
|
|
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, errors::ConnectorError>
|
|
where
|
|
Self: Sized;
|
|
/// Convert RouterDataV2 back to RouterData
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `new_router_data` - The new RouterDataV2
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// A `CustomResult` containing the old RouterData or a ConnectorError
|
|
fn to_old_router_data(
|
|
new_router_data: RouterDataV2<T, Self, Req, Resp>,
|
|
) -> CustomResult<RouterData<T, Req, Resp>, errors::ConnectorError>
|
|
where
|
|
Self: Sized;
|
|
}
|
|
/// Alias for Box<&'static (dyn Connector + Sync)>
|
|
pub type BoxedConnector = Box<&'static (dyn Connector + Sync)>;
|
|
/// Alias for Box<&'static (dyn ConnectorV2 + Sync)>
|
|
pub type BoxedConnectorV2 = Box<&'static (dyn ConnectorV2 + Sync)>;
|
|
|
|
/// Enum representing the Connector
|
|
#[derive(Clone)]
|
|
pub enum ConnectorEnum {
|
|
/// Old connector type
|
|
Old(BoxedConnector),
|
|
/// New connector type
|
|
New(BoxedConnectorV2),
|
|
}
|
|
|
|
impl std::fmt::Debug for ConnectorEnum {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::Old(_) => f
|
|
.debug_tuple("Old")
|
|
.field(&std::any::type_name::<BoxedConnector>().to_string())
|
|
.finish(),
|
|
Self::New(_) => f
|
|
.debug_tuple("New")
|
|
.field(&std::any::type_name::<BoxedConnectorV2>().to_string())
|
|
.finish(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(missing_debug_implementations)]
|
|
/// Enum representing the Connector Integration
|
|
#[derive(Clone)]
|
|
pub enum ConnectorIntegrationEnum<'a, F, ResourceCommonData, Req, Resp> {
|
|
/// Old connector integration type
|
|
Old(BoxedConnectorIntegration<'a, F, Req, Resp>),
|
|
/// New connector integration type
|
|
New(BoxedConnectorIntegrationV2<'a, F, ResourceCommonData, Req, Resp>),
|
|
}
|
|
|
|
/// Alias for Box<dyn ConnectorIntegrationInterface>
|
|
pub type BoxedConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp> =
|
|
Box<dyn ConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp> + Send + Sync>;
|
|
|
|
impl ConnectorEnum {
|
|
/// Get the connector integration
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// A `BoxedConnectorIntegrationInterface` containing the connector integration
|
|
pub fn get_connector_integration<F, ResourceCommonData, Req, Resp>(
|
|
&self,
|
|
) -> BoxedConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>
|
|
where
|
|
dyn Connector + Sync: ConnectorIntegration<F, Req, Resp>,
|
|
dyn ConnectorV2 + Sync: ConnectorIntegrationV2<F, ResourceCommonData, Req, Resp>,
|
|
ResourceCommonData: RouterDataConversion<F, Req, Resp> + Clone + 'static,
|
|
F: Clone + 'static,
|
|
Req: Clone + 'static,
|
|
Resp: Clone + 'static,
|
|
{
|
|
match self {
|
|
Self::Old(old_integration) => Box::new(ConnectorIntegrationEnum::Old(
|
|
old_integration.get_connector_integration(),
|
|
)),
|
|
Self::New(new_integration) => Box::new(ConnectorIntegrationEnum::New(
|
|
new_integration.get_connector_integration_v2(),
|
|
)),
|
|
}
|
|
}
|
|
/// validates the file upload
|
|
pub fn validate_file_upload(
|
|
&self,
|
|
purpose: api::files::FilePurpose,
|
|
file_size: i32,
|
|
file_type: mime::Mime,
|
|
) -> CustomResult<(), errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.validate_file_upload(purpose, file_size, file_type),
|
|
Self::New(connector) => {
|
|
connector.validate_file_upload_v2(purpose, file_size, file_type)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl IncomingWebhook for ConnectorEnum {
|
|
fn get_webhook_body_decoding_algorithm(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<Box<dyn crypto::DecodeMessage + Send>, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_webhook_body_decoding_algorithm(request),
|
|
Self::New(connector) => connector.get_webhook_body_decoding_algorithm(request),
|
|
}
|
|
}
|
|
|
|
fn get_webhook_body_decoding_message(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_webhook_body_decoding_message(request),
|
|
Self::New(connector) => connector.get_webhook_body_decoding_message(request),
|
|
}
|
|
}
|
|
|
|
async fn decode_webhook_body(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
merchant_id: &common_utils::id_type::MerchantId,
|
|
connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
|
|
connector_name: &str,
|
|
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => {
|
|
connector
|
|
.decode_webhook_body(
|
|
request,
|
|
merchant_id,
|
|
connector_webhook_details,
|
|
connector_name,
|
|
)
|
|
.await
|
|
}
|
|
Self::New(connector) => {
|
|
connector
|
|
.decode_webhook_body(
|
|
request,
|
|
merchant_id,
|
|
connector_webhook_details,
|
|
connector_name,
|
|
)
|
|
.await
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_webhook_source_verification_algorithm(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_webhook_source_verification_algorithm(request),
|
|
Self::New(connector) => connector.get_webhook_source_verification_algorithm(request),
|
|
}
|
|
}
|
|
|
|
async fn get_webhook_source_verification_merchant_secret(
|
|
&self,
|
|
merchant_id: &common_utils::id_type::MerchantId,
|
|
connector_name: &str,
|
|
connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
|
|
) -> CustomResult<api_models::webhooks::ConnectorWebhookSecrets, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => {
|
|
connector
|
|
.get_webhook_source_verification_merchant_secret(
|
|
merchant_id,
|
|
connector_name,
|
|
connector_webhook_details,
|
|
)
|
|
.await
|
|
}
|
|
Self::New(connector) => {
|
|
connector
|
|
.get_webhook_source_verification_merchant_secret(
|
|
merchant_id,
|
|
connector_name,
|
|
connector_webhook_details,
|
|
)
|
|
.await
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_webhook_source_verification_signature(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
|
|
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector
|
|
.get_webhook_source_verification_signature(request, connector_webhook_secrets),
|
|
Self::New(connector) => connector
|
|
.get_webhook_source_verification_signature(request, connector_webhook_secrets),
|
|
}
|
|
}
|
|
|
|
fn get_webhook_source_verification_message(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
merchant_id: &common_utils::id_type::MerchantId,
|
|
connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
|
|
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_webhook_source_verification_message(
|
|
request,
|
|
merchant_id,
|
|
connector_webhook_secrets,
|
|
),
|
|
Self::New(connector) => connector.get_webhook_source_verification_message(
|
|
request,
|
|
merchant_id,
|
|
connector_webhook_secrets,
|
|
),
|
|
}
|
|
}
|
|
|
|
async fn verify_webhook_source(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
merchant_id: &common_utils::id_type::MerchantId,
|
|
connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
|
|
connector_account_details: crypto::Encryptable<masking::Secret<serde_json::Value>>,
|
|
connector_name: &str,
|
|
) -> CustomResult<bool, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => {
|
|
connector
|
|
.verify_webhook_source(
|
|
request,
|
|
merchant_id,
|
|
connector_webhook_details,
|
|
connector_account_details,
|
|
connector_name,
|
|
)
|
|
.await
|
|
}
|
|
Self::New(connector) => {
|
|
connector
|
|
.verify_webhook_source(
|
|
request,
|
|
merchant_id,
|
|
connector_webhook_details,
|
|
connector_account_details,
|
|
connector_name,
|
|
)
|
|
.await
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_webhook_object_reference_id(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<ObjectReferenceId, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_webhook_object_reference_id(request),
|
|
Self::New(connector) => connector.get_webhook_object_reference_id(request),
|
|
}
|
|
}
|
|
|
|
fn get_webhook_event_type(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_webhook_event_type(request),
|
|
Self::New(connector) => connector.get_webhook_event_type(request),
|
|
}
|
|
}
|
|
|
|
fn get_webhook_resource_object(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_webhook_resource_object(request),
|
|
Self::New(connector) => connector.get_webhook_resource_object(request),
|
|
}
|
|
}
|
|
|
|
fn get_webhook_api_response(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
error_kind: Option<IncomingWebhookFlowError>,
|
|
) -> CustomResult<ApplicationResponse<serde_json::Value>, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_webhook_api_response(request, error_kind),
|
|
Self::New(connector) => connector.get_webhook_api_response(request, error_kind),
|
|
}
|
|
}
|
|
|
|
fn get_dispute_details(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<disputes::DisputePayload, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_dispute_details(request),
|
|
Self::New(connector) => connector.get_dispute_details(request),
|
|
}
|
|
}
|
|
|
|
fn get_external_authentication_details(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<ExternalAuthenticationPayload, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_external_authentication_details(request),
|
|
Self::New(connector) => connector.get_external_authentication_details(request),
|
|
}
|
|
}
|
|
|
|
fn get_mandate_details(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<
|
|
Option<hyperswitch_domain_models::router_flow_types::ConnectorMandateDetails>,
|
|
errors::ConnectorError,
|
|
> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_mandate_details(request),
|
|
Self::New(connector) => connector.get_mandate_details(request),
|
|
}
|
|
}
|
|
|
|
fn get_network_txn_id(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<
|
|
Option<hyperswitch_domain_models::router_flow_types::ConnectorNetworkTxnId>,
|
|
errors::ConnectorError,
|
|
> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_network_txn_id(request),
|
|
Self::New(connector) => connector.get_network_txn_id(request),
|
|
}
|
|
}
|
|
|
|
#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
|
|
fn get_revenue_recovery_invoice_details(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<
|
|
hyperswitch_domain_models::revenue_recovery::RevenueRecoveryInvoiceData,
|
|
errors::ConnectorError,
|
|
> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_revenue_recovery_invoice_details(request),
|
|
Self::New(connector) => connector.get_revenue_recovery_invoice_details(request),
|
|
}
|
|
}
|
|
|
|
#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
|
|
fn get_revenue_recovery_attempt_details(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<
|
|
hyperswitch_domain_models::revenue_recovery::RevenueRecoveryAttemptData,
|
|
errors::ConnectorError,
|
|
> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_revenue_recovery_attempt_details(request),
|
|
Self::New(connector) => connector.get_revenue_recovery_attempt_details(request),
|
|
}
|
|
}
|
|
fn get_subscription_mit_payment_data(
|
|
&self,
|
|
request: &IncomingWebhookRequestDetails<'_>,
|
|
) -> CustomResult<
|
|
hyperswitch_domain_models::router_flow_types::SubscriptionMitPaymentData,
|
|
errors::ConnectorError,
|
|
> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_subscription_mit_payment_data(request),
|
|
Self::New(connector) => connector.get_subscription_mit_payment_data(request),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ConnectorRedirectResponse for ConnectorEnum {
|
|
fn get_flow_type(
|
|
&self,
|
|
query_params: &str,
|
|
json_payload: Option<serde_json::Value>,
|
|
action: PaymentAction,
|
|
) -> CustomResult<common_enums::CallConnectorAction, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_flow_type(query_params, json_payload, action),
|
|
Self::New(connector) => connector.get_flow_type(query_params, json_payload, action),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ConnectorValidation for ConnectorEnum {
|
|
fn validate_connector_against_payment_request(
|
|
&self,
|
|
capture_method: Option<common_enums::CaptureMethod>,
|
|
payment_method: common_enums::PaymentMethod,
|
|
pmt: Option<common_enums::PaymentMethodType>,
|
|
) -> CustomResult<(), errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.validate_connector_against_payment_request(
|
|
capture_method,
|
|
payment_method,
|
|
pmt,
|
|
),
|
|
Self::New(connector) => connector.validate_connector_against_payment_request(
|
|
capture_method,
|
|
payment_method,
|
|
pmt,
|
|
),
|
|
}
|
|
}
|
|
|
|
fn validate_mandate_payment(
|
|
&self,
|
|
pm_type: Option<common_enums::PaymentMethodType>,
|
|
pm_data: PaymentMethodData,
|
|
) -> CustomResult<(), errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.validate_mandate_payment(pm_type, pm_data),
|
|
Self::New(connector) => connector.validate_mandate_payment(pm_type, pm_data),
|
|
}
|
|
}
|
|
|
|
fn validate_psync_reference_id(
|
|
&self,
|
|
data: &hyperswitch_domain_models::router_request_types::PaymentsSyncData,
|
|
is_three_ds: bool,
|
|
status: common_enums::enums::AttemptStatus,
|
|
connector_meta_data: Option<common_utils::pii::SecretSerdeValue>,
|
|
) -> CustomResult<(), errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.validate_psync_reference_id(
|
|
data,
|
|
is_three_ds,
|
|
status,
|
|
connector_meta_data,
|
|
),
|
|
Self::New(connector) => connector.validate_psync_reference_id(
|
|
data,
|
|
is_three_ds,
|
|
status,
|
|
connector_meta_data,
|
|
),
|
|
}
|
|
}
|
|
|
|
fn is_webhook_source_verification_mandatory(&self) -> bool {
|
|
match self {
|
|
Self::Old(connector) => connector.is_webhook_source_verification_mandatory(),
|
|
Self::New(connector) => connector.is_webhook_source_verification_mandatory(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ConnectorSpecifications for ConnectorEnum {
|
|
fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_supported_payment_methods(),
|
|
Self::New(connector) => connector.get_supported_payment_methods(),
|
|
}
|
|
}
|
|
|
|
/// Supported webhooks flows
|
|
fn get_supported_webhook_flows(&self) -> Option<&'static [common_enums::EventClass]> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_supported_webhook_flows(),
|
|
Self::New(connector) => connector.get_supported_webhook_flows(),
|
|
}
|
|
}
|
|
|
|
/// Details related to connector
|
|
fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_connector_about(),
|
|
Self::New(connector) => connector.get_connector_about(),
|
|
}
|
|
}
|
|
|
|
/// Check if connector supports authentication token
|
|
fn authentication_token_for_token_creation(&self) -> bool {
|
|
match self {
|
|
Self::Old(connector) => connector.authentication_token_for_token_creation(),
|
|
Self::New(connector) => connector.authentication_token_for_token_creation(),
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "v1")]
|
|
fn generate_connector_request_reference_id(
|
|
&self,
|
|
payment_intent: &hyperswitch_domain_models::payments::PaymentIntent,
|
|
payment_attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
|
|
is_config_enabled_to_send_payment_id_as_connector_request_id: bool,
|
|
) -> String {
|
|
match self {
|
|
Self::Old(connector) => connector.generate_connector_request_reference_id(
|
|
payment_intent,
|
|
payment_attempt,
|
|
is_config_enabled_to_send_payment_id_as_connector_request_id,
|
|
),
|
|
Self::New(connector) => connector.generate_connector_request_reference_id(
|
|
payment_intent,
|
|
payment_attempt,
|
|
is_config_enabled_to_send_payment_id_as_connector_request_id,
|
|
),
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "v2")]
|
|
/// Generate connector request reference ID
|
|
fn generate_connector_request_reference_id(
|
|
&self,
|
|
payment_intent: &hyperswitch_domain_models::payments::PaymentIntent,
|
|
payment_attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
|
|
) -> String {
|
|
match self {
|
|
Self::Old(connector) => {
|
|
connector.generate_connector_request_reference_id(payment_intent, payment_attempt)
|
|
}
|
|
Self::New(connector) => {
|
|
connector.generate_connector_request_reference_id(payment_intent, payment_attempt)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Check if connector requires create customer call
|
|
fn should_call_connector_customer(
|
|
&self,
|
|
payment_attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
|
|
) -> bool {
|
|
match self {
|
|
Self::Old(connector) => connector.should_call_connector_customer(payment_attempt),
|
|
Self::New(connector) => connector.should_call_connector_customer(payment_attempt),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ConnectorCommon for ConnectorEnum {
|
|
fn id(&self) -> &'static str {
|
|
match self {
|
|
Self::Old(connector) => connector.id(),
|
|
Self::New(connector) => connector.id(),
|
|
}
|
|
}
|
|
|
|
fn get_currency_unit(&self) -> CurrencyUnit {
|
|
match self {
|
|
Self::Old(connector) => connector.get_currency_unit(),
|
|
Self::New(connector) => connector.get_currency_unit(),
|
|
}
|
|
}
|
|
|
|
fn get_auth_header(
|
|
&self,
|
|
auth_type: &ConnectorAuthType,
|
|
) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.get_auth_header(auth_type),
|
|
Self::New(connector) => connector.get_auth_header(auth_type),
|
|
}
|
|
}
|
|
|
|
fn common_get_content_type(&self) -> &'static str {
|
|
match self {
|
|
Self::Old(connector) => connector.common_get_content_type(),
|
|
Self::New(connector) => connector.common_get_content_type(),
|
|
}
|
|
}
|
|
|
|
fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
|
|
match self {
|
|
Self::Old(connector) => connector.base_url(connectors),
|
|
Self::New(connector) => connector.base_url(connectors),
|
|
}
|
|
}
|
|
|
|
fn build_error_response(
|
|
&self,
|
|
res: types::Response,
|
|
event_builder: Option<&mut ConnectorEvent>,
|
|
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
|
match self {
|
|
Self::Old(connector) => connector.build_error_response(res, event_builder),
|
|
Self::New(connector) => connector.build_error_response(res, event_builder),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Trait representing the connector integration interface
|
|
///
|
|
/// This trait defines the methods required for a connector integration interface.
|
|
pub trait ConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>: Send + Sync {
|
|
/// Clone the connector integration interface
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// A `Box` containing the cloned connector integration interface
|
|
fn clone_box(
|
|
&self,
|
|
) -> Box<dyn ConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp> + Send + Sync>;
|
|
/// Get the multiple capture sync method
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// A `CustomResult` containing the `CaptureSyncMethod` or a `ConnectorError`
|
|
fn get_multiple_capture_sync_method(
|
|
&self,
|
|
) -> CustomResult<CaptureSyncMethod, errors::ConnectorError>;
|
|
/// Build a request for the connector integration
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `req` - A reference to the RouterData
|
|
/// # Returns
|
|
///
|
|
/// A `CustomResult` containing an optional Request or a ConnectorError
|
|
fn build_request(
|
|
&self,
|
|
req: &RouterData<F, Req, Resp>,
|
|
_connectors: &Connectors,
|
|
) -> CustomResult<Option<Request>, errors::ConnectorError>;
|
|
/// handles response from the connector
|
|
fn handle_response(
|
|
&self,
|
|
data: &RouterData<F, Req, Resp>,
|
|
event_builder: Option<&mut ConnectorEvent>,
|
|
_res: types::Response,
|
|
) -> CustomResult<RouterData<F, Req, Resp>, errors::ConnectorError>
|
|
where
|
|
F: Clone,
|
|
Req: Clone,
|
|
Resp: Clone;
|
|
/// Get the error response
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `res` - The response
|
|
/// * `event_builder` - An optional event builder
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// A `CustomResult` containing the `ErrorResponse` or a `ConnectorError`
|
|
fn get_error_response(
|
|
&self,
|
|
res: types::Response,
|
|
event_builder: Option<&mut ConnectorEvent>,
|
|
) -> CustomResult<ErrorResponse, errors::ConnectorError>;
|
|
/// Get the 5xx error response
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `res` - The response
|
|
/// * `event_builder` - An optional event builder
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// A `CustomResult` containing the `ErrorResponse` or a `ConnectorError`
|
|
fn get_5xx_error_response(
|
|
&self,
|
|
res: types::Response,
|
|
event_builder: Option<&mut ConnectorEvent>,
|
|
) -> CustomResult<ErrorResponse, errors::ConnectorError>;
|
|
}
|
|
|
|
impl<T: 'static, ResourceCommonData: 'static, Req: 'static, Resp: 'static>
|
|
ConnectorIntegrationInterface<T, ResourceCommonData, Req, Resp>
|
|
for ConnectorIntegrationEnum<'static, T, ResourceCommonData, Req, Resp>
|
|
where
|
|
ResourceCommonData: RouterDataConversion<T, Req, Resp> + Clone,
|
|
T: Clone,
|
|
Req: Clone,
|
|
Resp: Clone,
|
|
{
|
|
fn get_multiple_capture_sync_method(
|
|
&self,
|
|
) -> CustomResult<CaptureSyncMethod, errors::ConnectorError> {
|
|
match self {
|
|
ConnectorIntegrationEnum::Old(old_integration) => {
|
|
old_integration.get_multiple_capture_sync_method()
|
|
}
|
|
ConnectorIntegrationEnum::New(new_integration) => {
|
|
new_integration.get_multiple_capture_sync_method()
|
|
}
|
|
}
|
|
}
|
|
fn build_request(
|
|
&self,
|
|
req: &RouterData<T, Req, Resp>,
|
|
connectors: &Connectors,
|
|
) -> CustomResult<Option<Request>, errors::ConnectorError> {
|
|
match self {
|
|
ConnectorIntegrationEnum::Old(old_integration) => {
|
|
old_integration.build_request(req, connectors)
|
|
}
|
|
ConnectorIntegrationEnum::New(new_integration) => {
|
|
let new_router_data = ResourceCommonData::from_old_router_data(req)?;
|
|
new_integration.build_request_v2(&new_router_data)
|
|
}
|
|
}
|
|
}
|
|
fn handle_response(
|
|
&self,
|
|
data: &RouterData<T, Req, Resp>,
|
|
event_builder: Option<&mut ConnectorEvent>,
|
|
res: types::Response,
|
|
) -> CustomResult<RouterData<T, Req, Resp>, errors::ConnectorError>
|
|
where
|
|
T: Clone,
|
|
Req: Clone,
|
|
Resp: Clone,
|
|
{
|
|
match self {
|
|
ConnectorIntegrationEnum::Old(old_integration) => {
|
|
old_integration.handle_response(data, event_builder, res)
|
|
}
|
|
ConnectorIntegrationEnum::New(new_integration) => {
|
|
let new_router_data = ResourceCommonData::from_old_router_data(data)?;
|
|
new_integration
|
|
.handle_response_v2(&new_router_data, event_builder, res)
|
|
.map(ResourceCommonData::to_old_router_data)?
|
|
}
|
|
}
|
|
}
|
|
fn get_error_response(
|
|
&self,
|
|
res: types::Response,
|
|
event_builder: Option<&mut ConnectorEvent>,
|
|
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
|
match self {
|
|
ConnectorIntegrationEnum::Old(old_integration) => {
|
|
old_integration.get_error_response(res, event_builder)
|
|
}
|
|
ConnectorIntegrationEnum::New(new_integration) => {
|
|
new_integration.get_error_response_v2(res, event_builder)
|
|
}
|
|
}
|
|
}
|
|
fn get_5xx_error_response(
|
|
&self,
|
|
res: types::Response,
|
|
event_builder: Option<&mut ConnectorEvent>,
|
|
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
|
match self {
|
|
ConnectorIntegrationEnum::Old(old_integration) => {
|
|
old_integration.get_5xx_error_response(res, event_builder)
|
|
}
|
|
ConnectorIntegrationEnum::New(new_integration) => {
|
|
new_integration.get_5xx_error_response(res, event_builder)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn clone_box(
|
|
&self,
|
|
) -> Box<dyn ConnectorIntegrationInterface<T, ResourceCommonData, Req, Resp> + Send + Sync>
|
|
{
|
|
Box::new(self.clone())
|
|
}
|
|
}
|
|
|
|
impl api::ConnectorTransactionId for ConnectorEnum {
|
|
/// Get the connector transaction ID
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `payment_attempt` - The payment attempt
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// A `Result` containing an optional transaction ID or an ApiErrorResponse
|
|
fn connector_transaction_id(
|
|
&self,
|
|
payment_attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
|
|
) -> Result<Option<String>, ApiErrorResponse> {
|
|
match self {
|
|
Self::Old(connector) => connector.connector_transaction_id(payment_attempt),
|
|
Self::New(connector) => connector.connector_transaction_id(payment_attempt),
|
|
}
|
|
}
|
|
}
|