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

refactor: Move trait ConnectorIntegration to crate hyperswitch_interfaces #4946

Merged
merged 7 commits into from
Jun 18, 2024
Merged
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: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions crates/hyperswitch_interfaces/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,28 @@ rust-version.workspace = true
readme = "README.md"
license.workspace = true

[features]
default = ["dummy_connector", "payouts"]
dummy_connector = []
payouts = []

[dependencies]
async-trait = "0.1.79"
bytes = "1.6.0"
dyn-clone = "1.0.17"
http = "0.2.12"
mime = "0.3.17"
once_cell = "1.19.0"
reqwest = "0.11.27"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.115"
thiserror = "1.0.58"
time = "0.3.35"

# First party crates
common_utils = { version = "0.1.0", path = "../common_utils" }
hyperswitch_domain_models = { version = "0.1.0", path = "../hyperswitch_domain_models", default-features = false }
masking = { version = "0.1.0", path = "../masking" }
router_derive = { version = "0.1.0", path = "../router_derive" }
router_env = { version = "0.1.0", path = "../router_env" }
storage_impl = { version = "0.1.0", path = "../storage_impl", default-features = false }
183 changes: 183 additions & 0 deletions crates/hyperswitch_interfaces/src/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
//! API interface

use common_utils::{
errors::CustomResult,
request::{Method, Request, RequestContent},
};
use hyperswitch_domain_models::router_data::{ErrorResponse, RouterData};
use masking::Maskable;
use serde_json::json;

use crate::{
configs::Connectors, errors, events::connector_api_logs::ConnectorEvent, metrics, types,
};

/// type BoxedConnectorIntegration
pub type BoxedConnectorIntegration<'a, T, Req, Resp> =
Box<&'a (dyn ConnectorIntegration<T, Req, Resp> + Send + Sync)>;

/// trait ConnectorIntegrationAny
pub trait ConnectorIntegrationAny<T, Req, Resp>: Send + Sync + 'static {
/// fn get_connector_integration
fn get_connector_integration(&self) -> BoxedConnectorIntegration<'_, T, Req, Resp>;
}

impl<S, T, Req, Resp> ConnectorIntegrationAny<T, Req, Resp> for S
where
S: ConnectorIntegration<T, Req, Resp> + Send + Sync,
{
fn get_connector_integration(&self) -> BoxedConnectorIntegration<'_, T, Req, Resp> {
Box::new(self)
}
}

/// trait ConnectorIntegration
pub trait ConnectorIntegration<T, Req, Resp>: ConnectorIntegrationAny<T, Req, Resp> + Sync {
/// fn get_headers
fn get_headers(
&self,
_req: &RouterData<T, Req, Resp>,
_connectors: &Connectors,
) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
Ok(vec![])
}

/// fn get_content_type
fn get_content_type(&self) -> &'static str {
mime::APPLICATION_JSON.essence_str()
}

/// primarily used when creating signature based on request method of payment flow
fn get_http_method(&self) -> Method {
Method::Post
}

/// fn get_url
fn get_url(
&self,
_req: &RouterData<T, Req, Resp>,
_connectors: &Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Ok(String::new())
}

/// fn get_request_body
fn get_request_body(
&self,
_req: &RouterData<T, Req, Resp>,
_connectors: &Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
Ok(RequestContent::Json(Box::new(json!(r#"{}"#))))
}

/// fn get_request_form_data
fn get_request_form_data(
&self,
_req: &RouterData<T, Req, Resp>,
) -> CustomResult<Option<reqwest::multipart::Form>, errors::ConnectorError> {
Ok(None)
}

/// fn build_request
fn build_request(
&self,
req: &RouterData<T, Req, Resp>,
_connectors: &Connectors,
) -> CustomResult<Option<Request>, errors::ConnectorError> {
metrics::UNIMPLEMENTED_FLOW.add(
&metrics::CONTEXT,
1,
&[metrics::add_attributes("connector", req.connector.clone())],
);
Ok(None)
}

/// fn handle_response
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,
{
event_builder.map(|e| e.set_error(json!({"error": "Not Implemented"})));
Ok(data.clone())
}

/// fn get_error_response
fn get_error_response(
&self,
res: types::Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
event_builder.map(|event| event.set_error(json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code})));
Ok(ErrorResponse::get_not_implemented())
}

/// fn get_5xx_error_response
fn get_5xx_error_response(
&self,
res: types::Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
event_builder.map(|event| event.set_error(json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code})));
let error_message = match res.status_code {
500 => "internal_server_error",
501 => "not_implemented",
502 => "bad_gateway",
503 => "service_unavailable",
504 => "gateway_timeout",
505 => "http_version_not_supported",
506 => "variant_also_negotiates",
507 => "insufficient_storage",
508 => "loop_detected",
510 => "not_extended",
511 => "network_authentication_required",
_ => "unknown_error",
};
Ok(ErrorResponse {
code: res.status_code.to_string(),
message: error_message.to_string(),
reason: String::from_utf8(res.response.to_vec()).ok(),
status_code: res.status_code,
attempt_status: None,
connector_transaction_id: None,
})
}

