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

feat(events): add type info to outgoing requests & maintain structural & PII type info #2956

Merged
merged 28 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
14a9577
feat(events): update connector impl
lsampras Nov 22, 2023
c97c76a
feat(events): remove request logging
lsampras Nov 22, 2023
b7bc837
refactor(events): add request content type
lsampras Nov 22, 2023
a802493
feat(events): update request type for outgoing calls
lsampras Nov 22, 2023
06590e8
feat(events): update request type for outgoing calls for connectors
prasunna09 Nov 28, 2023
7e9be73
Merge remote-tracking branch 'origin/main' into connector_events_v3
lsampras Nov 29, 2023
df6d4f9
fix(connector): fix serialization failures for non-json formats with …
lsampras Dec 2, 2023
37c9081
Merge remote-tracking branch 'origin/main' into connector_events_v3
lsampras Dec 2, 2023
2bf7119
feat(events): add event generation for connector api calls
lsampras Dec 2, 2023
fbe5317
chore(lints): fix spell check lints
lsampras Dec 2, 2023
8d6b967
chore(lints): fix clippy lints
lsampras Dec 3, 2023
d291426
chore(deps): merge origin/main branch
lsampras Dec 8, 2023
e7b3f01
Merge remote-tracking branch 'origin/main' into connector_events_v3
lsampras Dec 8, 2023
b7e6a97
chore(lints): fix hack lints
lsampras Dec 8, 2023
f5dd6b0
fix(postman): fix bankofamerica postman collection json
lsampras Dec 8, 2023
9a9f68a
Merge remote-tracking branch 'origin/main' into connector_events_v3
lsampras Dec 8, 2023
db8c9ff
Merge remote-tracking branch 'origin/main' into connector_events_v3
lsampras Dec 11, 2023
50a2eae
chore(events): strip prefix from flow type
lsampras Dec 11, 2023
b888b85
Merge branch 'main' into connector_events_v3
lsampras Dec 11, 2023
ee3e3f4
chore(events): remove commented code
lsampras Dec 11, 2023
17c1126
fix(events): fix default values for request body
lsampras Dec 12, 2023
aab2e0f
Merge remote-tracking branch 'origin/main' into connector_events_v3
lsampras Dec 12, 2023
d02ee42
chore(deps): bump main branch
lsampras Dec 12, 2023
09abffe
Merge remote-tracking branch 'origin/main' into connector_events_v3
lsampras Dec 12, 2023
71064b1
chore(events): merge main branch
lsampras Dec 12, 2023
73e6ad2
chore(lints): fix hack lints
lsampras Dec 12, 2023
fd43308
Merge remote-tracking branch 'origin/main' into connector_events_v3
lsampras Dec 12, 2023
18f7a33
fix(connector): update connector template
lsampras Dec 12, 2023
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
16 changes: 14 additions & 2 deletions Cargo.lock

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

27 changes: 27 additions & 0 deletions config/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,12 @@ pm_auth_key = "Some_pm_auth_key"
[analytics]
source = "sqlx" # The Analytics source/strategy to be used

[analytics.clickhouse]
username = "" # Clickhouse username
password = "" # Clickhouse password (optional)
host = "" # Clickhouse host in http(s)://<URL>:<PORT> format
database_name = "" # Clickhouse database name

[analytics.sqlx]
username = "db_user" # Analytics DB Username
password = "db_pass" # Analytics DB Password
Expand All @@ -477,6 +483,7 @@ port = 5432 # Analytics DB Port
dbname = "hyperswitch_db" # Name of Database
pool_size = 5 # Number of connections to keep open
connection_timeout = 10 # Timeout for database connection in seconds
queue_strategy = "Fifo" # Add the queue strategy used by the database bb8 client

# Config for KV setup
[kv_config]
Expand All @@ -491,3 +498,23 @@ client_id = "paypal_client_id" # Client ID for PayPal onboarding
client_secret = "paypal_secret_key" # Secret key for PayPal onboarding
partner_id = "paypal_partner_id" # Partner ID for PayPal onboarding
enabled = true # Switch to enable or disable PayPal onboarding

[frm]
enabled = true

