-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into 4463-refactor-handle-network-delays-with-exp…
…iry-of-access-token
- Loading branch information
Showing
180 changed files
with
6,134 additions
and
3,193 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
pub mod accumulator; | ||
mod core; | ||
pub mod metrics; | ||
pub use accumulator::{AuthEventMetricAccumulator, AuthEventMetricsAccumulator}; | ||
|
||
pub use self::core::get_metrics; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
use api_models::analytics::auth_events::AuthEventMetricsBucketValue; | ||
|
||
use super::metrics::AuthEventMetricRow; | ||
|
||
#[derive(Debug, Default)] | ||
pub struct AuthEventMetricsAccumulator { | ||
pub three_ds_sdk_count: CountAccumulator, | ||
pub authentication_attempt_count: CountAccumulator, | ||
pub authentication_success_count: CountAccumulator, | ||
pub challenge_flow_count: CountAccumulator, | ||
pub challenge_attempt_count: CountAccumulator, | ||
pub challenge_success_count: CountAccumulator, | ||
pub frictionless_flow_count: CountAccumulator, | ||
} | ||
|
||
#[derive(Debug, Default)] | ||
#[repr(transparent)] | ||
pub struct CountAccumulator { | ||
pub count: Option<i64>, | ||
} | ||
|
||
pub trait AuthEventMetricAccumulator { | ||
type MetricOutput; | ||
|
||
fn add_metrics_bucket(&mut self, metrics: &AuthEventMetricRow); | ||
|
||
fn collect(self) -> Self::MetricOutput; | ||
} | ||
|
||
impl AuthEventMetricAccumulator for CountAccumulator { | ||
type MetricOutput = Option<u64>; | ||
#[inline] | ||
fn add_metrics_bucket(&mut self, metrics: &AuthEventMetricRow) { | ||
self.count = match (self.count, metrics.count) { | ||
(None, None) => None, | ||
(None, i @ Some(_)) | (i @ Some(_), None) => i, | ||
(Some(a), Some(b)) => Some(a + b), | ||
} | ||
} | ||
#[inline] | ||
fn collect(self) -> Self::MetricOutput { | ||
self.count.and_then(|i| u64::try_from(i).ok()) | ||
} | ||
} | ||
|
||
impl AuthEventMetricsAccumulator { | ||
pub fn collect(self) -> AuthEventMetricsBucketValue { | ||
AuthEventMetricsBucketValue { | ||
three_ds_sdk_count: self.three_ds_sdk_count.collect(), | ||
authentication_attempt_count: self.authentication_attempt_count.collect(), | ||
authentication_success_count: self.authentication_success_count.collect(), | ||
challenge_flow_count: self.challenge_flow_count.collect(), | ||
challenge_attempt_count: self.challenge_attempt_count.collect(), | ||
challenge_success_count: self.challenge_success_count.collect(), | ||
frictionless_flow_count: self.frictionless_flow_count.collect(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
use std::collections::HashMap; | ||
|
||
use api_models::analytics::{ | ||
auth_events::{AuthEventMetrics, AuthEventMetricsBucketIdentifier, MetricsBucketResponse}, | ||
AnalyticsMetadata, GetAuthEventMetricRequest, MetricsResponse, | ||
}; | ||
use error_stack::ResultExt; | ||
use router_env::{instrument, logger, tracing}; | ||
|
||
use super::AuthEventMetricsAccumulator; | ||
use crate::{ | ||
auth_events::AuthEventMetricAccumulator, | ||
errors::{AnalyticsError, AnalyticsResult}, | ||
AnalyticsProvider, | ||
}; | ||
|
||
#[instrument(skip_all)] | ||
pub async fn get_metrics( | ||
pool: &AnalyticsProvider, | ||
merchant_id: &String, | ||
publishable_key: Option<&String>, | ||
req: GetAuthEventMetricRequest, | ||
) -> AnalyticsResult<MetricsResponse<MetricsBucketResponse>> { | ||
let mut metrics_accumulator: HashMap< | ||
AuthEventMetricsBucketIdentifier, | ||
AuthEventMetricsAccumulator, | ||
> = HashMap::new(); | ||
|
||
if let Some(publishable_key) = publishable_key { | ||
let mut set = tokio::task::JoinSet::new(); | ||
for metric_type in req.metrics.iter().cloned() { | ||
let req = req.clone(); | ||
let merchant_id_scoped = merchant_id.to_owned(); | ||
let publishable_key_scoped = publishable_key.to_owned(); | ||
let pool = pool.clone(); | ||
set.spawn(async move { | ||
let data = pool | ||
.get_auth_event_metrics( | ||
&metric_type, | ||
&merchant_id_scoped, | ||
&publishable_key_scoped, | ||
&req.time_series.map(|t| t.granularity), | ||
&req.time_range, | ||
) | ||
.await | ||
.change_context(AnalyticsError::UnknownError); | ||
(metric_type, data) | ||
}); | ||
} | ||
|
||
while let Some((metric, data)) = set | ||
.join_next() | ||
.await | ||
.transpose() | ||
.change_context(AnalyticsError::UnknownError)? | ||
{ | ||
for (id, value) in data? { | ||
let metrics_builder = metrics_accumulator.entry(id).or_default(); | ||
match metric { | ||
AuthEventMetrics::ThreeDsSdkCount => metrics_builder | ||
.three_ds_sdk_count | ||
.add_metrics_bucket(&value), | ||
AuthEventMetrics::AuthenticationAttemptCount => metrics_builder | ||
.authentication_attempt_count | ||
.add_metrics_bucket(&value), | ||
AuthEventMetrics::AuthenticationSuccessCount => metrics_builder | ||
.authentication_success_count | ||
.add_metrics_bucket(&value), | ||
AuthEventMetrics::ChallengeFlowCount => metrics_builder | ||
.challenge_flow_count | ||
.add_metrics_bucket(&value), | ||
AuthEventMetrics::ChallengeAttemptCount => metrics_builder | ||
.challenge_attempt_count | ||
.add_metrics_bucket(&value), | ||
AuthEventMetrics::ChallengeSuccessCount => metrics_builder | ||
.challenge_success_count | ||
.add_metrics_bucket(&value), | ||
AuthEventMetrics::FrictionlessFlowCount => metrics_builder | ||
.frictionless_flow_count | ||
.add_metrics_bucket(&value), | ||
} | ||
} | ||
} | ||
|
||
let query_data: Vec<MetricsBucketResponse> = metrics_accumulator | ||
.into_iter() | ||
.map(|(id, val)| MetricsBucketResponse { | ||
values: val.collect(), | ||
dimensions: id, | ||
}) | ||
.collect(); | ||
|
||
Ok(MetricsResponse { | ||
query_data, | ||
meta_data: [AnalyticsMetadata { | ||
current_time_range: req.time_range, | ||
}], | ||
}) | ||
} else { | ||
logger::error!("Publishable key not present for merchant ID"); | ||
Ok(MetricsResponse { | ||
query_data: vec![], | ||
meta_data: [AnalyticsMetadata { | ||
current_time_range: req.time_range, | ||
}], | ||
}) | ||
} | ||
} |
Oops, something went wrong.