mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 19:42:27 +08:00
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com>
365 lines
10 KiB
Rust
365 lines
10 KiB
Rust
pub mod address;
|
|
pub mod api_keys;
|
|
pub mod authentication;
|
|
pub mod authorization;
|
|
pub mod blocklist;
|
|
pub mod blocklist_fingerprint;
|
|
pub mod blocklist_lookup;
|
|
pub mod business_profile;
|
|
pub mod capture;
|
|
pub mod cards_info;
|
|
pub mod configs;
|
|
pub mod customers;
|
|
pub mod dashboard_metadata;
|
|
pub mod dispute;
|
|
pub mod ephemeral_key;
|
|
pub mod events;
|
|
pub mod file;
|
|
pub mod fraud_check;
|
|
pub mod generic_link;
|
|
pub mod gsm;
|
|
pub mod health_check;
|
|
pub mod kafka_store;
|
|
pub mod locker_mock_up;
|
|
pub mod mandate;
|
|
pub mod merchant_account;
|
|
pub mod merchant_connector_account;
|
|
pub mod merchant_key_store;
|
|
pub mod organization;
|
|
pub mod payment_link;
|
|
pub mod payment_method;
|
|
pub mod refund;
|
|
pub mod reverse_lookup;
|
|
pub mod role;
|
|
pub mod routing_algorithm;
|
|
pub mod user;
|
|
pub mod user_authentication_method;
|
|
pub mod user_key_store;
|
|
pub mod user_role;
|
|
use common_utils::id_type;
|
|
use diesel_models::{
|
|
fraud_check::{FraudCheck, FraudCheckUpdate},
|
|
organization::{Organization, OrganizationNew, OrganizationUpdate},
|
|
};
|
|
use error_stack::ResultExt;
|
|
use hyperswitch_domain_models::payments::{
|
|
payment_attempt::PaymentAttemptInterface, payment_intent::PaymentIntentInterface,
|
|
};
|
|
#[cfg(feature = "payouts")]
|
|
use hyperswitch_domain_models::payouts::{
|
|
payout_attempt::PayoutAttemptInterface, payouts::PayoutsInterface,
|
|
};
|
|
#[cfg(not(feature = "payouts"))]
|
|
use hyperswitch_domain_models::{PayoutAttemptInterface, PayoutsInterface};
|
|
use masking::PeekInterface;
|
|
use redis_interface::errors::RedisError;
|
|
use router_env::logger;
|
|
use storage_impl::{errors::StorageError, redis::kv_store::RedisConnInterface, MockDb};
|
|
|
|
pub use self::kafka_store::KafkaStore;
|
|
use self::{fraud_check::FraudCheckInterface, organization::OrganizationInterface};
|
|
pub use crate::{
|
|
core::errors::{self, ProcessTrackerError},
|
|
errors::CustomResult,
|
|
services::{
|
|
kafka::{KafkaError, KafkaProducer, MQResult},
|
|
Store,
|
|
},
|
|
types::{
|
|
domain,
|
|
storage::{self},
|
|
AccessToken,
|
|
},
|
|
};
|
|
|
|
#[derive(PartialEq, Eq)]
|
|
pub enum StorageImpl {
|
|
Postgresql,
|
|
PostgresqlTest,
|
|
Mock,
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
pub trait StorageInterface:
|
|
Send
|
|
+ Sync
|
|
+ dyn_clone::DynClone
|
|
+ address::AddressInterface
|
|
+ api_keys::ApiKeyInterface
|
|
+ blocklist_lookup::BlocklistLookupInterface
|
|
+ configs::ConfigInterface
|
|
+ capture::CaptureInterface
|
|
+ customers::CustomerInterface
|
|
+ dashboard_metadata::DashboardMetadataInterface
|
|
+ dispute::DisputeInterface
|
|
+ ephemeral_key::EphemeralKeyInterface
|
|
+ events::EventInterface
|
|
+ file::FileMetadataInterface
|
|
+ FraudCheckInterface
|
|
+ locker_mock_up::LockerMockUpInterface
|
|
+ mandate::MandateInterface
|
|
+ merchant_account::MerchantAccountInterface
|
|
+ merchant_connector_account::ConnectorAccessToken
|
|
+ merchant_connector_account::MerchantConnectorAccountInterface
|
|
+ PaymentAttemptInterface
|
|
+ PaymentIntentInterface
|
|
+ payment_method::PaymentMethodInterface
|
|
+ blocklist::BlocklistInterface
|
|
+ blocklist_fingerprint::BlocklistFingerprintInterface
|
|
+ scheduler::SchedulerInterface
|
|
+ PayoutAttemptInterface
|
|
+ PayoutsInterface
|
|
+ refund::RefundInterface
|
|
+ reverse_lookup::ReverseLookupInterface
|
|
+ cards_info::CardsInfoInterface
|
|
+ merchant_key_store::MerchantKeyStoreInterface
|
|
+ MasterKeyInterface
|
|
+ payment_link::PaymentLinkInterface
|
|
+ RedisConnInterface
|
|
+ RequestIdStore
|
|
+ business_profile::BusinessProfileInterface
|
|
+ OrganizationInterface
|
|
+ routing_algorithm::RoutingAlgorithmInterface
|
|
+ gsm::GsmInterface
|
|
+ user_role::UserRoleInterface
|
|
+ authorization::AuthorizationInterface
|
|
+ user::sample_data::BatchSampleDataInterface
|
|
+ health_check::HealthCheckDbInterface
|
|
+ role::RoleInterface
|
|
+ user_authentication_method::UserAuthenticationMethodInterface
|
|
+ authentication::AuthenticationInterface
|
|
+ generic_link::GenericLinkInterface
|
|
+ 'static
|
|
{
|
|
fn get_scheduler_db(&self) -> Box<dyn scheduler::SchedulerInterface>;
|
|
|
|
fn get_cache_store(&self) -> Box<(dyn RedisConnInterface + Send + Sync + 'static)>;
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
pub trait GlobalStorageInterface:
|
|
Send
|
|
+ Sync
|
|
+ dyn_clone::DynClone
|
|
+ user::UserInterface
|
|
+ user_key_store::UserKeyStoreInterface
|
|
+ 'static
|
|
{
|
|
}
|
|
|
|
pub trait CommonStorageInterface: StorageInterface + GlobalStorageInterface {
|
|
fn get_storage_interface(&self) -> Box<dyn StorageInterface>;
|
|
fn get_global_storage_interface(&self) -> Box<dyn GlobalStorageInterface>;
|
|
}
|
|
|
|
pub trait MasterKeyInterface {
|
|
fn get_master_key(&self) -> &[u8];
|
|
}
|
|
|
|
impl MasterKeyInterface for Store {
|
|
fn get_master_key(&self) -> &[u8] {
|
|
self.master_key().peek()
|
|
}
|
|
}
|
|
|
|
/// Default dummy key for MockDb
|
|
impl MasterKeyInterface for MockDb {
|
|
fn get_master_key(&self) -> &[u8] {
|
|
&[
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
|
25, 26, 27, 28, 29, 30, 31, 32,
|
|
]
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl StorageInterface for Store {
|
|
fn get_scheduler_db(&self) -> Box<dyn scheduler::SchedulerInterface> {
|
|
Box::new(self.clone())
|
|
}
|
|
|
|
fn get_cache_store(&self) -> Box<(dyn RedisConnInterface + Send + Sync + 'static)> {
|
|
Box::new(self.clone())
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl GlobalStorageInterface for Store {}
|
|
|
|
#[async_trait::async_trait]
|
|
impl StorageInterface for MockDb {
|
|
fn get_scheduler_db(&self) -> Box<dyn scheduler::SchedulerInterface> {
|
|
Box::new(self.clone())
|
|
}
|
|
|
|
fn get_cache_store(&self) -> Box<(dyn RedisConnInterface + Send + Sync + 'static)> {
|
|
Box::new(self.clone())
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl GlobalStorageInterface for MockDb {}
|
|
|
|
impl CommonStorageInterface for MockDb {
|
|
fn get_global_storage_interface(&self) -> Box<dyn GlobalStorageInterface> {
|
|
Box::new(self.clone())
|
|
}
|
|
fn get_storage_interface(&self) -> Box<dyn StorageInterface> {
|
|
Box::new(self.clone())
|
|
}
|
|
}
|
|
|
|
impl CommonStorageInterface for Store {
|
|
fn get_global_storage_interface(&self) -> Box<dyn GlobalStorageInterface> {
|
|
Box::new(self.clone())
|
|
}
|
|
fn get_storage_interface(&self) -> Box<dyn StorageInterface> {
|
|
Box::new(self.clone())
|
|
}
|
|
}
|
|
|
|
pub trait RequestIdStore {
|
|
fn add_request_id(&mut self, _request_id: String) {}
|
|
fn get_request_id(&self) -> Option<String> {
|
|
None
|
|
}
|
|
}
|
|
|
|
impl RequestIdStore for MockDb {}
|
|
|
|
impl RequestIdStore for Store {
|
|
fn add_request_id(&mut self, request_id: String) {
|
|
self.request_id = Some(request_id)
|
|
}
|
|
|
|
fn get_request_id(&self) -> Option<String> {
|
|
self.request_id.clone()
|
|
}
|
|
}
|
|
|
|
pub async fn get_and_deserialize_key<T>(
|
|
db: &dyn StorageInterface,
|
|
key: &str,
|
|
type_name: &'static str,
|
|
) -> CustomResult<T, RedisError>
|
|
where
|
|
T: serde::de::DeserializeOwned,
|
|
{
|
|
use common_utils::ext_traits::ByteSliceExt;
|
|
|
|
let bytes = db.get_key(key).await?;
|
|
bytes
|
|
.parse_struct(type_name)
|
|
.change_context(RedisError::JsonDeserializationFailed)
|
|
}
|
|
|
|
dyn_clone::clone_trait_object!(StorageInterface);
|
|
dyn_clone::clone_trait_object!(GlobalStorageInterface);
|
|
|
|
impl RequestIdStore for KafkaStore {
|
|
fn add_request_id(&mut self, request_id: String) {
|
|
self.diesel_store.add_request_id(request_id)
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl FraudCheckInterface for KafkaStore {
|
|
async fn insert_fraud_check_response(
|
|
&self,
|
|
new: storage::FraudCheckNew,
|
|
) -> CustomResult<FraudCheck, StorageError> {
|
|
let frm = self.diesel_store.insert_fraud_check_response(new).await?;
|
|
if let Err(er) = self
|
|
.kafka_producer
|
|
.log_fraud_check(&frm, None, self.tenant_id.clone())
|
|
.await
|
|
{
|
|
logger::error!(message = "Failed to log analytics event for fraud check", error_message = ?er);
|
|
}
|
|
Ok(frm)
|
|
}
|
|
async fn update_fraud_check_response_with_attempt_id(
|
|
&self,
|
|
this: FraudCheck,
|
|
fraud_check: FraudCheckUpdate,
|
|
) -> CustomResult<FraudCheck, StorageError> {
|
|
let frm = self
|
|
.diesel_store
|
|
.update_fraud_check_response_with_attempt_id(this, fraud_check)
|
|
.await?;
|
|
if let Err(er) = self
|
|
.kafka_producer
|
|
.log_fraud_check(&frm, None, self.tenant_id.clone())
|
|
.await
|
|
{
|
|
logger::error!(message="Failed to log analytics event for fraud check {frm:?}", error_message=?er)
|
|
}
|
|
Ok(frm)
|
|
}
|
|
async fn find_fraud_check_by_payment_id(
|
|
&self,
|
|
payment_id: String,
|
|
merchant_id: id_type::MerchantId,
|
|
) -> CustomResult<FraudCheck, StorageError> {
|
|
let frm = self
|
|
.diesel_store
|
|
.find_fraud_check_by_payment_id(payment_id, merchant_id)
|
|
.await?;
|
|
if let Err(er) = self
|
|
.kafka_producer
|
|
.log_fraud_check(&frm, None, self.tenant_id.clone())
|
|
.await
|
|
{
|
|
logger::error!(message="Failed to log analytics event for fraud check {frm:?}", error_message=?er)
|
|
}
|
|
Ok(frm)
|
|
}
|
|
async fn find_fraud_check_by_payment_id_if_present(
|
|
&self,
|
|
payment_id: String,
|
|
merchant_id: id_type::MerchantId,
|
|
) -> CustomResult<Option<FraudCheck>, StorageError> {
|
|
let frm = self
|
|
.diesel_store
|
|
.find_fraud_check_by_payment_id_if_present(payment_id, merchant_id)
|
|
.await?;
|
|
|
|
if let Some(fraud_check) = frm.clone() {
|
|
if let Err(er) = self
|
|
.kafka_producer
|
|
.log_fraud_check(&fraud_check, None, self.tenant_id.clone())
|
|
.await
|
|
{
|
|
logger::error!(message="Failed to log analytics event for frm {frm:?}", error_message=?er);
|
|
}
|
|
}
|
|
Ok(frm)
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl OrganizationInterface for KafkaStore {
|
|
async fn insert_organization(
|
|
&self,
|
|
organization: OrganizationNew,
|
|
) -> CustomResult<Organization, StorageError> {
|
|
self.diesel_store.insert_organization(organization).await
|
|
}
|
|
async fn find_organization_by_org_id(
|
|
&self,
|
|
org_id: &id_type::OrganizationId,
|
|
) -> CustomResult<Organization, StorageError> {
|
|
self.diesel_store.find_organization_by_org_id(org_id).await
|
|
}
|
|
|
|
async fn update_organization_by_org_id(
|
|
&self,
|
|
org_id: &id_type::OrganizationId,
|
|
update: OrganizationUpdate,
|
|
) -> CustomResult<Organization, StorageError> {
|
|
self.diesel_store
|
|
.update_organization_by_org_id(org_id, update)
|
|
.await
|
|
}
|
|
}
|