[paypal_onboarding]
client_id = "paypal_client_id" # Client ID for PayPal onboarding
client_secret = "paypal_secret_key" # Secret key for PayPal onboarding
partner_id = "paypal_partner_id" # Partner ID for PayPal onboarding
enabled = true # Switch to enable or disable PayPal onboarding

[events]
source = "logs" # The event sink to push events supports kafka or logs (stdout)

[events.kafka]
brokers = [] # Kafka broker urls for bootstrapping the client
intent_analytics_topic = "topic" # Kafka topic to be used for PaymentIntent events
attempt_analytics_topic = "topic" # Kafka topic to be used for PaymentAttempt events
refund_analytics_topic = "topic" # Kafka topic to be used for Refund events
api_logs_topic = "topic" # Kafka topic to be used for incoming api events
connector_logs_topic = "topic" # Kafka topic to be used for connector api events
2 changes: 1 addition & 1 deletion config/docker_compose.toml
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ intent_analytics_topic = "hyperswitch-payment-intent-events"
attempt_analytics_topic = "hyperswitch-payment-attempt-events"
refund_analytics_topic = "hyperswitch-refund-events"
api_logs_topic = "hyperswitch-api-log-events"
connector_events_topic = "hyperswitch-connector-api-events"
lsampras marked this conversation as resolved.
Show resolved Hide resolved
connector_logs_topic = "hyperswitch-connector-api-events"

[analytics]
source = "sqlx"
Expand Down
75 changes: 36 additions & 39 deletions crates/common_utils/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub enum ContentType {
Json,
FormUrlEncoded,
FormData,
Xml,
}

fn default_request_headers() -> [(String, Maskable<String>); 1] {
Expand All @@ -37,12 +38,28 @@ fn default_request_headers() -> [(String, Maskable<String>); 1] {
pub struct Request {
pub url: String,
pub headers: Headers,
pub payload: Option<Secret<String>>,
pub method: Method,
pub content_type: Option<ContentType>,
pub certificate: Option<String>,
pub certificate_key: Option<String>,
pub form_data: Option<reqwest::multipart::Form>,
pub body: Option<RequestContent>,
}

impl std::fmt::Debug for RequestContent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Json(_) => "JsonRequestBody",
Self::FormUrlEncoded(_) => "FormUrlEncodedRequestBody",
Self::FormData(_) => "FormDataRequestBody",
Self::Xml(_) => "XmlRequestBody",
})
}
}

pub enum RequestContent {
Json(Box<dyn masking::ErasedMaskSerialize + Send>),
FormUrlEncoded(Box<dyn masking::ErasedMaskSerialize + Send>),
FormData(reqwest::multipart::Form),
Xml(Box<dyn masking::ErasedMaskSerialize + Send>),
}

impl Request {
Expand All @@ -51,16 +68,14 @@ impl Request {
method,
url: String::from(url),
headers: std::collections::HashSet::new(),
payload: None,
content_type: None,
certificate: None,
certificate_key: None,
form_data: None,
body: None,
}
}

