Skip to content

Commit cbe3a6d

Browse files
deepanshu-iiituDeepanshu Bansal
andauthored
refactor: Move trait ConnectorIntegration to crate hyperswitch_interfaces (#4946)
Co-authored-by: Deepanshu Bansal <[email protected]>
1 parent a0f3887 commit cbe3a6d

File tree

19 files changed

+635
-509
lines changed

19 files changed

+635
-509
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/hyperswitch_interfaces/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,28 @@ rust-version.workspace = true
66
readme = "README.md"
77
license.workspace = true
88

9+
[features]
10+
default = ["dummy_connector", "payouts"]
11+
dummy_connector = []
12+
payouts = []
13+
914
[dependencies]
1015
async-trait = "0.1.79"
16+
bytes = "1.6.0"
1117
dyn-clone = "1.0.17"
18+
http = "0.2.12"
19+
mime = "0.3.17"
20+
once_cell = "1.19.0"
21+
reqwest = "0.11.27"
1222
serde = { version = "1.0.197", features = ["derive"] }
23+
serde_json = "1.0.115"
1324
thiserror = "1.0.58"
25+
time = "0.3.35"
1426

1527
# First party crates
1628
common_utils = { version = "0.1.0", path = "../common_utils" }
29+
hyperswitch_domain_models = { version = "0.1.0", path = "../hyperswitch_domain_models", default-features = false }
1730
masking = { version = "0.1.0", path = "../masking" }
31+
router_derive = { version = "0.1.0", path = "../router_derive" }
32+
router_env = { version = "0.1.0", path = "../router_env" }
33+
storage_impl = { version = "0.1.0", path = "../storage_impl", default-features = false }
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
//! API interface
2+
3+
use common_utils::{
4+
errors::CustomResult,
5+
request::{Method, Request, RequestContent},
6+
};
7+
use hyperswitch_domain_models::router_data::{ErrorResponse, RouterData};
8+
use masking::Maskable;
9+
use serde_json::json;
10+
11+
use crate::{
12+
configs::Connectors, errors, events::connector_api_logs::ConnectorEvent, metrics, types,
13+
};
14+
15+
/// type BoxedConnectorIntegration
16+
pub type BoxedConnectorIntegration<'a, T, Req, Resp> =
17+
Box<&'a (dyn ConnectorIntegration<T, Req, Resp> + Send + Sync)>;
18+
19+
/// trait ConnectorIntegrationAny
20+
pub trait ConnectorIntegrationAny<T, Req, Resp>: Send + Sync + 'static {
21+
/// fn get_connector_integration
22+
fn get_connector_integration(&self) -> BoxedConnectorIntegration<'_, T, Req, Resp>;
23+
}
24+
25+
impl<S, T, Req, Resp> ConnectorIntegrationAny<T, Req, Resp> for S
26+
where
27+
S: ConnectorIntegration<T, Req, Resp> + Send + Sync,
28+
{
29+
fn get_connector_integration(&self) -> BoxedConnectorIntegration<'_, T, Req, Resp> {
30+
Box::new(self)
31+
}
32+
}
33+
34+
/// trait ConnectorIntegration
35+
pub trait ConnectorIntegration<T, Req, Resp>: ConnectorIntegrationAny<T, Req, Resp> + Sync {
36+
/// fn get_headers
37+
fn get_headers(
38+
&self,
39+
_req: &RouterData<T, Req, Resp>,
40+
_connectors: &Connectors,
41+
) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
42+
Ok(vec![])
43+
}
44+
45+
/// fn get_content_type
46+
fn get_content_type(&self) -> &'static str {
47+
mime::APPLICATION_JSON.essence_str()
48+
}
49+
50+
/// primarily used when creating signature based on request method of payment flow
51+
fn get_http_method(&self) -> Method {
52+
Method::Post
53+
}
54+
55+
/// fn get_url
56+
fn get_url(
57+
&self,
58+
_req: &RouterData<T, Req, Resp>,
59+
_connectors: &Connectors,
60+
) -> CustomResult<String, errors::ConnectorError> {
61+
Ok(String::new())
62+
}
63+
64+
/// fn get_request_body
65+
fn get_request_body(
66+
&self,
67+
_req: &RouterData<T, Req, Resp>,
68+
_connectors: &Connectors,
69+
) -> CustomResult<RequestContent, errors::ConnectorError> {
70+
Ok(RequestContent::Json(Box::new(json!(r#"{}"#))))
71+
}
72+
73+
/// fn get_request_form_data
74+
fn get_request_form_data(
75+
&self,
76+
_req: &RouterData<T, Req, Resp>,
77+
) -> CustomResult<Option<reqwest::multipart::Form>, errors::ConnectorError> {
78+
Ok(None)
79+
}
80+
81+
/// fn build_request
82+
fn build_request(
83+
&self,
84+
req: &RouterData<T, Req, Resp>,
85+
_connectors: &Connectors,
86+
) -> CustomResult<Option<Request>, errors::ConnectorError> {
87+
metrics::UNIMPLEMENTED_FLOW.add(
88+
&metrics::CONTEXT,
89+
1,
90+
&[metrics::add_attributes("connector", req.connector.clone())],
91+
);
92+
Ok(None)
93+
}
94+
95+
/// fn handle_response
96+
fn handle_response(
97+
&self,
98+
data: &RouterData<T, Req, Resp>,
99+
event_builder: Option<&mut ConnectorEvent>,
100+
_res: types::Response,
101+
) -> CustomResult<RouterData<T, Req, Resp>, errors::ConnectorError>
102+
where
103+
T: Clone,
104+
Req: Clone,
105+
Resp: Clone,
106+
{
107+
event_builder.map(|e| e.set_error(json!({"error": "Not Implemented"})));
108+
Ok(data.clone())
109+
}
110+
111+
/// fn get_error_response
112+
fn get_error_response(
113+
&self,
114+
res: types::Response,
115+
event_builder: Option<&mut ConnectorEvent>,
116+
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
117+
event_builder.map(|event| event.set_error(json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code})));
118+
Ok(ErrorResponse::get_not_implemented())
119+
}
120+
121+
/// fn get_5xx_error_response
122+
fn get_5xx_error_response(
123+
&self,
124+
res: types::Response,
125+
event_builder: Option<&mut ConnectorEvent>,
126+
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
127+
event_builder.map(|event| event.set_error(json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code})));
128+
let error_message = match res.status_code {
129+
500 => "internal_server_error",
130+
501 => "not_implemented",
131+
502 => "bad_gateway",
132+
503 => "service_unavailable",
133+
504 => "gateway_timeout",
134+
505 => "http_version_not_supported",
135+
506 => "variant_also_negotiates",
136+
507 => "insufficient_storage",
137+
508 => "loop_detected",
138+
510 => "not_extended",
139+
511 => "network_authentication_required",
140+
_ => "unknown_error",
141+
};
142+
Ok(ErrorResponse {
143+
code: res.status_code.to_string(),
144+
message: error_message.to_string(),
145+
reason: String::from_utf8(res.response.to_vec()).ok(),
146+
status_code: res.status_code,
147+
attempt_status: None,
148+
connector_transaction_id: None,
149+
})
150+
}
151+
152+
/// whenever capture sync is implemented at the connector side, this method should be overridden
153+
fn get_multiple_capture_sync_method(
154+
&self,
155+
) -> CustomResult<CaptureSyncMethod, errors::ConnectorError> {
156+
Err(errors::ConnectorError::NotImplemented("multiple capture sync".into()).into())
157+
}
158+
159+
/// fn get_certificate
160+
fn get_certificate(
161+
&self,
162+
_req: &RouterData<T, Req, Resp>,
163+
) -> CustomResult<Option<String>, errors::ConnectorError> {
164+
Ok(None)
165+
}
166+
167+
/// fn get_certificate_key
168+
fn get_certificate_key(
169+
&self,
170+
_req: &RouterData<T, Req, Resp>,
171+
) -> CustomResult<Option<String>, errors::ConnectorError> {
172+
Ok(None)
173+
}
174+
}
175+
176+
/// Sync Methods for multiple captures
177+
#[derive(Debug)]
178+
pub enum CaptureSyncMethod {
179+
/// For syncing multiple captures individually
180+
Individual,
181+
/// For syncing multiple captures together
182+
Bulk,
183+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
//! Configs interface
2+
use router_derive;
3+
use serde::Deserialize;
4+
use storage_impl::errors::ApplicationError;
5+
6+
// struct Connectors
7+
#[allow(missing_docs, missing_debug_implementations)]
8+
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
9+
#[serde(default)]
10+
pub struct Connectors {
11+
pub aci: ConnectorParams,
12+
#[cfg(feature = "payouts")]
13+
pub adyen: ConnectorParamsWithSecondaryBaseUrl,
14+
pub adyenplatform: ConnectorParams,
15+
#[cfg(not(feature = "payouts"))]
16+
pub adyen: ConnectorParams,
17+
pub airwallex: ConnectorParams,
18+
pub applepay: ConnectorParams,
19+
pub authorizedotnet: ConnectorParams,
20+
pub bambora: ConnectorParams,
21+
pub bankofamerica: ConnectorParams,
22+
pub billwerk: ConnectorParams,
23+
pub bitpay: ConnectorParams,
24+
pub bluesnap: ConnectorParamsWithSecondaryBaseUrl,
25+
pub boku: ConnectorParams,
26+
pub braintree: ConnectorParams,
27+
pub cashtocode: ConnectorParams,
28+
pub checkout: ConnectorParams,
29+
pub coinbase: ConnectorParams,
30+
pub cryptopay: ConnectorParams,
31+
pub cybersource: ConnectorParams,
32+
pub datatrans: ConnectorParams,
33+
pub dlocal: ConnectorParams,
34+
#[cfg(feature = "dummy_connector")]
35+
pub dummyconnector: ConnectorParams,
36+
pub ebanx: ConnectorParams,
37+
pub fiserv: ConnectorParams,
38+
pub forte: ConnectorParams,
39+
pub globalpay: ConnectorParams,
40+
pub globepay: ConnectorParams,
41+
pub gocardless: ConnectorParams,
42+
pub gpayments: ConnectorParams,
43+
pub helcim: ConnectorParams,
44+
pub iatapay: ConnectorParams,
45+
pub klarna: ConnectorParams,
46+
pub mifinity: ConnectorParams,
47+
pub mollie: ConnectorParams,
48+
pub multisafepay: ConnectorParams,
49+
pub netcetera: ConnectorParams,
50+
pub nexinets: ConnectorParams,
51+
pub nmi: ConnectorParams,
52+
pub noon: ConnectorParamsWithModeType,
53+
pub nuvei: ConnectorParams,
54+
pub opayo: ConnectorParams,
55+
pub opennode: ConnectorParams,
56+
pub payeezy: ConnectorParams,
57+
pub payme: ConnectorParams,
58+
pub payone: ConnectorParams,
59+
pub paypal: ConnectorParams,
60+
pub payu: ConnectorParams,
61+
pub placetopay: ConnectorParams,
62+
pub powertranz: ConnectorParams,
63+
pub prophetpay: ConnectorParams,
64+
pub rapyd: ConnectorParams,
65+
pub riskified: ConnectorParams,
66+
pub shift4: ConnectorParams,
67+
pub signifyd: ConnectorParams,
68+
pub square: ConnectorParams,
69+
pub stax: ConnectorParams,
70+
pub stripe: ConnectorParamsWithFileUploadUrl,
71+
pub threedsecureio: ConnectorParams,
72+
pub trustpay: ConnectorParamsWithMoreUrls,
73+
pub tsys: ConnectorParams,
74+
pub volt: ConnectorParams,
75+
pub wise: ConnectorParams,
76+
pub worldline: ConnectorParams,
77+
pub worldpay: ConnectorParams,
78+
pub zen: ConnectorParams,
79+
pub zsl: ConnectorParams,
80+
}
81+
82+
/// struct ConnectorParams
83+
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
84+
#[serde(default)]
85+
pub struct ConnectorParams {
86+
/// base url
87+
pub base_url: String,
88+
/// secondary base url
89+
pub secondary_base_url: Option<String>,
90+
}
91+
92+
/// struct ConnectorParamsWithModeType
93+
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
94+
#[serde(default)]
95+
pub struct ConnectorParamsWithModeType {
96+
/// base url
97+
pub base_url: String,
98+
/// secondary base url
99+
pub secondary_base_url: Option<String>,
100+
/// Can take values like Test or Live for Noon
101+
pub key_mode: String,
102+
}
103+
104+
/// struct ConnectorParamsWithMoreUrls
105+
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
106+
#[serde(default)]
107+
pub struct ConnectorParamsWithMoreUrls {
108+
/// base url
109+
pub base_url: String,
110+
/// base url for bank redirects
111+
pub base_url_bank_redirects: String,
112+
}
113+
114+
/// struct ConnectorParamsWithFileUploadUrl
115+
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
116+
#[serde(default)]
117+
pub struct ConnectorParamsWithFileUploadUrl {
118+
/// base url
119+
pub base_url: String,
120+
/// base url for file upload
121+
pub base_url_file_upload: String,
122+
}
123+
124+
/// struct ConnectorParamsWithSecondaryBaseUrl
125+
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
126+
#[serde(default)]
127+
pub struct ConnectorParamsWithSecondaryBaseUrl {
128+
/// base url
129+
pub base_url: String,
130+
/// secondary base url
131+
pub secondary_base_url: String,
132+
}

0 commit comments

Comments
 (0)