/// whenever capture sync is implemented at the connector side, this method should be overridden
fn get_multiple_capture_sync_method(
&self,
) -> CustomResult<CaptureSyncMethod, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("multiple capture sync".into()).into())
}

/// fn get_certificate
fn get_certificate(
&self,
_req: &RouterData<T, Req, Resp>,
) -> CustomResult<Option<String>, errors::ConnectorError> {
Ok(None)
}

/// fn get_certificate_key
fn get_certificate_key(
&self,
_req: &RouterData<T, Req, Resp>,
) -> CustomResult<Option<String>, errors::ConnectorError> {
Ok(None)
}
}

/// Sync Methods for multiple captures
#[derive(Debug)]
pub enum CaptureSyncMethod {
/// For syncing multiple captures individually
Individual,
/// For syncing multiple captures together
Bulk,
}
132 changes: 132 additions & 0 deletions crates/hyperswitch_interfaces/src/configs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//! Configs interface
use router_derive;
use serde::Deserialize;
use storage_impl::errors::ApplicationError;

// struct Connectors
#[allow(missing_docs, missing_debug_implementations)]
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct Connectors {
pub aci: ConnectorParams,
#[cfg(feature = "payouts")]
pub adyen: ConnectorParamsWithSecondaryBaseUrl,
pub adyenplatform: ConnectorParams,
#[cfg(not(feature = "payouts"))]
pub adyen: ConnectorParams,
pub airwallex: ConnectorParams,
pub applepay: ConnectorParams,
pub authorizedotnet: ConnectorParams,
pub bambora: ConnectorParams,
pub bankofamerica: ConnectorParams,
pub billwerk: ConnectorParams,
pub bitpay: ConnectorParams,
pub bluesnap: ConnectorParamsWithSecondaryBaseUrl,
pub boku: ConnectorParams,
pub braintree: ConnectorParams,
pub cashtocode: ConnectorParams,
pub checkout: ConnectorParams,
pub coinbase: ConnectorParams,
pub cryptopay: ConnectorParams,
pub cybersource: ConnectorParams,
pub datatrans: ConnectorParams,
pub dlocal: ConnectorParams,
#[cfg(feature = "dummy_connector")]
pub dummyconnector: ConnectorParams,
pub ebanx: ConnectorParams,
pub fiserv: ConnectorParams,
pub forte: ConnectorParams,
pub globalpay: ConnectorParams,
pub globepay: ConnectorParams,
pub gocardless: ConnectorParams,
pub gpayments: ConnectorParams,
pub helcim: ConnectorParams,
pub iatapay: ConnectorParams,
pub klarna: ConnectorParams,
pub mifinity: ConnectorParams,
pub mollie: ConnectorParams,
pub multisafepay: ConnectorParams,
pub netcetera: ConnectorParams,
pub nexinets: ConnectorParams,
pub nmi: ConnectorParams,
pub noon: ConnectorParamsWithModeType,
pub nuvei: ConnectorParams,
pub opayo: ConnectorParams,
pub opennode: ConnectorParams,
pub payeezy: ConnectorParams,
pub payme: ConnectorParams,
pub payone: ConnectorParams,
pub paypal: ConnectorParams,
pub payu: ConnectorParams,
pub placetopay: ConnectorParams,
pub powertranz: ConnectorParams,
pub prophetpay: ConnectorParams,
pub rapyd: ConnectorParams,
pub riskified: ConnectorParams,
pub shift4: ConnectorParams,
pub signifyd: ConnectorParams,
pub square: ConnectorParams,
pub stax: ConnectorParams,
pub stripe: ConnectorParamsWithFileUploadUrl,
pub threedsecureio: ConnectorParams,
pub trustpay: ConnectorParamsWithMoreUrls,
pub tsys: ConnectorParams,
pub volt: ConnectorParams,
pub wise: ConnectorParams,
pub worldline: ConnectorParams,
pub worldpay: ConnectorParams,
pub zen: ConnectorParams,
pub zsl: ConnectorParams,
}

/// struct ConnectorParams
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParams {
/// base url
pub base_url: String,
/// secondary base url
pub secondary_base_url: Option<String>,
}

/// struct ConnectorParamsWithModeType
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParamsWithModeType {
/// base url
pub base_url: String,
/// secondary base url
pub secondary_base_url: Option<String>,
/// Can take values like Test or Live for Noon
pub key_mode: String,
}

/// struct ConnectorParamsWithMoreUrls
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParamsWithMoreUrls {
/// base url
pub base_url: String,
/// base url for bank redirects
pub base_url_bank_redirects: String,
}

/// struct ConnectorParamsWithFileUploadUrl
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParamsWithFileUploadUrl {
/// base url
pub base_url: String,
/// base url for file upload
pub base_url_file_upload: String,
}

/// struct ConnectorParamsWithSecondaryBaseUrl
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParamsWithSecondaryBaseUrl {
/// base url
pub base_url: String,
/// secondary base url
pub secondary_base_url: String,
}
Loading
Loading