pub fn set_body(&mut self, body: String) {
self.payload = Some(body.into());
pub fn set_body<T: Into<RequestContent>>(&mut self, body: T) {
self.body.replace(body.into());
}

pub fn add_default_headers(&mut self) {
Expand All @@ -71,33 +86,23 @@ impl Request {
self.headers.insert((String::from(header), value));
}

pub fn add_content_type(&mut self, content_type: ContentType) {
self.content_type = Some(content_type);
}

pub fn add_certificate(&mut self, certificate: Option<String>) {
self.certificate = certificate;
}

pub fn add_certificate_key(&mut self, certificate_key: Option<String>) {
self.certificate = certificate_key;
}

pub fn set_form_data(&mut self, form_data: reqwest::multipart::Form) {
self.form_data = Some(form_data);
}
}

#[derive(Debug)]
pub struct RequestBuilder {
pub url: String,
pub headers: Headers,
pub payload: Option<Secret<String>>,
pub method: Method,
pub content_type: Option<ContentType>,
pub certificate: Option<String>,
pub certificate_key: Option<String>,
pub form_data: Option<reqwest::multipart::Form>,
pub body: Option<RequestContent>,
}

impl RequestBuilder {
Expand All @@ -106,11 +111,9 @@ impl RequestBuilder {
method: Method::Get,
url: String::with_capacity(1024),
headers: std::collections::HashSet::new(),
payload: None,
content_type: None,
certificate: None,
certificate_key: None,
form_data: None,
body: None,
}
}

Expand Down Expand Up @@ -140,18 +143,8 @@ impl RequestBuilder {
self
}

pub fn form_data(mut self, form_data: Option<reqwest::multipart::Form>) -> Self {
self.form_data = form_data;
self
}

pub fn body(mut self, option_body: Option<RequestBody>) -> Self {
self.payload = option_body.map(RequestBody::get_inner_value);
self
}

pub fn content_type(mut self, content_type: ContentType) -> Self {
self.content_type = Some(content_type);
pub fn set_body<T: Into<RequestContent>>(mut self, body: T) -> Self {
self.body.replace(body.into());
self
}

Expand All @@ -170,11 +163,9 @@ impl RequestBuilder {
method: self.method,
url: self.url,
headers: self.headers,
payload: self.payload,
content_type: self.content_type,
certificate: self.certificate,
certificate_key: self.certificate_key,
form_data: self.form_data,
body: self.body,
}
}
}
Expand All @@ -201,7 +192,13 @@ impl RequestBody {
logger::info!(connector_request_body=?body);
Ok(Self(Secret::new(encoder(body)?)))
}
pub fn get_inner_value(request_body: Self) -> Secret<String> {
request_body.0

pub fn get_inner_value(request_body: RequestContent) -> Secret<String> {
match request_body {
RequestContent::Json(i)
| RequestContent::FormUrlEncoded(i)
| RequestContent::Xml(i) => serde_json::to_string(&i).unwrap_or_default().into(),
NishantJoshi00 marked this conversation as resolved.
Show resolved Hide resolved
RequestContent::FormData(_) => String::new().into(),
}
}
}
1 change: 1 addition & 0 deletions crates/masking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
bytes = { version = "1", optional = true }
diesel = { version = "2.1.0", features = ["postgres", "serde_json", "time"], optional = true }
erased-serde = "0.3.31"
serde = { version = "1", features = ["derive"], optional = true }
serde_json = { version = "1.0.108", optional = true }
subtle = "=2.4.1"
Expand Down
25 changes: 19 additions & 6 deletions crates/masking/src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! Serde-related.
//!

pub use erased_serde::Serialize as ErasedSerialize;
pub use serde::{de, ser, Deserialize, Serialize, Serializer};
use serde_json::{value::Serializer as JsonValueSerializer, Value};

Expand Down Expand Up @@ -99,20 +100,32 @@ pub fn masked_serialize<T: Serialize>(value: &T) -> Result<Value, serde_json::Er
/// like &dyn Serialize or boxed trait objects like Box<dyn Serialize> because of Rust's "object safety" rules.
/// In particular, the trait contains generic methods which cannot be made into a trait object.
/// In this case we remove the generic for assuming the serialization to be of 2 types only raw json or masked json
pub trait ErasedMaskSerialize {
pub trait ErasedMaskSerialize: ErasedSerialize {
/// Masked serialization.
fn masked_serialize(&self) -> Result<Value, serde_json::Error>;
/// Normal serialization.
fn raw_serialize(&self) -> Result<Value, serde_json::Error>;
}

impl<T: Serialize> ErasedMaskSerialize for T {
impl<T: Serialize + ErasedSerialize> ErasedMaskSerialize for T {
fn masked_serialize(&self) -> Result<Value, serde_json::Error> {
masked_serialize(self)
}
}

impl<'a> Serialize for dyn ErasedMaskSerialize + 'a {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
erased_serde::serialize(self, serializer)
}
}

fn raw_serialize(&self) -> Result<Value, serde_json::Error> {
serde_json::to_value(self)
impl<'a> Serialize for dyn ErasedMaskSerialize + 'a + Send {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
erased_serde::serialize(self, serializer)
}
}

Expand Down
Loading
Loading