From ff8d69a042f84ec32fad2eb027a7163d9d3cdaab Mon Sep 17 00:00:00 2001 From: satlead Date: Tue, 11 Mar 2025 04:53:07 -0400 Subject: [PATCH 01/31] feat: Storage manager cleanup --- .../sdk/src/api/default_storage_properties.rs | 235 ++++++ core/sdk/src/api/mod.rs | 4 + core/sdk/src/api/ripple_cache.rs | 58 ++ core/sdk/src/api/storage_manager.rs | 678 ++++++++++++++++++ core/sdk/src/api/storage_manager_utils.rs | 122 ++++ .../processors/thunder_persistent_store.rs | 8 +- 6 files changed, 1103 insertions(+), 2 deletions(-) create mode 100644 core/sdk/src/api/default_storage_properties.rs create mode 100644 core/sdk/src/api/ripple_cache.rs create mode 100644 core/sdk/src/api/storage_manager.rs create mode 100644 core/sdk/src/api/storage_manager_utils.rs diff --git a/core/sdk/src/api/default_storage_properties.rs b/core/sdk/src/api/default_storage_properties.rs new file mode 100644 index 000000000..b77593b24 --- /dev/null +++ b/core/sdk/src/api/default_storage_properties.rs @@ -0,0 +1,235 @@ +// Copyright 2023 Comcast Cable Communications Management, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 +// + +use crate::{ + api::storage_property::{ + KEY_ALLOW_ACR_COLLECTION, KEY_ALLOW_APP_CONTENT_AD_TARGETING, KEY_ALLOW_BUSINESS_ANALYTICS, + KEY_ALLOW_CAMERA_ANALYTICS, KEY_ALLOW_PERSONALIZATION, + KEY_ALLOW_PRIMARY_BROWSE_AD_TARGETING, KEY_ALLOW_PRIMARY_CONTENT_AD_TARGETING, + KEY_ALLOW_PRODUCT_ANALYTICS, KEY_ALLOW_REMOTE_DIAGNOSTICS, KEY_ALLOW_RESUME_POINTS, + KEY_ALLOW_UNENTITLED_PERSONALIZATION, KEY_ALLOW_UNENTITLED_RESUME_POINTS, + KEY_ALLOW_WATCH_HISTORY, KEY_AUDIO_DESCRIPTION_ENABLED, KEY_BACKGROUND_COLOR, + KEY_BACKGROUND_OPACITY, KEY_ENABLED, KEY_FONT_COLOR, KEY_FONT_EDGE, KEY_FONT_EDGE_COLOR, + KEY_FONT_FAMILY, KEY_FONT_OPACITY, KEY_FONT_SIZE, KEY_LOCALE, KEY_NAME, + KEY_SKIP_RESTRICTION, KEY_TEXT_ALIGN, KEY_TEXT_ALIGN_VERTICAL, KEY_WINDOW_COLOR, + KEY_WINDOW_OPACITY, NAMESPACE_ADVERTISING, NAMESPACE_AUDIO_DESCRIPTION, + NAMESPACE_CLOSED_CAPTIONS, NAMESPACE_DEVICE_NAME, NAMESPACE_LOCALIZATION, + NAMESPACE_PRIVACY, + }, + log::trace, +}; + +use super::manifest::device_manifest::DefaultValues; + +#[derive(Debug, Clone)] +pub enum DefaultStoragePropertiesError { + UnreconizedKey(String), + UnreconizedNamespace(String), + NotFound(String), +} + +#[derive(Clone, Debug)] +pub struct DefaultStorageProperties; + +impl DefaultStorageProperties { + pub fn get_bool( + state: &DefaultValues, + namespace: &String, + key: &'static str, + ) -> Result { + trace!("get_bool: namespace={}, key={}", namespace, key); + if namespace.eq(NAMESPACE_CLOSED_CAPTIONS) { + match key { + KEY_ENABLED => Ok(state.captions.enabled), + _ => Err(DefaultStoragePropertiesError::UnreconizedKey( + key.to_owned(), + )), + } + } else if namespace.eq(NAMESPACE_PRIVACY) { + match key { + KEY_ALLOW_ACR_COLLECTION => Ok(state.allow_acr_collection), + KEY_ALLOW_APP_CONTENT_AD_TARGETING => Ok(state.allow_app_content_ad_targeting), + KEY_ALLOW_BUSINESS_ANALYTICS => Ok(state.allow_business_analytics), + KEY_ALLOW_CAMERA_ANALYTICS => Ok(state.allow_camera_analytics), + KEY_ALLOW_PERSONALIZATION => Ok(state.allow_personalization), + KEY_ALLOW_PRIMARY_BROWSE_AD_TARGETING => { + Ok(state.allow_primary_browse_ad_targeting) + } + KEY_ALLOW_PRIMARY_CONTENT_AD_TARGETING => { + Ok(state.allow_primary_content_ad_targeting) + } + KEY_ALLOW_PRODUCT_ANALYTICS => Ok(state.allow_product_analytics), + KEY_ALLOW_REMOTE_DIAGNOSTICS => Ok(state.allow_remote_diagnostics), + KEY_ALLOW_RESUME_POINTS => Ok(state.allow_resume_points), + KEY_ALLOW_UNENTITLED_PERSONALIZATION => Ok(state.allow_unentitled_personalization), + KEY_ALLOW_UNENTITLED_RESUME_POINTS => Ok(state.allow_unentitled_resume_points), + KEY_ALLOW_WATCH_HISTORY => Ok(state.allow_watch_history), + _ => Err(DefaultStoragePropertiesError::UnreconizedKey( + key.to_owned(), + )), + } + } else if namespace.eq(NAMESPACE_AUDIO_DESCRIPTION) { + match key { + KEY_AUDIO_DESCRIPTION_ENABLED => Ok(state.accessibility_audio_description_settings), + _ => Err(DefaultStoragePropertiesError::UnreconizedKey( + key.to_owned(), + )), + } + } else { + Err(DefaultStoragePropertiesError::UnreconizedNamespace( + namespace.to_owned(), + )) + } + } + + pub fn get_string( + state: &DefaultValues, + namespace: &String, + key: &'static str, + ) -> Result { + trace!("get_string: namespace={}, key={}", namespace, key); + if namespace.eq(NAMESPACE_CLOSED_CAPTIONS) { + let captions = state.clone().captions; + let not_found = DefaultStoragePropertiesError::NotFound(key.to_owned()); + match key { + KEY_FONT_FAMILY => match captions.font_family { + Some(val) => Ok(val), + _ => Err(not_found), + }, + KEY_FONT_COLOR => match captions.font_color { + Some(val) => Ok(val), + _ => Err(not_found), + }, + KEY_FONT_EDGE => match captions.font_edge { + Some(val) => Ok(val), + _ => Err(not_found), + }, + KEY_FONT_EDGE_COLOR => match captions.font_edge_color { + Some(val) => Ok(val), + _ => Err(not_found), + }, + KEY_BACKGROUND_COLOR => match captions.background_color { + Some(val) => Ok(val), + _ => Err(not_found), + }, + KEY_WINDOW_COLOR => match captions.window_color { + Some(val) => Ok(val), + _ => Err(not_found), + }, + KEY_TEXT_ALIGN => match captions.text_align { + Some(val) => Ok(val), + _ => Err(not_found), + }, + KEY_TEXT_ALIGN_VERTICAL => match captions.text_align_vertical { + Some(val) => Ok(val), + _ => Err(not_found), + }, + _ => Err(DefaultStoragePropertiesError::UnreconizedKey( + key.to_owned(), + )), + } + } else if namespace.eq(NAMESPACE_DEVICE_NAME) { + match key { + KEY_NAME => Ok(state.clone().name), + _ => Err(DefaultStoragePropertiesError::UnreconizedKey( + key.to_owned(), + )), + } + } else if namespace.eq(NAMESPACE_LOCALIZATION) { + match key { + KEY_LOCALE => Ok(state.clone().locale), + // Not used anywhere just yet + // KEY_ADDITIONAL_INFO => { + // let a_info_map: HashMap = state.clone().configuration.default_values.additional_info; + // Ok(serde_json::to_string(&a_info_map).unwrap()) + // } + _ => Err(DefaultStoragePropertiesError::UnreconizedKey( + key.to_owned(), + )), + } + } else if namespace.eq(NAMESPACE_ADVERTISING) { + match key { + KEY_SKIP_RESTRICTION => Ok(state.clone().skip_restriction), + _ => Err(DefaultStoragePropertiesError::UnreconizedKey( + key.to_owned(), + )), + } + } else { + Err(DefaultStoragePropertiesError::UnreconizedNamespace( + namespace.to_owned(), + )) + } + } + + pub fn get_number_as_u32( + state: &DefaultValues, + namespace: &String, + key: &'static str, + ) -> Result { + trace!("get_number_as_u32: namespace={}, key={}", namespace, key); + if namespace.eq(NAMESPACE_CLOSED_CAPTIONS) { + let captions = state.clone().captions; + let not_found = DefaultStoragePropertiesError::NotFound(key.to_owned()); + match key { + KEY_FONT_OPACITY => match captions.font_opacity { + Some(val) => Ok(val), + _ => Err(not_found), + }, + KEY_BACKGROUND_OPACITY => match captions.background_opacity { + Some(val) => Ok(val), + _ => Err(not_found), + }, + KEY_WINDOW_OPACITY => match captions.window_opacity { + Some(val) => Ok(val), + _ => Err(not_found), + }, + _ => Err(DefaultStoragePropertiesError::UnreconizedKey( + key.to_owned(), + )), + } + } else { + Err(DefaultStoragePropertiesError::UnreconizedNamespace( + namespace.to_owned(), + )) + } + } + + pub fn get_number_as_f32( + state: &DefaultValues, + namespace: &String, + key: &'static str, + ) -> Result { + trace!("get_number_as_f32: namespace={}, key={}", namespace, key); + if namespace.eq(NAMESPACE_CLOSED_CAPTIONS) { + let captions = state.clone().captions; + let not_found = DefaultStoragePropertiesError::NotFound(key.to_owned()); + match key { + KEY_FONT_SIZE => match captions.font_size { + Some(val) => Ok(val), + _ => Err(not_found), + }, + _ => Err(DefaultStoragePropertiesError::UnreconizedKey( + key.to_owned(), + )), + } + } else { + Err(DefaultStoragePropertiesError::UnreconizedNamespace( + namespace.to_owned(), + )) + } + } +} diff --git a/core/sdk/src/api/mod.rs b/core/sdk/src/api/mod.rs index ee24da531..a22846673 100644 --- a/core/sdk/src/api/mod.rs +++ b/core/sdk/src/api/mod.rs @@ -22,11 +22,15 @@ pub mod apps; pub mod caps; pub mod config; pub mod context; +pub mod default_storage_properties; pub mod device; pub mod manifest; +pub mod ripple_cache; pub mod session; pub mod settings; pub mod status_update; +pub mod storage_manager; +pub mod storage_manager_utils; pub mod storage_property; pub mod usergrant_entry; pub mod wifi; diff --git a/core/sdk/src/api/ripple_cache.rs b/core/sdk/src/api/ripple_cache.rs new file mode 100644 index 000000000..8549675c4 --- /dev/null +++ b/core/sdk/src/api/ripple_cache.rs @@ -0,0 +1,58 @@ +// Copyright 2023 Comcast Cable Communications Management, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 +// +use std::sync::{Arc, RwLock}; + +use crate::api::{ + distributor::distributor_privacy::PrivacySettingsData, storage_property::StorageProperty, +}; + +pub trait IPrivacyUpdated { + fn on_privacy_updated(&self, property: &StorageProperty, value: bool); +} + +#[derive(Debug, Clone, Default)] +pub struct RippleCache { + // Cache for privacy settings + privacy_settings_cache: Arc>, + // Add more caches for other settings as required +} + +impl RippleCache { + pub fn get_cached_bool_storage_property(&self, property: &StorageProperty) -> Option { + if property.is_a_privacy_setting_property() { + // check if the privacy setting property is available in cache + let cache = self.privacy_settings_cache.read().unwrap(); + property.get_privacy_setting_value(&cache) + } else { + // We can add caching support for non-privacy setting properties in future + None + } + } + + pub fn update_cached_bool_storage_property( + &self, + property: &StorageProperty, + value: bool, + ) -> PrivacySettingsData { + { + // update the privacy setting property in cache + let mut cache = self.privacy_settings_cache.write().unwrap(); + property.set_privacy_setting_value(&mut cache, value); + cache.clone() + } + } +} diff --git a/core/sdk/src/api/storage_manager.rs b/core/sdk/src/api/storage_manager.rs new file mode 100644 index 000000000..7a680e925 --- /dev/null +++ b/core/sdk/src/api/storage_manager.rs @@ -0,0 +1,678 @@ +// Copyright 2023 Comcast Cable Communications Management, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 +// + +use crate::{ + api::{ + default_storage_properties::DefaultStorageProperties, + device::device_peristence::{ + DeleteStorageProperty, DevicePersistenceRequest, GetStorageProperty, + SetStorageProperty, StorageData, + }, + firebolt::fb_capabilities::CAPABILITY_NOT_AVAILABLE, + storage_manager_utils::{ + storage_to_bool_rpc_result, storage_to_f32_rpc_result, storage_to_string_rpc_result, + storage_to_u32_rpc_result, storage_to_vec_string_rpc_result, + }, + storage_property::{StorageProperty, StoragePropertyData}, + }, + extn::extn_client_message::{ExtnMessage, ExtnResponse}, + framework::RippleResponse, + log::trace, + serde_json::{json, Value}, + utils::{error::RippleError, rpc_utils::rpc_error_with_code}, + JsonRpcErrorType, +}; +use async_trait::async_trait; +use jsonrpsee::core::RpcResult; +use std::collections::HashMap; + +use super::{manifest::device_manifest::DefaultValues, ripple_cache::IPrivacyUpdated}; + +#[derive(Debug)] +pub enum StorageManagerResponse { + Ok(T), + Default(T), + NoChange(T), +} + +impl StorageManagerResponse { + pub fn as_value(&self) -> T { + match self { + StorageManagerResponse::Ok(value) => value.clone(), + StorageManagerResponse::Default(value) => value.clone(), + StorageManagerResponse::NoChange(value) => value.clone(), + } + } +} + +#[derive(Debug)] +pub enum StorageManagerError { + NotFound, + WriteError, + DataTypeMisMatch, +} + +#[async_trait] +pub trait IStorageOperator { + fn get_cached(&self, property: &StorageProperty) -> Option; + fn get_default(&self) -> DefaultValues; + async fn persist(&self, request: DevicePersistenceRequest) -> RippleResponse; + async fn pull(&self, request: DevicePersistenceRequest) -> Result; + async fn delete(&self, request: DevicePersistenceRequest) -> RippleResponse; + fn on_privacy_updated(&self, property: &StorageProperty, value: bool); + fn emit(&self, event_name: &str, result: &Value, context: Option); +} + +#[derive(Clone)] +pub struct StorageManager; + +impl StorageManager { + pub async fn get_bool( + state: &impl IStorageOperator, + property: StorageProperty, + privacy_updater: Option<&impl IPrivacyUpdated>, + ) -> RpcResult { + if let Some(val) = state.get_cached(&property) { + return Ok(val); + } + let data = property.as_data(); + match StorageManager::get_bool_from_namespace(state, data.namespace.to_string(), data.key) + .await + { + Ok(StorageManagerResponse::Ok(value)) | Ok(StorageManagerResponse::NoChange(value)) => { + if property.is_a_privacy_setting_property() { + if let Some(privacy) = privacy_updater { + privacy.on_privacy_updated(&property, value); + } + } + Ok(value) + } + Ok(StorageManagerResponse::Default(value)) => Ok(value), + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + } + } + + pub async fn set_bool( + state: &impl IStorageOperator, + property: StorageProperty, + value: bool, + context: Option, + privacy_updater: Option<&impl IPrivacyUpdated>, + ) -> RpcResult<()> { + let data = property.as_data(); + trace!("Storage property: {:?} as data: {:?}", property, data); + if let Some(val) = state.get_cached::(&property) { + if val == value { + return Ok(()); + } + } + match StorageManager::set_in_namespace( + state, + data.namespace.to_string(), + data.key.to_string(), + json!(value), + None, + data.event_names, + context, + ) + .await + { + Ok(StorageManagerResponse::Ok(_)) | Ok(StorageManagerResponse::NoChange(_)) => { + if property.is_a_privacy_setting_property() && privacy_updater.is_some() { + if let Some(privacy) = privacy_updater { + privacy.on_privacy_updated(&property, value); + } + } + Ok(()) + } + Ok(StorageManagerResponse::Default(_)) => Ok(()), + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + } + } + + pub async fn get_string( + state: &impl IStorageOperator, + property: StorageProperty, + ) -> RpcResult { + let data = property.as_data(); + match StorageManager::get_string_from_namespace( + state, + data.namespace.to_string(), + data.key, + None, + ) + .await + { + Ok(resp) => Ok(resp.as_value()), + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + } + } + + pub async fn get_string_for_scope( + state: &impl IStorageOperator, + data: &StoragePropertyData, + ) -> RpcResult { + let namespace = data.namespace.clone(); + let scope = data.scope.clone(); + + StorageManager::get_string_from_namespace(state, namespace, data.key, scope) + .await + .map(|resp| resp.as_value()) + .map_err(|_| StorageManager::get_firebolt_error_namespace(&data.namespace, data.key)) + } + + pub async fn get_map( + state: &impl IStorageOperator, + property: StorageProperty, + ) -> RpcResult> { + match StorageManager::get_string(state, property.clone()).await { + Ok(raw_value) => match serde_json::from_str(&raw_value) { + Ok(raw_map) => { + let the_map: HashMap = raw_map; + Ok(the_map) + } + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + }, + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + } + } + + pub async fn set_value_in_map( + state: &impl IStorageOperator, + property: StorageProperty, + key: String, + value: String, + ) -> RpcResult<()> { + match StorageManager::get_map(state, property.clone()).await { + Ok(the_map) => { + let mut mutant: HashMap = the_map; + mutant.insert(key, serde_json::Value::String(value)); + match StorageManager::set_string( + state, + property.clone(), + serde_json::to_string(&mutant).unwrap(), + None, + ) + .await + { + Ok(_) => Ok(()), + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + } + } + Err(_) => { + let mut map: HashMap = Default::default(); + map.insert(key, serde_json::Value::String(value)); + match StorageManager::set_string( + state, + property.clone(), + serde_json::to_string(&map).unwrap(), + None, + ) + .await + { + Ok(_) => Ok(()), + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + } + } + } + } + + pub async fn remove_value_in_map( + state: &impl IStorageOperator, + property: StorageProperty, + key: String, + ) -> RpcResult<()> { + match StorageManager::get_map(state, property.clone()).await { + Ok(the_map) => { + let mut mutant: HashMap = the_map; + mutant.remove(&key); + match StorageManager::set_string( + state, + property.clone(), + serde_json::to_string(&mutant).unwrap(), + None, + ) + .await + { + Ok(_) => Ok(()), + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + } + } + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + } + } + + pub async fn set_string( + state: &impl IStorageOperator, + property: StorageProperty, + value: String, + context: Option, + ) -> RpcResult<()> { + let data = property.as_data(); + if StorageManager::set_in_namespace( + state, + data.namespace.to_string(), + data.key.to_string(), + json!(value), + None, + data.event_names, + context, + ) + .await + .is_err() + { + Err(StorageManager::get_firebolt_error(&property)) + } else { + Ok(()) + } + } + + pub async fn set_string_for_scope( + state: &impl IStorageOperator, + data: &StoragePropertyData, + context: Option, + ) -> RpcResult<()> { + let namespace = data.namespace.clone(); + let value = data.value.clone(); + let scope = data.scope.clone(); + + if StorageManager::set_in_namespace( + state, + namespace.clone(), + data.key.into(), + json!(value), + scope, + None, + context, + ) + .await + .is_err() + { + Err(StorageManager::get_firebolt_error_namespace( + &namespace, data.key, + )) + } else { + Ok(()) + } + } + + pub async fn get_number_as_u32( + state: &impl IStorageOperator, + property: StorageProperty, + ) -> RpcResult { + let data = property.as_data(); + match StorageManager::get_number_as_u32_from_namespace( + state, + data.namespace.to_string(), + data.key, + ) + .await + { + Ok(resp) => Ok(resp.as_value()), + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + } + } + + pub async fn get_number_as_f32( + state: &impl IStorageOperator, + property: StorageProperty, + ) -> RpcResult { + let data = property.as_data(); + StorageManager::get_number_as_f32_from_namespace( + state, + data.namespace.to_string(), + data.key, + ) + .await + .map_or(Err(StorageManager::get_firebolt_error(&property)), |resp| { + Ok(resp.as_value()) + }) + } + + pub async fn set_number_as_f32( + state: &impl IStorageOperator, + property: StorageProperty, + value: f32, + context: Option, + ) -> RpcResult<()> { + let data = property.as_data(); + if StorageManager::set_in_namespace( + state, + data.namespace.to_string(), + data.key.to_string(), + json!(value), + None, + data.event_names, + context, + ) + .await + .is_err() + { + return Err(StorageManager::get_firebolt_error(&property)); + } + Ok(()) + } + + pub async fn set_number_as_u32( + state: &impl IStorageOperator, + property: StorageProperty, + value: u32, + context: Option, + ) -> RpcResult<()> { + let data = property.as_data(); + if StorageManager::set_in_namespace( + state, + data.namespace.to_string(), + data.key.to_string(), + json!(value), + None, + data.event_names, + context, + ) + .await + .is_err() + { + return Err(StorageManager::get_firebolt_error(&property)); + } + Ok(()) + } + + /* + Used internally or when a custom namespace is required + */ + pub async fn get_bool_from_namespace( + state: &impl IStorageOperator, + namespace: String, + key: &'static str, + ) -> Result, StorageManagerError> { + trace!("get_bool: namespace={}, key={}", namespace, key); + let resp = StorageManager::get(state, &namespace, &key.to_string(), None).await; + match storage_to_bool_rpc_result(resp) { + Ok(value) => Ok(StorageManagerResponse::Ok(value)), + Err(_) => { + if let Ok(value) = + DefaultStorageProperties::get_bool(&state.get_default(), &namespace, key) + { + return Ok(StorageManagerResponse::Default(value)); + } + Err(StorageManagerError::NotFound) + } + } + } + + /* + Used internally or when a custom namespace is required + */ + pub async fn set_in_namespace( + state: &impl IStorageOperator, + namespace: String, + key: String, + value: Value, + scope: Option, + event_names: Option<&'static [&'static str]>, + context: Option, + ) -> Result, StorageManagerError> { + if let Ok(ExtnResponse::StorageData(storage_data)) = + StorageManager::get(state, &namespace, &key, scope.clone()).await + { + if storage_data.value.eq(&value) { + return Ok(StorageManagerResponse::NoChange(())); + } + + // The stored value may have preceeded StorageData implementation, if so + // allow the set to occur regardless of whether the values match or not in + // order to update peristent storage with the new StorageData format. + } + + let ssp = SetStorageProperty { + namespace, + key, + data: StorageData::new(value.clone()), + scope, + }; + + match state.persist(DevicePersistenceRequest::Set(ssp)).await { + Ok(_) => { + StorageManager::notify(state, value.clone(), event_names, context).await; + Ok(StorageManagerResponse::Ok(())) + } + Err(_) => Err(StorageManagerError::WriteError), + } + } + + /* + Used internally or when a custom namespace is required + */ + pub async fn get_string_from_namespace( + state: &impl IStorageOperator, + namespace: String, + key: &'static str, + scope: Option, + ) -> Result, StorageManagerError> { + trace!("get_string: namespace={}, key={}", namespace, key); + let resp = StorageManager::get(state, &namespace, &key.to_string(), scope).await; + match storage_to_string_rpc_result(resp) { + Ok(value) => Ok(StorageManagerResponse::Ok(value)), + Err(_) => { + if let Ok(value) = + DefaultStorageProperties::get_string(&state.get_default(), &namespace, key) + { + return Ok(StorageManagerResponse::Default(value)); + } + Err(StorageManagerError::NotFound) + } + } + } + + /* + Used internally or when a custom namespace is required + */ + pub async fn get_number_as_u32_from_namespace( + state: &impl IStorageOperator, + namespace: String, + key: &'static str, + ) -> Result, StorageManagerError> { + trace!("get_string: namespace={}, key={}", namespace, key); + let resp = StorageManager::get(state, &namespace, &key.to_string(), None).await; + match storage_to_u32_rpc_result(resp) { + Ok(value) => Ok(StorageManagerResponse::Ok(value)), + Err(_) => { + if let Ok(value) = DefaultStorageProperties::get_number_as_u32( + &state.get_default(), + &namespace, + key, + ) { + return Ok(StorageManagerResponse::Default(value)); + } + Err(StorageManagerError::NotFound) + } + } + } + + /* + Used internally or when a custom namespace is required + */ + pub async fn get_number_as_f32_from_namespace( + state: &impl IStorageOperator, + namespace: String, + key: &'static str, + ) -> Result, StorageManagerError> { + trace!( + "get_number_as_f32_from_namespace: namespace={}, key={}", + namespace, + key + ); + let resp = StorageManager::get(state, &namespace, &key.to_string(), None).await; + + storage_to_f32_rpc_result(resp).map_or_else( + |_| { + DefaultStorageProperties::get_number_as_f32(&state.get_default(), &namespace, key) + .map_or(Err(StorageManagerError::NotFound), |val| { + Ok(StorageManagerResponse::Ok(val)) + }) + }, + |val| Ok(StorageManagerResponse::Ok(val)), + ) + } + + pub async fn delete_key( + state: &impl IStorageOperator, + property: StorageProperty, + ) -> RpcResult<()> { + let mut result = Ok(()); + let data = property.as_data(); + + if let Ok(ExtnResponse::StorageData(_)) = StorageManager::get( + state, + &data.namespace.to_string(), + &data.key.to_string(), + None, + ) + .await + { + result = match StorageManager::delete( + state, + &data.namespace.to_string(), + &data.key.to_string(), + None, + ) + .await + { + Ok(_) => { + StorageManager::notify(state, Value::Null, data.event_names, None).await; + Ok(()) + } + Err(_) => Err(StorageManager::get_firebolt_error(&property)), + } + } + + result + } + + async fn get( + state: &impl IStorageOperator, + namespace: &String, + key: &String, + scope: Option, + ) -> Result { + trace!("get: namespace={}, key={}", namespace, key); + let data = GetStorageProperty { + namespace: namespace.clone(), + key: key.clone(), + scope, + }; + let result = state.pull(DevicePersistenceRequest::Get(data)).await; + + match result { + Ok(msg) => { + if let Some(m) = msg.payload.extract() { + Ok(m) + } else { + Err(RippleError::ParseError) + } + } + Err(e) => Err(e), + } + } + + pub async fn delete( + state: &impl IStorageOperator, + namespace: &String, + key: &String, + scope: Option, + ) -> RippleResponse { + trace!("delete: namespace={}, key={}", namespace, key); + let data = DeleteStorageProperty { + namespace: namespace.clone(), + key: key.clone(), + scope, + }; + state.delete(DevicePersistenceRequest::Delete(data)).await + } + + pub fn get_firebolt_error(property: &StorageProperty) -> JsonRpcErrorType { + let data = property.as_data(); + rpc_error_with_code::( + format!("{}.{} is not available", data.namespace, data.key), + CAPABILITY_NOT_AVAILABLE, + ) + } + + pub fn get_firebolt_error_namespace(namespace: &String, key: &'static str) -> JsonRpcErrorType { + rpc_error_with_code::( + format!("{}.{} is not available", namespace, key), + CAPABILITY_NOT_AVAILABLE, + ) + } + + pub async fn set_vec_string( + state: &impl IStorageOperator, + property: StorageProperty, + value: Vec, + context: Option, + ) -> RpcResult<()> { + let data = property.as_data(); + if StorageManager::set_in_namespace( + state, + data.namespace.to_string(), + data.key.to_string(), + json!(value), + None, + data.event_names, + context, + ) + .await + .is_err() + { + return Err(StorageManager::get_firebolt_error(&property)); + } + Ok(()) + } + + pub async fn get_vec_string( + state: &impl IStorageOperator, + property: StorageProperty, + ) -> RpcResult> { + let data = property.as_data(); + storage_to_vec_string_rpc_result( + StorageManager::get( + state, + &data.namespace.to_string(), + &data.key.to_string(), + None, + ) + .await, + ) + } + + async fn notify( + state: &impl IStorageOperator, + value: Value, + event_names: Option<&'static [&'static str]>, + context: Option, + ) { + if let Some(events) = event_names { + let val = value.clone(); + for event in events.iter() { + let result = val.clone(); + let ctx = context.clone(); + let evt = String::from(*event); + state.emit(&evt, &result, ctx); + } + } + } +} diff --git a/core/sdk/src/api/storage_manager_utils.rs b/core/sdk/src/api/storage_manager_utils.rs new file mode 100644 index 000000000..683a4c7a1 --- /dev/null +++ b/core/sdk/src/api/storage_manager_utils.rs @@ -0,0 +1,122 @@ +// Copyright 2023 Comcast Cable Communications Management, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 +// + +use crate::{ + api::device::device_peristence::StorageData, + extn::extn_client_message::ExtnResponse, + serde_json::{self, Value}, + utils::error::RippleError, +}; +use jsonrpsee::core::{Error, RpcResult}; + +fn storage_error() -> jsonrpsee::core::Error { + Error::Custom(String::from("error parsing response")) +} + +fn get_storage_data(resp: Result) -> Result, Error> { + match resp { + Ok(response) => match response { + ExtnResponse::StorageData(storage_data) => Ok(Some(storage_data)), + _ => Ok(None), + }, + Err(_) => Err(storage_error()), + } +} + +fn get_value(resp: Result) -> Result { + let has_storage_data = get_storage_data(resp.clone())?; + + if let Some(storage_data) = has_storage_data { + return Ok(storage_data.value); + } + + match resp.unwrap() { + ExtnResponse::Value(value) => Ok(value), + ExtnResponse::String(str_val) => match serde_json::from_str(&str_val) { + Ok(value) => Ok(value), + Err(_) => Ok(Value::String(str_val)), // An actual string was stored, return it as a Value. + }, + _ => Err(storage_error()), + } +} + +pub fn storage_to_string_rpc_result(resp: Result) -> RpcResult { + let value = get_value(resp)?; + + if let Some(s) = value.as_str() { + return Ok(s.to_string()); + } + + Err(storage_error()) +} + +pub fn storage_to_bool_rpc_result(resp: Result) -> RpcResult { + let value = get_value(resp)?; + + if let Some(b) = value.as_bool() { + return Ok(b); + } + if let Some(s) = value.as_str() { + return Ok(s == "true"); + } + + Err(storage_error()) +} + +pub fn storage_to_u32_rpc_result(resp: Result) -> RpcResult { + let value = get_value(resp)?; + if let Some(n) = value.as_u64() { + return Ok(n as u32); + } + if let Some(s) = value.as_str() { + return s.parse::().map_or(Err(storage_error()), Ok); + } + + Err(storage_error()) +} + +pub fn storage_to_f32_rpc_result(resp: Result) -> RpcResult { + let value = get_value(resp)?; + + if let Some(n) = value.as_f64() { + return Ok(n as f32); + } + if let Some(s) = value.as_str() { + return s + .parse::() + .map_or(Err(storage_error()), |v| Ok(v as f32)); + } + + Err(storage_error()) +} + +pub fn storage_to_void_rpc_result(resp: Result) -> RpcResult<()> { + match resp { + Ok(_) => Ok(()), + Err(_) => Err(storage_error()), + } +} + +pub fn storage_to_vec_string_rpc_result( + resp: Result, +) -> RpcResult> { + let value = get_value(resp)?; + match serde_json::from_value(value) { + Ok(v) => Ok(v), + Err(_) => Err(storage_error()), + } +} diff --git a/device/thunder_ripple_sdk/src/processors/thunder_persistent_store.rs b/device/thunder_ripple_sdk/src/processors/thunder_persistent_store.rs index 58ed72db1..fa1713e58 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_persistent_store.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_persistent_store.rs @@ -167,7 +167,11 @@ impl ThunderStorageRequestProcessor { true } - async fn get_value(state: ThunderState, req: ExtnMessage, data: GetStorageProperty) -> bool { + pub async fn get_value( + state: &ThunderState, + req: ExtnMessage, + data: GetStorageProperty, + ) -> bool { let mut params_json = json!({ "namespace": data.namespace, "key": data.key, @@ -308,7 +312,7 @@ impl ExtnRequestProcessor for ThunderStorageRequestProcessor { ) -> bool { match extracted_message { DevicePersistenceRequest::Get(get_params) => { - Self::get_value(state.clone(), msg, get_params).await + Self::get_value(&state, msg, get_params).await } DevicePersistenceRequest::Set(set_params) => { Self::set_value(state.clone(), msg, set_params).await From 7ad61eb8ad9560dcc2ea0ad2ac5aed337ac6b1a9 Mon Sep 17 00:00:00 2001 From: satlead Date: Tue, 18 Mar 2025 13:21:03 -0400 Subject: [PATCH 02/31] refactor: Cleanup Data Governance and related APIs --- Cargo.lock | 33 +- .../src/bootstrap/extn/load_session_step.rs | 7 - core/main/src/bootstrap/manifest/mod.rs | 1 - .../src/bootstrap/setup_extn_client_step.rs | 3 +- .../src/bootstrap/start_fbgateway_step.rs | 16 +- core/main/src/broker/broker_utils.rs | 20 +- core/main/src/broker/endpoint_broker.rs | 22 +- .../src/broker/event_management_utility.rs | 2 +- core/main/src/broker/rules_engine.rs | 6 +- core/main/src/firebolt/firebolt_gateway.rs | 44 +- core/main/src/firebolt/firebolt_ws.rs | 9 +- .../main/src/firebolt/handlers/account_rpc.rs | 2 +- core/main/src/firebolt/handlers/device_rpc.rs | 2 +- core/main/src/firebolt/handlers/lcm_rpc.rs | 20 + .../handlers/metrics_management_rpc.rs | 123 ---- .../main/src/firebolt/handlers/metrics_rpc.rs | 674 ------------------ .../main/src/firebolt/handlers/privacy_rpc.rs | 2 +- .../src/firebolt/handlers/telemetry_rpc.rs | 61 ++ core/main/src/firebolt/mod.rs | 3 +- core/main/src/firebolt/rpc_router.rs | 28 +- .../src/processor/main_context_processor.rs | 96 +-- core/main/src/processor/metrics_processor.rs | 207 +----- .../apps/delegated_launcher_handler.rs | 123 ++-- core/main/src/service/telemetry_builder.rs | 71 +- core/main/src/state/bootstrap_state.rs | 6 +- core/main/src/state/metrics_state.rs | 551 -------------- core/main/src/state/mod.rs | 2 +- core/main/src/state/otel_state.rs | 128 ++++ core/main/src/state/platform_state.rs | 8 +- core/main/src/state/ripple_cache.rs | 2 +- core/main/src/utils/router_utils.rs | 4 +- core/sdk/Cargo.toml | 1 + core/sdk/src/api/context.rs | 28 +- .../api/distributor/distributor_privacy.rs | 27 + .../src/api/distributor/distributor_sync.rs | 77 -- core/sdk/src/api/firebolt/fb_metrics.rs | 297 +------- core/sdk/src/api/firebolt/fb_telemetry.rs | 62 +- core/sdk/src/api/mod.rs | 2 - core/sdk/src/api/observability/analytics.rs | 34 - .../sdk/src/api/observability/metrics_util.rs | 116 +-- core/sdk/src/api/ripple_cache.rs | 19 +- core/sdk/src/api/storage_manager.rs | 60 +- core/sdk/src/extn/client/extn_client.rs | 6 - core/sdk/src/extn/extn_client_message.rs | 16 - .../framework/device_manifest_bootstrap.rs} | 4 +- core/sdk/src/framework/mod.rs | 1 + device/thunder_ripple_sdk/Cargo.toml | 2 + .../src/bootstrap/setup_thunder_processors.rs | 3 - .../src/processors/thunder_analytics.rs | 85 +-- .../src/processors/thunder_device_info.rs | 187 +++-- .../src/processors/thunder_package_manager.rs | 71 +- .../processors/thunder_persistent_store.rs | 91 +-- .../src/tests/mock_thunder_controller.rs | 25 + .../general/src/distributor_general_ffi.rs | 2 - .../general/src/general_metrics_processor.rs | 172 ----- distributor/general/src/lib.rs | 1 - 56 files changed, 737 insertions(+), 2928 deletions(-) delete mode 100644 core/main/src/firebolt/handlers/metrics_management_rpc.rs delete mode 100644 core/main/src/firebolt/handlers/metrics_rpc.rs create mode 100644 core/main/src/firebolt/handlers/telemetry_rpc.rs delete mode 100644 core/main/src/state/metrics_state.rs create mode 100644 core/main/src/state/otel_state.rs delete mode 100644 core/sdk/src/api/distributor/distributor_sync.rs delete mode 100644 core/sdk/src/api/observability/analytics.rs rename core/{main/src/bootstrap/manifest/device.rs => sdk/src/framework/device_manifest_bootstrap.rs} (95%) delete mode 100644 distributor/general/src/general_metrics_processor.rs diff --git a/Cargo.lock b/Cargo.lock index 5558621f4..185ac8e49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -520,7 +520,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e" dependencies = [ "chrono", - "chrono-tz-build", + "chrono-tz-build 0.2.1", + "phf", +] + +[[package]] +name = "chrono-tz" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6ac4f2c0bf0f44e9161aec9675e1050aa4a530663c4a9e37e108fa948bca9f" +dependencies = [ + "chrono", + "chrono-tz-build 0.4.0", "phf", ] @@ -535,6 +546,16 @@ dependencies = [ "phf_codegen", ] +[[package]] +name = "chrono-tz-build" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" +dependencies = [ + "parse-zoneinfo", + "phf_codegen", +] + [[package]] name = "chumsky" version = "0.9.3" @@ -790,7 +811,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2371,7 +2392,7 @@ dependencies = [ "base64 0.21.7", "bytes", "chrono", - "chrono-tz", + "chrono-tz 0.8.6", "fs2", "gregorian", "hashers", @@ -2978,7 +2999,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3436,7 +3457,7 @@ dependencies = [ "getrandom 0.3.1", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3492,6 +3513,8 @@ name = "thunder_ripple_sdk" version = "1.1.0" dependencies = [ "base64 0.22.1", + "chrono", + "chrono-tz 0.10.1", "csv", "expectest", "futures", diff --git a/core/main/src/bootstrap/extn/load_session_step.rs b/core/main/src/bootstrap/extn/load_session_step.rs index 4d34cd1f3..e15923867 100644 --- a/core/main/src/bootstrap/extn/load_session_step.rs +++ b/core/main/src/bootstrap/extn/load_session_step.rs @@ -16,13 +16,11 @@ // use ripple_sdk::framework::bootstrap::Bootstep; -use ripple_sdk::tokio; use ripple_sdk::{async_trait::async_trait, framework::RippleResponse}; use crate::processor::main_context_processor::MainContextProcessor; use crate::service::context_manager::ContextManager; use crate::state::bootstrap_state::BootstrapState; -use crate::state::metrics_state::MetricsState; pub struct LoadDistributorValuesStep; @@ -33,11 +31,6 @@ impl Bootstep for LoadDistributorValuesStep { } async fn setup(&self, s: BootstrapState) -> RippleResponse { - let mut ps = s.platform_state.clone(); - tokio::spawn(async move { - MetricsState::initialize(&mut ps).await; - }); - MainContextProcessor::remove_expired_and_inactive_entries(&s.platform_state); ContextManager::setup(&s.platform_state).await; diff --git a/core/main/src/bootstrap/manifest/mod.rs b/core/main/src/bootstrap/manifest/mod.rs index 09fb7a1f4..dd08b4b8f 100644 --- a/core/main/src/bootstrap/manifest/mod.rs +++ b/core/main/src/bootstrap/manifest/mod.rs @@ -16,5 +16,4 @@ // pub mod apps; -pub mod device; pub mod extn; diff --git a/core/main/src/bootstrap/setup_extn_client_step.rs b/core/main/src/bootstrap/setup_extn_client_step.rs index 0c224bc09..a95b3f99e 100644 --- a/core/main/src/bootstrap/setup_extn_client_step.rs +++ b/core/main/src/bootstrap/setup_extn_client_step.rs @@ -20,7 +20,7 @@ use ripple_sdk::{ }; use crate::processor::account_link_processor::AccountLinkProcessor; -use crate::processor::metrics_processor::{MetricsProcessor, OpMetricsProcessor}; +use crate::processor::metrics_processor::OpMetricsProcessor; use crate::processor::settings_processor::SettingsProcessor; use crate::processor::{ store_privacy_settings_processor::StorePrivacySettingsProcessor, @@ -62,7 +62,6 @@ impl Bootstep for SetupExtnClientStep { client.add_request_processor(AuthorizedInfoProcessor::new(state.platform_state.clone())); client.add_request_processor(AccountLinkProcessor::new(state.platform_state.clone())); client.add_request_processor(SettingsProcessor::new(state.platform_state.clone())); - client.add_request_processor(MetricsProcessor::new(state.platform_state.clone())); client.add_request_processor(OpMetricsProcessor::new(state.platform_state.clone())); Ok(()) } diff --git a/core/main/src/bootstrap/start_fbgateway_step.rs b/core/main/src/bootstrap/start_fbgateway_step.rs index 6d731e6e3..7e3c5ee3e 100644 --- a/core/main/src/bootstrap/start_fbgateway_step.rs +++ b/core/main/src/bootstrap/start_fbgateway_step.rs @@ -28,13 +28,12 @@ use crate::{ closed_captions_rpc::ClosedcaptionsRPCProvider, device_rpc::DeviceRPCProvider, discovery_rpc::DiscoveryRPCProvider, keyboard_rpc::KeyboardRPCProvider, lcm_rpc::LifecycleManagementProvider, lifecycle_rpc::LifecycleRippleProvider, - localization_rpc::LocalizationRPCProvider, - metrics_management_rpc::MetricsManagementProvider, metrics_rpc::MetricsRPCProvider, - parameters_rpc::ParametersRPCProvider, privacy_rpc::PrivacyProvider, - profile_rpc::ProfileRPCProvider, provider_registrar::ProviderRegistrar, - second_screen_rpc::SecondScreenRPCProvider, - secure_storage_rpc::SecureStorageRPCProvider, user_grants_rpc::UserGrantsRPCProvider, - voice_guidance_rpc::VoiceguidanceRPCProvider, wifi_rpc::WifiRPCProvider, + localization_rpc::LocalizationRPCProvider, parameters_rpc::ParametersRPCProvider, + privacy_rpc::PrivacyProvider, profile_rpc::ProfileRPCProvider, + provider_registrar::ProviderRegistrar, second_screen_rpc::SecondScreenRPCProvider, + secure_storage_rpc::SecureStorageRPCProvider, telemetry_rpc::TelemetryProvider, + user_grants_rpc::UserGrantsRPCProvider, voice_guidance_rpc::VoiceguidanceRPCProvider, + wifi_rpc::WifiRPCProvider, }, rpc::RippleRPCProvider, }, @@ -70,14 +69,13 @@ impl FireboltGatewayStep { let _ = methods.merge(ParametersRPCProvider::provide_with_alias(state.clone())); let _ = methods.merge(SecureStorageRPCProvider::provide_with_alias(state.clone())); let _ = methods.merge(AdvertisingRPCProvider::provide_with_alias(state.clone())); - let _ = methods.merge(MetricsRPCProvider::provide_with_alias(state.clone())); let _ = methods.merge(DiscoveryRPCProvider::provide_with_alias(state.clone())); let _ = methods.merge(AuthRPCProvider::provide_with_alias(state.clone())); let _ = methods.merge(AccountRPCProvider::provide_with_alias(state.clone())); - let _ = methods.merge(MetricsManagementProvider::provide_with_alias(state.clone())); let _ = methods.merge(AudioDescriptionRPCProvider::provide_with_alias( state.clone(), )); + let _ = methods.merge(TelemetryProvider::provide_with_alias(state.clone())); // LCM Api(s) not required for internal launcher if !state.has_internal_launcher() { diff --git a/core/main/src/broker/broker_utils.rs b/core/main/src/broker/broker_utils.rs index 911122770..ba6c84d81 100644 --- a/core/main/src/broker/broker_utils.rs +++ b/core/main/src/broker/broker_utils.rs @@ -72,15 +72,31 @@ impl BrokerUtils { } } + pub async fn process_for_app_main_request( + state: &mut PlatformState, + method: &str, + params: Option, + app_id: &str, + ) -> RpcResult { + let mut rpc_request = RpcRequest::internal(method).with_params(params); + rpc_request.ctx.app_id = app_id.to_owned(); + Self::process(state, rpc_request).await + } + pub async fn process_internal_main_request<'a>( state: &mut PlatformState, method: &'a str, params: Option, ) -> RpcResult { let rpc_request = RpcRequest::internal(method).with_params(params); + Self::process(state, rpc_request).await + } + + async fn process(state: &mut PlatformState, rpc_request: RpcRequest) -> RpcResult { + let method = rpc_request.method.clone(); state - .metrics - .add_api_stats(&rpc_request.ctx.request_id, method); + .otel + .add_api_stats(&rpc_request.ctx.request_id, &method); match state.internal_rpc_request(&rpc_request).await { Ok(res) => match res.as_value() { diff --git a/core/main/src/broker/endpoint_broker.rs b/core/main/src/broker/endpoint_broker.rs index d865d3530..fd187e968 100644 --- a/core/main/src/broker/endpoint_broker.rs +++ b/core/main/src/broker/endpoint_broker.rs @@ -49,7 +49,7 @@ use crate::{ broker::broker_utils::BrokerUtils, firebolt::firebolt_gateway::{FireboltGatewayCommand, JsonRpcError}, service::extn::ripple_client::RippleClient, - state::{metrics_state::MetricsState, platform_state::PlatformState, session_state::Session}, + state::{otel_state::OtelState, platform_state::PlatformState, session_state::Session}, utils::router_utils::{ add_telemetry_status_code, capture_stage, get_rpc_header, return_extn_response, }, @@ -372,7 +372,7 @@ pub struct EndpointBrokerState { cleaner_list: Arc>>, reconnect_tx: Sender, provider_broker_state: ProvideBrokerState, - metrics_state: MetricsState, + metrics_state: OtelState, } impl Default for EndpointBrokerState { fn default() -> Self { @@ -385,14 +385,14 @@ impl Default for EndpointBrokerState { cleaner_list: Arc::new(RwLock::new(Vec::new())), reconnect_tx: mpsc::channel(2).0, provider_broker_state: ProvideBrokerState::default(), - metrics_state: MetricsState::default(), + metrics_state: OtelState::default(), } } } impl EndpointBrokerState { pub fn new( - metrics_state: MetricsState, + metrics_state: OtelState, tx: Sender, rule_engine: RuleEngine, ripple_client: RippleClient, @@ -843,6 +843,10 @@ impl EndpointBrokerState { } } + pub fn has_rule(&self, method: &str) -> bool { + self.rule_engine.has_rule(method) + } + pub fn get_rule(&self, rpc_request: &RpcRequest) -> Option { self.rule_engine.get_rule(rpc_request) } @@ -1233,7 +1237,7 @@ impl BrokerOutputForwarder { } } - platform_state.metrics.update_api_stats_ref( + platform_state.otel.update_api_stats_ref( &rpc_request.ctx.request_id, add_telemetry_status_code( &tm_str, @@ -1242,14 +1246,14 @@ impl BrokerOutputForwarder { ); if let Some(api_stats) = platform_state - .metrics + .otel .get_api_stats(&rpc_request.ctx.request_id) { message.stats = Some(api_stats); if rpc_request.ctx.app_id.eq_ignore_ascii_case("internal") { platform_state - .metrics + .otel .remove_api_stats(&rpc_request.ctx.request_id); } } @@ -1602,7 +1606,7 @@ mod tests { endpoint_broker::tests::RippleClient, rules_engine::{Rule, RuleEngine, RuleSet, RuleTransform}, }, - state::{bootstrap_state::ChannelsState, metrics_state::MetricsState}, + state::{bootstrap_state::ChannelsState, otel_state::OtelState}, }; use super::EndpointBrokerState; @@ -1612,7 +1616,7 @@ mod tests { let (tx, _) = channel(2); let client = RippleClient::new(ChannelsState::new()); let state = EndpointBrokerState::new( - MetricsState::default(), + OtelState::default(), tx, RuleEngine { rules: RuleSet::default(), diff --git a/core/main/src/broker/event_management_utility.rs b/core/main/src/broker/event_management_utility.rs index 877c43022..297c18bc3 100644 --- a/core/main/src/broker/event_management_utility.rs +++ b/core/main/src/broker/event_management_utility.rs @@ -90,7 +90,7 @@ impl EventManagementUtility { }; platform_state - .metrics + .otel .add_api_stats(&ctx.request_id, "advertising.policy"); let resp = platform_state diff --git a/core/main/src/broker/rules_engine.rs b/core/main/src/broker/rules_engine.rs index 01f3a3d5a..281a6d32f 100644 --- a/core/main/src/broker/rules_engine.rs +++ b/core/main/src/broker/rules_engine.rs @@ -249,10 +249,8 @@ impl RuleEngine { } } - pub fn has_rule(&self, request: &RpcRequest) -> bool { - self.rules - .rules - .contains_key(&request.ctx.method.to_lowercase()) + pub fn has_rule(&self, request: &str) -> bool { + self.rules.rules.contains_key(&request.to_lowercase()) } pub fn get_rule(&self, rpc_request: &RpcRequest) -> Option { diff --git a/core/main/src/firebolt/firebolt_gateway.rs b/core/main/src/firebolt/firebolt_gateway.rs index b713c6cc0..7c325c109 100644 --- a/core/main/src/firebolt/firebolt_gateway.rs +++ b/core/main/src/firebolt/firebolt_gateway.rs @@ -193,7 +193,7 @@ impl FireboltGateway { ApiMessage::new(protocol, data, rpc_request.ctx.request_id.clone()); if let Some(api_stats) = platform_state - .metrics + .otel .get_api_stats(&rpc_request.ctx.request_id.clone()) { api_message.stats = Some(api_stats); @@ -288,14 +288,9 @@ impl FireboltGateway { request_c.method = FireboltOpenRpcMethod::name_with_lowercase_module(&request.method); platform_state - .metrics + .otel .add_api_stats(&request_c.ctx.request_id, &request_c.method); - let metrics_timer = TelemetryBuilder::start_firebolt_metrics_timer( - &platform_state.get_client().get_extn_client(), - request_c.method.clone(), - request_c.ctx.app_id.clone(), - ); let fail_open = matches!( platform_state .get_device_manifest() @@ -307,16 +302,9 @@ impl FireboltGateway { let open_rpc_state = self.state.platform_state.open_rpc_state.clone(); tokio::spawn(async move { - capture_stage(&platform_state.metrics, &request_c, "context_ready"); + capture_stage(&platform_state.otel, &request_c, "context_ready"); // Validate incoming request parameters. if let Err(error_string) = validate_request(open_rpc_state, &request_c, fail_open) { - TelemetryBuilder::stop_and_send_firebolt_metrics_timer( - &platform_state.clone(), - metrics_timer, - format!("{}", JSON_RPC_STANDARD_ERROR_INVALID_PARAMS), - ) - .await; - let json_rpc_error = JsonRpcError { code: JSON_RPC_STANDARD_ERROR_INVALID_PARAMS, message: error_string, @@ -327,7 +315,7 @@ impl FireboltGateway { return; } - capture_stage(&platform_state.metrics, &request_c, "openrpc_val"); + capture_stage(&platform_state.otel, &request_c, "openrpc_val"); let result = if extn_request { // extn protocol means its an internal Ripple request skip permissions. @@ -336,7 +324,7 @@ impl FireboltGateway { FireboltGatekeeper::gate(platform_state.clone(), request_c.clone()).await }; - capture_stage(&platform_state.metrics, &request_c, "permission"); + capture_stage(&platform_state.otel, &request_c, "permission"); match result { Ok(p) => { @@ -406,13 +394,8 @@ impl FireboltGateway { .emit_debug(); // if the websocket disconnects before the session is recieved this leads to an error - RpcRouter::route( - platform_state.clone(), - request_c, - session, - metrics_timer.clone(), - ) - .await; + RpcRouter::route(platform_state.clone(), request_c, session) + .await; } else { error!("session is missing request is not forwarded for request {:?}", request_c.ctx); } @@ -423,12 +406,6 @@ impl FireboltGateway { Err(e) => { let deny_reason = e.reason; // log firebolt response message in RDKTelemetry 1.0 friendly format - TelemetryBuilder::stop_and_send_firebolt_metrics_timer( - &platform_state.clone(), - metrics_timer, - format!("{}", deny_reason.get_observability_error_code()), - ) - .await; error!( "Failed gateway present error {:?} {:?}", @@ -561,17 +538,14 @@ async fn send_json_rpc_error( request.clone().ctx.request_id, ); - if let Some(api_stats) = platform_state - .metrics - .get_api_stats(&request.ctx.request_id) - { + if let Some(api_stats) = platform_state.otel.get_api_stats(&request.ctx.request_id) { api_message.stats = Some(ApiStats { api: request.method.clone(), stats_ref: get_rpc_header_with_status(request, status_code), stats: api_stats.stats.clone(), }); } - platform_state.metrics.update_api_stats_ref( + platform_state.otel.update_api_stats_ref( &request.ctx.request_id, get_rpc_header_with_status(request, status_code), ); diff --git a/core/main/src/firebolt/firebolt_ws.rs b/core/main/src/firebolt/firebolt_ws.rs index 0d9a94f3a..1304bf369 100644 --- a/core/main/src/firebolt/firebolt_ws.rs +++ b/core/main/src/firebolt/firebolt_ws.rs @@ -288,7 +288,7 @@ impl FireboltWs { match send_result { Ok(_) => { platform_state - .metrics + .otel .update_api_stage(&api_message.request_id, "response"); LogSignal::new( @@ -299,9 +299,8 @@ impl FireboltWs { .with_diagnostic_context_item("cid", &connection_id_c.clone()) .with_diagnostic_context_item("result", &api_message.jsonrpc_msg.clone()) .emit_debug(); - if let Some(stats) = platform_state - .metrics - .get_api_stats(&api_message.request_id) + if let Some(stats) = + platform_state.otel.get_api_stats(&api_message.request_id) { info!( "Sending Firebolt response: {:?},{}", @@ -314,7 +313,7 @@ impl FireboltWs { stats.stats.get_stage_durations() ); platform_state - .metrics + .otel .remove_api_stats(&api_message.request_id); } diff --git a/core/main/src/firebolt/handlers/account_rpc.rs b/core/main/src/firebolt/handlers/account_rpc.rs index c77ea1af8..2e64a58f3 100644 --- a/core/main/src/firebolt/handlers/account_rpc.rs +++ b/core/main/src/firebolt/handlers/account_rpc.rs @@ -66,7 +66,7 @@ impl AccountServer for AccountImpl { let mut platform_state = self.platform_state.clone(); platform_state - .metrics + .otel .add_api_stats(&_ctx.request_id, "account.setServiceAccessToken"); let success = rpc_request_setter( diff --git a/core/main/src/firebolt/handlers/device_rpc.rs b/core/main/src/firebolt/handlers/device_rpc.rs index f1143aad2..33e43400d 100644 --- a/core/main/src/firebolt/handlers/device_rpc.rs +++ b/core/main/src/firebolt/handlers/device_rpc.rs @@ -373,7 +373,7 @@ impl DeviceServer for DeviceImpl { let mut platform_state = self.state.clone(); platform_state - .metrics + .otel .add_api_stats(&_ctx.request_id, "account.setServiceAccountId"); let success = rpc_request_setter( diff --git a/core/main/src/firebolt/handlers/lcm_rpc.rs b/core/main/src/firebolt/handlers/lcm_rpc.rs index bb0e50f85..3e852df2e 100644 --- a/core/main/src/firebolt/handlers/lcm_rpc.rs +++ b/core/main/src/firebolt/handlers/lcm_rpc.rs @@ -93,6 +93,9 @@ pub trait LifecycleManagement { ctx: CallContext, request: ListenRequest, ) -> RpcResult; + + #[method(name = "ripple.getAppCatalogId")] + async fn get_app_catalog_id(&self, ctx: CallContext, app_id: String) -> RpcResult; } #[derive(Debug)] @@ -261,6 +264,23 @@ impl LifecycleManagementServer for LifecycleManagementImpl { event: LCM_EVENT_ON_SESSION_TRANSITION_CANCELED.to_string(), }) } + + async fn get_app_catalog_id(&self, _: CallContext, app_id: String) -> RpcResult { + let (app_resp_tx, app_resp_rx) = oneshot::channel::(); + + let app_request = + AppRequest::new(AppMethod::GetAppContentCatalog(app_id.clone()), app_resp_tx); + if let Err(e) = self.state.get_client().send_app_request(app_request) { + error!("Send error for AppMethod::GetAppContentCatalog {:?}", e); + } + let resp = rpc_await_oneshot(app_resp_rx).await; + + if let Ok(Ok(AppManagerResponse::AppContentCatalog(content_catalog))) = resp { + return Ok(content_catalog.map_or(app_id.to_owned(), |x| x)); + } + + Ok(app_id) + } } pub struct LifecycleManagementProvider; diff --git a/core/main/src/firebolt/handlers/metrics_management_rpc.rs b/core/main/src/firebolt/handlers/metrics_management_rpc.rs deleted file mode 100644 index 3701424f8..000000000 --- a/core/main/src/firebolt/handlers/metrics_management_rpc.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// -use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule}; -use ripple_sdk::{api::gateway::rpc_gateway_api::CallContext, async_trait::async_trait}; -use serde::{Deserialize, Deserializer, Serialize}; - -use crate::{firebolt::rpc::RippleRPCProvider, state::platform_state::PlatformState}; - -#[derive(Deserialize, Debug, Clone)] -pub struct MetricsContextParams { - context: MetricsContext, -} - -#[derive(Deserialize, Serialize, Default, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct MetricsContext { - pub device_session_id: Option, -} - -impl MetricsContext { - fn is_valid_key(&self, key: &str) -> bool { - let metrics_context_fields = match serde_json::to_value(self) { - Ok(val) => { - let field_map = val.as_object().unwrap(); - field_map.keys().map(|x| x.to_string()).collect::>() - } - Err(_) => return false, - }; - metrics_context_fields.contains(&key.to_string()) - } -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct MetricsContextKeys { - #[serde(deserialize_with = "validate_metrics_context_keys")] - pub keys: Vec, -} - -fn validate_metrics_context_keys<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let keys: Vec = Vec::deserialize(deserializer)?; - let metics_context = MetricsContext::default(); - for key in &keys { - if !metics_context.is_valid_key(key.as_str()) { - return Err(serde::de::Error::custom(format!("Invalid key : {}", key))); - } - } - Ok(keys) -} - -#[rpc(server)] -pub trait MetricsManagement { - #[method(name = "metricsmanagement.addContext")] - async fn add_context( - &self, - ctx: CallContext, - context_params: MetricsContextParams, - ) -> RpcResult<()>; - #[method(name = "metricsmanagement.removeContext")] - async fn remove_context(&self, ctx: CallContext, request: MetricsContextKeys) -> RpcResult<()>; -} - -pub struct MetricsManagementImpl { - pub state: PlatformState, -} - -#[async_trait] -impl MetricsManagementServer for MetricsManagementImpl { - async fn add_context( - &self, - _ctx: CallContext, - context_params: MetricsContextParams, - ) -> RpcResult<()> { - // check if device_session_id is available - if let Some(device_session_id) = context_params.context.device_session_id { - self.state - .metrics - .update_session_id(self.state.clone(), Some(device_session_id)); - } - Ok(()) - } - - async fn remove_context( - &self, - _ctx: CallContext, - request: MetricsContextKeys, - ) -> RpcResult<()> { - for key in request.keys { - // currently handling only one key which is deviceSessionId - if key.as_str() == "deviceSessionId" { - self.state.metrics.update_session_id( - self.state.clone(), - Some(self.state.device_session_id.clone().into()), - ); - } - } - Ok(()) - } -} - -pub struct MetricsManagementProvider; -impl RippleRPCProvider for MetricsManagementProvider { - fn provide(state: PlatformState) -> RpcModule { - (MetricsManagementImpl { state }).into_rpc() - } -} diff --git a/core/main/src/firebolt/handlers/metrics_rpc.rs b/core/main/src/firebolt/handlers/metrics_rpc.rs deleted file mode 100644 index b0b3a887c..000000000 --- a/core/main/src/firebolt/handlers/metrics_rpc.rs +++ /dev/null @@ -1,674 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use jsonrpsee::{ - core::{async_trait, RpcResult}, - proc_macros::rpc, - RpcModule, -}; -use std::collections::HashMap; - -use ripple_sdk::{ - api::{ - account_link::{AccountLinkRequest, WatchedRequest}, - firebolt::{ - fb_capabilities::JSON_RPC_STANDARD_ERROR_INVALID_PARAMS, - fb_discovery::WatchedInfo, - fb_metrics::{ - self, hashmap_to_param_vec, Action, BehavioralMetricContext, - BehavioralMetricPayload, CategoryType, ErrorParams, FlatMapValue, - InternalInitializeParams, InternalInitializeResponse, MediaEnded, MediaLoadStart, - MediaPause, MediaPlay, MediaPlaying, MediaPositionType, MediaProgress, - MediaRateChanged, MediaRenditionChanged, MediaSeeked, MediaSeeking, MediaWaiting, - MetricsError, Page, SignIn, SignOut, StartContent, StopContent, Version, - }, - }, - gateway::rpc_gateway_api::CallContext, - }, - log::{error, trace}, - utils::rpc_utils::rpc_error_with_code_result, -}; - -use serde::Deserialize; - -use crate::{ - firebolt::rpc::RippleRPCProvider, processor::metrics_processor::send_metric, - service::telemetry_builder::TelemetryBuilder, state::platform_state::PlatformState, - utils::rpc_utils::rpc_err, -}; - -//const LAUNCH_COMPLETED_SEGMENT: &'static str = "LAUNCH_COMPLETED"; - -#[derive(Deserialize, Debug)] -pub struct PageParams { - #[serde(rename = "pageId")] - pub page_id: String, -} - -#[derive(Debug, Deserialize, Clone)] -pub struct ActionParams { - pub category: CategoryType, - #[serde(rename = "type")] - pub action_type: String, - pub parameters: Option>, -} - -#[derive(Deserialize, Debug, Clone)] -pub struct StartContentParams { - #[serde(rename = "entityId")] - pub entity_id: Option, -} -#[derive(Deserialize, Debug, Clone)] -pub struct StopContentParams { - #[serde(rename = "entityId")] - pub entity_id: Option, -} - -fn validate_metrics_action_type(metrics_action: &str) -> RpcResult { - match metrics_action.len() { - 1..=256 => Ok(true), - _ => rpc_error_with_code_result( - "metrics.action.action_type out of range".to_string(), - JSON_RPC_STANDARD_ERROR_INVALID_PARAMS, - ), - } -} - -pub const ERROR_MEDIA_POSITION_OUT_OF_RANGE: &str = "absolute media position out of range"; -pub const ERROR_BAD_ABSOLUTE_MEDIA_POSITION: &str = - "absolute media position must not contain any numbers to the right of the decimal point."; -/* -implement this: https://developer.comcast.com/firebolt-apis/core-sdk/v0.9.0/metrics#mediaposition -*/ -fn convert_to_media_position_type(media_position: Option) -> RpcResult { - match media_position { - Some(position) => { - if (0.0..=0.999).contains(&position) { - Ok(MediaPositionType::PercentageProgress(position)) - } else { - if position.fract() != 0.0 { - return rpc_error_with_code_result( - ERROR_BAD_ABSOLUTE_MEDIA_POSITION.to_string(), - JSON_RPC_STANDARD_ERROR_INVALID_PARAMS, - ); - }; - let abs_position = position.round() as i32; - - if (1..=86400).contains(&abs_position) { - Ok(MediaPositionType::AbsolutePosition(abs_position)) - } else { - rpc_error_with_code_result( - ERROR_MEDIA_POSITION_OUT_OF_RANGE.to_string(), - JSON_RPC_STANDARD_ERROR_INVALID_PARAMS, - ) - } - } - } - None => Ok(MediaPositionType::None), - } -} - -#[derive(Deserialize, Debug, Clone)] -pub struct MediaLoadStartParams { - #[serde(rename = "entityId")] - pub entity_id: String, -} -#[derive(Deserialize, Debug, Clone)] -pub struct MediaPlayParams { - #[serde(rename = "entityId")] - pub entity_id: String, -} -#[derive(Deserialize, Debug, Clone)] -pub struct MediaPlayingParams { - #[serde(rename = "entityId")] - pub entity_id: String, -} -#[derive(Deserialize, Debug, Clone)] -pub struct MediaPauseParams { - #[serde(rename = "entityId")] - pub entity_id: String, -} -#[derive(Deserialize, Debug, Clone)] -pub struct MediaWaitingParams { - #[serde(rename = "entityId")] - pub entity_id: String, -} -#[derive(Deserialize, Debug, Clone)] -pub struct MediaProgressParams { - #[serde(rename = "entityId")] - pub entity_id: String, - pub progress: Option, -} -#[derive(Deserialize, Debug, Clone)] -pub struct MediaSeekingParams { - #[serde(rename = "entityId")] - pub entity_id: String, - pub target: Option, -} -#[derive(Deserialize, Debug, Clone)] -pub struct MediaSeekedParams { - #[serde(rename = "entityId")] - pub entity_id: String, - pub position: Option, -} -#[derive(Deserialize, Debug, Clone)] -pub struct MediaRateChangeParams { - #[serde(rename = "entityId")] - pub entity_id: String, - pub rate: u32, -} -#[derive(Deserialize, Debug, Clone)] -pub struct MediaRenditionChangeParams { - #[serde(rename = "entityId")] - pub entity_id: String, - pub bitrate: u32, - pub width: u32, - pub height: u32, - pub profile: Option, -} -#[derive(Deserialize, Debug, Clone)] -pub struct MediaEndedParams { - #[serde(rename = "entityId")] - pub entity_id: String, -} - -#[derive(Deserialize, Debug, Clone)] -pub struct AppInfoParams { - pub build: String, -} - -//https://developer.comcast.com/firebolt/core/sdk/latest/api/metrics -#[rpc(server)] -pub trait Metrics { - #[method(name = "metrics.startContent")] - async fn start_content( - &self, - ctx: CallContext, - page_params: StartContentParams, - ) -> RpcResult; - #[method(name = "metrics.stopContent")] - async fn stop_content( - &self, - ctx: CallContext, - stop_content_params: StopContentParams, - ) -> RpcResult; - #[method(name = "metrics.page")] - async fn page(&self, ctx: CallContext, page_params: PageParams) -> RpcResult; - #[method(name = "metrics.action")] - async fn action(&self, ctx: CallContext, action_params: ActionParams) -> RpcResult; - #[method(name = "metrics.error")] - async fn error(&self, ctx: CallContext, error_params: ErrorParams) -> RpcResult; - #[method(name = "metrics.ready")] - async fn ready(&self, ctx: CallContext) -> RpcResult; - #[method(name = "metrics.signin", aliases=["metrics.signIn"])] - async fn sign_in(&self, ctx: CallContext) -> RpcResult; - #[method(name = "metrics.signout", aliases=["metrics.signOut"])] - async fn sign_out(&self, ctx: CallContext) -> RpcResult; - #[method(name = "internal.initialize")] - async fn internal_initialize( - &self, - ctx: CallContext, - internal_initialize_params: InternalInitializeParams, - ) -> RpcResult; - #[method(name = "metrics.mediaLoadStart")] - async fn media_load_start( - &self, - ctx: CallContext, - media_load_start_params: MediaLoadStartParams, - ) -> RpcResult; - #[method(name = "metrics.mediaPlay")] - async fn media_play( - &self, - ctx: CallContext, - media_play_params: MediaPlayParams, - ) -> RpcResult; - #[method(name = "metrics.mediaPlaying")] - async fn media_playing( - &self, - ctx: CallContext, - media_playing_params: MediaPlayingParams, - ) -> RpcResult; - #[method(name = "metrics.mediaPause")] - async fn media_pause( - &self, - ctx: CallContext, - media_pause_params: MediaPauseParams, - ) -> RpcResult; - #[method(name = "metrics.mediaWaiting")] - async fn media_waiting( - &self, - ctx: CallContext, - media_waiting_params: MediaWaitingParams, - ) -> RpcResult; - #[method(name = "metrics.mediaProgress")] - async fn media_progress( - &self, - ctx: CallContext, - media_progress_params: MediaProgressParams, - ) -> RpcResult; - #[method(name = "metrics.mediaSeeking")] - async fn media_seeking( - &self, - ctx: CallContext, - media_seeking_params: MediaSeekingParams, - ) -> RpcResult; - #[method(name = "metrics.mediaSeeked")] - async fn media_seeked( - &self, - ctx: CallContext, - media_seeked_params: MediaSeekedParams, - ) -> RpcResult; - #[method(name = "metrics.mediaRateChange")] - async fn media_rate_change( - &self, - ctx: CallContext, - media_rate_changed_params: MediaRateChangeParams, - ) -> RpcResult; - #[method(name = "metrics.mediaRenditionChange")] - async fn media_rendition_change( - &self, - ctx: CallContext, - media_rendition_change_params: MediaRenditionChangeParams, - ) -> RpcResult; - #[method(name = "metrics.mediaEnded")] - async fn media_ended( - &self, - ctx: CallContext, - media_ended_params: MediaEndedParams, - ) -> RpcResult; - #[method(name = "metrics.appInfo")] - async fn app_info(&self, ctx: CallContext, app_info_params: AppInfoParams) -> RpcResult<()>; -} - -#[derive(Debug, Clone)] -pub struct MetricsImpl { - state: PlatformState, -} - -impl From for CategoryType { - fn from(action_params: ActionParams) -> Self { - action_params.category - } -} - -#[async_trait] -impl MetricsServer for MetricsImpl { - async fn start_content( - &self, - ctx: CallContext, - page_params: StartContentParams, - ) -> RpcResult { - let start_content = BehavioralMetricPayload::StartContent(StartContent { - context: ctx.clone().into(), - entity_id: page_params.entity_id, - }); - - trace!("metrics.startContent={:?}", start_content); - match send_metric(&self.state, start_content, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - - async fn stop_content( - &self, - ctx: CallContext, - stop_content_params: StopContentParams, - ) -> RpcResult { - let stop_content = BehavioralMetricPayload::StopContent(StopContent { - context: ctx.clone().into(), - entity_id: stop_content_params.entity_id, - }); - trace!("metrics.stopContent={:?}", stop_content); - match send_metric(&self.state, stop_content, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn page(&self, ctx: CallContext, page_params: PageParams) -> RpcResult { - let page = BehavioralMetricPayload::Page(Page { - context: ctx.clone().into(), - page_id: page_params.page_id, - }); - trace!("metrics.page={:?}", page); - match send_metric(&self.state, page, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn action(&self, ctx: CallContext, action_params: ActionParams) -> RpcResult { - let _ = validate_metrics_action_type(&action_params.action_type)?; - let p_type = action_params.clone(); - - let action = BehavioralMetricPayload::Action(Action { - context: ctx.clone().into(), - category: action_params.into(), - parameters: hashmap_to_param_vec(p_type.parameters), - _type: p_type.action_type, - }); - trace!("metrics.action={:?}", action); - - match send_metric(&self.state, action, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn ready(&self, ctx: CallContext) -> RpcResult { - let data = BehavioralMetricPayload::Ready(fb_metrics::Ready { - context: BehavioralMetricContext::from(ctx.clone()), - ttmu_ms: 12, - }); - trace!("metrics.action = {:?}", data); - match send_metric(&self.state, data, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - - async fn error(&self, ctx: CallContext, error_params: ErrorParams) -> RpcResult { - let app_id = ctx.app_id.clone(); - let error_message = BehavioralMetricPayload::Error(MetricsError { - context: ctx.clone().into(), - error_type: error_params.clone().into(), - code: error_params.code.clone(), - description: error_params.description.clone(), - visible: error_params.visible, - parameters: error_params.parameters.clone(), - durable_app_id: app_id.clone(), - third_party_error: true, - }); - trace!("metrics.error={:?}", error_message); - TelemetryBuilder::send_error(&self.state, ctx.app_id.to_owned(), error_params); - match send_metric(&self.state, error_message, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn sign_in(&self, ctx: CallContext) -> RpcResult { - let data = BehavioralMetricPayload::SignIn(SignIn { - context: ctx.clone().into(), - }); - trace!("metrics.action = {:?}", data); - Ok(send_metric(&self.state, data, &ctx).await.is_ok()) - } - - async fn sign_out(&self, ctx: CallContext) -> RpcResult { - let data = BehavioralMetricPayload::SignOut(SignOut { - context: ctx.clone().into(), - }); - trace!("metrics.action = {:?}", data); - Ok(send_metric(&self.state, data, &ctx).await.is_ok()) - } - - async fn internal_initialize( - &self, - ctx: CallContext, - internal_initialize_params: InternalInitializeParams, - ) -> RpcResult { - TelemetryBuilder::internal_initialize(&self.state, &ctx, &internal_initialize_params); - let readable_result = internal_initialize_params - .version - .readable - .replace("SDK", "FEE"); - let internal_initialize_resp = Version { - major: internal_initialize_params.version.major, - minor: internal_initialize_params.version.minor, - patch: internal_initialize_params.version.patch, - readable: readable_result, - }; - Ok(InternalInitializeResponse { - version: internal_initialize_resp, - }) - } - async fn media_load_start( - &self, - ctx: CallContext, - media_load_start_params: MediaLoadStartParams, - ) -> RpcResult { - let media_load_start_message = BehavioralMetricPayload::MediaLoadStart(MediaLoadStart { - context: ctx.clone().into(), - entity_id: media_load_start_params.entity_id, - }); - trace!("metrics.media_load_start={:?}", media_load_start_message); - match send_metric(&self.state, media_load_start_message, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn media_play( - &self, - ctx: CallContext, - media_play_params: MediaPlayParams, - ) -> RpcResult { - let media_play_message = BehavioralMetricPayload::MediaPlay(MediaPlay { - context: ctx.clone().into(), - entity_id: media_play_params.entity_id, - }); - trace!("metrics.media_play={:?}", media_play_message); - match send_metric(&self.state, media_play_message, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn media_playing( - &self, - ctx: CallContext, - media_playing_params: MediaPlayingParams, - ) -> RpcResult { - let media_playing = BehavioralMetricPayload::MediaPlaying(MediaPlaying { - context: ctx.clone().into(), - entity_id: media_playing_params.entity_id, - }); - trace!("metrics.media_playing={:?}", media_playing); - match send_metric(&self.state, media_playing, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn media_pause( - &self, - ctx: CallContext, - media_pause_params: MediaPauseParams, - ) -> RpcResult { - let media_pause = BehavioralMetricPayload::MediaPause(MediaPause { - context: ctx.clone().into(), - entity_id: media_pause_params.entity_id, - }); - trace!("metrics.media_pause={:?}", media_pause); - match send_metric(&self.state, media_pause, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn media_waiting( - &self, - ctx: CallContext, - media_waiting_params: MediaWaitingParams, - ) -> RpcResult { - let media_waiting = BehavioralMetricPayload::MediaWaiting(MediaWaiting { - context: ctx.clone().into(), - entity_id: media_waiting_params.entity_id, - }); - trace!("metrics.media_waiting={:?}", media_waiting); - match send_metric(&self.state, media_waiting, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn media_progress( - &self, - ctx: CallContext, - media_progress_params: MediaProgressParams, - ) -> RpcResult { - let progress = convert_to_media_position_type(media_progress_params.progress)?; - - if self - .state - .get_device_manifest() - .configuration - .default_values - .media_progress_as_watched_events - && progress != MediaPositionType::None - { - if let Some(p) = media_progress_params.progress { - let request = WatchedRequest { - context: ctx.clone(), - info: WatchedInfo { - entity_id: media_progress_params.entity_id.clone(), - progress: p, - completed: None, - watched_on: None, - }, - unit: None, - }; - - if let Err(e) = self - .state - .get_client() - .send_extn_request(AccountLinkRequest::Watched(request)) - .await - { - error!("Error sending watched event: {:?}", e); - } - } - } - - let media_progress = BehavioralMetricPayload::MediaProgress(MediaProgress { - context: ctx.clone().into(), - entity_id: media_progress_params.entity_id, - progress: Some(progress), - }); - trace!("metrics.media_progress={:?}", media_progress); - match send_metric(&self.state, media_progress, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn media_seeking( - &self, - ctx: CallContext, - media_seeking_params: MediaSeekingParams, - ) -> RpcResult { - let target = convert_to_media_position_type(media_seeking_params.target)?; - - let media_seeking = BehavioralMetricPayload::MediaSeeking(MediaSeeking { - context: ctx.clone().into(), - entity_id: media_seeking_params.entity_id, - target: Some(target), - }); - trace!("metrics.media_seeking={:?}", media_seeking); - match send_metric(&self.state, media_seeking, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn media_seeked( - &self, - ctx: CallContext, - media_seeked_params: MediaSeekedParams, - ) -> RpcResult { - let position = convert_to_media_position_type(media_seeked_params.position) - .unwrap_or(MediaPositionType::None); - let media_seeked = BehavioralMetricPayload::MediaSeeked(MediaSeeked { - context: ctx.clone().into(), - entity_id: media_seeked_params.entity_id, - position: Some(position), - }); - trace!("metrics.media_seeked={:?}", media_seeked); - match send_metric(&self.state, media_seeked, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn media_rate_change( - &self, - ctx: CallContext, - media_rate_changed_params: MediaRateChangeParams, - ) -> RpcResult { - let media_rate_change = BehavioralMetricPayload::MediaRateChanged(MediaRateChanged { - context: ctx.clone().into(), - entity_id: media_rate_changed_params.entity_id, - rate: media_rate_changed_params.rate, - }); - trace!("metrics.media_seeked={:?}", media_rate_change); - match send_metric(&self.state, media_rate_change, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn media_rendition_change( - &self, - ctx: CallContext, - media_rendition_change_params: MediaRenditionChangeParams, - ) -> RpcResult { - let media_rendition_change = - BehavioralMetricPayload::MediaRenditionChanged(MediaRenditionChanged { - context: ctx.clone().into(), - entity_id: media_rendition_change_params.entity_id, - bitrate: media_rendition_change_params.bitrate, - height: media_rendition_change_params.height, - profile: media_rendition_change_params.profile, - width: media_rendition_change_params.width, - }); - trace!( - "metrics.media_rendition_change={:?}", - media_rendition_change - ); - match send_metric(&self.state, media_rendition_change, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn media_ended( - &self, - ctx: CallContext, - media_ended_params: MediaEndedParams, - ) -> RpcResult { - let media_ended = BehavioralMetricPayload::MediaEnded(MediaEnded { - context: ctx.clone().into(), - entity_id: media_ended_params.entity_id, - }); - trace!("metrics.media_ended={:?}", media_ended); - - match send_metric(&self.state, media_ended, &ctx).await { - Ok(_) => Ok(true), - Err(_) => Err(rpc_err("parse error")), - } - } - async fn app_info(&self, ctx: CallContext, app_info_params: AppInfoParams) -> RpcResult<()> { - trace!("metrics.app_info: app_info_params={:?}", app_info_params); - match self - .state - .app_manager_state - .set_app_metrics_version(&ctx.app_id, app_info_params.build) - { - Ok(_) => Ok(()), - Err(e) => { - error!("Error setting app metrics version: {:?}", e); - Err(rpc_err("Unable to set app info")) - } - } - } -} - -#[derive(Debug, Clone)] -pub struct MetricsRPCProvider; -impl RippleRPCProvider for MetricsRPCProvider { - fn provide(state: PlatformState) -> RpcModule { - (MetricsImpl { state }).into_rpc() - } -} diff --git a/core/main/src/firebolt/handlers/privacy_rpc.rs b/core/main/src/firebolt/handlers/privacy_rpc.rs index 5a376123a..5bf05fed0 100644 --- a/core/main/src/firebolt/handlers/privacy_rpc.rs +++ b/core/main/src/firebolt/handlers/privacy_rpc.rs @@ -89,7 +89,7 @@ impl AllowAppContentAdTargetingSettings { new_ctx.protocol = ApiProtocol::Extn; platform_state - .metrics + .otel .add_api_stats(&ctx.request_id, "localization.countryCode"); let rpc_request = RpcRequest { diff --git a/core/main/src/firebolt/handlers/telemetry_rpc.rs b/core/main/src/firebolt/handlers/telemetry_rpc.rs new file mode 100644 index 000000000..4eb6fc636 --- /dev/null +++ b/core/main/src/firebolt/handlers/telemetry_rpc.rs @@ -0,0 +1,61 @@ +// Copyright 2023 Comcast Cable Communications Management, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 +// + +use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule}; +use ripple_sdk::{ + api::{firebolt::fb_telemetry::TelemetryPayload, gateway::rpc_gateway_api::CallContext}, + async_trait::async_trait, +}; + +use crate::{ + firebolt::rpc::RippleRPCProvider, service::telemetry_builder::TelemetryBuilder, + state::platform_state::PlatformState, +}; + +#[rpc(server)] +pub trait Telemetry { + #[method(name = "ripple.sendTelemetry")] + async fn send_telemetry(&self, ctx: CallContext, payload: TelemetryPayload) -> RpcResult<()>; + + #[method(name = "ripple.setTelemetrySessionId")] + fn set_telemetry_session_id(&self, ctx: CallContext, session_id: String) -> RpcResult<()>; +} + +#[derive(Debug)] +pub struct TelemetryImpl { + pub state: PlatformState, +} + +#[async_trait] +impl TelemetryServer for TelemetryImpl { + async fn send_telemetry(&self, _ctx: CallContext, payload: TelemetryPayload) -> RpcResult<()> { + let _ = TelemetryBuilder::send_telemetry(&self.state, payload); + Ok(()) + } + + fn set_telemetry_session_id(&self, _ctx: CallContext, session_id: String) -> RpcResult<()> { + self.state.otel.update_session_id(Some(session_id)); + Ok(()) + } +} + +pub struct TelemetryProvider; +impl RippleRPCProvider for TelemetryProvider { + fn provide(state: PlatformState) -> RpcModule { + (TelemetryImpl { state }).into_rpc() + } +} diff --git a/core/main/src/firebolt/mod.rs b/core/main/src/firebolt/mod.rs index 6a0d81197..4f040db54 100644 --- a/core/main/src/firebolt/mod.rs +++ b/core/main/src/firebolt/mod.rs @@ -31,14 +31,13 @@ pub mod handlers { pub mod lcm_rpc; pub mod lifecycle_rpc; pub mod localization_rpc; - pub mod metrics_management_rpc; - pub mod metrics_rpc; pub mod parameters_rpc; pub mod privacy_rpc; pub mod profile_rpc; pub mod provider_registrar; pub mod second_screen_rpc; pub mod secure_storage_rpc; + pub mod telemetry_rpc; pub mod user_grants_rpc; pub mod voice_guidance_rpc; pub mod wifi_rpc; diff --git a/core/main/src/firebolt/rpc_router.rs b/core/main/src/firebolt/rpc_router.rs index 01d50903c..fdf93cace 100644 --- a/core/main/src/firebolt/rpc_router.rs +++ b/core/main/src/firebolt/rpc_router.rs @@ -29,7 +29,6 @@ use jsonrpsee::{ }; use ripple_sdk::{ api::{ - firebolt::fb_metrics::Timer, gateway::rpc_gateway_api::{ApiMessage, RpcRequest}, observability::log_signal::LogSignal, }, @@ -184,15 +183,15 @@ async fn resolve_route( 1 }; - capture_stage(&platform_state.metrics, &req, "routing"); + capture_stage(&platform_state.otel, &req, "routing"); - platform_state.metrics.update_api_stats_ref( + platform_state.otel.update_api_stats_ref( &request_id, add_telemetry_status_code(&rpc_header, status_code.to_string().as_str()), ); let mut msg = ApiMessage::new(protocol, r, request_id.clone()); - if let Some(api_stats) = platform_state.metrics.get_api_stats(&request_id) { + if let Some(api_stats) = platform_state.otel.get_api_stats(&request_id) { msg.stats = Some(api_stats); } @@ -203,12 +202,7 @@ async fn resolve_route( } impl RpcRouter { - pub async fn route( - mut state: PlatformState, - mut req: RpcRequest, - session: Session, - timer: Option, - ) { + pub async fn route(mut state: PlatformState, mut req: RpcRequest, session: Session) { let methods = state.router_state.get_methods(); let resources = state.router_state.resources.clone(); @@ -219,20 +213,6 @@ impl RpcRouter { tokio::spawn(async move { let start = Utc::now().timestamp_millis(); let resp = resolve_route(&mut state, methods, resources, req.clone()).await; - - let status = match resp.clone() { - Ok(msg) => { - if msg.is_error() { - msg.jsonrpc_msg - } else { - "0".into() - } - } - Err(e) => format!("{}", e), - }; - - TelemetryBuilder::stop_and_send_firebolt_metrics_timer(&state, timer, status).await; - if let Ok(msg) = resp { let now = Utc::now().timestamp_millis(); let success = !msg.is_error(); diff --git a/core/main/src/processor/main_context_processor.rs b/core/main/src/processor/main_context_processor.rs index 2d0409276..e68edb64d 100644 --- a/core/main/src/processor/main_context_processor.rs +++ b/core/main/src/processor/main_context_processor.rs @@ -15,10 +15,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::{ - sync::{Arc, Once, RwLock}, - time::Duration, -}; +use std::sync::{Arc, RwLock}; use ripple_sdk::{ api::{ @@ -28,9 +25,7 @@ use ripple_sdk::{ device_request::{InternetConnectionStatus, PowerState, SystemPowerState}, device_user_grants_data::GrantLifespan, }, - distributor::distributor_sync::{SyncAndMonitorModule, SyncAndMonitorRequest}, firebolt::fb_capabilities::{CapEvent, CapabilityRole, FireboltCap, FireboltPermission}, - manifest::device_manifest::PrivacySettingsStorageType, session::{AccountSessionRequest, AccountSessionResponse}, }, async_trait::async_trait, @@ -46,11 +41,10 @@ use ripple_sdk::{ sync::{mpsc::Receiver as MReceiver, mpsc::Sender as MSender}, }, }; -static START_PARTNER_EXCLUSION_SYNC_THREAD: Once = Once::new(); use crate::{ - service::{apps::apps_updater::AppsUpdater, data_governance::DataGovernance}, - state::{cap::cap_state::CapState, metrics_state::MetricsState, platform_state::PlatformState}, + service::apps::apps_updater::AppsUpdater, + state::{cap::cap_state::CapState, platform_state::PlatformState}, }; #[derive(Debug, Clone)] @@ -92,7 +86,6 @@ impl MainContextProcessor { { if let Some(session) = response.payload.extract() { state.session_state.insert_account_session(session); - MetricsState::update_account_session(state).await; event = CapEvent::OnAvailable; let state_c = state.clone(); // update ripple context for token asynchronously @@ -145,30 +138,6 @@ impl MainContextProcessor { debug!("token::platform available status: {:?}", available_result); available_result.is_ok() } - - async fn sync_partner_exclusions(state: &PlatformState) { - let state_for_exclusion = state.clone(); - START_PARTNER_EXCLUSION_SYNC_THREAD.call_once(|| { - debug!("Starting partner exclusion sync thread"); - tokio::spawn(async move { - let duration = state_for_exclusion - .get_device_manifest() - .configuration - .partner_exclusion_refresh_timeout - .into(); - let mut interval = tokio::time::interval(Duration::from_secs(duration)); - loop { - let resp: bool = - DataGovernance::refresh_partner_exclusions(&state_for_exclusion).await; - debug!( - "refresh_partner_exclusions: {:?} interval : {:?}", - resp, interval - ); - interval.tick().await; - } - }); - }); - } pub async fn initialize_session(state: &PlatformState) { // If the platform:token capability is available then the current call is // to update token. If not it is the first time we are receiving token @@ -176,61 +145,10 @@ impl MainContextProcessor { let update_token = Self::is_update_token(state); if !update_token && !Self::check_account_session_token(state).await { error!("Account session still not available"); - } else { - if state.supports_cloud_sync() { - debug!("Cloud Sync configured as a required contract so starting."); - if state - .get_device_manifest() - .configuration - .features - .privacy_settings_storage_type - == PrivacySettingsStorageType::Sync - { - debug!( - "Privacy settings storage type is set as sync so starting cloud monitor" - ); - if let Some(account_session) = state.session_state.get_account_session() { - debug!("Successfully got account session"); - if !update_token { - let sync_response = state - .get_client() - .send_extn_request(SyncAndMonitorRequest::SyncAndMonitor( - SyncAndMonitorModule::Privacy, - account_session.clone(), - )) - .await; - debug!("Received Sync response for privacy: {:?}", sync_response); - let sync_response = state - .get_client() - .send_extn_request(SyncAndMonitorRequest::SyncAndMonitor( - SyncAndMonitorModule::UserGrants, - account_session.clone(), - )) - .await; - debug!( - "Received Sync response for user grants: {:?}", - sync_response - ); - } else { - debug!("cap already available so just updating the token alone"); - let update_token_response = state - .get_client() - .send_extn_request(SyncAndMonitorRequest::UpdateDistributorToken( - account_session.token.clone(), - )) - .await; - debug!("Cap token:account is already in available state. just updating Token res: {:?}", update_token_response); - } - //sync up partner exclusion data and setup polling thread for refreshing it. - Self::sync_partner_exclusions(state).await; - } - } - } - if state.supports_app_catalog() { - state - .get_client() - .add_event_processor(AppsUpdater::init(state).await); - } + } else if state.supports_app_catalog() { + state + .get_client() + .add_event_processor(AppsUpdater::init(state).await); } } diff --git a/core/main/src/processor/metrics_processor.rs b/core/main/src/processor/metrics_processor.rs index 2a2fd7062..1ff445db9 100644 --- a/core/main/src/processor/metrics_processor.rs +++ b/core/main/src/processor/metrics_processor.rs @@ -16,17 +16,7 @@ // use ripple_sdk::{ - api::{ - distributor::distributor_privacy::DataEventType, - firebolt::{ - fb_metrics::{ - AppDataGovernanceState, BehavioralMetricContext, BehavioralMetricPayload, - BehavioralMetricRequest, MetricsPayload, MetricsRequest, - }, - fb_telemetry::OperationalMetricRequest, - }, - gateway::rpc_gateway_api::CallContext, - }, + api::firebolt::fb_telemetry::OperationalMetricRequest, async_trait::async_trait, extn::{ client::extn_processor::{ @@ -34,191 +24,11 @@ use ripple_sdk::{ }, extn_client_message::ExtnMessage, }, - framework::RippleResponse, - log::debug, tokio::sync::mpsc::{Receiver as MReceiver, Sender as MSender}, }; -use crate::{ - service::{data_governance::DataGovernance, telemetry_builder::TelemetryBuilder}, - state::platform_state::PlatformState, - SEMVER_LIGHTWEIGHT, -}; - -pub async fn send_metric( - platform_state: &PlatformState, - mut payload: BehavioralMetricPayload, - ctx: &CallContext, -) -> RippleResponse { - // TODO use _ctx for any governance stuff - let drop_data = update_app_context(platform_state, ctx, &mut payload).await; - /* - not opted in, or configured out, do nothing - */ - if drop_data { - debug!("drop data is true, not sending BI metrics"); - return Ok(()); - } - - if let Some(session) = platform_state.session_state.get_account_session() { - let request = BehavioralMetricRequest { - context: Some(platform_state.metrics.get_context()), - payload, - session, - }; - return platform_state - .get_client() - .send_extn_request_transient(request); - } - - Err(ripple_sdk::utils::error::RippleError::ProcessorError) -} - -pub async fn update_app_context( - ps: &PlatformState, - ctx: &CallContext, - payload: &mut BehavioralMetricPayload, -) -> bool { - let mut context: BehavioralMetricContext = ctx.clone().into(); - if let Some(app) = ps.app_manager_state.get(&ctx.app_id) { - context.app_session_id = app.loaded_session_id.to_owned(); - context.app_user_session_id = app.active_session_id; - context.product_version = ps - .version - .clone() - .unwrap_or(String::from(SEMVER_LIGHTWEIGHT)); - - context.app_version = app.app_metrics_version.clone(); - } - if let Some(session) = ps.session_state.get_account_session() { - context.partner_id = session.id; - } - let (tags, drop_data) = - DataGovernance::resolve_tags(ps, ctx.app_id.clone(), DataEventType::BusinessIntelligence) - .await; - let tag_name_set = tags.iter().map(|tag| tag.tag_name.clone()).collect(); - context.governance_state = Some(AppDataGovernanceState::new(tag_name_set)); - - payload.update_context(context); - - match payload { - BehavioralMetricPayload::Ready(_) => { - TelemetryBuilder::send_app_load_stop(ps, ctx.app_id.clone(), true) - } - BehavioralMetricPayload::SignIn(_) => TelemetryBuilder::send_sign_in(ps, ctx), - BehavioralMetricPayload::SignOut(_) => TelemetryBuilder::send_sign_out(ps, ctx), - _ => {} - } - drop_data -} -pub async fn send_metric_for_app_state_change( - ps: &PlatformState, - mut payload: BehavioralMetricPayload, - app_id: &str, -) -> RippleResponse { - match payload { - BehavioralMetricPayload::AppStateChange(_) | BehavioralMetricPayload::Error(_) => { - let (tags, drop_data) = DataGovernance::resolve_tags( - ps, - app_id.to_string(), - DataEventType::BusinessIntelligence, - ) - .await; - let tag_name_set = tags.iter().map(|tag| tag.tag_name.clone()).collect(); - - if drop_data { - debug!("drop data is true, not sending BI metrics"); - return Ok(()); - } - - let mut context: BehavioralMetricContext = payload.get_context(); - let session = ps.session_state.get_account_session(); - if let Some(session) = session { - if let Some(app) = ps.app_manager_state.get(app_id) { - context.app_session_id = app.loaded_session_id.to_owned(); - context.app_user_session_id = app.active_session_id; - context.product_version = ps - .version - .clone() - .unwrap_or(String::from(SEMVER_LIGHTWEIGHT)); - } - context.governance_state = Some(AppDataGovernanceState::new(tag_name_set)); - context.partner_id = session.clone().id; - payload.update_context(context); - - let request = BehavioralMetricRequest { - context: Some(ps.metrics.get_context()), - payload, - session, - }; - return ps.get_client().send_extn_request_transient(request); - } - Err(ripple_sdk::utils::error::RippleError::ProcessorError) - } - _ => Ok(()), - } -} +use crate::state::platform_state::PlatformState; /// Supports processing of Metrics request from extensions and forwards the metrics accordingly. -#[derive(Debug)] -pub struct MetricsProcessor { - state: PlatformState, - streamer: DefaultExtnStreamer, -} - -impl MetricsProcessor { - pub fn new(state: PlatformState) -> MetricsProcessor { - MetricsProcessor { - state, - streamer: DefaultExtnStreamer::new(), - } - } -} - -impl ExtnStreamProcessor for MetricsProcessor { - type STATE = PlatformState; - type VALUE = MetricsRequest; - fn get_state(&self) -> Self::STATE { - self.state.clone() - } - - fn sender(&self) -> MSender { - self.streamer.sender() - } - - fn receiver(&mut self) -> MReceiver { - self.streamer.receiver() - } -} - -#[async_trait] -impl ExtnRequestProcessor for MetricsProcessor { - fn get_client(&self) -> ripple_sdk::extn::client::extn_client::ExtnClient { - self.state.get_client().get_extn_client() - } - - async fn process_request( - state: Self::STATE, - msg: ExtnMessage, - extracted_message: Self::VALUE, - ) -> bool { - let client = state.get_client().get_extn_client(); - match extracted_message.payload { - MetricsPayload::BehaviorMetric(b, c) => { - return match send_metric(&state, b, &c).await { - Ok(_) => Self::ack(client, msg).await.is_ok(), - Err(e) => Self::handle_error(client, msg, e).await, - } - } - MetricsPayload::TelemetryPayload(t) => { - match TelemetryBuilder::update_session_id_and_send_telemetry(&state, t) { - Ok(_) => Self::ack(client, msg).await.is_ok(), - Err(e) => Self::handle_error(client, msg, e).await, - } - } - MetricsPayload::OperationalMetric(_) => true, - } - } -} /// Supports processing of Metrics request from extensions and forwards the metrics accordingly. #[derive(Debug)] @@ -265,13 +75,12 @@ impl ExtnRequestProcessor for OpMetricsProcessor { ) -> bool { let requestor = msg.requestor.to_string(); match extracted_message { - OperationalMetricRequest::Subscribe => state - .metrics - .operational_telemetry_listener(&requestor, true), - OperationalMetricRequest::UnSubscribe => state - .metrics - .operational_telemetry_listener(&requestor, false), - _ => (), + OperationalMetricRequest::Subscribe => { + state.otel.operational_telemetry_listener(&requestor, true) + } + OperationalMetricRequest::UnSubscribe => { + state.otel.operational_telemetry_listener(&requestor, false) + } } Self::ack(state.get_client().get_extn_client(), msg) .await diff --git a/core/main/src/service/apps/delegated_launcher_handler.rs b/core/main/src/service/apps/delegated_launcher_handler.rs index 8d44da155..377ca6b2f 100644 --- a/core/main/src/service/apps/delegated_launcher_handler.rs +++ b/core/main/src/service/apps/delegated_launcher_handler.rs @@ -34,15 +34,12 @@ use ripple_sdk::{ LCM_EVENT_ON_SESSION_TRANSITION_CANCELED, LCM_EVENT_ON_SESSION_TRANSITION_COMPLETED, }, - fb_metrics::{ - AppLifecycleState, AppLifecycleStateChange, BehavioralMetricContext, - BehavioralMetricPayload, - }, + fb_metrics::{AppLifecycleState, AppLifecycleStateChange}, fb_secondscreen::SECOND_SCREEN_EVENT_ON_LAUNCH_REQUEST, }, gateway::rpc_gateway_api::{AppIdentification, CallerSession}, }, - log::{debug, error, trace, warn}, + log::{debug, error, warn}, serde_json::{self}, tokio::sync::oneshot, utils::{error::RippleError, time_utils::Timer}, @@ -71,7 +68,7 @@ use ripple_sdk::{ use serde_json::{json, Value}; use crate::{ - processor::metrics_processor::send_metric_for_app_state_change, + broker::broker_utils::BrokerUtils, service::{ apps::{ app_events::AppEvents, pending_session_event_processor::PendingSessionEventProcessor, @@ -85,7 +82,6 @@ use crate::{ platform_state::PlatformState, session_state::PendingSessionInfo, }, utils::rpc_utils::rpc_await_oneshot, - SEMVER_LIGHTWEIGHT, }; const APP_ID_TITLE_FILE_NAME: &str = "appInfo.json"; @@ -547,61 +543,80 @@ impl DelegatedLauncherHandler { &mut self, app_id: &str, method: &AppMethod, - _app_manager_response: Result, + app_manager_response: Result, ) { - let previous_state = self + if self .platform_state - .app_manager_state - .get_internal_state(app_id); - - let context = BehavioralMetricContext { - app_id: app_id.to_string(), - product_version: SEMVER_LIGHTWEIGHT.to_string(), - partner_id: String::from("partner.id.not.set"), - app_session_id: String::from("app_session_id.not.set"), - durable_app_id: app_id.to_string(), - app_version: None, - app_user_session_id: None, - governance_state: None, - }; - - /* - Do not forward internal errors from the launch handler as AppErrors. Only forward third-party application error messages as AppErrors. - TBD: Collaborate with the SIFT team to obtain the appropriate SIFT code for sharing error messages from the AppLauncher. - */ + .endpoint_state + .has_rule("ripple.reportLifecycleStateChange") + { + let previous_state = self + .platform_state + .app_manager_state + .get_internal_state(app_id); - let inactive = self - .platform_state - .app_manager_state - .get(app_id) - .map_or(false, |app| app.initial_session.launch.inactive); + /* + Do not forward internal errors from the launch handler as AppErrors. Only forward third-party application error messages as AppErrors. + TBD: Collaborate with the SIFT team to obtain the appropriate SIFT code for sharing error messages from the AppLauncher. + */ - let to_state = map_event(method, inactive); + let inactive = self + .platform_state + .app_manager_state + .get(app_id) + .map_or(false, |app| app.initial_session.launch.inactive); - if to_state.is_none() { - /* - NOOP, the launcher implementation does not care about this state w/respect to metrics */ - return; - }; - let from_state = match previous_state { - Some(state) => map_event(&state, inactive), - None => None, - }; + let to_state = map_event(method, inactive); - let app_state_change_message = - BehavioralMetricPayload::AppStateChange(AppLifecycleStateChange { - context, - previous_state: from_state, + if to_state.is_none() { + /* + NOOP, the launcher implementation does not care about this state w/respect to metrics */ + return; + }; + let from_state = match previous_state { + Some(state) => map_event(&state, inactive), + None => None, + }; + let params = serde_json::to_value(AppLifecycleStateChange { + context: app_id.into(), new_state: to_state.unwrap(), - }); + previous_state: from_state, + }) + .unwrap(); + if BrokerUtils::process_for_app_main_request( + &mut self.platform_state.clone(), + "ripple.reportLifecycleStateChange", + Some(params), + app_id, + ) + .await + .is_err() + { + error!("Error reporting lifecycle state") + } + } - trace!("metrics.media_load_start={:?}", app_state_change_message); - let _ = send_metric_for_app_state_change( - &self.platform_state, - app_state_change_message, - app_id, - ) - .await; + if let AppMethod::BrowserSession(_) = method { + if self + .platform_state + .endpoint_state + .has_rule("ripple.reportSessionUpdate") + { + if let Ok(AppManagerResponse::Session(a)) = app_manager_response { + let params = serde_json::to_value(a).unwrap(); + if BrokerUtils::process_internal_main_request( + &mut self.platform_state.clone(), + "ripple.reportSessionUpdate", + Some(params), + ) + .await + .is_err() + { + error!("Error reporting lifecycle state") + } + } + } + } self.platform_state .app_manager_state diff --git a/core/main/src/service/telemetry_builder.rs b/core/main/src/service/telemetry_builder.rs index c24a4483e..22d1bb456 100644 --- a/core/main/src/service/telemetry_builder.rs +++ b/core/main/src/service/telemetry_builder.rs @@ -18,10 +18,7 @@ use ripple_sdk::{ api::{ firebolt::{ - fb_metrics::{ - get_metrics_tags, ErrorParams, InteractionType, InternalInitializeParams, - SystemErrorParams, Tag, Timer, TimerType, - }, + fb_metrics::{ErrorParams, InternalInitializeParams, SystemErrorParams}, fb_telemetry::{ AppLoadStart, AppLoadStop, FireboltInteraction, InternalInitialize, TelemetryAppError, TelemetryPayload, TelemetrySignIn, TelemetrySignOut, @@ -31,7 +28,6 @@ use ripple_sdk::{ gateway::rpc_gateway_api::{ApiMessage, CallContext, RpcRequest}, }, chrono::{DateTime, Utc}, - extn::client::extn_client::ExtnClient, framework::RippleResponse, log::{error, trace}, }; @@ -55,7 +51,7 @@ impl TelemetryBuilder { app_id, app_version, start_time: start_time.unwrap_or_default().timestamp_millis(), - ripple_session_id: ps.metrics.get_context().device_session_id, + ripple_session_id: ps.otel.get_device_session_id(), ripple_version: ps .version .clone() @@ -74,7 +70,7 @@ impl TelemetryBuilder { app_id, stop_time: Utc::now().timestamp_millis(), app_session_id: None, - ripple_session_id: ps.metrics.get_context().device_session_id, + ripple_session_id: ps.otel.get_device_session_id(), success, }), ) { @@ -86,15 +82,15 @@ impl TelemetryBuilder { ps: &PlatformState, mut t: TelemetryPayload, ) -> RippleResponse { - let session_id = ps.metrics.get_context().device_session_id; + let session_id = ps.otel.get_device_session_id(); t.update_session_id(session_id); Self::send_telemetry(ps, t) } - fn send_telemetry(ps: &PlatformState, t: TelemetryPayload) -> RippleResponse { + pub fn send_telemetry(ps: &PlatformState, t: TelemetryPayload) -> RippleResponse { trace!("send_telemetry: t={:?}", t); - let listeners = ps.metrics.get_listeners(); + let listeners = ps.otel.get_listeners(); let client = ps.get_client().get_extn_client(); let mut result = Ok(()); for id in listeners { @@ -115,14 +111,14 @@ impl TelemetryBuilder { .clone() .unwrap_or(String::from(SEMVER_LIGHTWEIGHT)), ), - Some(ps.metrics.start_time), + Some(ps.otel.start_time), ); Self::send_app_load_stop(ps, "ripple".to_string(), true); } pub fn send_error(ps: &PlatformState, app_id: String, error_params: ErrorParams) { let mut app_error: TelemetryAppError = error_params.into(); - app_error.ripple_session_id = ps.metrics.get_context().device_session_id; + app_error.ripple_session_id = ps.otel.get_device_session_id(); app_error.app_id = app_id; if let Err(e) = Self::send_telemetry(ps, TelemetryPayload::AppError(app_error)) { @@ -132,7 +128,7 @@ impl TelemetryBuilder { pub fn send_system_error(ps: &PlatformState, error_params: SystemErrorParams) { let mut system_error: TelemetrySystemError = error_params.into(); - system_error.ripple_session_id = ps.metrics.get_context().device_session_id; + system_error.ripple_session_id = ps.otel.get_device_session_id(); if let Err(e) = Self::send_telemetry(ps, TelemetryPayload::SystemError(system_error)) { error!("send_telemetry={:?}", e) @@ -144,7 +140,7 @@ impl TelemetryBuilder { ps, TelemetryPayload::SignIn(TelemetrySignIn { app_id: ctx.app_id.to_owned(), - ripple_session_id: ps.metrics.get_context().device_session_id, + ripple_session_id: ps.otel.get_device_session_id(), app_session_id: Some(ctx.session_id.to_owned()), }), ) { @@ -157,7 +153,7 @@ impl TelemetryBuilder { ps, TelemetryPayload::SignOut(TelemetrySignOut { app_id: ctx.app_id.to_owned(), - ripple_session_id: ps.metrics.get_context().device_session_id, + ripple_session_id: ps.otel.get_device_session_id(), app_session_id: Some(ctx.session_id.to_owned()), }), ) { @@ -174,7 +170,7 @@ impl TelemetryBuilder { ps, TelemetryPayload::InternalInitialize(InternalInitialize { app_id: ctx.app_id.to_owned(), - ripple_session_id: ps.metrics.get_context().device_session_id, + ripple_session_id: ps.otel.get_device_session_id(), app_session_id: Some(ctx.session_id.to_owned()), semantic_version: params.version.to_string(), }), @@ -208,7 +204,7 @@ impl TelemetryBuilder { ps, TelemetryPayload::FireboltInteraction(FireboltInteraction { app_id: ctx.app_id.to_owned(), - ripple_session_id: ps.metrics.get_context().device_session_id, + ripple_session_id: ps.otel.get_device_session_id(), app_session_id: Some(ctx.session_id), tt, method, @@ -220,45 +216,4 @@ impl TelemetryBuilder { error!("send_telemetry={:?}", e) } } - - pub fn start_firebolt_metrics_timer( - extn_client: &ExtnClient, - name: String, - app_id: String, - ) -> Option { - let metrics_tags = get_metrics_tags(extn_client, InteractionType::Firebolt, Some(app_id))?; - - trace!("start_firebolt_metrics_timer: {}: {:?}", name, metrics_tags); - - Some(Timer::start( - name, - Some(metrics_tags), - Some(TimerType::Local), - )) - } - - pub async fn stop_and_send_firebolt_metrics_timer( - ps: &PlatformState, - timer: Option, - status: String, - ) { - if let Some(mut timer) = timer { - timer.stop(); - timer.insert_tag(Tag::Status.key(), status); - if let Err(e) = &ps - .get_client() - .send_extn_request( - ripple_sdk::api::firebolt::fb_telemetry::OperationalMetricRequest::Timer( - timer.clone(), - ), - ) - .await - { - error!( - "stop_and_send_firebolt_metrics_timer: send_telemetry={:?}", - e - ) - } - } - } } diff --git a/core/main/src/state/bootstrap_state.rs b/core/main/src/state/bootstrap_state.rs index 86d9be7bf..7b8c0e99b 100644 --- a/core/main/src/state/bootstrap_state.rs +++ b/core/main/src/state/bootstrap_state.rs @@ -21,16 +21,14 @@ use ripple_sdk::{ api::apps::AppRequest, async_channel::{unbounded, Receiver as CReceiver, Sender as CSender}, extn::ffi::ffi_message::CExtnMessage, - framework::bootstrap::TransientChannel, + framework::{bootstrap::TransientChannel, device_manifest_bootstrap::LoadDeviceManifestStep}, log::{info, warn}, tokio::sync::mpsc::{self, Receiver, Sender}, utils::error::RippleError, }; use crate::{ - bootstrap::manifest::{ - apps::LoadAppLibraryStep, device::LoadDeviceManifestStep, extn::LoadExtnManifestStep, - }, + bootstrap::manifest::{apps::LoadAppLibraryStep, extn::LoadExtnManifestStep}, broker::endpoint_broker::BrokerOutput, firebolt::firebolt_gateway::FireboltGatewayCommand, service::extn::ripple_client::RippleClient, diff --git a/core/main/src/state/metrics_state.rs b/core/main/src/state/metrics_state.rs deleted file mode 100644 index 128e28a36..000000000 --- a/core/main/src/state/metrics_state.rs +++ /dev/null @@ -1,551 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use std::{ - collections::{HashMap, HashSet}, - sync::{Arc, RwLock}, -}; - -use jsonrpsee::tracing::debug; -use ripple_sdk::{ - api::{ - context::RippleContextUpdateRequest, - device::device_info_request::{DeviceInfoRequest, DeviceResponse, FirmwareInfo}, - distributor::distributor_privacy::{DataEventType, PrivacySettingsData}, - firebolt::{fb_metrics::MetricsContext, fb_openrpc::FireboltSemanticVersion}, - gateway::rpc_gateway_api::rpc_value_result_to_string_result, - manifest::device_manifest::DataGovernanceConfig, - observability::metrics_util::ApiStats, - storage_property::StorageProperty, - }, - chrono::{DateTime, Utc}, - extn::extn_client_message::ExtnResponse, - log::{error, warn}, - utils::{error::RippleError, rpc_utils::rpc_error_with_code}, -}; - -use rand::Rng; -use serde_json::from_value; - -use crate::{ - broker::broker_utils::BrokerUtils, processor::storage::storage_manager::StorageManager, -}; - -use super::platform_state::PlatformState; - -include!(concat!(env!("OUT_DIR"), "/version.rs")); - -const PERSISTENT_STORAGE_NAMESPACE: &str = "accountProfile"; -const PERSISTENT_STORAGE_KEY_PROPOSITION: &str = "proposition"; -const PERSISTENT_STORAGE_KEY_RETAILER: &str = "retailer"; -const PERSISTENT_STORAGE_KEY_PRIMARY_PROVIDER: &str = "jvagent"; -const PERSISTENT_STORAGE_KEY_COAM: &str = "coam"; -const PERSISTENT_STORAGE_KEY_ACCOUNT_TYPE: &str = "accountType"; -const PERSISTENT_STORAGE_KEY_OPERATOR: &str = "operator"; -const PERSISTENT_STORAGE_ACCOUNT_DETAIL_TYPE: &str = "detailType"; -const PERSISTENT_STORAGE_ACCOUNT_DEVICE_TYPE: &str = "deviceType"; -const PERSISTENT_STORAGE_ACCOUNT_DEVICE_MANUFACTURER: &str = "deviceManufacturer"; - -const API_STATS_MAP_SIZE_WARNING: usize = 10; - -#[derive(Debug, Clone, Default)] -pub struct MetricsState { - pub start_time: DateTime, - pub context: Arc>, - operational_telemetry_listeners: Arc>>, - api_stats_map: Arc>>, -} - -impl MetricsState { - fn send_context_update_request(platform_state: &PlatformState) { - let extn_client = platform_state.get_client().get_extn_client(); - let metrics_context = platform_state.metrics.context.read().unwrap().clone(); - - if let Err(e) = extn_client - .request_transient(RippleContextUpdateRequest::MetricsContext(metrics_context)) - { - error!( - "Error sending context update: RippleContextUpdateRequest::MetricsContext: {:?}", - e - ); - } - } - - pub fn get_context(&self) -> MetricsContext { - self.context.read().unwrap().clone() - } - - fn get_option_string(s: String) -> Option { - if !s.is_empty() { - return Some(s); - } - None - } - - pub fn update_data_governance_tags( - &self, - platform_state: &PlatformState, - privacy_settings_data: &PrivacySettingsData, - ) { - fn update_tags( - data_governance_config: &DataGovernanceConfig, - data: Option, - tags: &mut Vec, - data_event_type: DataEventType, - storage_property: StorageProperty, - ) { - if let Some(true) = data { - if let Some(policy) = data_governance_config.get_policy(data_event_type) { - if let Some(setting_tag) = policy - .setting_tags - .iter() - .find(|t| t.setting == storage_property) - { - for tag in setting_tag.tags.clone() { - tags.push(tag); - } - } - } - } - } - - let mut governance_tags: Vec = Vec::new(); - let data_governance_config = platform_state - .get_device_manifest() - .configuration - .data_governance; - - update_tags( - &data_governance_config, - privacy_settings_data.allow_business_analytics, - &mut governance_tags, - DataEventType::BusinessIntelligence, - StorageProperty::AllowBusinessAnalytics, - ); - - update_tags( - &data_governance_config, - privacy_settings_data.allow_resume_points, - &mut governance_tags, - DataEventType::Watched, - StorageProperty::AllowWatchHistory, - ); - - update_tags( - &data_governance_config, - privacy_settings_data.allow_personalization, - &mut governance_tags, - DataEventType::BusinessIntelligence, - StorageProperty::AllowPersonalization, - ); - - update_tags( - &data_governance_config, - privacy_settings_data.allow_product_analytics, - &mut governance_tags, - DataEventType::BusinessIntelligence, - StorageProperty::AllowProductAnalytics, - ); - - self.context.write().unwrap().data_governance_tags = if !governance_tags.is_empty() { - Some(governance_tags) - } else { - None - }; - } - - async fn get_persistent_store_string( - state: &PlatformState, - key: &'static str, - ) -> Option { - match StorageManager::get_string_from_namespace( - state, - PERSISTENT_STORAGE_NAMESPACE.to_string(), - key, - None, - ) - .await - { - Ok(resp) => Self::get_option_string(resp.as_value()), - Err(e) => { - error!( - "get_persistent_store_string: Could not retrieve value: e={:?}", - e - ); - None - } - } - } - - async fn get_persistent_store_bool(state: &PlatformState, key: &'static str) -> Option { - match StorageManager::get_bool_from_namespace( - state, - PERSISTENT_STORAGE_NAMESPACE.to_string(), - key, - ) - .await - { - Ok(resp) => Some(resp.as_value()), - Err(e) => { - error!( - "get_persistent_store_bool: Could not retrieve value: e={:?}", - e - ); - None - } - } - } - fn unset(s: &str) -> String { - format!("{}{}", s, ".unset") - } - - pub async fn initialize(state: &mut PlatformState) { - let metrics_percentage = state - .get_device_manifest() - .configuration - .metrics_logging_percentage; - - let random_number = rand::thread_rng().gen_range(1..101); - let metrics_enabled = random_number <= metrics_percentage; - - debug!( - "initialize: metrics_percentage={}, random_number={}, enabled={}", - metrics_percentage, random_number, metrics_enabled - ); - - let mut mac_address: Option = None; - if let Ok(resp) = state - .get_client() - .send_extn_request(DeviceInfoRequest::MacAddress) - .await - { - if let Some(ExtnResponse::String(mac)) = resp.payload.extract() { - let _ = mac_address.insert(mac); - } - } - - let mut serial_number: Option = None; - if let Ok(resp) = state - .get_client() - .send_extn_request(DeviceInfoRequest::SerialNumber) - .await - { - if let Some(ExtnResponse::String(sn)) = resp.payload.extract() { - let _ = serial_number.insert(sn); - } - } - - let mut device_model: Option = None; - if let Ok(resp) = state - .get_client() - .send_extn_request(DeviceInfoRequest::Model) - .await - { - if let Some(ExtnResponse::String(model)) = resp.payload.extract() { - let _ = device_model.insert(model); - } - } - - let language = - BrokerUtils::process_internal_main_request(state, "localization.language", None) - .await - .and_then(|val| { - from_value::(val).map_err(|_| { - rpc_error_with_code::( - "Failed to parse language".to_string(), - -32100, - ) - }) - }) - .unwrap_or_else(|_| Self::unset("language")); - - let os_info = match Self::get_os_info_from_firebolt(state).await { - Ok(info) => info, - Err(_) => FirmwareInfo { - name: Self::unset("os.name"), - version: FireboltSemanticVersion::new(0, 0, 0, Self::unset("os.ver")), - }, - }; - - debug!("got os_info={:?}", &os_info); - - let os_ver = - BrokerUtils::process_internal_main_request(state, "ripple.device_os_version", None) - .await - .and_then(|val| { - from_value::(val).map_err(|_| { - rpc_error_with_code::( - "Failed to parse ripple.device_os_version".to_string(), - -32100, - ) - }) - }) - .unwrap_or("not.set".into()); - - let device_name = rpc_value_result_to_string_result( - BrokerUtils::process_internal_main_request(state, "device.name", None).await, - Some(Self::unset("device.name")), - ) - .unwrap_or(Self::unset("device.name")); - - /* Removing the call to get timezone from Thunder as this is not used in ontology. - let mut timezone: Option = None; - if let Ok(resp) = state - .get_client() - .send_extn_request(DeviceInfoRequest::GetTimezoneWithOffset) - .await - { - if let Some(ExtnResponse::TimezoneWithOffset(tz, offset)) = resp.payload.extract() { - timezone = Some(format!("{} {}", tz, offset)); - } - } - */ - - let mut firmware = String::default(); - if let Ok(resp) = state - .get_client() - .send_extn_request(DeviceInfoRequest::FirmwareInfo) - .await - { - if let Some(DeviceResponse::FirmwareInfo(info)) = resp.payload.extract() { - firmware = info.name; - } - } - - let activated = Some(true); - let proposition = - Self::get_persistent_store_string(state, PERSISTENT_STORAGE_KEY_PROPOSITION) - .await - .unwrap_or("Proposition.missing.from.persistent.store".into()); - - let retailer = - Self::get_persistent_store_string(state, PERSISTENT_STORAGE_KEY_RETAILER).await; - - let primary_provider = - Self::get_persistent_store_string(state, PERSISTENT_STORAGE_KEY_PRIMARY_PROVIDER).await; - - let platform = proposition.clone(); - - let coam = Self::get_persistent_store_bool(state, PERSISTENT_STORAGE_KEY_COAM).await; - - let country = - BrokerUtils::process_internal_main_request(state, "localization.countryCode", None) - .await - .ok() - .and_then(|val| from_value::(val).ok()); - debug!("got country_code={:?}", &country); - - let region = StorageManager::get_string(state, StorageProperty::Locality) - .await - .ok(); - - let account_type = - Self::get_persistent_store_string(state, PERSISTENT_STORAGE_KEY_ACCOUNT_TYPE).await; - - let operator = - Self::get_persistent_store_string(state, PERSISTENT_STORAGE_KEY_OPERATOR).await; - - let account_detail_type = - Self::get_persistent_store_string(state, PERSISTENT_STORAGE_ACCOUNT_DETAIL_TYPE).await; - - let device_type = - match Self::get_persistent_store_string(state, PERSISTENT_STORAGE_ACCOUNT_DEVICE_TYPE) - .await - { - Some(s) => s, - None => state.get_device_manifest().get_form_factor(), - }; - - let device_manufacturer = match Self::get_persistent_store_string( - state, - PERSISTENT_STORAGE_ACCOUNT_DEVICE_MANUFACTURER, - ) - .await - { - Some(s) => s, - None => rpc_value_result_to_string_result( - BrokerUtils::process_internal_main_request(state, "device.make", None).await, - Some(Self::unset("device.make")), - ) - .unwrap_or(Self::unset("device.make")), - }; - let authenticated = Some(true); - - { - // Time to set them - let mut context = state.metrics.context.write().unwrap(); - - context.enabled = metrics_enabled; - - if let Some(mac) = mac_address { - context.mac_address = mac; - } - - if let Some(sn) = serial_number { - context.serial_number = sn; - } - - if let Some(model) = device_model { - context.device_model = model; - } - - context.device_language = language; - context.os_name = os_info.name; - context.os_ver = os_ver; - context.device_name = Some(device_name); - context.device_session_id = state.device_session_id.clone().into(); - context.firmware = firmware; - context.ripple_version = state - .version - .clone() - .unwrap_or(String::from(SEMVER_LIGHTWEIGHT)); - - // Removing the call to get timezone from Thunder as this is not used in ontology. - /*if let Some(t) = timezone { - context.device_timezone = t; - }*/ - - context.activated = activated; - context.proposition = proposition; - context.retailer = retailer; - context.primary_provider = primary_provider; - context.platform = platform; - context.coam = coam; - context.country = country; - context.region = region; - context.account_type = account_type; - context.operator = operator; - context.account_detail_type = account_detail_type; - context.device_type = device_type; - context.device_manufacturer = device_manufacturer; - context.authenticated = authenticated; - } - { - Self::update_account_session(state).await; - } - - Self::send_context_update_request(state); - } - - async fn get_os_info_from_firebolt( - platform_state: &PlatformState, - ) -> Result { - match platform_state - .get_client() - .send_extn_request(DeviceInfoRequest::FirmwareInfo) - .await - { - Ok(message) => { - if let Some(DeviceResponse::FirmwareInfo(info)) = message.payload.extract() { - Ok(info) - } else { - Err(RippleError::InvalidOutput) - } - } - Err(e) => Err(e), - } - } - - pub async fn update_account_session(state: &PlatformState) { - { - let mut context = state.metrics.context.write().unwrap(); - let account_session = state.session_state.get_account_session(); - if let Some(session) = account_session { - context.account_id = Some(session.account_id); - context.device_id = Some(session.device_id); - context.distribution_tenant_id = session.id; - } else { - context.account_id = None; - context.device_id = None; - context.distribution_tenant_id = Self::unset("distribution_tenant_id"); - } - } - Self::send_context_update_request(state); - } - - pub fn operational_telemetry_listener(&self, target: &str, listen: bool) { - let mut listeners = self.operational_telemetry_listeners.write().unwrap(); - if listen { - listeners.insert(target.to_string()); - } else { - listeners.remove(target); - } - } - - pub fn get_listeners(&self) -> Vec { - self.operational_telemetry_listeners - .read() - .unwrap() - .iter() - .map(|x| x.to_owned()) - .collect() - } - - pub fn update_session_id(&self, platform_state: PlatformState, value: Option) { - let value = value.unwrap_or_default(); - { - let mut context = self.context.write().unwrap(); - context.device_session_id = value; - } - Self::send_context_update_request(&platform_state); - } - - pub fn add_api_stats(&mut self, request_id: &str, api: &str) { - let mut api_stats_map = self.api_stats_map.write().unwrap(); - api_stats_map.insert(request_id.to_string(), ApiStats::new(api.into())); - - let size = api_stats_map.len(); - if size >= API_STATS_MAP_SIZE_WARNING { - warn!("add_api_stats: api_stats_map size warning: {}", size); - } - } - - pub fn remove_api_stats(&mut self, request_id: &str) { - let mut api_stats_map = self.api_stats_map.write().unwrap(); - api_stats_map.remove(request_id); - } - - pub fn update_api_stats_ref(&mut self, request_id: &str, stats_ref: Option) { - let mut api_stats_map = self.api_stats_map.write().unwrap(); - if let Some(stats) = api_stats_map.get_mut(request_id) { - stats.stats_ref = stats_ref; - } else { - println!( - "update_api_stats_ref: request_id not found: request_id={}", - request_id - ); - } - } - - pub fn update_api_stage(&mut self, request_id: &str, stage: &str) -> i64 { - let mut api_stats_map = self.api_stats_map.write().unwrap(); - if let Some(stats) = api_stats_map.get_mut(request_id) { - stats.stats.update_stage(stage) - } else { - error!( - "update_api_stage: request_id not found: request_id={}", - request_id - ); - -1 - } - } - - pub fn get_api_stats(&self, request_id: &str) -> Option { - let api_stats_map = self.api_stats_map.read().unwrap(); - api_stats_map.get(request_id).cloned() - } -} diff --git a/core/main/src/state/mod.rs b/core/main/src/state/mod.rs index fd45b6445..5785d9d39 100644 --- a/core/main/src/state/mod.rs +++ b/core/main/src/state/mod.rs @@ -17,8 +17,8 @@ pub mod bootstrap_state; pub mod extn_state; -pub mod metrics_state; pub mod openrpc_state; +pub mod otel_state; pub mod platform_state; pub mod ripple_cache; pub mod session_state; diff --git a/core/main/src/state/otel_state.rs b/core/main/src/state/otel_state.rs new file mode 100644 index 000000000..728e0fd40 --- /dev/null +++ b/core/main/src/state/otel_state.rs @@ -0,0 +1,128 @@ +// Copyright 2023 Comcast Cable Communications Management, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 +// + +use std::{ + collections::{HashMap, HashSet}, + sync::{Arc, RwLock}, +}; + +use ripple_sdk::{ + api::{ + distributor::distributor_privacy::PrivacySettingsData, + observability::metrics_util::ApiStats, + }, + chrono::{DateTime, Utc}, + log::{error, warn}, +}; + +use super::platform_state::PlatformState; + +include!(concat!(env!("OUT_DIR"), "/version.rs")); + +const API_STATS_MAP_SIZE_WARNING: usize = 10; + +#[derive(Debug, Clone, Default)] +pub struct OtelState { + pub start_time: DateTime, + operational_telemetry_listeners: Arc>>, + api_stats_map: Arc>>, + device_session_id: Arc>>, +} + +impl OtelState { + pub fn get_device_session_id(&self) -> String { + self.device_session_id.read().unwrap().clone().unwrap() + } + + pub fn update_data_governance_tags( + &self, + _platform_state: &PlatformState, + _privacy_settings_data: &PrivacySettingsData, + ) { + } + + pub fn operational_telemetry_listener(&self, target: &str, listen: bool) { + let mut listeners = self.operational_telemetry_listeners.write().unwrap(); + if listen { + listeners.insert(target.to_string()); + } else { + listeners.remove(target); + } + } + + pub fn get_listeners(&self) -> Vec { + self.operational_telemetry_listeners + .read() + .unwrap() + .iter() + .map(|x| x.to_owned()) + .collect() + } + + pub fn update_session_id(&self, value: Option) { + let value = value.unwrap_or_default(); + { + let mut context = self.device_session_id.write().unwrap(); + let _ = context.insert(value); + } + } + + pub fn add_api_stats(&mut self, request_id: &str, api: &str) { + let mut api_stats_map = self.api_stats_map.write().unwrap(); + api_stats_map.insert(request_id.to_string(), ApiStats::new(api.into())); + + let size = api_stats_map.len(); + if size >= API_STATS_MAP_SIZE_WARNING { + warn!("add_api_stats: api_stats_map size warning: {}", size); + } + } + + pub fn remove_api_stats(&mut self, request_id: &str) { + let mut api_stats_map = self.api_stats_map.write().unwrap(); + api_stats_map.remove(request_id); + } + + pub fn update_api_stats_ref(&mut self, request_id: &str, stats_ref: Option) { + let mut api_stats_map = self.api_stats_map.write().unwrap(); + if let Some(stats) = api_stats_map.get_mut(request_id) { + stats.stats_ref = stats_ref; + } else { + println!( + "update_api_stats_ref: request_id not found: request_id={}", + request_id + ); + } + } + + pub fn update_api_stage(&mut self, request_id: &str, stage: &str) -> i64 { + let mut api_stats_map = self.api_stats_map.write().unwrap(); + if let Some(stats) = api_stats_map.get_mut(request_id) { + stats.stats.update_stage(stage) + } else { + error!( + "update_api_stage: request_id not found: request_id={}", + request_id + ); + -1 + } + } + + pub fn get_api_stats(&self, request_id: &str) -> Option { + let api_stats_map = self.api_stats_map.read().unwrap(); + api_stats_map.get(request_id).cloned() + } +} diff --git a/core/main/src/state/platform_state.rs b/core/main/src/state/platform_state.rs index 55e80370a..bcf8ec4a6 100644 --- a/core/main/src/state/platform_state.rs +++ b/core/main/src/state/platform_state.rs @@ -50,7 +50,7 @@ use crate::{ }; use super::{ - cap::cap_state::CapState, metrics_state::MetricsState, openrpc_state::OpenRpcState, + cap::cap_state::CapState, openrpc_state::OpenRpcState, otel_state::OtelState, ripple_cache::RippleCache, session_state::SessionState, }; @@ -104,7 +104,7 @@ pub struct PlatformState { pub open_rpc_state: OpenRpcState, pub router_state: RouterState, pub data_governance: DataGovernanceState, - pub metrics: MetricsState, + pub otel: OtelState, pub device_session_id: DeviceSessionIdentifier, pub ripple_cache: RippleCache, pub version: Option, @@ -124,7 +124,7 @@ impl PlatformState { let rule_engine = RuleEngine::build(&extn_manifest); let extn_sdks = extn_manifest.extn_sdks.clone(); let provider_registations = extn_manifest.provider_registrations.clone(); - let metrics_state = MetricsState::default(); + let metrics_state = OtelState::default(); Self { extn_manifest, cap_state: CapState::new(manifest.clone()), @@ -138,7 +138,7 @@ impl PlatformState { open_rpc_state: OpenRpcState::new(Some(exclusory), extn_sdks, provider_registations), router_state: RouterState::new(), data_governance: DataGovernanceState::default(), - metrics: metrics_state.clone(), + otel: metrics_state.clone(), device_session_id: DeviceSessionIdentifier::default(), ripple_cache: RippleCache::default(), version, diff --git a/core/main/src/state/ripple_cache.rs b/core/main/src/state/ripple_cache.rs index a4b23be27..769b8d490 100644 --- a/core/main/src/state/ripple_cache.rs +++ b/core/main/src/state/ripple_cache.rs @@ -52,7 +52,7 @@ impl RippleCache { let mut cache = self.privacy_settings_cache.write().unwrap(); property.set_privacy_setting_value(&mut cache, value); platform_state - .metrics + .otel .update_data_governance_tags(platform_state, &cache); } } diff --git a/core/main/src/utils/router_utils.rs b/core/main/src/utils/router_utils.rs index 87737878d..13c0a86af 100644 --- a/core/main/src/utils/router_utils.rs +++ b/core/main/src/utils/router_utils.rs @@ -22,7 +22,7 @@ use ripple_sdk::{ utils::error::RippleError, }; -use crate::state::metrics_state::MetricsState; +use crate::state::otel_state::OtelState; pub fn return_extn_response(msg: ApiMessage, extn_msg: ExtnMessage) { let callback = match extn_msg.clone().callback { @@ -70,7 +70,7 @@ pub fn add_telemetry_status_code(original_ref: &str, status_code: &str) -> Optio Some(format!("{},{}", original_ref, status_code)) } -pub fn capture_stage(metrics_state: &MetricsState, request: &RpcRequest, stage: &str) { +pub fn capture_stage(metrics_state: &OtelState, request: &RpcRequest, stage: &str) { let mut state = metrics_state.clone(); let duration = state.update_api_stage(&request.ctx.request_id, stage); diff --git a/core/sdk/Cargo.toml b/core/sdk/Cargo.toml index ab02227c3..d541249e6 100644 --- a/core/sdk/Cargo.toml +++ b/core/sdk/Cargo.toml @@ -29,6 +29,7 @@ sysd = [] test = ["jsonrpsee", "mock"] contract_tests = [] mock = [] +local_dev = [] [dependencies] diff --git a/core/sdk/src/api/context.rs b/core/sdk/src/api/context.rs index accaff84e..ce1102416 100644 --- a/core/sdk/src/api/context.rs +++ b/core/sdk/src/api/context.rs @@ -26,9 +26,8 @@ use crate::{ }; use serde::{Deserialize, Serialize}; -use super::{ - device::device_request::{AccountToken, InternetConnectionStatus, SystemPowerState, TimeZone}, - firebolt::fb_metrics::MetricsContext, +use super::device::device_request::{ + AccountToken, InternetConnectionStatus, SystemPowerState, TimeZone, }; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] @@ -64,7 +63,6 @@ pub struct RippleContext { pub time_zone: Option, pub update_type: Option, pub features: Vec, - pub metrics_context: Option, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] @@ -86,7 +84,6 @@ impl RippleContext { time_zone: Option, update_type: Option, features: Vec, - metrics_context: Option, ) -> RippleContext { RippleContext { activation_status, @@ -95,7 +92,6 @@ impl RippleContext { time_zone, update_type, features, - metrics_context, } } @@ -185,16 +181,6 @@ impl RippleContext { } changed } - RippleContextUpdateRequest::MetricsContext(context) => { - if let Some(metrics_context) = self.metrics_context.as_ref() { - if metrics_context == &context { - return false; - } - } - self.metrics_context = Some(context); - self.update_type = Some(RippleContextUpdateType::MetricsContextChanged); - true - } } } @@ -203,7 +189,6 @@ impl RippleContext { self.internet_connectivity = context.internet_connectivity; self.time_zone = context.time_zone; self.features = context.features; - self.metrics_context = context.metrics_context; } pub fn get_event_message(&self) -> ExtnMessage { @@ -267,7 +252,6 @@ pub enum RippleContextUpdateRequest { PowerState(SystemPowerState), TimeZone(TimeZone), UpdateFeatures(Vec), - MetricsContext(MetricsContext), RefreshContext(Option), } @@ -310,7 +294,6 @@ mod tests { assert_eq!(context.system_power_state, None); assert_eq!(context.time_zone, None); assert_eq!(context.features, Vec::::default()); - assert_eq!(context.metrics_context, None); } #[test] @@ -337,7 +320,6 @@ mod tests { }), update_type: None, features: Vec::default(), - metrics_context: Some(MetricsContext::default()), }; let context2 = RippleContext { @@ -350,7 +332,6 @@ mod tests { }), update_type: None, features: Vec::default(), - metrics_context: Some(MetricsContext::default()), }; assert_eq!( @@ -381,7 +362,6 @@ mod tests { }), update_type: None, features: Vec::default(), - metrics_context: Some(MetricsContext::default()), }; let contract_type: RippleContract = RippleContract::RippleContext; @@ -399,7 +379,6 @@ mod tests { None, None, vec![some_other_feature.clone()], - None, ); let changed = ripple_context.update(RippleContextUpdateRequest::UpdateFeatures(vec![ FeatureUpdate::new(name.clone(), true), @@ -420,7 +399,6 @@ mod tests { None, None, vec![some_other_feature.clone()], - None, ); ripple_context.update(RippleContextUpdateRequest::UpdateFeatures(vec![ FeatureUpdate::new(name.clone(), true), @@ -444,7 +422,6 @@ mod tests { None, None, vec![some_other_feature.clone()], - None, ); let changed = ripple_context.update(RippleContextUpdateRequest::UpdateFeatures(vec![ FeatureUpdate::new(name.clone(), false), @@ -465,7 +442,6 @@ mod tests { None, None, vec![some_other_feature.clone()], - None, ); ripple_context.update(RippleContextUpdateRequest::UpdateFeatures(vec![ FeatureUpdate::new(name.clone(), true), diff --git a/core/sdk/src/api/distributor/distributor_privacy.rs b/core/sdk/src/api/distributor/distributor_privacy.rs index 6b1ffb26b..7afa83036 100644 --- a/core/sdk/src/api/distributor/distributor_privacy.rs +++ b/core/sdk/src/api/distributor/distributor_privacy.rs @@ -85,6 +85,33 @@ impl PrivacySettings { allow_watch_history: false, } } + + pub fn update(&mut self, data: PrivacySettings) { + self.allow_acr_collection = data.allow_acr_collection; + self.allow_resume_points = data.allow_resume_points; + + self.allow_app_content_ad_targeting = data.allow_app_content_ad_targeting; + + self.allow_business_analytics = data.allow_business_analytics; + + self.allow_camera_analytics = data.allow_camera_analytics; + + self.allow_personalization = data.allow_personalization; + + self.allow_primary_browse_ad_targeting = data.allow_primary_browse_ad_targeting; + + self.allow_primary_content_ad_targeting = data.allow_primary_content_ad_targeting; + + self.allow_product_analytics = data.allow_product_analytics; + + self.allow_remote_diagnostics = data.allow_remote_diagnostics; + + self.allow_unentitled_personalization = data.allow_unentitled_personalization; + + self.allow_unentitled_resume_points = data.allow_unentitled_resume_points; + + self.allow_watch_history = data.allow_watch_history; + } } impl Default for PrivacySettings { diff --git a/core/sdk/src/api/distributor/distributor_sync.rs b/core/sdk/src/api/distributor/distributor_sync.rs deleted file mode 100644 index a01967a63..000000000 --- a/core/sdk/src/api/distributor/distributor_sync.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use serde::{Deserialize, Serialize}; - -use crate::{ - api::session::AccountSession, - extn::extn_client_message::{ExtnPayload, ExtnPayloadProvider, ExtnRequest}, - framework::ripple_contract::RippleContract, -}; - -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -pub enum SyncAndMonitorRequest { - SyncAndMonitor(SyncAndMonitorModule, AccountSession), - UpdateDistributorToken(String), -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)] -pub enum SyncAndMonitorModule { - Privacy, - UserGrants, -} - -impl ExtnPayloadProvider for SyncAndMonitorRequest { - fn get_from_payload(payload: ExtnPayload) -> Option { - if let ExtnPayload::Request(ExtnRequest::CloudSync(p)) = payload { - return Some(p); - } - - None - } - - fn get_extn_payload(&self) -> ExtnPayload { - ExtnPayload::Request(ExtnRequest::CloudSync(self.clone())) - } - - fn contract() -> crate::framework::ripple_contract::RippleContract { - RippleContract::CloudSync - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::utils::test_utils::test_extn_payload_provider; - - #[test] - fn test_extn_request_sync_and_monitor() { - let sync_and_monitor_module = SyncAndMonitorModule::Privacy; - let account_session = AccountSession { - id: "test_session_id".to_string(), - token: "test_token".to_string(), - account_id: "test_account_id".to_string(), - device_id: "test_device_id".to_string(), - }; - - let sync_and_monitor_request = - SyncAndMonitorRequest::SyncAndMonitor(sync_and_monitor_module, account_session); - let contract_type: RippleContract = RippleContract::CloudSync; - - test_extn_payload_provider(sync_and_monitor_request, contract_type); - } -} diff --git a/core/sdk/src/api/firebolt/fb_metrics.rs b/core/sdk/src/api/firebolt/fb_metrics.rs index 5c03d9f4b..6ea4bbd1d 100644 --- a/core/sdk/src/api/firebolt/fb_metrics.rs +++ b/core/sdk/src/api/firebolt/fb_metrics.rs @@ -21,16 +21,7 @@ use async_trait::async_trait; use serde::{Deserialize, Serialize}; use serde_json::Value; -use crate::{ - api::{gateway::rpc_gateway_api::CallContext, session::AccountSession}, - extn::{ - client::extn_client::ExtnClient, - extn_client_message::{ExtnPayload, ExtnPayloadProvider, ExtnRequest, ExtnResponse}, - }, - framework::ripple_contract::RippleContract, -}; - -use super::fb_telemetry::{OperationalMetricRequest, TelemetryPayload}; +use crate::api::gateway::rpc_gateway_api::CallContext; //https://developer.comcast.com/firebolt/core/sdk/latest/api/metrics @@ -62,6 +53,21 @@ impl From for BehavioralMetricContext { } } +impl From<&str> for BehavioralMetricContext { + fn from(app_id: &str) -> Self { + BehavioralMetricContext { + app_id: app_id.to_owned(), + product_version: String::from("product.version.not.implemented"), + partner_id: String::from("partner.id.not.set"), + app_session_id: String::from("app_session_id.not.set"), + durable_app_id: app_id.to_owned(), + app_version: None, + app_user_session_id: None, + governance_state: None, + } + } +} + #[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default)] pub struct AppDataGovernanceState { pub data_tags_to_apply: HashSet, @@ -396,6 +402,12 @@ pub struct AppLifecycleStateChange { pub previous_state: Option, pub new_state: AppLifecycleState, } + +pub trait IUpdateContext { + fn update_context(&mut self, context: BehavioralMetricContext); + fn get_context(&self) -> BehavioralMetricContext; +} + #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub enum BehavioralMetricPayload { Ready(Ready), @@ -421,8 +433,8 @@ pub enum BehavioralMetricPayload { Raw(RawBehaviorMetricRequest), } -impl BehavioralMetricPayload { - pub fn update_context(&mut self, context: BehavioralMetricContext) { +impl IUpdateContext for BehavioralMetricPayload { + fn update_context(&mut self, context: BehavioralMetricContext) { match self { Self::Ready(r) => r.context = context, Self::SignIn(s) => s.context = context, @@ -447,7 +459,8 @@ impl BehavioralMetricPayload { Self::Raw(r) => r.context = context, } } - pub fn get_context(&self) -> BehavioralMetricContext { + + fn get_context(&self) -> BehavioralMetricContext { match self { Self::Ready(r) => r.context.clone(), Self::SignIn(s) => s.context.clone(), @@ -543,9 +556,6 @@ impl Counter { false } } - pub fn to_extn_request(&self) -> OperationalMetricRequest { - OperationalMetricRequest::Counter(self.clone()) - } } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub enum TimeUnit { @@ -657,18 +667,9 @@ impl Timer { my_tags.insert("error".to_string(), true.to_string()); } } - - pub fn to_extn_request(&self) -> OperationalMetricRequest { - OperationalMetricRequest::Timer(self.clone()) - } } static FIREBOLT_RPC_NAME: &str = "firebolt_rpc_call"; -impl From for OperationalMetricRequest { - fn from(timer: Timer) -> Self { - OperationalMetricRequest::Timer(timer) - } -} pub fn fb_api_counter(method_name: String, tags: Option>) -> Counter { let counter_tags = match tags { @@ -688,11 +689,6 @@ pub fn fb_api_counter(method_name: String, tags: Option> tags: Some(counter_tags), } } -#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] -pub enum OperationalMetricPayload { - Timer(Timer), - Counter(Counter), -} #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[serde(rename_all = "lowercase")] @@ -832,7 +828,7 @@ impl MetricsContext { #[async_trait] pub trait BehavioralMetricsService { - async fn send_metric(&mut self, metrics: BehavioralMetricPayload) -> (); + async fn send_metric(&self, metrics: BehavioralMetricPayload) -> (); } #[async_trait] pub trait ContextualMetricsService { @@ -842,89 +838,6 @@ pub trait ContextualMetricsService { pub trait MetricsManager: Send + Sync { async fn send_metric(&mut self, metrics: BehavioralMetricPayload) -> (); } -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct BehavioralMetricRequest { - pub context: Option, - pub payload: BehavioralMetricPayload, - pub session: AccountSession, -} - -impl ExtnPayloadProvider for BehavioralMetricRequest { - fn get_extn_payload(&self) -> ExtnPayload { - ExtnPayload::Request(ExtnRequest::BehavioralMetric(self.clone())) - } - - fn get_from_payload(payload: ExtnPayload) -> Option { - if let ExtnPayload::Request(ExtnRequest::BehavioralMetric(r)) = payload { - return Some(r); - } - - None - } - - fn contract() -> RippleContract { - RippleContract::BehaviorMetrics - } -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub enum MetricsResponse { - None, - Boolean, -} - -impl ExtnPayloadProvider for MetricsResponse { - fn get_extn_payload(&self) -> ExtnPayload { - ExtnPayload::Response(ExtnResponse::Value( - serde_json::to_value(self.clone()).unwrap(), - )) - } - - fn get_from_payload(payload: ExtnPayload) -> Option { - if let ExtnPayload::Response(ExtnResponse::Value(value)) = payload { - if let Ok(v) = serde_json::from_value(value) { - return Some(v); - } - } - - None - } - - fn contract() -> RippleContract { - RippleContract::BehaviorMetrics - } -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub enum MetricsPayload { - BehaviorMetric(BehavioralMetricPayload, CallContext), - TelemetryPayload(TelemetryPayload), - OperationalMetric(OperationalMetricPayload), -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub struct MetricsRequest { - pub payload: MetricsPayload, - /// Additional info extensions want to send which can be appended to the context of the Metrics data - pub context: Option>, -} - -impl ExtnPayloadProvider for MetricsRequest { - fn get_extn_payload(&self) -> ExtnPayload { - ExtnPayload::Request(ExtnRequest::Metrics(self.clone())) - } - - fn get_from_payload(payload: ExtnPayload) -> Option { - if let ExtnPayload::Request(ExtnRequest::Metrics(r)) = payload { - return Some(r); - } - None - } - - fn contract() -> RippleContract { - RippleContract::Metrics - } -} #[derive(Deserialize, Debug, Clone)] pub struct ErrorParams { @@ -989,41 +902,6 @@ impl Tag { } } -pub fn get_metrics_tags( - extn_client: &ExtnClient, - interaction_type: InteractionType, - app_id: Option, -) -> Option> { - let metrics_context = extn_client.get_metrics_context()?; - let mut tags: HashMap = HashMap::new(); - - tags.insert(Tag::Type.key(), interaction_type.to_string()); - - if let Some(app) = app_id { - tags.insert(Tag::App.key(), app); - } - - tags.insert(Tag::Firmware.key(), metrics_context.firmware.clone()); - tags.insert(Tag::RippleVersion.key(), metrics_context.ripple_version); - - let features = extn_client.get_features(); - let feature_count = features.len(); - let mut features_str = String::new(); - - if feature_count > 0 { - for (i, feature) in features.iter().enumerate() { - features_str.push_str(feature); - if i < feature_count - 1 { - features_str.push(','); - } - } - } - - tags.insert(Tag::Features.key(), features_str); - - Some(tags) -} - #[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct BehavioralMetricsEvent { @@ -1043,8 +921,6 @@ pub struct BehavioralMetricsEvent { #[cfg(test)] mod tests { use super::*; - use crate::api::gateway::rpc_gateway_api::ApiProtocol; - use crate::utils::test_utils::test_extn_payload_provider; use serde_json::json; #[test] @@ -1102,118 +978,6 @@ mod tests { assert!(timer.elapsed().as_millis() < 200); } - #[test] - fn test_extn_request_behavioral_metric() { - let behavioral_metric_context = BehavioralMetricContext { - app_id: "test_app_id".to_string(), - product_version: "test_product_version".to_string(), - partner_id: "test_partner_id".to_string(), - app_session_id: "test_app_session_id".to_string(), - app_user_session_id: Some("test_user_session_id".to_string()), - durable_app_id: "test_durable_app_id".to_string(), - app_version: Some("test_app_version".to_string()), - governance_state: Some(AppDataGovernanceState { - data_tags_to_apply: HashSet::new(), - }), - }; - - let ready_payload = Ready { - context: behavioral_metric_context, - ttmu_ms: 100, - }; - - let behavioral_metric_request = BehavioralMetricRequest { - context: Some(MetricsContext { - enabled: true, - device_language: "en".to_string(), - device_model: "iPhone".to_string(), - device_id: Some("test_device_id".to_string()), - account_id: Some("test_account_id".to_string()), - device_timezone: "GMT".to_string(), - device_timezone_offset: "+0:00".to_string(), - device_name: Some("TestDevice".to_string()), - platform: "iOS".to_string(), - os_name: "test_os_name".to_string(), - os_ver: "14.0".to_string(), - distribution_tenant_id: "test_distribution_tenant_id".to_string(), - device_session_id: "test_device_session_id".to_string(), - mac_address: "test_mac_address".to_string(), - serial_number: "test_serial_number".to_string(), - firmware: "test_firmware".to_string(), - ripple_version: "test_ripple_version".to_string(), - data_governance_tags: None, - activated: None, - proposition: "test_proposition".to_string(), - retailer: None, - primary_provider: None, - coam: None, - country: None, - region: None, - account_type: None, - operator: None, - account_detail_type: None, - device_type: "test_device_type".to_string(), - device_manufacturer: "test_device_manufacturer".to_string(), - authenticated: None, - }), - payload: BehavioralMetricPayload::Ready(ready_payload), - session: AccountSession { - id: "test_session_id".to_string(), - token: "test_token".to_string(), - account_id: "test_account_id".to_string(), - device_id: "test_device_id".to_string(), - }, - }; - - let contract_type: RippleContract = RippleContract::BehaviorMetrics; - test_extn_payload_provider(behavioral_metric_request, contract_type); - } - - #[test] - fn test_extn_request_metrics() { - let behavior_metric_payload = BehavioralMetricPayload::Ready(Ready { - context: BehavioralMetricContext { - app_id: "test_app_id".to_string(), - product_version: "test_product_version".to_string(), - partner_id: "test_partner_id".to_string(), - app_session_id: "test_app_session_id".to_string(), - app_user_session_id: Some("test_user_session_id".to_string()), - durable_app_id: "test_durable_app_id".to_string(), - app_version: Some("test_app_version".to_string()), - governance_state: Some(AppDataGovernanceState { - data_tags_to_apply: HashSet::new(), - }), - }, - ttmu_ms: 100, - }); - let call_context = CallContext { - session_id: "test_session_id".to_string(), - request_id: "test_request_id".to_string(), - app_id: "test_app_id".to_string(), - call_id: 123, - protocol: ApiProtocol::Extn, - method: "some method".to_string(), - cid: Some("test_cid".to_string()), - gateway_secure: true, - context: Vec::new(), - }; - - let metrics_request = MetricsRequest { - payload: MetricsPayload::BehaviorMetric(behavior_metric_payload, call_context), - context: None, - }; - - let contract_type: RippleContract = RippleContract::Metrics; - test_extn_payload_provider(metrics_request, contract_type); - } - - #[test] - fn test_extn_response_metrics() { - let metrics_response = MetricsResponse::None; - let contract_type: RippleContract = RippleContract::BehaviorMetrics; - test_extn_payload_provider(metrics_response, contract_type); - } - #[test] fn test_hashmap_to_param_vec() { let mut map = HashMap::new(); @@ -1403,13 +1167,6 @@ mod tests { assert_eq!(timer.tags.unwrap().get("error"), Some(&"true".to_string())); } - #[test] - fn test_timer_to_extn_request() { - let timer = Timer::start("test_timer".to_string(), None, None); - let request = timer.to_extn_request(); - assert_eq!(request, OperationalMetricRequest::Timer(timer)); - } - #[test] fn test_fb_api_counter() { let counter = fb_api_counter("test_method".to_string(), None); diff --git a/core/sdk/src/api/firebolt/fb_telemetry.rs b/core/sdk/src/api/firebolt/fb_telemetry.rs index 8d066ba44..f4d93f100 100644 --- a/core/sdk/src/api/firebolt/fb_telemetry.rs +++ b/core/sdk/src/api/firebolt/fb_telemetry.rs @@ -19,14 +19,20 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use crate::{ - extn::extn_client_message::{ExtnEvent, ExtnPayload, ExtnPayloadProvider}, + api::gateway::rpc_gateway_api::{CallContext, RpcRequest}, + extn::{ + client::extn_client::ExtnClient, + extn_client_message::{ExtnEvent, ExtnPayload, ExtnPayloadProvider}, + }, framework::ripple_contract::RippleContract, }; use super::fb_metrics::{ - Counter, ErrorParams, ErrorType, FlatMapValue, Param, SystemErrorParams, Timer, + ErrorParams, ErrorType, FlatMapValue, InternalInitializeParams, Param, SystemErrorParams, }; +use log::error; + #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub struct AppLoadStart { pub app_id: String, @@ -203,8 +209,56 @@ impl ExtnPayloadProvider for TelemetryPayload { pub enum OperationalMetricRequest { Subscribe, UnSubscribe, - Counter(Counter), - Timer(Timer), +} + +pub struct TelemetryUtil; + +impl TelemetryUtil { + pub fn send_telemetry(client: &ExtnClient, payload: TelemetryPayload) { + if let Err(e) = client.request_transient(RpcRequest::get_new_internal( + "ripple.sendTelemetry".to_owned(), + Some(serde_json::to_value(payload).unwrap()), + )) { + error!("Error sending telemetry {:?}", e); + } + } + + pub fn update_telemetry_session_id(client: &ExtnClient, session_id: String) { + if let Err(e) = client.request_transient(RpcRequest::get_new_internal( + "ripple.setTelemetrySessionId".to_owned(), + Some(serde_json::to_value(session_id).unwrap()), + )) { + error!("Error sending telemetry {:?}", e); + } + } + + pub fn send_initialize( + client: &ExtnClient, + ctx: &CallContext, + internal_initialize_params: &InternalInitializeParams, + ripple_session_id: String, + ) { + let payload = TelemetryPayload::InternalInitialize(InternalInitialize { + app_id: ctx.app_id.to_owned(), + ripple_session_id, + app_session_id: Some(ctx.session_id.to_owned()), + semantic_version: internal_initialize_params.version.to_string(), + }); + Self::send_telemetry(client, payload); + } + + pub fn send_error( + client: &ExtnClient, + app_id: &str, + error_params: ErrorParams, + ripple_session_id: String, + ) { + let mut app_error: TelemetryAppError = error_params.into(); + app_error.ripple_session_id = ripple_session_id; + app_error.app_id = app_id.to_owned(); + let payload = TelemetryPayload::AppError(app_error); + Self::send_telemetry(client, payload); + } } #[cfg(test)] diff --git a/core/sdk/src/api/mod.rs b/core/sdk/src/api/mod.rs index a22846673..77940f69f 100644 --- a/core/sdk/src/api/mod.rs +++ b/core/sdk/src/api/mod.rs @@ -47,7 +47,6 @@ pub mod distributor { pub mod distributor_platform; pub mod distributor_privacy; pub mod distributor_request; - pub mod distributor_sync; pub mod distributor_token; pub mod distributor_usergrants; } @@ -74,7 +73,6 @@ pub mod firebolt { } pub mod observability { - pub mod analytics; pub mod log_signal; pub mod metrics_util; pub mod operational_metrics; diff --git a/core/sdk/src/api/observability/analytics.rs b/core/sdk/src/api/observability/analytics.rs deleted file mode 100644 index 276f6112d..000000000 --- a/core/sdk/src/api/observability/analytics.rs +++ /dev/null @@ -1,34 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::{ - api::firebolt::fb_metrics::BehavioralMetricsEvent, - extn::extn_client_message::{ExtnPayload, ExtnPayloadProvider, ExtnRequest}, - framework::ripple_contract::RippleContract, -}; - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub enum AnalyticsRequest { - SendMetrics(BehavioralMetricsEvent), -} -#[cfg(test)] -impl Default for AnalyticsRequest { - fn default() -> Self { - AnalyticsRequest::SendMetrics(BehavioralMetricsEvent::default()) - } -} -impl ExtnPayloadProvider for AnalyticsRequest { - fn get_extn_payload(&self) -> ExtnPayload { - ExtnPayload::Request(ExtnRequest::Analytics(self.clone())) - } - - fn get_from_payload(payload: ExtnPayload) -> Option { - if let ExtnPayload::Request(ExtnRequest::Analytics(analytics_request)) = payload { - return Some(analytics_request); - } - None - } - - fn contract() -> RippleContract { - RippleContract::Analytics - } -} diff --git a/core/sdk/src/api/observability/metrics_util.rs b/core/sdk/src/api/observability/metrics_util.rs index 75a377b6e..7f1987cc8 100644 --- a/core/sdk/src/api/observability/metrics_util.rs +++ b/core/sdk/src/api/observability/metrics_util.rs @@ -1,18 +1,5 @@ -use crate::{ - api::firebolt::{ - fb_metrics::{ - get_metrics_tags, InteractionType, Tag, Timer, TimerType, - SERVICE_METRICS_SEND_REQUEST_TIMEOUT_MS, - }, - fb_telemetry::OperationalMetricRequest, - }, - extn::{client::extn_client::ExtnClient, extn_client_message::ExtnResponse}, - utils::error::RippleError, -}; - use chrono::Utc; -#[cfg(not(test))] -use log::{debug, error}; + use serde::{Deserialize, Serialize}; #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] @@ -76,112 +63,11 @@ impl ApiStats { } } -#[cfg(test)] -use {println as debug, println as error}; - -pub fn start_service_metrics_timer(extn_client: &ExtnClient, name: String) -> Option { - let metrics_tags = get_metrics_tags(extn_client, InteractionType::Service, None)?; - - debug!("start_service_metrics_timer: {}: {:?}", name, metrics_tags); - - Some(Timer::start( - name, - Some(metrics_tags), - Some(TimerType::Remote), - )) -} - -pub async fn stop_and_send_service_metrics_timer( - client: ExtnClient, - timer: Option, - status: String, -) { - if let Some(mut timer) = timer { - timer.stop(); - timer.insert_tag(Tag::Status.key(), status); - - debug!("stop_and_send_service_metrics_timer: {:?}", timer); - - let req = OperationalMetricRequest::Timer(timer); - - let resp: Result = client - .standalone_request(req, SERVICE_METRICS_SEND_REQUEST_TIMEOUT_MS) - .await; - - if let Err(e) = resp { - error!( - "stop_and_send_service_metrics_timer: Failed to send metrics request: e={:?}", - e - ); - } - } -} - #[cfg(test)] mod tests { use super::*; - use crate::api::{context::RippleContextUpdateRequest, firebolt::fb_metrics::MetricsContext}; - use crate::extn::client::extn_client::tests::Mockable; use rstest::rstest; - fn get_mock_metrics_context() -> MetricsContext { - MetricsContext { - enabled: true, - device_language: "en".to_string(), - device_model: "iPhone".to_string(), - device_id: Some("test_device_id".to_string()), - account_id: Some("test_account_id".to_string()), - device_timezone: "GMT".to_string(), - device_timezone_offset: "+0:00".to_string(), - device_name: Some("TestDevice".to_string()), - platform: "iOS".to_string(), - os_name: "test_os_name".to_string(), - os_ver: "14.0".to_string(), - distribution_tenant_id: "test_distribution_tenant_id".to_string(), - device_session_id: "test_device_session_id".to_string(), - mac_address: "test_mac_address".to_string(), - serial_number: "test_serial_number".to_string(), - firmware: "test_firmware".to_string(), - ripple_version: "test_ripple_version".to_string(), - data_governance_tags: None, - activated: None, - proposition: "test_proposition".to_string(), - retailer: None, - primary_provider: None, - coam: None, - country: None, - region: None, - account_type: None, - operator: None, - account_detail_type: None, - device_type: "test_device_type".to_string(), - device_manufacturer: "test_device_manufacturer".to_string(), - authenticated: None, - } - } - - #[rstest] - fn test_start_service_metrics_timer() { - let extn_client = ExtnClient::mock(); - let request = RippleContextUpdateRequest::MetricsContext(get_mock_metrics_context()); - extn_client.context_update(request); - let timer = start_service_metrics_timer(&extn_client, "package_manager_get_list".into()); - assert!(timer.is_some(), "Timer should not be None"); - - let timer = timer.unwrap(); - assert_eq!( - timer.name, - "package_manager_get_list".to_string(), - "Timer name does not match" - ); - assert_eq!(timer.timer_type, TimerType::Remote); - - let expected_tags = get_metrics_tags(&extn_client, InteractionType::Service, None); - assert_eq!( - timer.tags, expected_tags, - "Timer tags do not match expected tags" - ); - } #[rstest] fn test_update_stage() { let mut rpc_stats = RpcStats::default(); diff --git a/core/sdk/src/api/ripple_cache.rs b/core/sdk/src/api/ripple_cache.rs index 8549675c4..1f2314077 100644 --- a/core/sdk/src/api/ripple_cache.rs +++ b/core/sdk/src/api/ripple_cache.rs @@ -20,9 +20,7 @@ use crate::api::{ distributor::distributor_privacy::PrivacySettingsData, storage_property::StorageProperty, }; -pub trait IPrivacyUpdated { - fn on_privacy_updated(&self, property: &StorageProperty, value: bool); -} +use super::storage_manager::IStorageOperator; #[derive(Debug, Clone, Default)] pub struct RippleCache { @@ -32,6 +30,10 @@ pub struct RippleCache { } impl RippleCache { + pub fn get(&self) -> PrivacySettingsData { + self.privacy_settings_cache.read().unwrap().clone() + } + pub fn get_cached_bool_storage_property(&self, property: &StorageProperty) -> Option { if property.is_a_privacy_setting_property() { // check if the privacy setting property is available in cache @@ -45,14 +47,17 @@ impl RippleCache { pub fn update_cached_bool_storage_property( &self, + state: &impl IStorageOperator, property: &StorageProperty, value: bool, - ) -> PrivacySettingsData { + ) { { // update the privacy setting property in cache - let mut cache = self.privacy_settings_cache.write().unwrap(); - property.set_privacy_setting_value(&mut cache, value); - cache.clone() + { + let mut cache = self.privacy_settings_cache.write().unwrap(); + property.set_privacy_setting_value(&mut cache, value); + } + state.on_privacy_updated(self.clone()); } } } diff --git a/core/sdk/src/api/storage_manager.rs b/core/sdk/src/api/storage_manager.rs index 7a680e925..3f6e3a1b2 100644 --- a/core/sdk/src/api/storage_manager.rs +++ b/core/sdk/src/api/storage_manager.rs @@ -19,8 +19,7 @@ use crate::{ api::{ default_storage_properties::DefaultStorageProperties, device::device_peristence::{ - DeleteStorageProperty, DevicePersistenceRequest, GetStorageProperty, - SetStorageProperty, StorageData, + DeleteStorageProperty, GetStorageProperty, SetStorageProperty, StorageData, }, firebolt::fb_capabilities::CAPABILITY_NOT_AVAILABLE, storage_manager_utils::{ @@ -29,7 +28,7 @@ use crate::{ }, storage_property::{StorageProperty, StoragePropertyData}, }, - extn::extn_client_message::{ExtnMessage, ExtnResponse}, + extn::extn_client_message::ExtnResponse, framework::RippleResponse, log::trace, serde_json::{json, Value}, @@ -40,7 +39,7 @@ use async_trait::async_trait; use jsonrpsee::core::RpcResult; use std::collections::HashMap; -use super::{manifest::device_manifest::DefaultValues, ripple_cache::IPrivacyUpdated}; +use super::{manifest::device_manifest::DefaultValues, ripple_cache::RippleCache}; #[derive(Debug)] pub enum StorageManagerResponse { @@ -68,12 +67,12 @@ pub enum StorageManagerError { #[async_trait] pub trait IStorageOperator { - fn get_cached(&self, property: &StorageProperty) -> Option; + fn get_cache(&self) -> RippleCache; fn get_default(&self) -> DefaultValues; - async fn persist(&self, request: DevicePersistenceRequest) -> RippleResponse; - async fn pull(&self, request: DevicePersistenceRequest) -> Result; - async fn delete(&self, request: DevicePersistenceRequest) -> RippleResponse; - fn on_privacy_updated(&self, property: &StorageProperty, value: bool); + async fn persist(&self, request: SetStorageProperty) -> RippleResponse; + async fn pull(&self, request: GetStorageProperty) -> Result; + async fn delete(&self, request: DeleteStorageProperty) -> RippleResponse; + fn on_privacy_updated(&self, cache: RippleCache); fn emit(&self, event_name: &str, result: &Value, context: Option); } @@ -84,9 +83,11 @@ impl StorageManager { pub async fn get_bool( state: &impl IStorageOperator, property: StorageProperty, - privacy_updater: Option<&impl IPrivacyUpdated>, ) -> RpcResult { - if let Some(val) = state.get_cached(&property) { + if let Some(val) = state + .get_cache() + .get_cached_bool_storage_property(&property) + { return Ok(val); } let data = property.as_data(); @@ -95,9 +96,9 @@ impl StorageManager { { Ok(StorageManagerResponse::Ok(value)) | Ok(StorageManagerResponse::NoChange(value)) => { if property.is_a_privacy_setting_property() { - if let Some(privacy) = privacy_updater { - privacy.on_privacy_updated(&property, value); - } + state + .get_cache() + .update_cached_bool_storage_property(state, &property, value); } Ok(value) } @@ -111,11 +112,13 @@ impl StorageManager { property: StorageProperty, value: bool, context: Option, - privacy_updater: Option<&impl IPrivacyUpdated>, ) -> RpcResult<()> { let data = property.as_data(); trace!("Storage property: {:?} as data: {:?}", property, data); - if let Some(val) = state.get_cached::(&property) { + if let Some(val) = state + .get_cache() + .get_cached_bool_storage_property(&property) + { if val == value { return Ok(()); } @@ -132,10 +135,10 @@ impl StorageManager { .await { Ok(StorageManagerResponse::Ok(_)) | Ok(StorageManagerResponse::NoChange(_)) => { - if property.is_a_privacy_setting_property() && privacy_updater.is_some() { - if let Some(privacy) = privacy_updater { - privacy.on_privacy_updated(&property, value); - } + if property.is_a_privacy_setting_property() { + state + .get_cache() + .update_cached_bool_storage_property(state, &property, value); } Ok(()) } @@ -445,7 +448,7 @@ impl StorageManager { scope, }; - match state.persist(DevicePersistenceRequest::Set(ssp)).await { + match state.persist(ssp).await { Ok(_) => { StorageManager::notify(state, value.clone(), event_names, context).await; Ok(StorageManagerResponse::Ok(())) @@ -575,18 +578,7 @@ impl StorageManager { key: key.clone(), scope, }; - let result = state.pull(DevicePersistenceRequest::Get(data)).await; - - match result { - Ok(msg) => { - if let Some(m) = msg.payload.extract() { - Ok(m) - } else { - Err(RippleError::ParseError) - } - } - Err(e) => Err(e), - } + state.pull(data).await } pub async fn delete( @@ -601,7 +593,7 @@ impl StorageManager { key: key.clone(), scope, }; - state.delete(DevicePersistenceRequest::Delete(data)).await + state.delete(data).await } pub fn get_firebolt_error(property: &StorageProperty) -> JsonRpcErrorType { diff --git a/core/sdk/src/extn/client/extn_client.rs b/core/sdk/src/extn/client/extn_client.rs index f72eb60be..04a7b649e 100644 --- a/core/sdk/src/extn/client/extn_client.rs +++ b/core/sdk/src/extn/client/extn_client.rs @@ -43,7 +43,6 @@ use crate::{ device_info_request::DeviceInfoRequest, device_request::{InternetConnectionStatus, TimeZone}, }, - firebolt::fb_metrics::MetricsContext, manifest::extn_manifest::ExtnSymbol, }, extn::{ @@ -992,11 +991,6 @@ impl ExtnClient { let ripple_context = self.ripple_context.read().unwrap(); ripple_context.features.clone() } - - pub fn get_metrics_context(&self) -> Option { - let ripple_context = self.ripple_context.read().unwrap(); - ripple_context.metrics_context.clone() - } } #[cfg(test)] diff --git a/core/sdk/src/extn/extn_client_message.rs b/core/sdk/src/extn/extn_client_message.rs index 08ac969b8..200869229 100644 --- a/core/sdk/src/extn/extn_client_message.rs +++ b/core/sdk/src/extn/extn_client_message.rs @@ -46,7 +46,6 @@ use crate::{ distributor_platform::PlatformTokenRequest, distributor_privacy::{PrivacyCloudRequest, PrivacySettingsStoreRequest}, distributor_request::DistributorRequest, - distributor_sync::SyncAndMonitorRequest, distributor_token::DistributorTokenRequest, distributor_usergrants::UserGrantsCloudStoreRequest, }, @@ -55,14 +54,12 @@ use crate::{ fb_authentication::TokenResult, fb_keyboard::{KeyboardSessionRequest, KeyboardSessionResponse}, fb_lifecycle_management::LifecycleManagementRequest, - fb_metrics::{BehavioralMetricRequest, MetricsRequest}, fb_pin::{PinChallengeRequestWithContext, PinChallengeResponse}, fb_secure_storage::{SecureStorageRequest, SecureStorageResponse}, fb_telemetry::{OperationalMetricRequest, TelemetryPayload}, }, gateway::rpc_gateway_api::RpcRequest, manifest::device_manifest::AppLibraryEntry, - observability::analytics::AnalyticsRequest, session::{AccountSessionRequest, AccountSessionResponse, SessionTokenRequest}, settings::{SettingValue, SettingsRequest}, status_update::ExtnStatus, @@ -307,22 +304,18 @@ pub enum ExtnRequest { SecureStorage(SecureStorageRequest), Advertising(AdvertisingRequest), PrivacySettings(PrivacyCloudRequest), - BehavioralMetric(BehavioralMetricRequest), StorageManager(StorageManagerRequest), AccountLink(AccountLinkRequest), Settings(SettingsRequest), - CloudSync(SyncAndMonitorRequest), UserGrantsCloudStore(UserGrantsCloudStoreRequest), UserGrantsStore(UserGrantsStoreRequest), PrivacySettingsStore(PrivacySettingsStoreRequest), AuthorizedInfo(CapsRequest), - Metrics(MetricsRequest), OperationalMetricsRequest(OperationalMetricRequest), PlatformToken(PlatformTokenRequest), DistributorToken(DistributorTokenRequest), Context(RippleContextUpdateRequest), AppCatalog(AppCatalogRequest), - Analytics(AnalyticsRequest), } impl ExtnPayloadProvider for ExtnRequest { @@ -619,13 +612,4 @@ mod tests { assert!(value.id.eq_ignore_ascii_case("test_id")); assert!(value.payload.eq(&extn_event_payload)); } - #[test] - fn test_analytics_request_serialization() { - let analytics_request = ExtnRequest::Analytics(AnalyticsRequest::default()); - let payload = ExtnPayload::Request(analytics_request.clone()); - - // Test extraction - let extracted: Option = payload.extract(); - assert_eq!(extracted, Some(analytics_request)); - } } diff --git a/core/main/src/bootstrap/manifest/device.rs b/core/sdk/src/framework/device_manifest_bootstrap.rs similarity index 95% rename from core/main/src/bootstrap/manifest/device.rs rename to core/sdk/src/framework/device_manifest_bootstrap.rs index 8d575502d..80ca224bc 100644 --- a/core/main/src/bootstrap/manifest/device.rs +++ b/core/sdk/src/framework/device_manifest_bootstrap.rs @@ -15,9 +15,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use ripple_sdk::{ - api::manifest::device_manifest::DeviceManifest, log::info, utils::error::RippleError, -}; +use crate::{api::manifest::device_manifest::DeviceManifest, log::info, utils::error::RippleError}; pub struct LoadDeviceManifestStep; diff --git a/core/sdk/src/framework/mod.rs b/core/sdk/src/framework/mod.rs index 70abb9f41..c1e746155 100644 --- a/core/sdk/src/framework/mod.rs +++ b/core/sdk/src/framework/mod.rs @@ -18,6 +18,7 @@ use crate::utils::error::RippleError; pub mod bootstrap; +pub mod device_manifest_bootstrap; pub mod file_store; pub mod ripple_contract; pub type RippleResponse = Result<(), RippleError>; diff --git a/device/thunder_ripple_sdk/Cargo.toml b/device/thunder_ripple_sdk/Cargo.toml index 176f9362c..77dabd778 100644 --- a/device/thunder_ripple_sdk/Cargo.toml +++ b/device/thunder_ripple_sdk/Cargo.toml @@ -64,6 +64,8 @@ home = { version = "=0.5.5", optional = true } tree_magic_mini = { version = "=3.0.3", optional = true } rstest = { version = "0.18.2", optional = true, default-features = false } futures-util = { version = "0.3.28", features = ["sink", "std"], default-features = false, optional = true} +chrono = { workspace = true, features = ["clock"]} +chrono-tz = "0.10" [dev-dependencies] diff --git a/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_processors.rs b/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_processors.rs index e041b586c..ead76cbe1 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_processors.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_processors.rs @@ -19,7 +19,6 @@ use ripple_sdk::api::firebolt::fb_telemetry::OperationalMetricRequest; use ripple_sdk::api::status_update::ExtnStatus; use ripple_sdk::log::error; -use crate::processors::thunder_analytics::ThunderAnalyticsProcessor; use crate::processors::thunder_package_manager::ThunderPackageManagerRequestProcessor; use crate::processors::thunder_rfc::ThunderRFCProcessor; use crate::processors::thunder_telemetry::ThunderTelemetryProcessor; @@ -60,8 +59,6 @@ impl SetupThunderProcessor { } } - let thunder_analytics_processor = ThunderAnalyticsProcessor::new(state.clone().state); - extn_client.add_request_processor(thunder_analytics_processor); extn_client.add_request_processor(ThunderRFCProcessor::new(state.clone().state)); let _ = extn_client.event(ExtnStatus::Ready); } diff --git a/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs b/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs index afc92582c..034570442 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs @@ -15,24 +15,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use ripple_sdk::{ - api::{ - firebolt::fb_metrics::BehavioralMetricsEvent, observability::analytics::AnalyticsRequest, - }, - async_trait::async_trait, - extn::{ - client::{ - extn_client::ExtnClient, - extn_processor::{ - DefaultExtnStreamer, ExtnRequestProcessor, ExtnStreamProcessor, ExtnStreamer, - }, - }, - extn_client_message::{ExtnMessage, ExtnResponse}, - }, - serde_json, - tokio::sync::mpsc::{Receiver as MReceiver, Sender as MSender}, - utils::error::RippleError, -}; +use ripple_sdk::{api::firebolt::fb_metrics::BehavioralMetricsEvent, serde_json}; use crate::{ client::{ @@ -44,71 +27,7 @@ use crate::{ thunder_state::ThunderState, }; -#[derive(Debug)] -pub struct ThunderAnalyticsProcessor { - state: ThunderState, - streamer: DefaultExtnStreamer, -} - -impl ThunderAnalyticsProcessor { - pub fn new(state: ThunderState) -> ThunderAnalyticsProcessor { - ThunderAnalyticsProcessor { - state, - streamer: DefaultExtnStreamer::new(), - } - } -} - -impl ExtnStreamProcessor for ThunderAnalyticsProcessor { - type VALUE = AnalyticsRequest; - type STATE = ThunderState; - - fn get_state(&self) -> Self::STATE { - self.state.clone() - } - - fn sender(&self) -> MSender { - self.streamer.sender() - } - - fn receiver(&mut self) -> MReceiver { - self.streamer.receiver() - } -} - -#[async_trait] -impl ExtnRequestProcessor for ThunderAnalyticsProcessor { - fn get_client(&self) -> ExtnClient { - self.state.get_client() - } - - async fn process_request( - state: Self::STATE, - msg: ExtnMessage, - extracted_message: Self::VALUE, - ) -> bool { - let response_message = match extracted_message { - AnalyticsRequest::SendMetrics(event) => send_metrics(state.clone(), event).await, - }; - - let extn_response = match response_message.message["success"].as_bool() { - Some(success) => { - if success { - ExtnResponse::None(()) - } else { - ExtnResponse::Error(RippleError::ExtnError) - } - } - None => ExtnResponse::Error(RippleError::ExtnError), - }; - - Self::respond(state.get_client(), msg, extn_response) - .await - .is_ok() - } -} - -async fn send_metrics( +pub async fn send_to_analytics_plugin( thunder_state: ThunderState, metrics_event: BehavioralMetricsEvent, ) -> DeviceResponseMessage { diff --git a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs index 81bb6a5a4..e0253a370 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs @@ -29,7 +29,6 @@ use crate::{ }, ripple_sdk::{ api::device::{device_info_request::DeviceCapabilities, device_request::AudioProfile}, - chrono::NaiveDateTime, extn::client::extn_client::ExtnClient, tokio::sync::mpsc, }, @@ -59,6 +58,8 @@ use crate::{ }, utils::get_audio_profile_from_value, }; +use chrono::{TimeZone as ChronoTimezone, Utc}; +use chrono_tz::{OffsetComponents, Tz}; use regex::{Match, Regex}; use ripple_sdk::{ api::{ @@ -234,7 +235,7 @@ impl CachedState { pub struct ThunderNetworkService; impl ThunderNetworkService { - async fn has_internet(state: &CachedState) -> bool { + pub async fn has_internet(state: &ThunderState) -> bool { let response = state .get_thunder_client() .call(DeviceCallRequest { @@ -302,22 +303,6 @@ impl ThunderAllTimezonesResponse { fn as_array(&self) -> Vec { self.timezones.keys().cloned().collect() } - - fn get_offset(&self, key: &str) -> i64 { - if let Some(tz) = self.timezones.get(key) { - if let Some(utc_tz) = self.timezones.get("Etc/UTC").cloned() { - if let Ok(ntz) = NaiveDateTime::parse_from_str(tz, "%a %b %d %H:%M:%S %Y %Z") { - if let Ok(nutz) = - NaiveDateTime::parse_from_str(&utc_tz, "%a %b %d %H:%M:%S %Y %Z") - { - let delta = (ntz - nutz).num_seconds(); - return round_to_nearest_quarter_hour(delta); - } - } - } - } - 0 - } } impl<'de> Deserialize<'de> for ThunderAllTimezonesResponse { fn deserialize(deserializer: D) -> Result @@ -822,7 +807,7 @@ impl ThunderDeviceInfoRequestProcessor { if tokio::time::timeout( Duration::from_millis(timeout), Self::respond(state.get_client(), req.clone(), { - let value = ThunderNetworkService::has_internet(&state).await; + let value = ThunderNetworkService::has_internet(&state.state).await; if let ExtnPayload::Response(r) = DeviceResponse::InternetConnectionStatus(match value { @@ -846,49 +831,51 @@ impl ThunderDeviceInfoRequestProcessor { } } + pub async fn get_firmware_version(state: &ThunderState) -> FireboltSemanticVersion { + let version: FireboltSemanticVersion; + let resp = state + .get_thunder_client() + .call(DeviceCallRequest { + method: ThunderPlugin::System.method("getSystemVersions"), + params: None, + }) + .await; + info!("{}", resp.message); + if let Ok(tsv) = serde_json::from_value::(resp.message) { + let tsv_split = tsv.receiver_version.split('.'); + let tsv_vec: Vec<&str> = tsv_split.collect(); + + if tsv_vec.len() >= 3 { + let major: String = tsv_vec[0].chars().filter(|c| c.is_ascii_digit()).collect(); + let minor: String = tsv_vec[1].chars().filter(|c| c.is_ascii_digit()).collect(); + let patch: String = tsv_vec[2].chars().filter(|c| c.is_ascii_digit()).collect(); + + version = FireboltSemanticVersion { + major: major.parse::().unwrap(), + minor: minor.parse::().unwrap(), + patch: patch.parse::().unwrap(), + readable: tsv.stb_version, + }; + } else { + version = FireboltSemanticVersion { + readable: tsv.stb_version, + ..FireboltSemanticVersion::default() + }; + } + } else { + version = FireboltSemanticVersion::default() + } + version + } + async fn get_os_info(state: &CachedState) -> FirmwareInfo { let version: FireboltSemanticVersion; // TODO: refactor this to use return syntax and not use response variable across branches match state.get_version() { Some(v) => version = v, None => { - let resp = state - .get_thunder_client() - .call(DeviceCallRequest { - method: ThunderPlugin::System.method("getSystemVersions"), - params: None, - }) - .await; - info!("{}", resp.message); - if let Ok(tsv) = serde_json::from_value::(resp.message) { - let tsv_split = tsv.receiver_version.split('.'); - let tsv_vec: Vec<&str> = tsv_split.collect(); - - if tsv_vec.len() >= 3 { - let major: String = - tsv_vec[0].chars().filter(|c| c.is_ascii_digit()).collect(); - let minor: String = - tsv_vec[1].chars().filter(|c| c.is_ascii_digit()).collect(); - let patch: String = - tsv_vec[2].chars().filter(|c| c.is_ascii_digit()).collect(); - - version = FireboltSemanticVersion { - major: major.parse::().unwrap(), - minor: minor.parse::().unwrap(), - patch: patch.parse::().unwrap(), - readable: tsv.stb_version, - }; - state.update_version(version.clone()); - } else { - version = FireboltSemanticVersion { - readable: tsv.stb_version, - ..FireboltSemanticVersion::default() - }; - state.update_version(version.clone()) - } - } else { - version = FireboltSemanticVersion::default() - } + version = Self::get_firmware_version(&state.state).await; + state.update_version(version.clone()); } } FirmwareInfo { @@ -934,7 +921,7 @@ impl ThunderDeviceInfoRequestProcessor { Self::handle_error(state.get_client(), req, RippleError::ProcessorError).await } - async fn get_timezone_value(state: &CachedState) -> Result { + async fn get_timezone_value(state: &ThunderState) -> Result { let response = state .get_thunder_client() .call(DeviceCallRequest { @@ -953,7 +940,7 @@ impl ThunderDeviceInfoRequestProcessor { } async fn get_timezone(state: CachedState, req: ExtnMessage) -> bool { - if let Ok(v) = Self::get_timezone_value(&state).await { + if let Ok(v) = Self::get_timezone_value(&state.state).await { Self::respond(state.get_client(), req, ExtnResponse::String(v)) .await .is_ok() @@ -1001,19 +988,43 @@ impl ThunderDeviceInfoRequestProcessor { } pub async fn get_timezone_and_offset(state: &CachedState) -> Option { - let timezone_result = ThunderDeviceInfoRequestProcessor::get_timezone_value(state).await; - let timezones_result = ThunderDeviceInfoRequestProcessor::get_all_timezones(state).await; + let timezone_result = + ThunderDeviceInfoRequestProcessor::get_timezone_value(&state.state).await; - if let (Ok(timezone), Ok(timezones)) = (timezone_result, timezones_result) { + if let Ok(timezone) = timezone_result { Some(TimeZone { time_zone: timezone.clone(), - offset: timezones.get_offset(&timezone), + offset: Self::get_offset_seconds(&timezone).unwrap_or(0), }) } else { None } } + pub fn get_offset_seconds(timezone: &str) -> Option { + // Parse the timezone (e.g., "America/Los_Angeles") + let tz: Tz = timezone.parse().ok()?; + + // Get the current UTC time + let utc_now = Utc::now(); + + // Convert the current UTC time to the specified timezone + let local_time = tz.from_utc_datetime(&utc_now.naive_utc()); + + // Get the base UTC offset and DST adjustment + let base_offset = local_time.offset().base_utc_offset().num_seconds(); + let dst_offset = local_time.offset().dst_offset().num_seconds(); + + // Calculate the total offset in seconds + let total_offset = base_offset + dst_offset; + + // Round the total offset to the nearest quarter hour + const QUARER_HOUR: i64 = 900; + let rounded_offset = ((total_offset as f64 / 900.0).round() as i64) * QUARER_HOUR; + + Some(rounded_offset) + } + async fn get_all_timezones( state: &CachedState, ) -> Result { @@ -1176,7 +1187,7 @@ impl ThunderDeviceInfoRequestProcessor { Self::handle_error(state.get_client(), request, RippleError::ProcessorError).await } - async fn power_state(state: CachedState, req: ExtnMessage) -> bool { + pub async fn get_power_state(state: &ThunderState) -> Result { let dev_response = state .get_thunder_client() .call(DeviceCallRequest { @@ -1184,31 +1195,26 @@ impl ThunderDeviceInfoRequestProcessor { params: None, }) .await; - let resp = dev_response.message.get("powerState").cloned(); - if resp.is_none() { - error!("Unable to get power state from thunder"); - return Self::handle_error(state.get_client(), req, RippleError::ProcessorError).await; + + if let Some(response) = dev_response.message.get("powerState").cloned() { + if let Ok(v) = serde_json::from_value(response) { + return Ok(v); + } } + Err(RippleError::ProcessorError) + } - let value = resp.unwrap(); - let power_state = serde_json::from_value::(value); - if power_state.is_err() { - return Self::handle_error(state.get_client(), req, RippleError::ProcessorError).await; + async fn power_state(state: CachedState, req: ExtnMessage) -> bool { + let mut response = ExtnResponse::Error(RippleError::ProcessorError); + if let Ok(v) = Self::get_power_state(&state.state).await { + if let ExtnPayload::Response(r) = DeviceResponse::PowerState(v).get_extn_payload() { + response = r; + } } - let power_state = power_state.unwrap(); - Self::respond( - state.get_client(), - req, - if let ExtnPayload::Response(r) = - DeviceResponse::PowerState(power_state).get_extn_payload() - { - r - } else { - ExtnResponse::Error(RippleError::ProcessorError) - }, - ) - .await - .is_ok() + + Self::respond(state.get_client(), req, response) + .await + .is_ok() } async fn get_device_capabilities(state: CachedState, keys: &[&str], msg: ExtnMessage) -> bool { @@ -1492,17 +1498,6 @@ impl ExtnRequestProcessor for ThunderDeviceInfoRequestProcessor { } } -fn round_to_nearest_quarter_hour(offset_seconds: i64) -> i64 { - // Convert minutes to quarter hours - let quarter_hours = (offset_seconds as f64 / 900.0).round() as i64; - - // Convert back to minutes - let rounded_minutes = quarter_hours * 15; - - // Convert minutes back to seconds - rounded_minutes * 60 -} - #[cfg(test)] pub mod tests { use std::{fs::File, sync::Arc}; diff --git a/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs b/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs index c6d3333e2..86fd712cf 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs @@ -48,9 +48,6 @@ use ripple_sdk::api::app_catalog::{AppCatalogRequest, AppOperationComplete, Apps use ripple_sdk::api::device::device_apps::DeviceAppMetadata; use ripple_sdk::api::firebolt::fb_capabilities::FireboltPermissions; use ripple_sdk::api::firebolt::fb_metrics::{Timer, TimerType}; -use ripple_sdk::api::observability::metrics_util::{ - start_service_metrics_timer, stop_and_send_service_metrics_timer, -}; #[cfg(not(test))] use ripple_sdk::log::{debug, error, info}; @@ -65,7 +62,7 @@ use serde_json::Value; #[cfg(test)] use {println as info, println as debug, println as error}; -use super::thunder_telemetry::{ThunderMetricsTimerName, ThunderResponseStatus}; +use super::thunder_telemetry::ThunderResponseStatus; // TODO: If/when ripple supports selectable download speeds we'll probably want multiple configurable values or compute this based on throughput. const DEFAULT_OPERATION_TIMEOUT_SECS: u64 = 12 * 60; // 12 minutes @@ -578,11 +575,6 @@ impl ThunderPackageManagerRequestProcessor { let method: String = ThunderPlugin::PackageManager.method("getlist"); let request = GetListRequest::new(id.unwrap_or_default()); - let metrics_timer = start_service_metrics_timer( - &thunder_state.get_client(), - ThunderMetricsTimerName::PackageManagerGetList.to_string(), - ); - let device_response = thunder_state .get_thunder_client() .call(DeviceCallRequest { @@ -593,7 +585,7 @@ impl ThunderPackageManagerRequestProcessor { }) .await; - let (status, extn_resp) = + let (_, extn_resp) = match serde_json::from_value::>(device_response.message) { Ok(apps) => ( ThunderResponseStatus::Success, @@ -605,13 +597,6 @@ impl ThunderPackageManagerRequestProcessor { ), }; - stop_and_send_service_metrics_timer( - thunder_state.get_client().clone(), - metrics_timer, - status.to_string(), - ) - .await; - extn_resp } @@ -659,11 +644,6 @@ impl ThunderPackageManagerRequestProcessor { let method: String = ThunderPlugin::PackageManager.method("install"); let request = InstallAppRequest::new(app.clone()); - let metrics_timer = start_service_metrics_timer( - &state.thunder_state.get_client(), - ThunderMetricsTimerName::PackageManagerInstall.to_string(), - ); - let device_response = state .thunder_state .get_thunder_client() @@ -683,13 +663,6 @@ impl ThunderPackageManagerRequestProcessor { ThunderResponseStatus::Failure }; - stop_and_send_service_metrics_timer( - state.thunder_state.get_client().clone(), - metrics_timer, - status.to_string(), - ) - .await; - match thunder_resp { Ok(handle) => { Self::add_or_remove_operation( @@ -742,11 +715,6 @@ impl ThunderPackageManagerRequestProcessor { let method: String = ThunderPlugin::PackageManager.method("uninstall"); let request = UninstallAppRequest::new(app.clone()); - let metrics_timer = start_service_metrics_timer( - &state.thunder_state.get_client(), - ThunderMetricsTimerName::PackageManagerUninstall.to_string(), - ); - let device_response = state .thunder_state .get_thunder_client() @@ -766,13 +734,6 @@ impl ThunderPackageManagerRequestProcessor { ThunderResponseStatus::Failure }; - stop_and_send_service_metrics_timer( - state.thunder_state.get_client().clone(), - metrics_timer, - status.to_string(), - ) - .await; - let extn_resp = match thunder_resp { Ok(handle) => { Self::add_or_remove_operation( @@ -888,11 +849,6 @@ impl ThunderPackageManagerRequestProcessor { let method: String = ThunderPlugin::PackageManager.method("getmetadata"); let request = GetMetadataRequest::new(app.id.clone(), app.version.clone()); - let metrics_timer = start_service_metrics_timer( - &state.thunder_state.get_client(), - ThunderMetricsTimerName::PackageManagerGetMetadata.to_string(), - ); - let device_response = state .thunder_state .get_thunder_client() @@ -908,19 +864,12 @@ impl ThunderPackageManagerRequestProcessor { let thunder_resp = serde_json::from_value::(device_response.message); - let status = if thunder_resp.is_ok() { + if thunder_resp.is_ok() { ThunderResponseStatus::Success } else { ThunderResponseStatus::Failure }; - stop_and_send_service_metrics_timer( - state.thunder_state.get_client().clone(), - metrics_timer, - status.to_string(), - ) - .await; - let extn_resp = match thunder_resp { Ok(metadata) => { match metadata @@ -951,11 +900,6 @@ impl ThunderPackageManagerRequestProcessor { let method: String = ThunderPlugin::PackageManager.method("cancel"); let request = CancelRequest::new(handle); - let metrics_timer = start_service_metrics_timer( - &state.thunder_state.get_client(), - ThunderMetricsTimerName::PackageManagerUninstall.to_string(), - ); - let device_response = state .thunder_state .get_thunder_client() @@ -967,7 +911,7 @@ impl ThunderPackageManagerRequestProcessor { }) .await; - let status = if device_response.message.is_null() { + if device_response.message.is_null() { ThunderResponseStatus::Success } else { error!( @@ -977,13 +921,6 @@ impl ThunderPackageManagerRequestProcessor { ThunderResponseStatus::Failure }; - - stop_and_send_service_metrics_timer( - state.thunder_state.get_client().clone(), - metrics_timer, - status.to_string(), - ) - .await; } } diff --git a/device/thunder_ripple_sdk/src/processors/thunder_persistent_store.rs b/device/thunder_ripple_sdk/src/processors/thunder_persistent_store.rs index fa1713e58..cbd605385 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_persistent_store.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_persistent_store.rs @@ -81,12 +81,10 @@ impl ThunderStorageRequestProcessor { } } - #[allow(dead_code)] - async fn delete_key( - state: ThunderState, - req: ExtnMessage, + pub async fn delete_key_in_persistent_store( + state: &ThunderState, data: DeleteStorageProperty, - ) -> bool { + ) -> Result { let mut params_json = json!({ "namespace": data.namespace, "key": data.key, @@ -109,14 +107,26 @@ impl ThunderStorageRequestProcessor { .await; match response.message["success"].as_bool() { - Some(success) => { - let response = ExtnResponse::Boolean(success); + Some(success) => Ok(success), + None => Err(RippleError::ProcessorError), + } + } + + #[allow(dead_code)] + async fn delete_key( + state: ThunderState, + req: ExtnMessage, + data: DeleteStorageProperty, + ) -> bool { + match Self::delete_key_in_persistent_store(&state, data).await { + Ok(v) => { + let response = ExtnResponse::Boolean(v); info!("thunder : {:?}", response); Self::respond(state.get_client(), req, response) .await .is_ok() } - None => false, + Err(e) => Self::handle_error(state.get_client(), req, e).await, } } @@ -167,11 +177,10 @@ impl ThunderStorageRequestProcessor { true } - pub async fn get_value( + pub async fn get_value_in_persistent_store( state: &ThunderState, - req: ExtnMessage, data: GetStorageProperty, - ) -> bool { + ) -> Result { let mut params_json = json!({ "namespace": data.namespace, "key": data.key, @@ -205,30 +214,12 @@ impl ThunderStorageRequestProcessor { if value_resp.success { if let Ok(v) = serde_json::from_str::(&value_resp.value) { if let Ok(v) = serde_json::from_value(v.clone()) { - return Self::respond( - state.get_client(), - req.clone(), - ExtnResponse::StorageData(v), - ) - .await - .is_ok(); + return Ok(ExtnResponse::StorageData(v)); } else if let Ok(v) = serde_json::from_value(v.clone()) { - return Self::respond( - state.get_client(), - req.clone(), - ExtnResponse::Value(v), - ) - .await - .is_ok(); + return Ok(ExtnResponse::Value(v)); } } else { - return Self::respond( - state.get_client(), - req.clone(), - ExtnResponse::String(value_resp.value), - ) - .await - .is_ok(); + return Ok(ExtnResponse::String(value_resp.value)); } } else { error!("success failure response from thunder"); @@ -236,16 +227,26 @@ impl ThunderStorageRequestProcessor { } else { error!("malformed response from thunder"); } - } else { - return Self::respond(state.get_client(), req.clone(), ExtnResponse::None(())) - .await - .is_ok(); } } - Self::handle_error(state.get_client(), req, RippleError::ProcessorError).await + Ok(ExtnResponse::None(())) } - async fn set_value(state: ThunderState, req: ExtnMessage, data: SetStorageProperty) -> bool { + pub async fn get_value( + state: &ThunderState, + req: ExtnMessage, + data: GetStorageProperty, + ) -> bool { + match Self::get_value_in_persistent_store(state, data).await { + Ok(v) => Self::respond(state.get_client(), req, v).await.is_ok(), + Err(e) => Self::handle_error(state.get_client(), req, e).await, + } + } + + pub async fn set_in_peristent_store( + state: &ThunderState, + data: SetStorageProperty, + ) -> Result { let mut params_json = json!({ "namespace": data.namespace, "key": data.key, @@ -271,10 +272,18 @@ impl ThunderStorageRequestProcessor { .await; info!("{}", response.message); - let response = match response.message["success"].as_bool() { - Some(v) => ExtnResponse::Boolean(v), - None => ExtnResponse::Error(RippleError::InvalidOutput), + match response.message["success"].as_bool() { + Some(v) => Ok(v), + None => Err(RippleError::InvalidOutput), + } + } + + async fn set_value(state: ThunderState, req: ExtnMessage, data: SetStorageProperty) -> bool { + let response = match Self::set_in_peristent_store(&state, data).await { + Ok(v) => ExtnResponse::Boolean(v), + Err(e) => ExtnResponse::Error(e), }; + info!("thunder : {:?}", response); Self::respond(state.get_client(), req, response) diff --git a/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs b/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs index 6284888bb..108b2e6c9 100644 --- a/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs +++ b/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs @@ -184,4 +184,29 @@ impl MockThunderController { let thunder_state = ThunderState::new(extn_client, thunder_client); (CachedState::new(thunder_state), r) } + + /** + * Creates state object that points to a mock thunder controller. + * Pass in the custom thunder handlers to mock the thunder responses + * Returns the state and a receiver which can be used to listen to responses that + * come back from the extension + */ + pub fn get_thunder_state_mock() -> ThunderState { + let s_thunder = MockThunderController::start_with_custom_handlers(None); + let thunder_client = ThunderClient { + sender: Some(s_thunder), + pooled_sender: None, + id: Uuid::new_v4(), + plugin_manager_tx: None, + subscriptions: None, + thunder_async_client: None, + thunder_async_subscriptions: None, + thunder_async_callbacks: None, + use_thunder_async: false, + }; + + let (s, _) = unbounded(); + let extn_client = MockExtnClient::client(s); + ThunderState::new(extn_client, thunder_client) + } } diff --git a/distributor/general/src/distributor_general_ffi.rs b/distributor/general/src/distributor_general_ffi.rs index 7a24e0d6f..78fee9ed4 100644 --- a/distributor/general/src/distributor_general_ffi.rs +++ b/distributor/general/src/distributor_general_ffi.rs @@ -44,7 +44,6 @@ use crate::{ general_discovery_processor::DistributorDiscoveryProcessor, general_distributor_token_processor::DistributorTokenProcessor, general_media_events_processor::DistributorMediaEventProcessor, - general_metrics_processor::DistributorMetricsProcessor, general_paltform_token_processor::PlatformTokenProcessor, general_permission_processor::DistributorPermissionProcessor, general_privacy_processor::DistributorPrivacyProcessor, @@ -109,7 +108,6 @@ fn start_launcher(sender: ExtnSender, receiver: CReceiver) { client.add_request_processor(DistributorPermissionProcessor::new(client.clone())); client.add_request_processor(DistributorSecureStorageProcessor::new(client.clone())); client.add_request_processor(DistributorAdvertisingProcessor::new(client.clone())); - client.add_request_processor(DistributorMetricsProcessor::new(client.clone())); client.add_request_processor(GeneralTokenProcessor::new(client.clone())); client.add_request_processor(DistributorDiscoveryProcessor::new(client.clone())); client.add_request_processor(DistributorMediaEventProcessor::new(client.clone())); diff --git a/distributor/general/src/general_metrics_processor.rs b/distributor/general/src/general_metrics_processor.rs deleted file mode 100644 index 5a418b607..000000000 --- a/distributor/general/src/general_metrics_processor.rs +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use ripple_sdk::{ - api::firebolt::fb_metrics::{BehavioralMetricPayload, BehavioralMetricRequest}, - async_trait::async_trait, - extn::client::{ - extn_client::ExtnClient, - extn_processor::{ - DefaultExtnStreamer, ExtnRequestProcessor, ExtnStreamProcessor, ExtnStreamer, - }, - }, - log::error, -}; - -pub struct DistributorMetricsProcessor { - client: ExtnClient, - streamer: DefaultExtnStreamer, -} - -impl DistributorMetricsProcessor { - pub fn new(client: ExtnClient) -> DistributorMetricsProcessor { - DistributorMetricsProcessor { - client, - streamer: DefaultExtnStreamer::new(), - } - } -} - -impl ExtnStreamProcessor for DistributorMetricsProcessor { - type STATE = ExtnClient; - type VALUE = BehavioralMetricRequest; - - fn get_state(&self) -> Self::STATE { - self.client.clone() - } - - fn receiver( - &mut self, - ) -> ripple_sdk::tokio::sync::mpsc::Receiver - { - self.streamer.receiver() - } - - fn sender( - &self, - ) -> ripple_sdk::tokio::sync::mpsc::Sender - { - self.streamer.sender() - } -} - -#[async_trait] -impl ExtnRequestProcessor for DistributorMetricsProcessor { - fn get_client(&self) -> ExtnClient { - self.client.clone() - } - async fn process_request( - mut state: Self::STATE, - msg: ripple_sdk::extn::extn_client_message::ExtnMessage, - extracted_message: Self::VALUE, - ) -> bool { - match extracted_message.clone().payload { - BehavioralMetricPayload::Ready(_) => { - if let Err(e) = state - .respond( - msg, - ripple_sdk::extn::extn_client_message::ExtnResponse::Boolean(true), - ) - .await - { - error!("Error sending back response {:?}", e); - return false; - } - true - } - BehavioralMetricPayload::SignIn(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::SignOut(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::StartContent(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::StopContent(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::Page(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::Action(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::Error(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaLoadStart(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaPlay(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaPlaying(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaPause(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaWaiting(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaProgress(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaSeeking(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaSeeked(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaRateChanged(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaRenditionChanged(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::MediaEnded(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::AppStateChange(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - BehavioralMetricPayload::Raw(_) => { - mock_metrics_response(state, msg, extracted_message).await - } - } - } -} - -/// listener for events any events. -pub async fn mock_metrics_response( - mut state: ExtnClient, - msg: ripple_sdk::extn::extn_client_message::ExtnMessage, - _extracted_message: BehavioralMetricRequest, -) -> bool { - if let Err(e) = state - .respond( - msg, - ripple_sdk::extn::extn_client_message::ExtnResponse::Boolean(true), - ) - .await - { - error!("Error sending back response {:?}", e); - return false; - } - true -} diff --git a/distributor/general/src/lib.rs b/distributor/general/src/lib.rs index ad310aea0..8101aeef5 100644 --- a/distributor/general/src/lib.rs +++ b/distributor/general/src/lib.rs @@ -20,7 +20,6 @@ mod general_advertising_processor; mod general_discovery_processor; mod general_distributor_token_processor; mod general_media_events_processor; -mod general_metrics_processor; mod general_paltform_token_processor; mod general_permission_processor; mod general_privacy_processor; From baf8b6c812045d5f4675ee821b7a0549564ac996 Mon Sep 17 00:00:00 2001 From: satlead Date: Fri, 21 Mar 2025 06:09:54 -0400 Subject: [PATCH 03/31] cp: Cleanup account link and data governance --- .../src/bootstrap/setup_extn_client_step.rs | 2 - .../src/bootstrap/start_fbgateway_step.rs | 18 +- .../src/firebolt/handlers/discovery_rpc.rs | 265 +------------ .../{telemetry_rpc.rs => internal_rpc.rs} | 49 ++- core/main/src/firebolt/mod.rs | 2 +- .../src/processor/account_link_processor.rs | 351 ------------------ core/main/src/processor/mod.rs | 1 - .../src/processor/storage/storage_manager.rs | 4 +- core/main/src/service/mod.rs | 1 - core/main/src/state/otel_state.rs | 14 +- core/main/src/state/platform_state.rs | 3 - core/main/src/state/ripple_cache.rs | 12 +- core/sdk/src/api/account_link.rs | 63 +--- .../api/distributor/distributor_discovery.rs | 158 -------- .../api/distributor/distributor_encoder.rs | 69 ---- .../api/distributor/distributor_request.rs | 33 -- core/sdk/src/api/firebolt/fb_general.rs | 6 + core/sdk/src/api/mod.rs | 3 - core/sdk/src/extn/extn_client_message.rs | 4 - core/sdk/src/framework/ripple_contract.rs | 4 +- .../general/src/distributor_general_ffi.rs | 6 - .../src/general_discovery_processor.rs | 84 ----- .../src/general_media_events_processor.rs | 84 ----- distributor/general/src/lib.rs | 2 - 24 files changed, 66 insertions(+), 1172 deletions(-) rename core/main/src/firebolt/handlers/{telemetry_rpc.rs => internal_rpc.rs} (53%) delete mode 100644 core/main/src/processor/account_link_processor.rs delete mode 100644 core/sdk/src/api/distributor/distributor_discovery.rs delete mode 100644 core/sdk/src/api/distributor/distributor_encoder.rs delete mode 100644 core/sdk/src/api/distributor/distributor_request.rs delete mode 100644 distributor/general/src/general_discovery_processor.rs delete mode 100644 distributor/general/src/general_media_events_processor.rs diff --git a/core/main/src/bootstrap/setup_extn_client_step.rs b/core/main/src/bootstrap/setup_extn_client_step.rs index a95b3f99e..edc175f72 100644 --- a/core/main/src/bootstrap/setup_extn_client_step.rs +++ b/core/main/src/bootstrap/setup_extn_client_step.rs @@ -19,7 +19,6 @@ use ripple_sdk::{ async_trait::async_trait, framework::bootstrap::Bootstep, utils::error::RippleError, }; -use crate::processor::account_link_processor::AccountLinkProcessor; use crate::processor::metrics_processor::OpMetricsProcessor; use crate::processor::settings_processor::SettingsProcessor; use crate::processor::{ @@ -60,7 +59,6 @@ impl Bootstep for SetupExtnClientStep { state.platform_state.clone(), )); client.add_request_processor(AuthorizedInfoProcessor::new(state.platform_state.clone())); - client.add_request_processor(AccountLinkProcessor::new(state.platform_state.clone())); client.add_request_processor(SettingsProcessor::new(state.platform_state.clone())); client.add_request_processor(OpMetricsProcessor::new(state.platform_state.clone())); Ok(()) diff --git a/core/main/src/bootstrap/start_fbgateway_step.rs b/core/main/src/bootstrap/start_fbgateway_step.rs index 7e3c5ee3e..96299588b 100644 --- a/core/main/src/bootstrap/start_fbgateway_step.rs +++ b/core/main/src/bootstrap/start_fbgateway_step.rs @@ -26,14 +26,14 @@ use crate::{ audio_description_rpc::AudioDescriptionRPCProvider, authentication_rpc::AuthRPCProvider, capabilities_rpc::CapRPCProvider, closed_captions_rpc::ClosedcaptionsRPCProvider, device_rpc::DeviceRPCProvider, - discovery_rpc::DiscoveryRPCProvider, keyboard_rpc::KeyboardRPCProvider, - lcm_rpc::LifecycleManagementProvider, lifecycle_rpc::LifecycleRippleProvider, - localization_rpc::LocalizationRPCProvider, parameters_rpc::ParametersRPCProvider, - privacy_rpc::PrivacyProvider, profile_rpc::ProfileRPCProvider, - provider_registrar::ProviderRegistrar, second_screen_rpc::SecondScreenRPCProvider, - secure_storage_rpc::SecureStorageRPCProvider, telemetry_rpc::TelemetryProvider, - user_grants_rpc::UserGrantsRPCProvider, voice_guidance_rpc::VoiceguidanceRPCProvider, - wifi_rpc::WifiRPCProvider, + discovery_rpc::DiscoveryRPCProvider, internal_rpc::InternalProvider, + keyboard_rpc::KeyboardRPCProvider, lcm_rpc::LifecycleManagementProvider, + lifecycle_rpc::LifecycleRippleProvider, localization_rpc::LocalizationRPCProvider, + parameters_rpc::ParametersRPCProvider, privacy_rpc::PrivacyProvider, + profile_rpc::ProfileRPCProvider, provider_registrar::ProviderRegistrar, + second_screen_rpc::SecondScreenRPCProvider, + secure_storage_rpc::SecureStorageRPCProvider, user_grants_rpc::UserGrantsRPCProvider, + voice_guidance_rpc::VoiceguidanceRPCProvider, wifi_rpc::WifiRPCProvider, }, rpc::RippleRPCProvider, }, @@ -75,7 +75,7 @@ impl FireboltGatewayStep { let _ = methods.merge(AudioDescriptionRPCProvider::provide_with_alias( state.clone(), )); - let _ = methods.merge(TelemetryProvider::provide_with_alias(state.clone())); + let _ = methods.merge(InternalProvider::provide_with_alias(state.clone())); // LCM Api(s) not required for internal launcher if !state.has_internal_launcher() { diff --git a/core/main/src/firebolt/handlers/discovery_rpc.rs b/core/main/src/firebolt/handlers/discovery_rpc.rs index 9a813acda..e4e685953 100644 --- a/core/main/src/firebolt/handlers/discovery_rpc.rs +++ b/core/main/src/firebolt/handlers/discovery_rpc.rs @@ -24,9 +24,7 @@ use crate::{ app_events::{AppEventDecorationError, AppEventDecorator, AppEvents}, provider_broker::{self, ProviderBroker}, }, - utils::rpc_utils::{ - rpc_await_oneshot, rpc_downstream_service_err, rpc_err, rpc_navigate_reserved_app_err, - }, + utils::rpc_utils::{rpc_await_oneshot, rpc_err, rpc_navigate_reserved_app_err}, }; use jsonrpsee::{ core::{async_trait, Error, RpcResult}, @@ -36,16 +34,14 @@ use jsonrpsee::{ use ripple_sdk::{ api::{ - account_link::AccountLinkRequest, apps::{AppError, AppManagerResponse, AppMethod, AppRequest, AppResponse}, config::Config, firebolt::{ fb_capabilities::FireboltCap, fb_discovery::{ - ContentAccessRequest, EntitlementsInfo, LaunchRequest, LocalizedString, SignInInfo, - WatchNextInfo, WatchedInfo, DISCOVERY_EVENT_ON_NAVIGATE_TO, ENTITY_INFO_CAPABILITY, - ENTITY_INFO_EVENT, EVENT_DISCOVERY_POLICY_CHANGED, PURCHASED_CONTENT_CAPABILITY, - PURCHASED_CONTENT_EVENT, + LaunchRequest, LocalizedString, DISCOVERY_EVENT_ON_NAVIGATE_TO, + ENTITY_INFO_CAPABILITY, ENTITY_INFO_EVENT, EVENT_DISCOVERY_POLICY_CHANGED, + PURCHASED_CONTENT_CAPABILITY, PURCHASED_CONTENT_EVENT, }, provider::{ProviderRequestPayload, ProviderResponse, ProviderResponsePayload}, }, @@ -56,11 +52,9 @@ use ripple_sdk::{ }; use ripple_sdk::{ api::{ - account_link::WatchedRequest, device::entertainment_data::*, firebolt::{ fb_capabilities::JSON_RPC_STANDARD_ERROR_INVALID_PARAMS, - fb_discovery::{EVENT_ON_SIGN_IN, EVENT_ON_SIGN_OUT}, fb_general::{ListenRequest, ListenerResponse}, provider::ExternalProviderResponse, }, @@ -74,47 +68,8 @@ use serde_json::Value; use crate::state::platform_state::PlatformState; -#[derive(Default, Debug)] -pub struct DiscoveryEmptyResult { - //Empty object to take care of OTTX-28709 -} - -impl PartialEq for DiscoveryEmptyResult { - fn eq(&self, _other: &Self) -> bool { - true - } -} -type EmptyResult = DiscoveryEmptyResult; - #[rpc(server)] pub trait Discovery { - #[method(name = "discovery.entitlements")] - async fn entitlements( - &self, - ctx: CallContext, - entitlements_info: EntitlementsInfo, - ) -> RpcResult; - #[method(name = "discovery.signIn")] - async fn sign_in(&self, ctx: CallContext, sign_in_info: SignInInfo) -> RpcResult; - #[method(name = "discovery.signOut")] - async fn sign_out(&self, ctx: CallContext) -> RpcResult; - #[method(name = "discovery.onSignIn")] - async fn on_sign_in( - &self, - ctx: CallContext, - request: ListenRequest, - ) -> RpcResult; - #[method(name = "discovery.onSignOut")] - async fn on_sign_out( - &self, - ctx: CallContext, - request: ListenRequest, - ) -> RpcResult; - #[method(name = "discovery.watched")] - async fn watched(&self, ctx: CallContext, watched_info: WatchedInfo) -> RpcResult; - #[method(name = "discovery.watchNext")] - async fn watch_next(&self, ctx: CallContext, watch_next_info: WatchNextInfo) - -> RpcResult; #[method(name = "discovery.launch")] async fn launch(&self, ctx: CallContext, request: LaunchRequest) -> RpcResult; #[method(name = "discovery.onPullEntityInfo")] @@ -171,14 +126,6 @@ pub trait Discovery { ctx: CallContext, request: ListenRequest, ) -> RpcResult; - #[method(name = "discovery.contentAccess")] - async fn discovery_content_access( - &self, - ctx: CallContext, - request: ContentAccessRequest, - ) -> RpcResult<()>; - #[method(name = "discovery.clearContentAccess")] - async fn discovery_clear_content_access(&self, ctx: CallContext) -> RpcResult<()>; } pub struct DiscoveryImpl { @@ -292,69 +239,6 @@ impl DiscoveryImpl { } title_map } - - async fn process_sign_in_request( - &self, - ctx: CallContext, - is_signed_in: bool, - ) -> RpcResult { - let app_id = ctx.app_id.to_owned(); - let res = self - .state - .get_client() - .send_extn_request(match is_signed_in { - true => AccountLinkRequest::SignIn(ctx), - false => AccountLinkRequest::SignOut(ctx), - }) - .await - .is_ok(); - if res { - AppEvents::emit( - &self.state, - if is_signed_in { - EVENT_ON_SIGN_IN - } else { - EVENT_ON_SIGN_OUT - }, - &serde_json::json!({"appId": app_id,}), - ) - .await; - return Ok(true); - } - Ok(false) - } - - async fn content_access( - &self, - ctx: CallContext, - request: ContentAccessRequest, - ) -> RpcResult { - match self - .state - .get_client() - .send_extn_request(AccountLinkRequest::ContentAccess(ctx, request)) - .await - { - Ok(_) => Ok(EmptyResult::default()), - Err(_) => Err(rpc_downstream_service_err( - "Could not notify Content AccessList to the platform", - )), - } - } - - async fn clear_content_access(&self, ctx: CallContext) -> RpcResult { - match self - .state - .get_client() - .send_extn_request(AccountLinkRequest::ClearContentAccess(ctx)) - .await - { - Ok(_) => Ok(EmptyResult::default()), - Err(_) => Err(rpc_downstream_service_err( - "Could not notify Content AccessList to the platform", - )), - } - } } #[derive(Clone)] @@ -401,128 +285,6 @@ impl DiscoveryServer for DiscoveryImpl { }) } - async fn entitlements( - &self, - ctx: CallContext, - entitlements_info: EntitlementsInfo, - ) -> RpcResult { - info!("Discovery.entitlements"); - let resp = self.content_access(ctx, entitlements_info.into()).await; - match resp { - Ok(_) => Ok(true), - Err(e) => Err(e), - } - } - - async fn sign_in(&self, ctx: CallContext, sign_in_info: SignInInfo) -> RpcResult { - info!("Discovery.signIn"); - - let mut resp = Ok(EmptyResult::default()); - let fut = self.process_sign_in_request(ctx.clone(), true); - - if sign_in_info.entitlements.is_some() { - resp = self.content_access(ctx, sign_in_info.into()).await; - } - - let mut sign_in_resp = fut.await; - - // Return Ok if both dpap calls are successful. - if sign_in_resp.is_ok() && resp.is_ok() { - sign_in_resp = Ok(true); - } else { - sign_in_resp = Err(rpc_downstream_service_err("Received error from Server")); - } - sign_in_resp - } - async fn sign_out(&self, ctx: CallContext) -> RpcResult { - info!("Discovery.signOut"); - // Note : Do NOT issue clearContentAccess for Firebolt SignOut case. - self.process_sign_in_request(ctx.clone(), false).await - } - - async fn on_sign_in( - &self, - ctx: CallContext, - request: ListenRequest, - ) -> RpcResult { - let listen = request.listen; - AppEvents::add_listener(&self.state, EVENT_ON_SIGN_IN.to_string(), ctx, request); - - Ok(ListenerResponse { - listening: listen, - event: EVENT_ON_SIGN_IN.to_owned(), - }) - } - async fn on_sign_out( - &self, - ctx: CallContext, - request: ListenRequest, - ) -> RpcResult { - let listen = request.listen; - AppEvents::add_listener(&self.state, EVENT_ON_SIGN_OUT.to_string(), ctx, request); - - Ok(ListenerResponse { - listening: listen, - event: EVENT_ON_SIGN_OUT.to_owned(), - }) - } - - async fn watched(&self, context: CallContext, info: WatchedInfo) -> RpcResult { - info!("Discovery.watched"); - let request = WatchedRequest { - context, - info, - unit: None, - }; - if let Ok(response) = self - .state - .get_client() - .send_extn_request(AccountLinkRequest::Watched(request)) - .await - { - if let Some(ExtnResponse::Boolean(v)) = response.payload.extract() { - return Ok(v); - } - } - - Err(rpc_err( - "Did not receive a valid resposne from platform when notifying watched info", - )) - } - - async fn watch_next( - &self, - ctx: CallContext, - watch_next_info: WatchNextInfo, - ) -> RpcResult { - info!("Discovery.watchNext"); - let watched_info = WatchedInfo { - entity_id: watch_next_info.identifiers.entity_id.unwrap_or_default(), - progress: 1.0, - completed: Some(false), - watched_on: None, - }; - let request = WatchedRequest { - context: ctx.clone(), - info: watched_info, - unit: None, - }; - if let Ok(response) = self - .state - .get_client() - .send_extn_request(AccountLinkRequest::Watched(request)) - .await - { - if let Some(ExtnResponse::Boolean(v)) = response.payload.extract() { - return Ok(v); - } - } - - Err(rpc_err( - "Did not receive a valid resposne from platform when notifying watched info", - )) - } - async fn get_content_policy_rpc(&self, ctx: CallContext) -> RpcResult { DiscoveryImpl::get_content_policy(&ctx, &self.state, &ctx.app_id).await } @@ -768,25 +530,6 @@ impl DiscoveryServer for DiscoveryImpl { ProviderBroker::provider_response(&self.state, response).await; Ok(true) } - - async fn discovery_content_access( - &self, - ctx: CallContext, - request: ContentAccessRequest, - ) -> RpcResult<()> { - let resp = self.content_access(ctx, request).await; - match resp { - Ok(_) => Ok(()), - Err(e) => Err(e), - } - } - async fn discovery_clear_content_access(&self, ctx: CallContext) -> RpcResult<()> { - let resp = self.clear_content_access(ctx).await; - match resp { - Ok(_) => Ok(()), - Err(e) => Err(e), - } - } } fn update_intent_source(source_app_id: String, request: LaunchRequest) -> LaunchRequest { let source = format!("xrn:firebolt:application:{}", source_app_id); diff --git a/core/main/src/firebolt/handlers/telemetry_rpc.rs b/core/main/src/firebolt/handlers/internal_rpc.rs similarity index 53% rename from core/main/src/firebolt/handlers/telemetry_rpc.rs rename to core/main/src/firebolt/handlers/internal_rpc.rs index 4eb6fc636..57687428e 100644 --- a/core/main/src/firebolt/handlers/telemetry_rpc.rs +++ b/core/main/src/firebolt/handlers/internal_rpc.rs @@ -17,31 +17,46 @@ use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule}; use ripple_sdk::{ - api::{firebolt::fb_telemetry::TelemetryPayload, gateway::rpc_gateway_api::CallContext}, + api::{ + apps::AppEvent, + firebolt::{fb_general::ListenRequestWithEvent, fb_telemetry::TelemetryPayload}, + gateway::rpc_gateway_api::CallContext, + }, async_trait::async_trait, }; use crate::{ - firebolt::rpc::RippleRPCProvider, service::telemetry_builder::TelemetryBuilder, + firebolt::rpc::RippleRPCProvider, + service::{apps::app_events::AppEvents, telemetry_builder::TelemetryBuilder}, state::platform_state::PlatformState, }; #[rpc(server)] -pub trait Telemetry { +pub trait Internal { #[method(name = "ripple.sendTelemetry")] async fn send_telemetry(&self, ctx: CallContext, payload: TelemetryPayload) -> RpcResult<()>; #[method(name = "ripple.setTelemetrySessionId")] fn set_telemetry_session_id(&self, ctx: CallContext, session_id: String) -> RpcResult<()>; + + #[method(name = "ripple.sendAppEvent")] + async fn send_app_event(&self, ctx: CallContext, event: AppEvent) -> RpcResult<()>; + + #[method(name = "ripple.registerAppEvent")] + async fn register_app_event( + &self, + ctx: CallContext, + request: ListenRequestWithEvent, + ) -> RpcResult<()>; } #[derive(Debug)] -pub struct TelemetryImpl { +pub struct InternalImpl { pub state: PlatformState, } #[async_trait] -impl TelemetryServer for TelemetryImpl { +impl InternalServer for InternalImpl { async fn send_telemetry(&self, _ctx: CallContext, payload: TelemetryPayload) -> RpcResult<()> { let _ = TelemetryBuilder::send_telemetry(&self.state, payload); Ok(()) @@ -51,11 +66,27 @@ impl TelemetryServer for TelemetryImpl { self.state.otel.update_session_id(Some(session_id)); Ok(()) } + + async fn send_app_event(&self, _ctx: CallContext, event: AppEvent) -> RpcResult<()> { + AppEvents::emit_with_context(&self.state, &event.event_name, &event.result, event.context) + .await; + Ok(()) + } + + async fn register_app_event( + &self, + ctx: CallContext, + request: ListenRequestWithEvent, + ) -> RpcResult<()> { + let event = request.event.clone(); + AppEvents::add_listener(&self.state, event, ctx, request.request); + Ok(()) + } } -pub struct TelemetryProvider; -impl RippleRPCProvider for TelemetryProvider { - fn provide(state: PlatformState) -> RpcModule { - (TelemetryImpl { state }).into_rpc() +pub struct InternalProvider; +impl RippleRPCProvider for InternalProvider { + fn provide(state: PlatformState) -> RpcModule { + (InternalImpl { state }).into_rpc() } } diff --git a/core/main/src/firebolt/mod.rs b/core/main/src/firebolt/mod.rs index 4f040db54..99af0780c 100644 --- a/core/main/src/firebolt/mod.rs +++ b/core/main/src/firebolt/mod.rs @@ -27,6 +27,7 @@ pub mod handlers { pub mod closed_captions_rpc; pub mod device_rpc; pub mod discovery_rpc; + pub mod internal_rpc; pub mod keyboard_rpc; pub mod lcm_rpc; pub mod lifecycle_rpc; @@ -37,7 +38,6 @@ pub mod handlers { pub mod provider_registrar; pub mod second_screen_rpc; pub mod secure_storage_rpc; - pub mod telemetry_rpc; pub mod user_grants_rpc; pub mod voice_guidance_rpc; pub mod wifi_rpc; diff --git a/core/main/src/processor/account_link_processor.rs b/core/main/src/processor/account_link_processor.rs deleted file mode 100644 index bd15ef273..000000000 --- a/core/main/src/processor/account_link_processor.rs +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use ripple_sdk::{ - api::{ - account_link::{AccountLinkRequest, WatchedRequest}, - apps::{AppManagerResponse, AppMethod, AppRequest, AppResponse}, - distributor::{ - distributor_discovery::{DiscoveryRequest, MediaEventRequest}, - distributor_privacy::DataEventType, - }, - firebolt::fb_discovery::{ - ClearContentSetParams, ContentAccessAvailability, ContentAccessEntitlement, - ContentAccessInfo, ContentAccessListSetParams, ContentAccessRequest, MediaEvent, - MediaEventsAccountLinkRequestParams, SessionParams, SignInRequestParams, - }, - gateway::rpc_gateway_api::CallContext, - }, - async_trait::async_trait, - extn::{ - client::extn_processor::{ - DefaultExtnStreamer, ExtnRequestProcessor, ExtnStreamProcessor, ExtnStreamer, - }, - extn_client_message::{ExtnMessage, ExtnResponse}, - }, - log::{debug, error}, - tokio::sync::{ - mpsc::{Receiver as MReceiver, Sender as MSender}, - oneshot, - }, - utils::error::RippleError, -}; - -use crate::{ - firebolt::handlers::discovery_rpc::DiscoveryImpl, service::data_governance::DataGovernance, - state::platform_state::PlatformState, utils::rpc_utils::rpc_await_oneshot, -}; - -/// Supports processing of [Config] request from extensions and also -/// internal services. -#[derive(Debug)] -pub struct AccountLinkProcessor { - state: PlatformState, - streamer: DefaultExtnStreamer, -} - -impl AccountLinkProcessor { - pub fn new(state: PlatformState) -> AccountLinkProcessor { - AccountLinkProcessor { - state, - streamer: DefaultExtnStreamer::new(), - } - } - - async fn process_sign_in_request( - state: &PlatformState, - msg: ExtnMessage, - ctx: CallContext, - is_signed_in: bool, - ) -> bool { - let session = match state.session_state.get_account_session() { - Some(session) => session, - None => { - error!("No account session found"); - return false; - } - }; - - let payload = DiscoveryRequest::SignIn(SignInRequestParams { - session_info: SessionParams { - app_id: ctx.app_id.to_owned(), - dist_session: session, - }, - is_signed_in, - }); - - let resp = state.get_client().send_extn_request(payload).await; - - if let Ok(v) = resp { - if let Some(ExtnResponse::None(())) = v.payload.extract() { - return Self::respond( - state.get_client().get_extn_client(), - msg, - ExtnResponse::None(()), - ) - .await - .is_ok(); - } - } - - Self::handle_error( - state.get_client().get_extn_client(), - msg, - RippleError::ProcessorError, - ) - .await - } - - async fn content_access( - state: &PlatformState, - msg: ExtnMessage, - ctx: CallContext, - request: ContentAccessRequest, - ) -> bool { - let session = match state.session_state.get_account_session() { - Some(session) => session, - None => { - error!("No account session found"); - return false; - } - }; - - // If both entitlement & availability are None return EmptyResult - if request.ids.availabilities.is_none() && request.ids.entitlements.is_none() { - return Self::respond( - state.get_client().get_extn_client(), - msg, - ExtnResponse::None(()), - ) - .await - .is_ok(); - } - - let payload = DiscoveryRequest::SetContentAccess(ContentAccessListSetParams { - session_info: SessionParams { - app_id: ctx.app_id.to_owned(), - dist_session: session, - }, - content_access_info: ContentAccessInfo { - availabilities: request.ids.availabilities.map(|availability_vec| { - availability_vec - .into_iter() - .map(|x| ContentAccessAvailability { - _type: x._type.as_string().to_owned(), - id: x.id, - catalog_id: x.catalog_id, - start_time: x.start_time, - end_time: x.end_time, - }) - .collect() - }), - entitlements: request.ids.entitlements.map(|entitlement_vec| { - entitlement_vec - .into_iter() - .map(|x| ContentAccessEntitlement { - entitlement_id: x.entitlement_id, - start_time: x.start_time, - end_time: x.end_time, - }) - .collect() - }), - }, - }); - - let resp = state.get_client().send_extn_request(payload).await; - if let Ok(v) = resp { - if let Some(ExtnResponse::None(())) = v.payload.extract() { - return Self::respond( - state.get_client().get_extn_client(), - msg, - ExtnResponse::None(()), - ) - .await - .is_ok(); - } - } - - Self::handle_error( - state.get_client().get_extn_client(), - msg, - RippleError::ProcessorError, - ) - .await - } - - async fn clear_content_access( - state: &PlatformState, - msg: ExtnMessage, - ctx: CallContext, - ) -> bool { - let session = match state.session_state.get_account_session() { - Some(session) => session, - None => { - error!("No account session found"); - return false; - } - }; - - let payload = DiscoveryRequest::ClearContent(ClearContentSetParams { - session_info: SessionParams { - app_id: ctx.app_id.to_owned(), - dist_session: session, - }, - }); - - let resp = state.get_client().send_extn_request(payload).await; - if let Ok(v) = resp { - if let Some(ExtnResponse::None(())) = v.payload.extract() { - return Self::respond( - state.get_client().get_extn_client(), - msg, - ExtnResponse::None(()), - ) - .await - .is_ok(); - } - } - - Self::handle_error( - state.get_client().get_extn_client(), - msg, - RippleError::ProcessorError, - ) - .await - } - - pub async fn get_content_partner_id( - platform_state: &PlatformState, - ctx: &CallContext, - ) -> Result { - let mut content_partner_id = ctx.app_id.to_owned(); - let (app_resp_tx, app_resp_rx) = oneshot::channel::(); - - let app_request = AppRequest::new( - AppMethod::GetAppContentCatalog(ctx.app_id.clone()), - app_resp_tx, - ); - if let Err(e) = platform_state.get_client().send_app_request(app_request) { - error!("Send error for AppMethod::GetAppContentCatalog {:?}", e); - return Err(RippleError::ProcessorError); - } - let resp = rpc_await_oneshot(app_resp_rx).await; - - if let Ok(Ok(AppManagerResponse::AppContentCatalog(content_catalog))) = resp { - content_partner_id = content_catalog.map_or(ctx.app_id.to_owned(), |x| x) - } - Ok(content_partner_id) - } - - async fn watched(state: &PlatformState, msg: ExtnMessage, request: WatchedRequest) -> bool { - let watched_info = request.info; - let ctx = request.context; - let (data_tags, drop_data) = - DataGovernance::resolve_tags(state, ctx.app_id.clone(), DataEventType::Watched).await; - debug!("drop_all={:?} data_tags={:?}", drop_data, data_tags); - if drop_data { - return Self::respond( - state.get_client().get_extn_client(), - msg, - ExtnResponse::Boolean(false), - ) - .await - .is_ok(); - } - - if let Some(dist_session) = state.session_state.get_account_session() { - let request = - MediaEventRequest::MediaEventAccountLink(MediaEventsAccountLinkRequestParams { - media_event: MediaEvent { - content_id: watched_info.entity_id.to_owned(), - completed: watched_info.completed.unwrap_or(false), - progress: watched_info.progress, - progress_unit: request.unit.clone(), - watched_on: watched_info.watched_on.clone(), - app_id: ctx.app_id.to_owned(), - }, - content_partner_id: Self::get_content_partner_id(state, &ctx) - .await - .unwrap_or_else(|_| ctx.app_id.to_owned()), - client_supports_opt_out: DiscoveryImpl::get_share_watch_history(), - dist_session, - data_tags, - }); - - if state.get_client().send_extn_request(request).await.is_ok() { - return Self::respond( - state.get_client().get_extn_client(), - msg, - ExtnResponse::Boolean(true), - ) - .await - .is_ok(); - } - } - Self::handle_error( - state.get_client().get_extn_client(), - msg, - RippleError::ProcessorError, - ) - .await - } -} - -impl ExtnStreamProcessor for AccountLinkProcessor { - type STATE = PlatformState; - type VALUE = AccountLinkRequest; - fn get_state(&self) -> Self::STATE { - self.state.clone() - } - - fn sender(&self) -> MSender { - self.streamer.sender() - } - - fn receiver(&mut self) -> MReceiver { - self.streamer.receiver() - } -} - -#[async_trait] -impl ExtnRequestProcessor for AccountLinkProcessor { - fn get_client(&self) -> ripple_sdk::extn::client::extn_client::ExtnClient { - self.state.get_client().get_extn_client() - } - - async fn process_request( - state: Self::STATE, - msg: ExtnMessage, - extracted_message: Self::VALUE, - ) -> bool { - match extracted_message { - AccountLinkRequest::SignIn(ctx) => { - Self::process_sign_in_request(&state, msg, ctx, true).await - } - AccountLinkRequest::SignOut(ctx) => { - Self::process_sign_in_request(&state, msg, ctx, false).await - } - AccountLinkRequest::ContentAccess(ctx, request) => { - Self::content_access(&state, msg, ctx, request).await - } - AccountLinkRequest::ClearContentAccess(ctx) => { - Self::clear_content_access(&state, msg, ctx).await - } - AccountLinkRequest::Watched(request) => Self::watched(&state, msg, request).await, - } - } -} diff --git a/core/main/src/processor/mod.rs b/core/main/src/processor/mod.rs index a527e9538..637149980 100644 --- a/core/main/src/processor/mod.rs +++ b/core/main/src/processor/mod.rs @@ -15,7 +15,6 @@ // SPDX-License-Identifier: Apache-2.0 // -pub mod account_link_processor; pub mod app_events_processor; pub mod authorized_info_processor; pub mod config_processor; diff --git a/core/main/src/processor/storage/storage_manager.rs b/core/main/src/processor/storage/storage_manager.rs index de5af9fe1..fa4259064 100644 --- a/core/main/src/processor/storage/storage_manager.rs +++ b/core/main/src/processor/storage/storage_manager.rs @@ -90,7 +90,7 @@ impl StorageManager { Ok(StorageManagerResponse::Ok(value)) | Ok(StorageManagerResponse::NoChange(value)) => { state .ripple_cache - .update_cached_bool_storage_property(state, &property, value); + .update_cached_bool_storage_property(&property, value); Ok(value) } Ok(StorageManagerResponse::Default(value)) => Ok(value), @@ -128,7 +128,7 @@ impl StorageManager { Ok(StorageManagerResponse::Ok(_)) | Ok(StorageManagerResponse::NoChange(_)) => { state .ripple_cache - .update_cached_bool_storage_property(state, &property, value); + .update_cached_bool_storage_property(&property, value); Ok(()) } Ok(StorageManagerResponse::Default(_)) => Ok(()), diff --git a/core/main/src/service/mod.rs b/core/main/src/service/mod.rs index 577c82fcc..97ea571ac 100644 --- a/core/main/src/service/mod.rs +++ b/core/main/src/service/mod.rs @@ -17,7 +17,6 @@ pub mod apps; pub mod context_manager; -pub mod data_governance; pub mod extn; pub mod telemetry_builder; pub mod user_grants; diff --git a/core/main/src/state/otel_state.rs b/core/main/src/state/otel_state.rs index 728e0fd40..b1ff131bf 100644 --- a/core/main/src/state/otel_state.rs +++ b/core/main/src/state/otel_state.rs @@ -21,16 +21,11 @@ use std::{ }; use ripple_sdk::{ - api::{ - distributor::distributor_privacy::PrivacySettingsData, - observability::metrics_util::ApiStats, - }, + api::observability::metrics_util::ApiStats, chrono::{DateTime, Utc}, log::{error, warn}, }; -use super::platform_state::PlatformState; - include!(concat!(env!("OUT_DIR"), "/version.rs")); const API_STATS_MAP_SIZE_WARNING: usize = 10; @@ -48,13 +43,6 @@ impl OtelState { self.device_session_id.read().unwrap().clone().unwrap() } - pub fn update_data_governance_tags( - &self, - _platform_state: &PlatformState, - _privacy_settings_data: &PrivacySettingsData, - ) { - } - pub fn operational_telemetry_listener(&self, target: &str, listen: bool) { let mut listeners = self.operational_telemetry_listeners.write().unwrap(); if listen { diff --git a/core/main/src/state/platform_state.rs b/core/main/src/state/platform_state.rs index bcf8ec4a6..a0fb5e0cb 100644 --- a/core/main/src/state/platform_state.rs +++ b/core/main/src/state/platform_state.rs @@ -44,7 +44,6 @@ use crate::{ app_events::AppEventsState, delegated_launcher_handler::AppManagerState, provider_broker::ProviderBrokerState, }, - data_governance::DataGovernanceState, extn::ripple_client::RippleClient, }, }; @@ -103,7 +102,6 @@ pub struct PlatformState { pub app_manager_state: AppManagerState, pub open_rpc_state: OpenRpcState, pub router_state: RouterState, - pub data_governance: DataGovernanceState, pub otel: OtelState, pub device_session_id: DeviceSessionIdentifier, pub ripple_cache: RippleCache, @@ -137,7 +135,6 @@ impl PlatformState { app_manager_state: AppManagerState::new(&manifest.configuration.saved_dir), open_rpc_state: OpenRpcState::new(Some(exclusory), extn_sdks, provider_registations), router_state: RouterState::new(), - data_governance: DataGovernanceState::default(), otel: metrics_state.clone(), device_session_id: DeviceSessionIdentifier::default(), ripple_cache: RippleCache::default(), diff --git a/core/main/src/state/ripple_cache.rs b/core/main/src/state/ripple_cache.rs index 769b8d490..498666126 100644 --- a/core/main/src/state/ripple_cache.rs +++ b/core/main/src/state/ripple_cache.rs @@ -20,8 +20,6 @@ use ripple_sdk::api::{ distributor::distributor_privacy::PrivacySettingsData, storage_property::StorageProperty, }; -use super::platform_state::PlatformState; - #[derive(Debug, Clone, Default)] pub struct RippleCache { // Cache for privacy settings @@ -41,19 +39,11 @@ impl RippleCache { } } - pub fn update_cached_bool_storage_property( - &self, - platform_state: &PlatformState, - property: &StorageProperty, - value: bool, - ) { + pub fn update_cached_bool_storage_property(&self, property: &StorageProperty, value: bool) { if property.is_a_privacy_setting_property() { // update the privacy setting property in cache let mut cache = self.privacy_settings_cache.write().unwrap(); property.set_privacy_setting_value(&mut cache, value); - platform_state - .otel - .update_data_governance_tags(platform_state, &cache); } } } diff --git a/core/sdk/src/api/account_link.rs b/core/sdk/src/api/account_link.rs index ba0c9ae46..982e54e4a 100644 --- a/core/sdk/src/api/account_link.rs +++ b/core/sdk/src/api/account_link.rs @@ -16,26 +16,11 @@ // use serde::{Deserialize, Serialize}; -use crate::{ - extn::extn_client_message::{ExtnPayload, ExtnPayloadProvider, ExtnRequest}, - framework::ripple_contract::RippleContract, -}; - use super::{ - firebolt::fb_discovery::{ContentAccessRequest, ProgressUnit, WatchedInfo}, + firebolt::fb_discovery::{ProgressUnit, WatchedInfo}, gateway::rpc_gateway_api::CallContext, }; -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -#[serde(rename_all = "camelCase")] -pub enum AccountLinkRequest { - SignIn(CallContext), - SignOut(CallContext), - ContentAccess(CallContext, ContentAccessRequest), - ClearContentAccess(CallContext), - Watched(WatchedRequest), -} - #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct WatchedRequest { @@ -43,49 +28,3 @@ pub struct WatchedRequest { pub info: WatchedInfo, pub unit: Option, } - -impl ExtnPayloadProvider for AccountLinkRequest { - fn get_extn_payload(&self) -> ExtnPayload { - ExtnPayload::Request(ExtnRequest::AccountLink(self.clone())) - } - - fn get_from_payload(payload: ExtnPayload) -> Option { - if let ExtnPayload::Request(ExtnRequest::AccountLink(value)) = payload { - return Some(value); - } - - None - } - - fn contract() -> RippleContract { - RippleContract::AccountLink - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::api::account_link::AccountLinkRequest; - use crate::api::gateway::rpc_gateway_api::{ApiProtocol, CallContext}; - use crate::utils::test_utils::test_extn_payload_provider; - - #[test] - fn test_extn_request_account_link() { - let call_context = CallContext { - session_id: "test_session_id".to_string(), - request_id: "test_request_id".to_string(), - app_id: "test_app_id".to_string(), - call_id: 123, - protocol: ApiProtocol::Bridge, - method: "some_method".to_string(), - cid: Some("test_cid".to_string()), - gateway_secure: true, - context: Vec::new(), - }; - - let account_link_request = AccountLinkRequest::SignIn(call_context); - let contract_type: RippleContract = RippleContract::AccountLink; - - test_extn_payload_provider(account_link_request, contract_type); - } -} diff --git a/core/sdk/src/api/distributor/distributor_discovery.rs b/core/sdk/src/api/distributor/distributor_discovery.rs deleted file mode 100644 index 0cadd54b3..000000000 --- a/core/sdk/src/api/distributor/distributor_discovery.rs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use serde::{Deserialize, Serialize}; - -use crate::{ - api::firebolt::fb_discovery::{ - ClearContentSetParams, ContentAccessListSetParams, MediaEventsAccountLinkRequestParams, - SignInRequestParams, - }, - extn::extn_client_message::{ExtnPayload, ExtnPayloadProvider, ExtnRequest}, - framework::ripple_contract::RippleContract, -}; - -use super::distributor_request::DistributorRequest; - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub enum DiscoveryRequest { - SetContentAccess(ContentAccessListSetParams), - ClearContent(ClearContentSetParams), - SignIn(SignInRequestParams), -} - -impl ExtnPayloadProvider for DiscoveryRequest { - fn get_from_payload(payload: ExtnPayload) -> Option { - if let ExtnPayload::Request(ExtnRequest::Distributor(DistributorRequest::Discovery(d))) = - payload - { - return Some(d); - } - - None - } - - fn get_extn_payload(&self) -> ExtnPayload { - ExtnPayload::Request(ExtnRequest::Distributor(DistributorRequest::Discovery( - self.clone(), - ))) - } - - fn contract() -> RippleContract { - RippleContract::Discovery - } -} - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub enum MediaEventRequest { - MediaEventAccountLink(MediaEventsAccountLinkRequestParams), -} - -impl ExtnPayloadProvider for MediaEventRequest { - fn get_from_payload(payload: ExtnPayload) -> Option { - if let ExtnPayload::Request(ExtnRequest::Distributor(DistributorRequest::MediaEvent(d))) = - payload - { - return Some(d); - } - - None - } - - fn get_extn_payload(&self) -> ExtnPayload { - ExtnPayload::Request(ExtnRequest::Distributor(DistributorRequest::MediaEvent( - self.clone(), - ))) - } - - fn contract() -> RippleContract { - RippleContract::MediaEvents - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::api::firebolt::fb_discovery::{ - ContentAccessEntitlement, ContentAccessInfo, ContentAccessListSetParams, SessionParams, - }; - use crate::api::firebolt::fb_discovery::{MediaEvent, ProgressUnit}; - use crate::api::session::AccountSession; - use crate::utils::test_utils::test_extn_payload_provider; - use std::collections::HashSet; - - #[test] - fn test_extn_request_discovery() { - let content_access_entitlement = ContentAccessEntitlement { - entitlement_id: "test_entitlement_id".to_string(), - start_time: Some("2024-01-26T12:00:00Z".to_string()), - end_time: Some("2024-02-01T12:00:00Z".to_string()), - }; - - let content_access_info = ContentAccessInfo { - availabilities: Some(vec![]), - entitlements: Some(vec![content_access_entitlement]), - }; - - let session_params = SessionParams { - app_id: "test_app_id".to_string(), - dist_session: AccountSession { - id: "test_session_id".to_string(), - token: "test_token".to_string(), - account_id: "test_account_id".to_string(), - device_id: "test_device_id".to_string(), - }, - }; - - let content_access_list_set_params = ContentAccessListSetParams { - session_info: session_params, - content_access_info, - }; - - let discovery_request = DiscoveryRequest::SetContentAccess(content_access_list_set_params); - let contract_type: RippleContract = RippleContract::Discovery; - - test_extn_payload_provider(discovery_request, contract_type); - } - - #[test] - fn test_extn_payload_provider_for_media_event_request() { - let media_event_request = - MediaEventRequest::MediaEventAccountLink(MediaEventsAccountLinkRequestParams { - media_event: MediaEvent { - content_id: String::from("your_content_id"), - completed: true, - progress: 0.75, - progress_unit: Some(ProgressUnit::Percent), - watched_on: Some(String::from("2024-01-26")), - app_id: String::from("your_app_id"), - }, - content_partner_id: String::from("your_content_partner_id"), - client_supports_opt_out: true, - dist_session: AccountSession { - id: String::from("your_session_id"), - token: String::from("your_token"), - account_id: String::from("your_account_id"), - device_id: String::from("your_device_id"), - }, - data_tags: HashSet::new(), - }); - - let contract_type: RippleContract = RippleContract::MediaEvents; - test_extn_payload_provider(media_event_request, contract_type); - } -} diff --git a/core/sdk/src/api/distributor/distributor_encoder.rs b/core/sdk/src/api/distributor/distributor_encoder.rs deleted file mode 100644 index cfe91d3eb..000000000 --- a/core/sdk/src/api/distributor/distributor_encoder.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use serde::{Deserialize, Serialize}; - -use crate::{ - extn::extn_client_message::{ExtnPayload, ExtnPayloadProvider, ExtnRequest}, - framework::ripple_contract::RippleContract, -}; - -use super::distributor_request::DistributorRequest; - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct EncoderRequest { - pub reference: String, - pub scope: String, -} - -impl ExtnPayloadProvider for EncoderRequest { - fn get_from_payload(payload: ExtnPayload) -> Option { - if let ExtnPayload::Request(ExtnRequest::Distributor(DistributorRequest::Encoder(d))) = - payload - { - return Some(d); - } - None - } - - fn get_extn_payload(&self) -> ExtnPayload { - ExtnPayload::Request(ExtnRequest::Distributor(DistributorRequest::Encoder( - self.clone(), - ))) - } - - fn contract() -> RippleContract { - RippleContract::Encoder - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::utils::test_utils::test_extn_payload_provider; - - #[test] - fn test_extn_payload_provider_for_encoder_request() { - let encoder_request = EncoderRequest { - reference: String::from("example_reference"), - scope: String::from("example_scope"), - }; - - let contract_type: RippleContract = RippleContract::Encoder; - test_extn_payload_provider(encoder_request, contract_type); - } -} diff --git a/core/sdk/src/api/distributor/distributor_request.rs b/core/sdk/src/api/distributor/distributor_request.rs deleted file mode 100644 index 6e272a445..000000000 --- a/core/sdk/src/api/distributor/distributor_request.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use serde::{Deserialize, Serialize}; - -use super::{ - distributor_discovery::{DiscoveryRequest, MediaEventRequest}, - distributor_encoder::EncoderRequest, - distributor_permissions::PermissionRequest, -}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr(test, derive(PartialEq))] -pub enum DistributorRequest { - Permission(PermissionRequest), - Discovery(DiscoveryRequest), - MediaEvent(MediaEventRequest), - Encoder(EncoderRequest), -} diff --git a/core/sdk/src/api/firebolt/fb_general.rs b/core/sdk/src/api/firebolt/fb_general.rs index d4a922f6b..98feedd81 100644 --- a/core/sdk/src/api/firebolt/fb_general.rs +++ b/core/sdk/src/api/firebolt/fb_general.rs @@ -22,6 +22,12 @@ pub struct ListenRequest { pub listen: bool, } +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct ListenRequestWithEvent { + pub event: String, + pub request: ListenRequest, +} + #[derive(Serialize, Deserialize, Debug)] pub struct ListenerResponse { pub listening: bool, diff --git a/core/sdk/src/api/mod.rs b/core/sdk/src/api/mod.rs index 77940f69f..29860db8f 100644 --- a/core/sdk/src/api/mod.rs +++ b/core/sdk/src/api/mod.rs @@ -41,12 +41,9 @@ pub mod gateway { } pub mod distributor { - pub mod distributor_discovery; - pub mod distributor_encoder; pub mod distributor_permissions; pub mod distributor_platform; pub mod distributor_privacy; - pub mod distributor_request; pub mod distributor_token; pub mod distributor_usergrants; } diff --git a/core/sdk/src/extn/extn_client_message.rs b/core/sdk/src/extn/extn_client_message.rs index 200869229..5d973b06c 100644 --- a/core/sdk/src/extn/extn_client_message.rs +++ b/core/sdk/src/extn/extn_client_message.rs @@ -29,7 +29,6 @@ use println as error; use crate::{ api::{ - account_link::AccountLinkRequest, app_catalog::{AppCatalogRequest, AppMetadata, AppsUpdate}, apps::AppEventRequest, caps::CapsRequest, @@ -45,7 +44,6 @@ use crate::{ distributor_permissions::{PermissionRequest, PermissionResponse}, distributor_platform::PlatformTokenRequest, distributor_privacy::{PrivacyCloudRequest, PrivacySettingsStoreRequest}, - distributor_request::DistributorRequest, distributor_token::DistributorTokenRequest, distributor_usergrants::UserGrantsCloudStoreRequest, }, @@ -298,14 +296,12 @@ pub enum ExtnRequest { PinChallenge(PinChallengeRequestWithContext), Keyboard(KeyboardSessionRequest), Permission(PermissionRequest), - Distributor(DistributorRequest), AccountSession(AccountSessionRequest), SessionToken(SessionTokenRequest), SecureStorage(SecureStorageRequest), Advertising(AdvertisingRequest), PrivacySettings(PrivacyCloudRequest), StorageManager(StorageManagerRequest), - AccountLink(AccountLinkRequest), Settings(SettingsRequest), UserGrantsCloudStore(UserGrantsCloudStoreRequest), UserGrantsStore(UserGrantsStoreRequest), diff --git a/core/sdk/src/framework/ripple_contract.rs b/core/sdk/src/framework/ripple_contract.rs index 18e49c930..8d582bdf1 100644 --- a/core/sdk/src/framework/ripple_contract.rs +++ b/core/sdk/src/framework/ripple_contract.rs @@ -44,9 +44,7 @@ pub enum RippleContract { /// Provided by the distributor useful for adding Governance implementation for handling /// privacy information and other sensitive data. Governance, - /// Provided by the distributor to discover content, apps, history and recommendations. - /// Used by [crate::api::distributor::distributor_discovery::DiscoveryRequest] - Discovery, + /// Provided by the platform to handle launching and managing applications. /// Used by [crate::api::firebolt::fb_lifecycle_management::LifecycleManagementEventRequest] Launcher, diff --git a/distributor/general/src/distributor_general_ffi.rs b/distributor/general/src/distributor_general_ffi.rs index 78fee9ed4..3d716ef73 100644 --- a/distributor/general/src/distributor_general_ffi.rs +++ b/distributor/general/src/distributor_general_ffi.rs @@ -41,9 +41,7 @@ use ripple_sdk::{ use crate::{ general_advertising_processor::DistributorAdvertisingProcessor, - general_discovery_processor::DistributorDiscoveryProcessor, general_distributor_token_processor::DistributorTokenProcessor, - general_media_events_processor::DistributorMediaEventProcessor, general_paltform_token_processor::PlatformTokenProcessor, general_permission_processor::DistributorPermissionProcessor, general_privacy_processor::DistributorPrivacyProcessor, @@ -66,8 +64,6 @@ fn init_library() -> CExtnMetadata { RippleContract::Session(SessionAdjective::Root), RippleContract::BehaviorMetrics, RippleContract::Session(SessionAdjective::Device), - RippleContract::Discovery, - RippleContract::MediaEvents, RippleContract::Session(SessionAdjective::Distributor), RippleContract::Session(SessionAdjective::Platform), ]), @@ -109,8 +105,6 @@ fn start_launcher(sender: ExtnSender, receiver: CReceiver) { client.add_request_processor(DistributorSecureStorageProcessor::new(client.clone())); client.add_request_processor(DistributorAdvertisingProcessor::new(client.clone())); client.add_request_processor(GeneralTokenProcessor::new(client.clone())); - client.add_request_processor(DistributorDiscoveryProcessor::new(client.clone())); - client.add_request_processor(DistributorMediaEventProcessor::new(client.clone())); client.add_request_processor(DistributorTokenProcessor::new(client.clone())); client.add_request_processor(PlatformTokenProcessor::new(client.clone())); diff --git a/distributor/general/src/general_discovery_processor.rs b/distributor/general/src/general_discovery_processor.rs deleted file mode 100644 index 25afd2d0f..000000000 --- a/distributor/general/src/general_discovery_processor.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use ripple_sdk::{ - api::distributor::distributor_discovery::DiscoveryRequest, - async_trait::async_trait, - extn::client::{ - extn_client::ExtnClient, - extn_processor::{ - DefaultExtnStreamer, ExtnRequestProcessor, ExtnStreamProcessor, ExtnStreamer, - }, - }, -}; - -pub struct DistributorDiscoveryProcessor { - client: ExtnClient, - streamer: DefaultExtnStreamer, -} - -impl DistributorDiscoveryProcessor { - pub fn new(client: ExtnClient) -> DistributorDiscoveryProcessor { - DistributorDiscoveryProcessor { - client, - streamer: DefaultExtnStreamer::new(), - } - } -} - -impl ExtnStreamProcessor for DistributorDiscoveryProcessor { - type STATE = ExtnClient; - type VALUE = DiscoveryRequest; - - fn get_state(&self) -> Self::STATE { - self.client.clone() - } - - fn receiver( - &mut self, - ) -> ripple_sdk::tokio::sync::mpsc::Receiver - { - self.streamer.receiver() - } - - fn sender( - &self, - ) -> ripple_sdk::tokio::sync::mpsc::Sender - { - self.streamer.sender() - } -} - -#[async_trait] -impl ExtnRequestProcessor for DistributorDiscoveryProcessor { - fn get_client(&self) -> ExtnClient { - self.client.clone() - } - async fn process_request( - mut state: Self::STATE, - msg: ripple_sdk::extn::extn_client_message::ExtnMessage, - _: Self::VALUE, - ) -> bool { - state - .respond( - msg, - ripple_sdk::extn::extn_client_message::ExtnResponse::None(()), - ) - .await - .is_ok() - } -} diff --git a/distributor/general/src/general_media_events_processor.rs b/distributor/general/src/general_media_events_processor.rs deleted file mode 100644 index 1c59a4d39..000000000 --- a/distributor/general/src/general_media_events_processor.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use ripple_sdk::{ - api::distributor::distributor_discovery::MediaEventRequest, - async_trait::async_trait, - extn::client::{ - extn_client::ExtnClient, - extn_processor::{ - DefaultExtnStreamer, ExtnRequestProcessor, ExtnStreamProcessor, ExtnStreamer, - }, - }, -}; - -pub struct DistributorMediaEventProcessor { - client: ExtnClient, - streamer: DefaultExtnStreamer, -} - -impl DistributorMediaEventProcessor { - pub fn new(client: ExtnClient) -> DistributorMediaEventProcessor { - DistributorMediaEventProcessor { - client, - streamer: DefaultExtnStreamer::new(), - } - } -} - -impl ExtnStreamProcessor for DistributorMediaEventProcessor { - type STATE = ExtnClient; - type VALUE = MediaEventRequest; - - fn get_state(&self) -> Self::STATE { - self.client.clone() - } - - fn receiver( - &mut self, - ) -> ripple_sdk::tokio::sync::mpsc::Receiver - { - self.streamer.receiver() - } - - fn sender( - &self, - ) -> ripple_sdk::tokio::sync::mpsc::Sender - { - self.streamer.sender() - } -} - -#[async_trait] -impl ExtnRequestProcessor for DistributorMediaEventProcessor { - fn get_client(&self) -> ExtnClient { - self.client.clone() - } - async fn process_request( - mut state: Self::STATE, - msg: ripple_sdk::extn::extn_client_message::ExtnMessage, - _: Self::VALUE, - ) -> bool { - state - .respond( - msg, - ripple_sdk::extn::extn_client_message::ExtnResponse::None(()), - ) - .await - .is_ok() - } -} diff --git a/distributor/general/src/lib.rs b/distributor/general/src/lib.rs index 8101aeef5..24976fe12 100644 --- a/distributor/general/src/lib.rs +++ b/distributor/general/src/lib.rs @@ -17,9 +17,7 @@ mod distributor_general_ffi; mod general_advertising_processor; -mod general_discovery_processor; mod general_distributor_token_processor; -mod general_media_events_processor; mod general_paltform_token_processor; mod general_permission_processor; mod general_privacy_processor; From b18dcfb82148af0267f84d73683450a189489d15 Mon Sep 17 00:00:00 2001 From: satlead Date: Fri, 21 Mar 2025 09:51:48 -0400 Subject: [PATCH 04/31] cp: Cleanup context managaer --- .../src/bootstrap/extn/load_session_step.rs | 2 - .../src/processor/main_context_processor.rs | 62 +----- core/main/src/service/context_manager.rs | 210 ------------------ core/main/src/service/mod.rs | 1 - .../sdk/src/api/device/device_info_request.rs | 2 - .../src/processors/thunder_device_info.rs | 26 --- 6 files changed, 4 insertions(+), 299 deletions(-) delete mode 100644 core/main/src/service/context_manager.rs diff --git a/core/main/src/bootstrap/extn/load_session_step.rs b/core/main/src/bootstrap/extn/load_session_step.rs index e15923867..6daf1eae2 100644 --- a/core/main/src/bootstrap/extn/load_session_step.rs +++ b/core/main/src/bootstrap/extn/load_session_step.rs @@ -19,7 +19,6 @@ use ripple_sdk::framework::bootstrap::Bootstep; use ripple_sdk::{async_trait::async_trait, framework::RippleResponse}; use crate::processor::main_context_processor::MainContextProcessor; -use crate::service::context_manager::ContextManager; use crate::state::bootstrap_state::BootstrapState; pub struct LoadDistributorValuesStep; @@ -33,7 +32,6 @@ impl Bootstep for LoadDistributorValuesStep { async fn setup(&self, s: BootstrapState) -> RippleResponse { MainContextProcessor::remove_expired_and_inactive_entries(&s.platform_state); - ContextManager::setup(&s.platform_state).await; if !s.platform_state.supports_session() { return Ok(()); } diff --git a/core/main/src/processor/main_context_processor.rs b/core/main/src/processor/main_context_processor.rs index e68edb64d..431e2552d 100644 --- a/core/main/src/processor/main_context_processor.rs +++ b/core/main/src/processor/main_context_processor.rs @@ -21,25 +21,21 @@ use ripple_sdk::{ api::{ context::{ActivationStatus, RippleContext, RippleContextUpdateType}, device::{ - device_info_request::DeviceInfoRequest, - device_request::{InternetConnectionStatus, PowerState, SystemPowerState}, + device_request::{PowerState, SystemPowerState}, device_user_grants_data::GrantLifespan, }, firebolt::fb_capabilities::{CapEvent, CapabilityRole, FireboltCap, FireboltPermission}, - session::{AccountSessionRequest, AccountSessionResponse}, + session::AccountSessionRequest, }, async_trait::async_trait, extn::{ client::extn_processor::{ DefaultExtnStreamer, ExtnEventProcessor, ExtnStreamProcessor, ExtnStreamer, }, - extn_client_message::{ExtnMessage, ExtnResponse}, + extn_client_message::ExtnMessage, }, log::{debug, error, info}, - tokio::{ - self, - sync::{mpsc::Receiver as MReceiver, mpsc::Sender as MSender}, - }, + tokio::sync::{mpsc::Receiver as MReceiver, mpsc::Sender as MSender}, }; use crate::{ @@ -87,26 +83,6 @@ impl MainContextProcessor { if let Some(session) = response.payload.extract() { state.session_state.insert_account_session(session); event = CapEvent::OnAvailable; - let state_c = state.clone(); - // update ripple context for token asynchronously - tokio::spawn(async move { - if let Ok(response) = state_c - .get_client() - .send_extn_request(AccountSessionRequest::GetAccessToken) - .await - { - if let Some(ExtnResponse::AccountSession( - AccountSessionResponse::AccountSessionToken(token), - )) = response.payload.extract::() - { - state_c.get_client().get_extn_client().context_update( - ripple_sdk::api::context::RippleContextUpdateRequest::Token(token), - ) - } else { - error!("couldnt update the session response") - } - } - }); token_available = true; } } @@ -152,30 +128,6 @@ impl MainContextProcessor { } } - fn handle_internet_connection_change( - state: &PlatformState, - internet_state: &Option, - // internet_state: &InternetConnectionStatus, - ) { - debug!("handling internet connection change: {:?}", internet_state); - let internet_state = match internet_state { - Some(state) => state, - None => return, - }; - - if matches!(internet_state, InternetConnectionStatus::FullyConnected) { - // get internet monitoring interval from platformState configuration - let interval_in_seconds = state - .get_device_manifest() - .get_internet_monitoring_interval(); - //Send request to start internet monitoring. - if let Err(err) = state.get_client().get_extn_client().request_transient( - DeviceInfoRequest::StartMonitoringInternetChanges(interval_in_seconds), - ) { - error!("Error in sending start monitoring: {:?}", err); - } - } - } fn handle_power_state(state: &PlatformState, power_state: &Option) { // fn handle_power_state(state: &PlatformState, power_state: &SystemPowerState) { let power_state = match power_state { @@ -247,12 +199,6 @@ impl ExtnEventProcessor for MainContextProcessor { RippleContextUpdateType::PowerStateChanged => { Self::handle_power_state(&state.state, &extracted_message.system_power_state) } - RippleContextUpdateType::InternetConnectionChanged => { - Self::handle_internet_connection_change( - &state.state, - &extracted_message.internet_connectivity, - ) - } _ => {} } { diff --git a/core/main/src/service/context_manager.rs b/core/main/src/service/context_manager.rs deleted file mode 100644 index 38a337fdc..000000000 --- a/core/main/src/service/context_manager.rs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use crate::state::platform_state::PlatformState; -use ripple_sdk::api::config::FEATURE_CLOUD_PERMISSIONS; -use ripple_sdk::api::context::{FeatureUpdate, RippleContextUpdateRequest}; -use ripple_sdk::api::device::device_events::{ - DeviceEvent, DeviceEventCallback, DeviceEventRequest, -}; -use ripple_sdk::api::device::device_info_request::{DeviceInfoRequest, DeviceResponse}; -use ripple_sdk::api::device::device_request::{ - OnInternetConnectedRequest, SystemPowerState, TimeZone, -}; -use ripple_sdk::api::session::{AccountSessionRequest, AccountSessionResponse}; -use ripple_sdk::extn::extn_client_message::ExtnResponse; -use ripple_sdk::log::{debug, error, warn}; -use ripple_sdk::tokio; - -pub struct ContextManager; - -impl ContextManager { - pub async fn setup(ps: &PlatformState) { - // Setup listeners here - - // Setup the Session listener is session is enabled on the manifest - if ps.supports_session() - && ps - .get_client() - .send_extn_request(AccountSessionRequest::Subscribe) - .await - .is_err() - { - warn!("No processor to set Session Token changed listener") - } - - // Setup the Power status listener - if ps - .get_client() - .send_extn_request(DeviceEventRequest { - event: DeviceEvent::SystemPowerStateChanged, - subscribe: true, - callback_type: DeviceEventCallback::ExtnEvent, - }) - .await - .is_err() - { - warn!("No processor to set System power status listener") - } - - // Setup the TimeZoneChanged status listener - if ps - .get_client() - .send_extn_request(DeviceEventRequest { - event: DeviceEvent::TimeZoneChanged, - subscribe: true, - callback_type: DeviceEventCallback::ExtnEvent, - }) - .await - .is_err() - { - warn!("No processor to set TimeZoneChanged status listener") - } - - let ps_c = ps.clone(); - - // Asynchronously get context and update the state - tokio::spawn(async move { - // Set default cloud permissions value - ps_c.get_client().get_extn_client().context_update( - RippleContextUpdateRequest::UpdateFeatures(vec![FeatureUpdate::new( - FEATURE_CLOUD_PERMISSIONS.into(), - ps_c.get_device_manifest().get_features().cloud_permissions, - )]), - ); - - // Get Initial power state - if let Ok(resp) = ps_c - .get_client() - .send_extn_request(DeviceInfoRequest::PowerState) - .await - { - if let Some(DeviceResponse::PowerState(p)) = - resp.payload.extract::() - { - ps_c.get_client().get_extn_client().context_update( - RippleContextUpdateRequest::PowerState(SystemPowerState { - current_power_state: p.clone(), - power_state: p, - }), - ); - } - } - - // Get Initial TimeZone - if let Ok(resp) = ps_c - .get_client() - .send_extn_request(DeviceInfoRequest::GetTimezoneWithOffset) - .await - { - if let Some(ExtnResponse::TimezoneWithOffset(tz, offset)) = - resp.payload.extract::() - { - ps_c.get_client().get_extn_client().context_update( - RippleContextUpdateRequest::TimeZone(TimeZone { - time_zone: tz, - offset, - }), - ); - } - } - - // Get Account session - if let Ok(resp) = ps_c - .get_client() - .send_extn_request(AccountSessionRequest::GetAccessToken) - .await - { - if let Some(ExtnResponse::AccountSession( - AccountSessionResponse::AccountSessionToken(account_token), - )) = resp.payload.extract::() - { - ps_c.get_client() - .get_extn_client() - .context_update(RippleContextUpdateRequest::Token(account_token)); - } - } - - // Setup the Internet Status listener. - // Moved Network plugin subscribe request to a seperate task to avoid blocking the main bootstrap thread. - // This is required since Network plugin is taking a little longer than expected time for activation under certain scenarios. - debug!("Subscribing for change in Internet connection Status"); - if ps_c - .get_client() - .send_extn_request(DeviceEventRequest { - event: DeviceEvent::InternetConnectionStatusChanged, - subscribe: true, - callback_type: DeviceEventCallback::ExtnEvent, - }) - .await - .is_err() - { - warn!("No processor to set Internet status listener") - } - - debug!("Getting the current status of internet connection"); - // Get Internet Connection state - if let Ok(resp) = ps_c - .get_client() - .send_extn_request(DeviceInfoRequest::OnInternetConnected( - OnInternetConnectedRequest { timeout: 1000 }, - )) - .await - { - ripple_sdk::log::debug!("[RIPPLE CONTEXT] Sending OnInternetConnected request"); - if let Some(DeviceResponse::InternetConnectionStatus(s)) = - resp.payload.extract::() - { - ripple_sdk::log::debug!( - "[RIPPLE CONTEXT] OnInternetConnected response: {:?}", - s - ); - ps_c.get_client() - .get_extn_client() - .context_update(RippleContextUpdateRequest::InternetStatus(s)); - } else { - ripple_sdk::log::debug!( - "[RIPPLE CONTEXT] OnInternetConnected response was NONE" - ); - } - } - }); - } - - // Update the Context with session information during startup - pub fn update_context_for_session(state_c: PlatformState) { - // update ripple context for token asynchronously - tokio::spawn(async move { - if let Ok(response) = state_c - .get_client() - .send_extn_request(AccountSessionRequest::GetAccessToken) - .await - { - if let Some(ExtnResponse::AccountSession( - AccountSessionResponse::AccountSessionToken(token), - )) = response.payload.extract::() - { - state_c.get_client().get_extn_client().context_update( - ripple_sdk::api::context::RippleContextUpdateRequest::Token(token), - ) - } else { - error!("couldnt update the session response") - } - } - }); - } -} diff --git a/core/main/src/service/mod.rs b/core/main/src/service/mod.rs index 97ea571ac..41ace0e8f 100644 --- a/core/main/src/service/mod.rs +++ b/core/main/src/service/mod.rs @@ -16,7 +16,6 @@ // pub mod apps; -pub mod context_manager; pub mod extn; pub mod telemetry_builder; pub mod user_grants; diff --git a/core/sdk/src/api/device/device_info_request.rs b/core/sdk/src/api/device/device_info_request.rs index b6a59695d..14131f310 100644 --- a/core/sdk/src/api/device/device_info_request.rs +++ b/core/sdk/src/api/device/device_info_request.rs @@ -58,8 +58,6 @@ pub enum DeviceInfoRequest { FullCapabilities(Vec), PowerState, SerialNumber, - StartMonitoringInternetChanges(u32), - StopMonitoringInternetChanges, PlatformBuildInfo, } diff --git a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs index e0253a370..3f3b74af2 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs @@ -500,28 +500,6 @@ impl ThunderDeviceInfoRequestProcessor { } } - async fn start_internet_monitoring_changes( - state: CachedState, - request: ExtnMessage, - interval_in_seconds: u32, - ) -> bool { - // Self::start_internet_monitoring(&state).await - let response = state - .get_thunder_client() - .call(DeviceCallRequest { - method: ThunderPlugin::Network.method("startConnectivityMonitoring"), - params: Some(DeviceChannelParams::Json( - json!({"interval":interval_in_seconds}).to_string(), - )), - }) - .await; - if check_thunder_response_success(&response) { - return Self::respond(state.get_client(), request, ExtnResponse::None(())) - .await - .is_ok(); - } - Self::handle_error(state.get_client(), request, RippleError::ProcessorError).await - } async fn internet_connection_status(state: CachedState, req: ExtnMessage) -> bool { if let Some(response) = Self::get_internet_connection_status(&state).await { trace!( @@ -1482,9 +1460,6 @@ impl ExtnRequestProcessor for ThunderDeviceInfoRequestProcessor { DeviceInfoRequest::InternetConnectionStatus => { Self::internet_connection_status(state.clone(), msg).await } - DeviceInfoRequest::StartMonitoringInternetChanges(i) => { - Self::start_internet_monitoring_changes(state.clone(), msg, i).await - } DeviceInfoRequest::FullCapabilities(keys) => { let keys_as_str: Vec<&str> = keys.iter().map(String::as_str).collect(); Self::get_device_capabilities(state.clone(), &keys_as_str, msg).await @@ -1493,7 +1468,6 @@ impl ExtnRequestProcessor for ThunderDeviceInfoRequestProcessor { DeviceInfoRequest::PlatformBuildInfo => { Self::platform_build_info(state.clone(), msg).await } - _ => false, } } } From 799e2a5d9ccf959d37c505f6c2e0e496b4469615 Mon Sep 17 00:00:00 2001 From: satlead Date: Tue, 25 Mar 2025 12:59:22 -0400 Subject: [PATCH 05/31] cp: existing unit tests passed --- device/thunder_ripple_sdk/Cargo.toml | 1 + device/thunder_ripple_sdk/src/client/plugin_manager.rs | 6 +++--- device/thunder_ripple_sdk/src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/device/thunder_ripple_sdk/Cargo.toml b/device/thunder_ripple_sdk/Cargo.toml index 19ce44477..c4a69e4f6 100644 --- a/device/thunder_ripple_sdk/Cargo.toml +++ b/device/thunder_ripple_sdk/Cargo.toml @@ -52,6 +52,7 @@ contract_tests = [ "websocket_contract_tests", ] local_dev=[] +mock=[] [dependencies] tokio-tungstenite = { workspace = true, features = ["native-tls"] } diff --git a/device/thunder_ripple_sdk/src/client/plugin_manager.rs b/device/thunder_ripple_sdk/src/client/plugin_manager.rs index 621f4334e..75af5bc35 100644 --- a/device/thunder_ripple_sdk/src/client/plugin_manager.rs +++ b/device/thunder_ripple_sdk/src/client/plugin_manager.rs @@ -50,7 +50,7 @@ pub struct PluginManager { } #[derive(Debug, Deserialize, Clone)] -#[cfg_attr(test, derive(Serialize))] +#[cfg_attr(any(test, feature = "mock"), derive(Serialize))] pub struct PluginStateChangeEvent { pub callsign: String, pub state: PluginState, @@ -62,7 +62,7 @@ pub struct ThunderActivatePluginParams { } #[derive(Debug, PartialEq, Deserialize, Clone)] -#[cfg_attr(test, derive(Serialize))] +#[cfg_attr(any(test, feature = "mock"), derive(Serialize))] pub struct PluginStatus { pub state: String, } @@ -96,7 +96,7 @@ impl PluginStatus { } #[derive(Debug, Deserialize, PartialEq, Clone)] -#[cfg_attr(test, derive(Serialize))] +#[cfg_attr(any(test, feature = "mock"), derive(Serialize))] pub enum PluginState { Activated, Activation, diff --git a/device/thunder_ripple_sdk/src/lib.rs b/device/thunder_ripple_sdk/src/lib.rs index c2f87058a..f4610073d 100644 --- a/device/thunder_ripple_sdk/src/lib.rs +++ b/device/thunder_ripple_sdk/src/lib.rs @@ -55,7 +55,7 @@ pub mod utils; pub mod thunder_state; pub extern crate ripple_sdk; -#[cfg(test)] +#[cfg(any(test, feature = "mock"))] pub mod tests { #[cfg(feature = "websocket_contract_tests")] pub mod contracts { From 28a17d602fc40ef4454585828d2fea3c514a1a78 Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 26 Mar 2025 18:10:07 -0400 Subject: [PATCH 06/31] cp: Cleanup Metrics Context --- core/sdk/src/api/context.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/core/sdk/src/api/context.rs b/core/sdk/src/api/context.rs index ce1102416..897b74106 100644 --- a/core/sdk/src/api/context.rs +++ b/core/sdk/src/api/context.rs @@ -73,7 +73,6 @@ pub enum RippleContextUpdateType { PowerStateChanged, TimeZoneChanged, FeaturesChanged, - MetricsContextChanged, } impl RippleContext { @@ -99,6 +98,18 @@ impl RippleContext { RippleContext::get_from_payload(msg.clone()) } + pub fn update_with_context(&mut self, context: &RippleContext) { + if let Some(update_type) = context.update_type.clone() { + match update_type { + RippleContextUpdateType::ActivationStatusChanged | RippleContextUpdateType::TokenChanged => self.activation_status = context.activation_status.clone(), + RippleContextUpdateType::InternetConnectionChanged => self.internet_connectivity = context.internet_connectivity.clone(), + RippleContextUpdateType::FeaturesChanged => self.features = context.features.clone(), + RippleContextUpdateType::PowerStateChanged => self.system_power_state = context.system_power_state.clone(), + RippleContextUpdateType::TimeZoneChanged => self.time_zone = context.time_zone.clone(), + } + } + } + pub fn update(&mut self, request: RippleContextUpdateRequest) -> bool { match request { RippleContextUpdateRequest::Activation(a) => { From 8df8b99f228661547c634f979b092f00fd9b7e21 Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 26 Mar 2025 18:12:53 -0400 Subject: [PATCH 07/31] fix: format --- core/sdk/src/api/context.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/core/sdk/src/api/context.rs b/core/sdk/src/api/context.rs index 897b74106..9741429df 100644 --- a/core/sdk/src/api/context.rs +++ b/core/sdk/src/api/context.rs @@ -101,11 +101,22 @@ impl RippleContext { pub fn update_with_context(&mut self, context: &RippleContext) { if let Some(update_type) = context.update_type.clone() { match update_type { - RippleContextUpdateType::ActivationStatusChanged | RippleContextUpdateType::TokenChanged => self.activation_status = context.activation_status.clone(), - RippleContextUpdateType::InternetConnectionChanged => self.internet_connectivity = context.internet_connectivity.clone(), - RippleContextUpdateType::FeaturesChanged => self.features = context.features.clone(), - RippleContextUpdateType::PowerStateChanged => self.system_power_state = context.system_power_state.clone(), - RippleContextUpdateType::TimeZoneChanged => self.time_zone = context.time_zone.clone(), + RippleContextUpdateType::ActivationStatusChanged + | RippleContextUpdateType::TokenChanged => { + self.activation_status = context.activation_status.clone() + } + RippleContextUpdateType::InternetConnectionChanged => { + self.internet_connectivity = context.internet_connectivity.clone() + } + RippleContextUpdateType::FeaturesChanged => { + self.features = context.features.clone() + } + RippleContextUpdateType::PowerStateChanged => { + self.system_power_state = context.system_power_state.clone() + } + RippleContextUpdateType::TimeZoneChanged => { + self.time_zone = context.time_zone.clone() + } } } } From 738ed1db555fd04c4cd16237b2ace752a546b577 Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 26 Mar 2025 18:22:26 -0400 Subject: [PATCH 08/31] fix: Move LCM to internal for appcatalogId --- .../src/firebolt/handlers/internal_rpc.rs | 21 +++++++++++++++++++ core/main/src/firebolt/handlers/lcm_rpc.rs | 20 ------------------ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/core/main/src/firebolt/handlers/internal_rpc.rs b/core/main/src/firebolt/handlers/internal_rpc.rs index 57687428e..286e80ca0 100644 --- a/core/main/src/firebolt/handlers/internal_rpc.rs +++ b/core/main/src/firebolt/handlers/internal_rpc.rs @@ -19,6 +19,7 @@ use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule}; use ripple_sdk::{ api::{ apps::AppEvent, + context::{RippleContext, RippleContextUpdateRequest}, firebolt::{fb_general::ListenRequestWithEvent, fb_telemetry::TelemetryPayload}, gateway::rpc_gateway_api::CallContext, }, @@ -48,6 +49,9 @@ pub trait Internal { ctx: CallContext, request: ListenRequestWithEvent, ) -> RpcResult<()>; + + #[method(name = "ripple.getAppCatalogId")] + async fn get_app_catalog_id(&self, ctx: CallContext, app_id: String) -> RpcResult; } #[derive(Debug)] @@ -82,6 +86,23 @@ impl InternalServer for InternalImpl { AppEvents::add_listener(&self.state, event, ctx, request.request); Ok(()) } + + async fn get_app_catalog_id(&self, _: CallContext, app_id: String) -> RpcResult { + let (app_resp_tx, app_resp_rx) = oneshot::channel::(); + + let app_request = + AppRequest::new(AppMethod::GetAppContentCatalog(app_id.clone()), app_resp_tx); + if let Err(e) = self.state.get_client().send_app_request(app_request) { + error!("Send error for AppMethod::GetAppContentCatalog {:?}", e); + } + let resp = rpc_await_oneshot(app_resp_rx).await; + + if let Ok(Ok(AppManagerResponse::AppContentCatalog(content_catalog))) = resp { + return Ok(content_catalog.map_or(app_id.to_owned(), |x| x)); + } + + Ok(app_id) + } } pub struct InternalProvider; diff --git a/core/main/src/firebolt/handlers/lcm_rpc.rs b/core/main/src/firebolt/handlers/lcm_rpc.rs index 3e852df2e..bb0e50f85 100644 --- a/core/main/src/firebolt/handlers/lcm_rpc.rs +++ b/core/main/src/firebolt/handlers/lcm_rpc.rs @@ -93,9 +93,6 @@ pub trait LifecycleManagement { ctx: CallContext, request: ListenRequest, ) -> RpcResult; - - #[method(name = "ripple.getAppCatalogId")] - async fn get_app_catalog_id(&self, ctx: CallContext, app_id: String) -> RpcResult; } #[derive(Debug)] @@ -264,23 +261,6 @@ impl LifecycleManagementServer for LifecycleManagementImpl { event: LCM_EVENT_ON_SESSION_TRANSITION_CANCELED.to_string(), }) } - - async fn get_app_catalog_id(&self, _: CallContext, app_id: String) -> RpcResult { - let (app_resp_tx, app_resp_rx) = oneshot::channel::(); - - let app_request = - AppRequest::new(AppMethod::GetAppContentCatalog(app_id.clone()), app_resp_tx); - if let Err(e) = self.state.get_client().send_app_request(app_request) { - error!("Send error for AppMethod::GetAppContentCatalog {:?}", e); - } - let resp = rpc_await_oneshot(app_resp_rx).await; - - if let Ok(Ok(AppManagerResponse::AppContentCatalog(content_catalog))) = resp { - return Ok(content_catalog.map_or(app_id.to_owned(), |x| x)); - } - - Ok(app_id) - } } pub struct LifecycleManagementProvider; From db90ebe9332580d650535491bddddf0aa8d7edd8 Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 26 Mar 2025 18:46:53 -0400 Subject: [PATCH 09/31] fix: contracts --- .../src/firebolt/handlers/internal_rpc.rs | 6 ++-- core/main/src/state/platform_state.rs | 10 ------- core/sdk/src/framework/ripple_contract.rs | 30 ------------------- .../general/src/distributor_general_ffi.rs | 1 - 4 files changed, 4 insertions(+), 43 deletions(-) diff --git a/core/main/src/firebolt/handlers/internal_rpc.rs b/core/main/src/firebolt/handlers/internal_rpc.rs index 286e80ca0..9ccca65d3 100644 --- a/core/main/src/firebolt/handlers/internal_rpc.rs +++ b/core/main/src/firebolt/handlers/internal_rpc.rs @@ -18,18 +18,20 @@ use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule}; use ripple_sdk::{ api::{ - apps::AppEvent, - context::{RippleContext, RippleContextUpdateRequest}, + apps::{AppEvent, AppManagerResponse, AppMethod, AppRequest, AppResponse}, firebolt::{fb_general::ListenRequestWithEvent, fb_telemetry::TelemetryPayload}, gateway::rpc_gateway_api::CallContext, }, async_trait::async_trait, + log::error, + tokio::sync::oneshot, }; use crate::{ firebolt::rpc::RippleRPCProvider, service::{apps::app_events::AppEvents, telemetry_builder::TelemetryBuilder}, state::platform_state::PlatformState, + utils::rpc_utils::rpc_await_oneshot, }; #[rpc(server)] diff --git a/core/main/src/state/platform_state.rs b/core/main/src/state/platform_state.rs index a0fb5e0cb..acf4ee692 100644 --- a/core/main/src/state/platform_state.rs +++ b/core/main/src/state/platform_state.rs @@ -180,16 +180,6 @@ impl PlatformState { self.get_client().respond(msg).await } - pub fn supports_cloud_sync(&self) -> bool { - let contract = RippleContract::CloudSync.as_clear_string(); - self.extn_manifest.required_contracts.contains(&contract) - } - - pub fn supports_encoding(&self) -> bool { - let contract = RippleContract::Encoder.as_clear_string(); - self.extn_manifest.required_contracts.contains(&contract) - } - pub fn supports_distributor_session(&self) -> bool { let contract = RippleContract::Session(SessionAdjective::Distributor).as_clear_string(); self.extn_manifest.required_contracts.contains(&contract) diff --git a/core/sdk/src/framework/ripple_contract.rs b/core/sdk/src/framework/ripple_contract.rs index 8d582bdf1..f204f481e 100644 --- a/core/sdk/src/framework/ripple_contract.rs +++ b/core/sdk/src/framework/ripple_contract.rs @@ -41,9 +41,6 @@ pub enum RippleContract { /// Used by Main application to provide internal contracts for Extensions #[default] Internal, - /// Provided by the distributor useful for adding Governance implementation for handling - /// privacy information and other sensitive data. - Governance, /// Provided by the platform to handle launching and managing applications. /// Used by [crate::api::firebolt::fb_lifecycle_management::LifecycleManagementEventRequest] @@ -88,26 +85,12 @@ pub enum RippleContract { VoiceGuidance, /// Distributor Contract for handling Advertising requirements. Advertising, - /// Contract focussed on Aggregating the App Behavior metrics before sending to the Distributor ingestors. - BehaviorMetrics, - /// Contract focussed on getting more real time media playback events like Pause, Play, Seek useful for - /// features like Continue Watching - MediaEvents, /// Contract which controls User Privacy Settings will become an Adjective in near future PrivacySettings, - /// Contract used for tracking Sign in / Sign Out across apps so Distributor can provide better discovery - /// of the signed in Application. - AccountLink, /// Contract to allow Extensions to get and set Settings. Settings, - /// Used for synchronization enforcement between cloud and local data - CloudSync, /// Extensions can use this contract to get more information on the firebolt capabilities Caps, - /// Distributors can add their encoding algorithms to account and device id for security. - Encoder, - /// Contract for Main to forward behavior and operational metrics to processors - Metrics, /// Contract for Extensions to recieve Telemetry events from Main OperationalMetricListener, Observability, @@ -336,19 +319,6 @@ mod tests { )); } - #[test] - fn test_as_clear_string() { - assert_eq!( - RippleContract::AccountLink.as_clear_string(), - "account_link".to_owned() - ); - assert_eq!( - RippleContract::Session(crate::api::session::SessionAdjective::Account) - .as_clear_string(), - "account.session".to_owned() - ) - } - #[test] fn test_from_manifest() { assert!(RippleContract::from_manifest("account_link").is_some()); diff --git a/distributor/general/src/distributor_general_ffi.rs b/distributor/general/src/distributor_general_ffi.rs index 3d716ef73..364a583bb 100644 --- a/distributor/general/src/distributor_general_ffi.rs +++ b/distributor/general/src/distributor_general_ffi.rs @@ -62,7 +62,6 @@ fn init_library() -> CExtnMetadata { RippleContract::Advertising, RippleContract::Storage(StorageAdjective::PrivacyCloud), RippleContract::Session(SessionAdjective::Root), - RippleContract::BehaviorMetrics, RippleContract::Session(SessionAdjective::Device), RippleContract::Session(SessionAdjective::Distributor), RippleContract::Session(SessionAdjective::Platform), From e6e0e70e6f0334d79bb35a834c17f333b1b752d0 Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 26 Mar 2025 19:28:43 -0400 Subject: [PATCH 10/31] fix: thunder_device_info --- Cargo.lock | 26 +---- .../sdk/src/api/device/device_info_request.rs | 1 - device/thunder_ripple_sdk/Cargo.toml | 1 - .../events/thunder_event_handlers.rs | 4 +- .../src/processors/thunder_device_info.rs | 99 ++++++++++++------- 5 files changed, 66 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 185ac8e49..d077fa9ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -520,18 +520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e" dependencies = [ "chrono", - "chrono-tz-build 0.2.1", - "phf", -] - -[[package]] -name = "chrono-tz" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6ac4f2c0bf0f44e9161aec9675e1050aa4a530663c4a9e37e108fa948bca9f" -dependencies = [ - "chrono", - "chrono-tz-build 0.4.0", + "chrono-tz-build", "phf", ] @@ -546,16 +535,6 @@ dependencies = [ "phf_codegen", ] -[[package]] -name = "chrono-tz-build" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" -dependencies = [ - "parse-zoneinfo", - "phf_codegen", -] - [[package]] name = "chumsky" version = "0.9.3" @@ -2392,7 +2371,7 @@ dependencies = [ "base64 0.21.7", "bytes", "chrono", - "chrono-tz 0.8.6", + "chrono-tz", "fs2", "gregorian", "hashers", @@ -3514,7 +3493,6 @@ version = "1.1.0" dependencies = [ "base64 0.22.1", "chrono", - "chrono-tz 0.10.1", "csv", "expectest", "futures", diff --git a/core/sdk/src/api/device/device_info_request.rs b/core/sdk/src/api/device/device_info_request.rs index 883af2f5d..04edeaf2d 100644 --- a/core/sdk/src/api/device/device_info_request.rs +++ b/core/sdk/src/api/device/device_info_request.rs @@ -51,7 +51,6 @@ pub enum DeviceInfoRequest { SetVoiceGuidanceEnabled(bool), VoiceGuidanceSpeed, SetVoiceGuidanceSpeed(f32), - GetTimezoneWithOffset, FullCapabilities(Vec), PowerState, SerialNumber, diff --git a/device/thunder_ripple_sdk/Cargo.toml b/device/thunder_ripple_sdk/Cargo.toml index c4a69e4f6..215372d43 100644 --- a/device/thunder_ripple_sdk/Cargo.toml +++ b/device/thunder_ripple_sdk/Cargo.toml @@ -80,7 +80,6 @@ tree_magic_mini = { version = "=3.0.3", optional = true } rstest = { version = "0.18.2", optional = true, default-features = false } futures-util = { version = "0.3.28", features = ["sink", "std"], default-features = false, optional = true} chrono = { workspace = true, features = ["clock"]} -chrono-tz = "0.10" [dev-dependencies] diff --git a/device/thunder_ripple_sdk/src/processors/events/thunder_event_handlers.rs b/device/thunder_ripple_sdk/src/processors/events/thunder_event_handlers.rs index 58013c7f9..060d988f8 100644 --- a/device/thunder_ripple_sdk/src/processors/events/thunder_event_handlers.rs +++ b/device/thunder_ripple_sdk/src/processors/events/thunder_event_handlers.rs @@ -35,7 +35,6 @@ use crate::{ events::thunder_event_processor::{ ThunderEventHandler, ThunderEventHandlerProvider, ThunderEventMessage, }, - processors::thunder_device_info::CachedState, ripple_sdk::{ api::device::{ device_events::{DeviceEventCallback, HDCP_CHANGED_EVENT, POWER_STATE_CHANGED}, @@ -388,10 +387,9 @@ impl TimezoneChangedEventHandler { _callback_type: DeviceEventCallback, ) { if let ThunderEventMessage::TimeZone(_v) = value { - let cached_state = CachedState::new(state.clone()); tokio::spawn(async move { if let Some(tz) = - ThunderDeviceInfoRequestProcessor::get_timezone_and_offset(&cached_state).await + ThunderDeviceInfoRequestProcessor::get_timezone_and_offset(&state).await { let event = ExtnEvent::AppEvent(AppEventRequest::Emit(AppEvent { event_name: TIME_ZONE_CHANGED.to_string(), diff --git a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs index 302587548..f62c8d1ff 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs @@ -45,6 +45,7 @@ use crate::{ firebolt::fb_openrpc::FireboltSemanticVersion, }, async_trait::async_trait, + chrono::NaiveDateTime, extn::{ client::extn_processor::{ DefaultExtnStreamer, ExtnRequestProcessor, ExtnStreamProcessor, ExtnStreamer, @@ -58,8 +59,6 @@ use crate::{ }, utils::get_audio_profile_from_value, }; -use chrono::{TimeZone as ChronoTimezone, Utc}; -use chrono_tz::{OffsetComponents, Tz}; use regex::{Match, Regex}; use ripple_sdk::{ api::{ @@ -148,7 +147,7 @@ pub struct CachedDeviceInfo { #[derive(Debug, Clone)] pub struct CachedState { - state: ThunderState, + pub state: ThunderState, cached: Arc>, } @@ -299,6 +298,22 @@ impl ThunderAllTimezonesResponse { } } } + + fn get_offset(&self, key: &str) -> i64 { + if let Some(tz) = self.timezones.get(key) { + if let Some(utc_tz) = self.timezones.get("Etc/UTC").cloned() { + if let Ok(ntz) = NaiveDateTime::parse_from_str(tz, "%a %b %d %H:%M:%S %Y %Z") { + if let Ok(nutz) = + NaiveDateTime::parse_from_str(&utc_tz, "%a %b %d %H:%M:%S %Y %Z") + { + let delta = (ntz - nutz).num_seconds(); + return round_to_nearest_quarter_hour(delta); + } + } + } + } + 0 + } } impl<'de> Deserialize<'de> for ThunderAllTimezonesResponse { fn deserialize(deserializer: D) -> Result @@ -927,7 +942,7 @@ impl ThunderDeviceInfoRequestProcessor { } // If timezone or offset is None or empty - if let Some(tz) = Self::get_timezone_and_offset(&state).await { + if let Some(tz) = Self::get_timezone_and_offset(&state.state).await { let cloned_state = state.clone(); let cloned_tz = tz.clone(); @@ -951,42 +966,46 @@ impl ThunderDeviceInfoRequestProcessor { Self::handle_error(state.get_client(), req, RippleError::ProcessorError).await } - pub async fn get_timezone_and_offset(state: &CachedState) -> Option { - let timezone_result = - ThunderDeviceInfoRequestProcessor::get_timezone_value(&state.state).await; + pub async fn get_timezone_and_offset(state: &ThunderState) -> Option { + let timezone_result = ThunderDeviceInfoRequestProcessor::get_timezone_value(&state).await; + let timezones_result = ThunderDeviceInfoRequestProcessor::get_all_timezones(state).await; - if let Ok(timezone) = timezone_result { - Some(TimeZone { + if let (Ok(timezone), Ok(timezones)) = (timezone_result, timezones_result) { + let timezone = TimeZone { time_zone: timezone.clone(), - offset: Self::get_offset_seconds(&timezone).unwrap_or(0), - }) + offset: timezones.get_offset(&timezone), + }; + let timezone_c = timezone.clone(); + let _ = state + .get_client() + .request_transient(RippleContextUpdateRequest::TimeZone(timezone_c)); + Some(timezone) } else { None } } - pub fn get_offset_seconds(timezone: &str) -> Option { - // Parse the timezone (e.g., "America/Los_Angeles") - let tz: Tz = timezone.parse().ok()?; - - // Get the current UTC time - let utc_now = Utc::now(); - - // Convert the current UTC time to the specified timezone - let local_time = tz.from_utc_datetime(&utc_now.naive_utc()); - - // Get the base UTC offset and DST adjustment - let base_offset = local_time.offset().base_utc_offset().num_seconds(); - let dst_offset = local_time.offset().dst_offset().num_seconds(); - - // Calculate the total offset in seconds - let total_offset = base_offset + dst_offset; - - // Round the total offset to the nearest quarter hour - const QUARER_HOUR: i64 = 900; - let rounded_offset = ((total_offset as f64 / 900.0).round() as i64) * QUARER_HOUR; - - Some(rounded_offset) + async fn get_all_timezones( + state: &ThunderState, + ) -> Result { + let response = state + .get_thunder_client() + .call(DeviceCallRequest { + method: ThunderPlugin::System.method("getTimeZones"), + params: None, + }) + .await; + if check_thunder_response_success(&response) { + match serde_json::from_value::(response.message) { + Ok(timezones) => Ok(timezones), + Err(e) => { + error!("{}", e.to_string()); + Err(RippleError::ProcessorError) + } + } + } else { + Err(RippleError::ProcessorError) + } } async fn voice_guidance_enabled(state: CachedState, request: ExtnMessage) -> bool { @@ -1359,9 +1378,6 @@ impl ExtnRequestProcessor for ThunderDeviceInfoRequestProcessor { DeviceInfoRequest::OnInternetConnected(time_out) => { Self::on_internet_connected(state.clone(), msg, time_out.timeout).await } - DeviceInfoRequest::GetTimezoneWithOffset => { - Self::get_timezone_with_offset(state.clone(), msg).await - } DeviceInfoRequest::SetVoiceGuidanceEnabled(v) => { Self::voice_guidance_set_enabled(state.clone(), msg, v).await } @@ -1389,6 +1405,17 @@ impl ExtnRequestProcessor for ThunderDeviceInfoRequestProcessor { } } +fn round_to_nearest_quarter_hour(offset_seconds: i64) -> i64 { + // Convert minutes to quarter hours + let quarter_hours = (offset_seconds as f64 / 900.0).round() as i64; + + // Convert back to minutes + let rounded_minutes = quarter_hours * 15; + + // Convert minutes back to seconds + rounded_minutes * 60 +} + #[cfg(test)] pub mod tests { use std::{fs::File, sync::Arc}; From 9b2a81b21a6bd3e03c79f689646fbec08bd827da Mon Sep 17 00:00:00 2001 From: satlead Date: Fri, 28 Mar 2025 10:40:08 -0400 Subject: [PATCH 11/31] Fix: Unit tests and cleanup manifests --- core/sdk/src/framework/ripple_contract.rs | 2 +- examples/manifest/extn-manifest-example.json | 10 ++-------- .../manifest/extn-manifest-mock-device-example.json | 10 ++-------- examples/manifest/extn-manifest-tm-example.json | 10 ++-------- examples/manifest/mock/mock-extn-manifest.json | 7 ------- .../IpStb/firebolt-extn-manifest.json | 5 +---- 6 files changed, 8 insertions(+), 36 deletions(-) diff --git a/core/sdk/src/framework/ripple_contract.rs b/core/sdk/src/framework/ripple_contract.rs index f204f481e..1a096d41f 100644 --- a/core/sdk/src/framework/ripple_contract.rs +++ b/core/sdk/src/framework/ripple_contract.rs @@ -321,7 +321,7 @@ mod tests { #[test] fn test_from_manifest() { - assert!(RippleContract::from_manifest("account_link").is_some()); + assert!(RippleContract::from_manifest("permissions").is_some()); assert!(RippleContract::from_manifest("account.session").is_some()); } } diff --git a/examples/manifest/extn-manifest-example.json b/examples/manifest/extn-manifest-example.json index ea8edcba1..6d0f0834b 100644 --- a/examples/manifest/extn-manifest-example.json +++ b/examples/manifest/extn-manifest-example.json @@ -50,10 +50,7 @@ "secure_storage", "advertising", "privacy_settings", - "metrics", - "session_token", - "discovery", - "media_events" + "session_token" ] } ] @@ -73,10 +70,7 @@ "secure_storage", "advertising", "privacy_settings", - "session_token", - "metrics", - "discovery", - "media_events" + "session_token" ], "rpc_aliases": { "device.model": [ diff --git a/examples/manifest/extn-manifest-mock-device-example.json b/examples/manifest/extn-manifest-mock-device-example.json index acc5fda94..b42ea1ddd 100644 --- a/examples/manifest/extn-manifest-mock-device-example.json +++ b/examples/manifest/extn-manifest-mock-device-example.json @@ -37,10 +37,7 @@ "secure_storage", "advertising", "privacy_settings", - "metrics", - "session_token", - "discovery", - "media_events" + "session_token" ] } ] @@ -85,10 +82,7 @@ "secure_storage", "advertising", "privacy_settings", - "session_token", - "metrics", - "discovery", - "media_events" + "session_token" ], "rpc_aliases": { "device.model": [ diff --git a/examples/manifest/extn-manifest-tm-example.json b/examples/manifest/extn-manifest-tm-example.json index 74452a8e3..63781d940 100644 --- a/examples/manifest/extn-manifest-tm-example.json +++ b/examples/manifest/extn-manifest-tm-example.json @@ -50,10 +50,7 @@ "secure_storage", "advertising", "privacy_settings", - "metrics", - "session_token", - "discovery", - "media_events" + "session_token" ] } ] @@ -88,10 +85,7 @@ "secure_storage", "advertising", "privacy_settings", - "session_token", - "metrics", - "discovery", - "media_events" + "session_token" ], "rpc_aliases": { "device.model": [ diff --git a/examples/manifest/mock/mock-extn-manifest.json b/examples/manifest/mock/mock-extn-manifest.json index b75eacf19..fffa1d6eb 100644 --- a/examples/manifest/mock/mock-extn-manifest.json +++ b/examples/manifest/mock/mock-extn-manifest.json @@ -46,11 +46,7 @@ "secure.storage", "advertising", "privacy_cloud.storage", - "metrics", "session.token", - "discovery", - "media_events", - "behavior_metrics", "root.session", "device.session" ] @@ -99,9 +95,6 @@ "advertising", "privacy_settings", "session_token", - "metrics", - "discovery", - "media_events", "account.session" ], "rpc_aliases": { diff --git a/examples/reference-manifest/IpStb/firebolt-extn-manifest.json b/examples/reference-manifest/IpStb/firebolt-extn-manifest.json index 12ccabb93..b95b1004a 100644 --- a/examples/reference-manifest/IpStb/firebolt-extn-manifest.json +++ b/examples/reference-manifest/IpStb/firebolt-extn-manifest.json @@ -68,8 +68,6 @@ "root.session", "secure.storage", "advertising", - "media_events", - "discovery", "behavior_metrics" ] } @@ -89,7 +87,6 @@ "secure.storage", "advertising", "privacy_settings", - "metrics", "account.session", "device.session", "distributor.session", @@ -100,4 +97,4 @@ "custom.model" ] } -} +} \ No newline at end of file From 3c7b8c704cab3125b8eb353662e3cd5061f3c8a9 Mon Sep 17 00:00:00 2001 From: satlead Date: Fri, 28 Mar 2025 10:52:13 -0400 Subject: [PATCH 12/31] fix: Clippy errors --- .../src/processors/thunder_device_info.rs | 2 +- .../tests/contracts/thunder_controller_pacts.rs | 9 ++++++++- .../contracts/thunder_device_info_pacts.rs | 17 +++++++++++------ .../contracts/thunder_package_manager_pacts.rs | 10 ++++++++++ .../contracts/thunder_persistent_store_pacts.rs | 14 +++++++++++++- 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs index f62c8d1ff..2450ff9f0 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs @@ -967,7 +967,7 @@ impl ThunderDeviceInfoRequestProcessor { } pub async fn get_timezone_and_offset(state: &ThunderState) -> Option { - let timezone_result = ThunderDeviceInfoRequestProcessor::get_timezone_value(&state).await; + let timezone_result = ThunderDeviceInfoRequestProcessor::get_timezone_value(state).await; let timezones_result = ThunderDeviceInfoRequestProcessor::get_all_timezones(state).await; if let (Ok(timezone), Ok(timezones)) = (timezone_result, timezones_result) { diff --git a/device/thunder_ripple_sdk/src/tests/contracts/thunder_controller_pacts.rs b/device/thunder_ripple_sdk/src/tests/contracts/thunder_controller_pacts.rs index 4afcb23aa..85b0d1ebb 100644 --- a/device/thunder_ripple_sdk/src/tests/contracts/thunder_controller_pacts.rs +++ b/device/thunder_ripple_sdk/src/tests/contracts/thunder_controller_pacts.rs @@ -1,15 +1,22 @@ +#[allow(dead_code, unused_imports)] use crate::ripple_sdk::{ serde_json::{self, json}, tokio, }; - +#[allow(dead_code, unused_imports)] use crate::{mock_websocket_server, send_thunder_call_message}; +#[allow(dead_code, unused_imports)] use pact_consumer::mock_server::StartMockServerAsync; +#[allow(dead_code, unused_imports)] use pact_consumer::prelude::*; +#[allow(dead_code, unused_imports)] use futures_util::{SinkExt, StreamExt}; +#[allow(dead_code, unused_imports)] use tokio::time::{timeout, Duration}; +#[allow(dead_code, unused_imports)] use tokio_tungstenite::connect_async; +#[allow(dead_code, unused_imports)] use tokio_tungstenite::tungstenite::protocol::Message; #[tokio::test(flavor = "multi_thread")] diff --git a/device/thunder_ripple_sdk/src/tests/contracts/thunder_device_info_pacts.rs b/device/thunder_ripple_sdk/src/tests/contracts/thunder_device_info_pacts.rs index 58ca55dd2..c252dd5ac 100644 --- a/device/thunder_ripple_sdk/src/tests/contracts/thunder_device_info_pacts.rs +++ b/device/thunder_ripple_sdk/src/tests/contracts/thunder_device_info_pacts.rs @@ -14,24 +14,29 @@ // // SPDX-License-Identifier: Apache-2.0 // - -use serde_json::json; +#[allow(dead_code, unused_imports)] use std::collections::HashMap; - +#[allow(dead_code, unused_imports)] use crate::get_pact_with_params; - +#[allow(dead_code, unused_imports)] use crate::ripple_sdk::{ - serde_json::{self}, + serde_json::{self, json}, tokio, }; - +#[allow(dead_code, unused_imports)] use crate::tests::contracts::contract_utils::*; +#[allow(dead_code, unused_imports)] use crate::{get_pact, send_thunder_call_message}; +#[allow(dead_code, unused_imports)] use pact_consumer::mock_server::StartMockServerAsync; +#[allow(dead_code, unused_imports)] use futures_util::{SinkExt, StreamExt}; +#[allow(dead_code, unused_imports)] use tokio::time::{timeout, Duration}; +#[allow(dead_code, unused_imports)] use tokio_tungstenite::connect_async; +#[allow(dead_code, unused_imports)] use tokio_tungstenite::tungstenite::protocol::Message; #[tokio::test(flavor = "multi_thread")] diff --git a/device/thunder_ripple_sdk/src/tests/contracts/thunder_package_manager_pacts.rs b/device/thunder_ripple_sdk/src/tests/contracts/thunder_package_manager_pacts.rs index 36e357234..612385a0f 100644 --- a/device/thunder_ripple_sdk/src/tests/contracts/thunder_package_manager_pacts.rs +++ b/device/thunder_ripple_sdk/src/tests/contracts/thunder_package_manager_pacts.rs @@ -1,5 +1,8 @@ +#[allow(dead_code, unused_imports)] use crate::tests::contracts::contract_utils::*; +#[allow(dead_code, unused_imports)] use crate::thunder_state::ThunderConnectionState; +#[allow(dead_code, unused_imports)] use crate::{ client::thunder_client_pool::ThunderClientPool, get_pact_with_params, @@ -25,13 +28,20 @@ use crate::{ }, thunder_state::ThunderState, }; +#[allow(dead_code, unused_imports)] use base64::{engine::general_purpose::STANDARD as base64, Engine}; +#[allow(dead_code, unused_imports)] use pact_consumer::mock_server::StartMockServerAsync; +#[allow(dead_code, unused_imports)] use rstest::rstest; +#[allow(dead_code, unused_imports)] use serde_json::json; +#[allow(dead_code, unused_imports)] use std::collections::HashMap; +#[allow(dead_code, unused_imports)] use std::sync::{Arc, Mutex}; +#[allow(dead_code)] const OPERATION_TIMEOUT_SECS: u64 = 12 * 60; // 12 minutes #[rstest( diff --git a/device/thunder_ripple_sdk/src/tests/contracts/thunder_persistent_store_pacts.rs b/device/thunder_ripple_sdk/src/tests/contracts/thunder_persistent_store_pacts.rs index ac13712fd..0aeaca6ee 100644 --- a/device/thunder_ripple_sdk/src/tests/contracts/thunder_persistent_store_pacts.rs +++ b/device/thunder_ripple_sdk/src/tests/contracts/thunder_persistent_store_pacts.rs @@ -14,20 +14,32 @@ // // SPDX-License-Identifier: Apache-2.0 // - +#[allow(dead_code, unused_imports)] use crate::ripple_sdk::{serde_json::json, tokio}; +#[allow(dead_code, unused_imports)] use crate::tests::contracts::contract_utils::*; +#[allow(dead_code, unused_imports)] use crate::tests::contracts::thunder_persistent_store_pacts::chrono::Utc; +#[allow(dead_code, unused_imports)] use crate::{get_pact_with_params, send_thunder_call_message}; +#[allow(dead_code, unused_imports)] use pact_consumer::mock_server::StartMockServerAsync; +#[allow(dead_code, unused_imports)] use pact_consumer::prelude::*; +#[allow(dead_code, unused_imports)] use ripple_sdk::chrono; +#[allow(dead_code, unused_imports)] use rstest::rstest; +#[allow(dead_code, unused_imports)] use std::collections::HashMap; +#[allow(dead_code, unused_imports)] use futures_util::{SinkExt, StreamExt}; +#[allow(dead_code, unused_imports)] use tokio::time::{timeout, Duration}; +#[allow(dead_code, unused_imports)] use tokio_tungstenite::connect_async; +#[allow(dead_code, unused_imports)] use tokio_tungstenite::tungstenite::protocol::Message; #[rstest(with_scope, case(true), case(false))] From c9a4923a6b900694d700b9b33f7e68efcf0ecc43 Mon Sep 17 00:00:00 2001 From: satlead Date: Fri, 28 Mar 2025 10:54:22 -0400 Subject: [PATCH 13/31] fix: formatter --- .../src/tests/contracts/thunder_device_info_pacts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/device/thunder_ripple_sdk/src/tests/contracts/thunder_device_info_pacts.rs b/device/thunder_ripple_sdk/src/tests/contracts/thunder_device_info_pacts.rs index c252dd5ac..b166cb403 100644 --- a/device/thunder_ripple_sdk/src/tests/contracts/thunder_device_info_pacts.rs +++ b/device/thunder_ripple_sdk/src/tests/contracts/thunder_device_info_pacts.rs @@ -15,8 +15,6 @@ // SPDX-License-Identifier: Apache-2.0 // #[allow(dead_code, unused_imports)] -use std::collections::HashMap; -#[allow(dead_code, unused_imports)] use crate::get_pact_with_params; #[allow(dead_code, unused_imports)] use crate::ripple_sdk::{ @@ -29,6 +27,8 @@ use crate::tests::contracts::contract_utils::*; use crate::{get_pact, send_thunder_call_message}; #[allow(dead_code, unused_imports)] use pact_consumer::mock_server::StartMockServerAsync; +#[allow(dead_code, unused_imports)] +use std::collections::HashMap; #[allow(dead_code, unused_imports)] use futures_util::{SinkExt, StreamExt}; From 604ca5934dd50e29e3a0dce298adcc00c085b630 Mon Sep 17 00:00:00 2001 From: satlead Date: Fri, 28 Mar 2025 11:53:30 -0400 Subject: [PATCH 14/31] Cleanup: Large enum unused variants --- core/main/src/service/data_governance.rs | 264 ------------------ .../sdk/src/api/device/device_info_request.rs | 2 - .../api/distributor/distributor_privacy.rs | 1 - .../src/processors/thunder_device_info.rs | 231 +-------------- 4 files changed, 2 insertions(+), 496 deletions(-) delete mode 100644 core/main/src/service/data_governance.rs diff --git a/core/main/src/service/data_governance.rs b/core/main/src/service/data_governance.rs deleted file mode 100644 index d8a4d70b0..000000000 --- a/core/main/src/service/data_governance.rs +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2023 Comcast Cable Communications Management, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// - -use ripple_sdk::{ - api::{ - distributor::distributor_privacy::{ - DataEventType, ExclusionPolicy, ExclusionPolicyData, PrivacyCloudRequest, - }, - firebolt::fb_discovery::DataTagInfo, - manifest::device_manifest::DataGovernancePolicy, - storage_property::StorageProperty, - }, - log::{debug, info}, - utils::error::RippleError, -}; -use std::collections::HashSet; -use std::sync::{Arc, RwLock}; - -use crate::{ - processor::storage::storage_manager::StorageManager, state::platform_state::PlatformState, -}; - -pub fn default_enforcement_value() -> bool { - false -} - -pub fn default_drop_on_all_tags() -> bool { - true -} - -pub struct DataGovernance {} - -#[derive(Clone)] -pub struct DataGovernanceState { - pub exclusions: Arc>>, -} - -impl Default for DataGovernanceState { - fn default() -> Self { - DataGovernanceState { - exclusions: Arc::new(RwLock::new(None)), - } - } -} - -impl std::fmt::Debug for DataGovernanceState { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("DataGovernanceState").finish() - } -} - -impl DataGovernance { - fn update_local_exclusion_policy(state: &DataGovernanceState, excl: ExclusionPolicy) { - let mut dg = state.exclusions.write().unwrap(); - *dg = Some(excl) - } - - fn get_local_exclusion_policy(state: &DataGovernanceState) -> Option { - let dg = state.exclusions.read().unwrap(); - (*dg).clone() - } - - pub async fn get_tags( - state: &PlatformState, - app_id: String, - data_type: DataEventType, - policy: &DataGovernancePolicy, - ) -> (HashSet, bool) { - let mut tags = HashSet::default(); - let mut all_settings_enforced = true; - let exclusions = DataGovernance::get_partner_exclusions(state) - .await - .unwrap_or_default(); - for tag in &policy.setting_tags { - let mut excluded = false; - let mut propagation_state = true; - let data = DataGovernance::get_exclusion_data(tag.setting.clone(), exclusions.clone()); - if let Some(d) = data { - let (excluded_tmp, propagation_state_tmp) = - DataGovernance::is_app_excluded_and_get_propagation_state( - &app_id, &data_type, &d, - ); - excluded = excluded_tmp; - propagation_state = propagation_state_tmp; - debug!( - "get_tags: app_id={:?} setting={:?} is_excluded={:?}", - app_id.clone(), - tag, - excluded - ); - } - - // do not get user setting if excluded - if excluded { - let tags_to_add: HashSet = tag - .tags - .iter() - .cloned() - .map(|name| DataTagInfo { - tag_name: name, - propagation_state, - }) - .collect(); - tags.extend(tags_to_add); - } else { - let val = StorageManager::get_bool(state, tag.setting.clone()) - .await - .unwrap_or(false); - if val == tag.enforcement_value { - let tags_to_add: HashSet = tag - .tags - .iter() - .cloned() - .map(|name| DataTagInfo { - tag_name: name, - propagation_state: true, - }) - .collect(); - tags.extend(tags_to_add); - } else { - all_settings_enforced = false; - } - } - } - (tags, all_settings_enforced) - } - - pub async fn resolve_tags( - platform_state: &PlatformState, - app_id: String, - data_type: DataEventType, - ) -> (HashSet, bool) { - let data_gov_cfg = platform_state - .get_device_manifest() - .configuration - .data_governance - .clone(); - let data_tags = match data_gov_cfg.get_policy(data_type.clone()) { - Some(policy) => { - let (t, all) = - DataGovernance::get_tags(platform_state, app_id, data_type, &policy).await; - if policy.drop_on_all_tags && all { - return (t, true); - } - t - } - None => { - info!("data_governance.policies not found"); - HashSet::default() - } - }; - (data_tags, false) - } - - pub async fn refresh_partner_exclusions(state: &PlatformState) -> bool { - if let Some(session) = state.session_state.get_account_session() { - if let Ok(response) = state - .get_client() - .send_extn_request(PrivacyCloudRequest::GetPartnerExclusions(session)) - .await - { - if let Some(excl) = response.payload.clone().extract::() { - DataGovernance::update_local_exclusion_policy( - &state.data_governance, - excl.clone(), - ); - let result = serde_json::to_string(&excl); - // result.unwrap_or(""); // XXX: when server return 404 or empty string - if let Ok(res) = result { - return StorageManager::set_string( - state, - StorageProperty::PartnerExclusions, - res, - None, - ) - .await - .is_ok(); - } - } - } - } - false - } - - pub async fn get_partner_exclusions( - state: &PlatformState, - ) -> Result { - let mut result = Err(RippleError::InvalidOutput); - if let Some(excl) = DataGovernance::get_local_exclusion_policy(&state.data_governance) { - return Ok(excl); - } - - let resp = StorageManager::get_string(state, StorageProperty::PartnerExclusions).await; - debug!("StorageProperty::PartnerExclusions resp={:?}", resp); - - if let Ok(res) = resp { - if !res.is_empty() { - let excl = serde_json::from_str(&res); - if let Ok(exc_policy) = excl { - let exclusion_policy: ExclusionPolicy = exc_policy; - DataGovernance::update_local_exclusion_policy( - &state.data_governance, - exclusion_policy.clone(), - ); - result = Ok(exclusion_policy) - } - } - } - result - } - - pub fn get_exclusion_data( - setting: StorageProperty, - exclusions: ExclusionPolicy, - ) -> Option { - match setting { - StorageProperty::AllowPersonalization => exclusions.personalization, - StorageProperty::AllowProductAnalytics => exclusions.product_analytics, - StorageProperty::AllowBusinessAnalytics => exclusions.business_analytics, - _ => None, - } - } - - fn is_app_excluded_and_get_propagation_state( - app_id: &String, - data_type: &DataEventType, - excl: &ExclusionPolicyData, - ) -> (bool, bool) { - let mut app_found: bool = false; - let mut event_found: bool = false; - let mut propagation_state: bool = true; - - for evt in &excl.data_events { - if *evt == *data_type { - event_found = true; - propagation_state = excl.derivative_propagation; - break; - } - } - if event_found { - for app in &excl.entity_reference { - if app.as_str() == app_id { - app_found = true; - break; - } - } - } - (app_found, propagation_state) - } -} diff --git a/core/sdk/src/api/device/device_info_request.rs b/core/sdk/src/api/device/device_info_request.rs index 04edeaf2d..d6af0e36e 100644 --- a/core/sdk/src/api/device/device_info_request.rs +++ b/core/sdk/src/api/device/device_info_request.rs @@ -51,7 +51,6 @@ pub enum DeviceInfoRequest { SetVoiceGuidanceEnabled(bool), VoiceGuidanceSpeed, SetVoiceGuidanceSpeed(f32), - FullCapabilities(Vec), PowerState, SerialNumber, PlatformBuildInfo, @@ -110,7 +109,6 @@ pub enum DeviceResponse { HdcpSupportResponse(HashMap), HdcpStatusResponse(HDCPStatus), FirmwareInfo(FirmwareInfo), - FullCapabilities(DeviceCapabilities), InternetConnectionStatus(InternetConnectionStatus), PowerState(PowerState), TimeZone(TimeZone), diff --git a/core/sdk/src/api/distributor/distributor_privacy.rs b/core/sdk/src/api/distributor/distributor_privacy.rs index 7afa83036..e7b9d94be 100644 --- a/core/sdk/src/api/distributor/distributor_privacy.rs +++ b/core/sdk/src/api/distributor/distributor_privacy.rs @@ -361,7 +361,6 @@ pub enum PrivacyResponse { None, Bool(bool), Settings(PrivacySettings), - Exclusions(ExclusionPolicy), Grants(UserGrants), } diff --git a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs index 2450ff9f0..c43d9ae76 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs @@ -28,7 +28,7 @@ use crate::{ thunder_plugin::ThunderPlugin, }, ripple_sdk::{ - api::device::{device_info_request::DeviceCapabilities, device_request::AudioProfile}, + api::device::device_request::AudioProfile, extn::client::extn_client::ExtnClient, tokio::sync::mpsc, }, @@ -62,23 +62,15 @@ use crate::{ use regex::{Match, Regex}; use ripple_sdk::{ api::{ - config::Config, context::RippleContextUpdateRequest, device::{ device_info_request::{FirmwareInfo, PlatformBuildInfo}, device_request::{InternetConnectionStatus, PowerState}, }, - device::{ - device_info_request::{ - DEVICE_INFO_AUTHORIZED, DEVICE_MAKE_MODEL_AUTHORIZED, DEVICE_SKU_AUTHORIZED, - }, - device_request::TimeZone, - }, - manifest::device_manifest::DefaultValues, + device::device_request::TimeZone, }, log::trace, serde_json::{Map, Value}, - tokio::join, }; use serde::{Deserialize, Deserializer, Serialize}; use serde_json::json; @@ -139,9 +131,7 @@ pub struct CachedDeviceInfo { mac_address: Option, serial_number: Option, model: Option, - make: Option, hdcp_support: Option>, - hdr_profile: Option>, version: Option, } @@ -176,15 +166,6 @@ impl CachedState { let _ = hdcp.hdcp_support.insert(value); } - fn get_hdr(&self) -> Option> { - self.cached.read().unwrap().hdr_profile.clone() - } - - fn update_hdr_support(&self, value: HashMap) { - let mut hdr = self.cached.write().unwrap(); - let _ = hdr.hdr_profile.insert(value); - } - fn get_mac_address(&self) -> Option { self.cached.read().unwrap().mac_address.clone() } @@ -212,15 +193,6 @@ impl CachedState { let _ = cached.model.insert(model); } - fn get_make(&self) -> Option { - self.cached.read().unwrap().make.clone() - } - - fn update_make(&self, make: String) { - let mut cached = self.cached.write().unwrap(); - let _ = cached.make.insert(make); - } - fn get_version(&self) -> Option { self.cached.read().unwrap().version.clone() } @@ -487,29 +459,6 @@ impl ThunderDeviceInfoRequestProcessor { } None } - async fn get_make(state: &CachedState) -> String { - match state.get_make() { - Some(value) => value, - None => { - let resp = state - .get_thunder_client() - .call(DeviceCallRequest { - method: ThunderPlugin::System.method("getDeviceInfo"), - params: None, - }) - .await; - info!("{}", resp.message); - let r = resp.message.get("make"); - if r.is_none() { - "".into() - } else { - let make = r.unwrap().as_str().unwrap().trim_matches('"'); - state.update_make(make.to_string()); - make.to_string() - } - } - } - } async fn internet_connection_status(state: CachedState, req: ExtnMessage) -> bool { if let Some(response) = Self::get_internet_connection_status(&state).await { @@ -671,16 +620,6 @@ impl ThunderDeviceInfoRequestProcessor { .is_ok() } - async fn get_cached_hdr(state: &CachedState) -> HashMap { - if let Some(v) = state.get_hdr() { - v - } else { - let v = Self::get_hdr(state.clone().state).await; - state.update_hdr_support(v.clone()); - v - } - } - pub async fn get_hdr(state: ThunderState) -> HashMap { let response = state .get_thunder_client() @@ -718,79 +657,6 @@ impl ThunderDeviceInfoRequestProcessor { hm } - async fn get_screen_resolution(state: &CachedState) -> Vec { - let response = state - .get_thunder_client() - .call(DeviceCallRequest { - method: ThunderPlugin::DisplaySettings.method("getCurrentResolution"), - params: None, - }) - .await; - info!("{}", response.message); - - if !check_thunder_response_success(&response) { - error!("{}", response.message); - return Vec::new(); - } - info!("{}", response.message); - let resol = response.message["resolution"].as_str().unwrap_or_default(); - get_dimension_from_resolution(resol) - } - - async fn get_current_resolution(state: &CachedState) -> Result, ()> { - let response = state - .get_thunder_client() - .call(DeviceCallRequest { - method: ThunderPlugin::DisplaySettings.method("getCurrentResolution"), - params: None, - }) - .await; - if !check_thunder_response_success(&response) { - error!("{}", response.message); - return Err(()); - } - info!("{}", response.message); - let resol = response.message["resolution"].as_str().unwrap_or_default(); - Ok(get_dimension_from_resolution(resol)) - } - - async fn get_default_resolution(state: &CachedState) -> Result, ()> { - let response = state - .get_thunder_client() - .call(DeviceCallRequest { - method: ThunderPlugin::DisplaySettings.method("getDefaultResolution"), - params: None, - }) - .await; - if !check_thunder_response_success(&response) { - error!("{}", response.message); - return Err(()); - } - info!("{}", response.message); - if let Some(resol) = response.message.get("defaultResolution") { - if let Some(r) = resol.as_str() { - return Ok(get_dimension_from_resolution(r)); - } - } - Err(()) - } - - async fn get_video_resolution(state: &CachedState) -> Vec { - if let Ok(resolution) = Self::get_current_resolution(state).await { - return resolution; - } - if let Ok(resolution) = Self::get_default_resolution(state).await { - return resolution; - } - if let Ok(response) = state.get_client().request(Config::DefaultValues).await { - if let Some(ExtnResponse::Value(value)) = response.payload.extract() { - if let Ok(default_values) = serde_json::from_value::(value) { - return default_values.video_dimensions; - } - } - } - vec![] - } async fn on_internet_connected(state: CachedState, req: ExtnMessage, timeout: u64) -> bool { if tokio::time::timeout( @@ -1138,95 +1004,6 @@ impl ThunderDeviceInfoRequestProcessor { .is_ok() } - async fn get_device_capabilities(state: CachedState, keys: &[&str], msg: ExtnMessage) -> bool { - let device_info_authorized = keys.contains(&DEVICE_INFO_AUTHORIZED); - let ( - video_dimensions, - native_dimensions, - firmware_info_result, - hdr_info, - hdcp_result, - audio_result, - model_result, - make_result, - ) = join!( - async { - if device_info_authorized { - Some(Self::get_video_resolution(&state).await) - } else { - None - } - }, - async { - if device_info_authorized { - Some(Self::get_screen_resolution(&state).await) - } else { - None - } - }, - async { - if device_info_authorized { - Some(Self::get_os_info(&state).await.version) - } else { - None - } - }, - async { - if device_info_authorized { - Some(Self::get_cached_hdr(&state).await) - } else { - None - } - }, - async { - if device_info_authorized { - Some(Self::get_hdcp_status(&state).await) - } else { - None - } - }, - async { - if device_info_authorized { - Some(Self::get_audio(&state).await) - } else { - None - } - }, - async { - if keys.contains(&DEVICE_SKU_AUTHORIZED) { - Some(Self::get_model(&state).await) - } else { - None - } - }, - async { - if keys.contains(&DEVICE_MAKE_MODEL_AUTHORIZED) { - Some(Self::get_make(&state).await) - } else { - None - } - } - ); - - let device_capabilities = DeviceCapabilities { - audio: audio_result, - firmware_info: firmware_info_result, - hdcp: hdcp_result, - hdr: hdr_info, - make: make_result, - model: model_result, - video_resolution: video_dimensions, - screen_resolution: native_dimensions, - }; - if let ExtnPayload::Response(r) = - DeviceResponse::FullCapabilities(device_capabilities).get_extn_payload() - { - Self::respond(state.get_client(), msg, r).await.is_ok() - } else { - Self::handle_error(state.get_client(), msg, RippleError::ProcessorError).await - } - } - async fn platform_build_info(state: CachedState, msg: ExtnMessage) -> bool { let resp = state .get_thunder_client() @@ -1393,10 +1170,6 @@ impl ExtnRequestProcessor for ThunderDeviceInfoRequestProcessor { DeviceInfoRequest::InternetConnectionStatus => { Self::internet_connection_status(state.clone(), msg).await } - DeviceInfoRequest::FullCapabilities(keys) => { - let keys_as_str: Vec<&str> = keys.iter().map(String::as_str).collect(); - Self::get_device_capabilities(state.clone(), &keys_as_str, msg).await - } DeviceInfoRequest::PowerState => Self::power_state(state.clone(), msg).await, DeviceInfoRequest::PlatformBuildInfo => { Self::platform_build_info(state.clone(), msg).await From c08b632088ab78a213b6ec5acf2627405c7fdc46 Mon Sep 17 00:00:00 2001 From: satlead Date: Mon, 31 Mar 2025 06:22:09 -0400 Subject: [PATCH 15/31] fix: cleanup internet connection --- .../sdk/src/api/device/device_info_request.rs | 3 +- core/sdk/src/api/device/device_request.rs | 15 ++- core/sdk/src/extn/client/extn_processor.rs | 14 +-- .../src/processors/thunder_device_info.rs | 97 +------------------ 4 files changed, 18 insertions(+), 111 deletions(-) diff --git a/core/sdk/src/api/device/device_info_request.rs b/core/sdk/src/api/device/device_info_request.rs index d6af0e36e..135bf448c 100644 --- a/core/sdk/src/api/device/device_info_request.rs +++ b/core/sdk/src/api/device/device_info_request.rs @@ -28,7 +28,7 @@ use std::collections::HashMap; use super::device_request::{ AudioProfile, DeviceRequest, HDCPStatus, HdcpProfile, HdrProfile, InternetConnectionStatus, - OnInternetConnectedRequest, PowerState, TimeZone, + PowerState, TimeZone, }; pub const DEVICE_INFO_AUTHORIZED: &str = "device_info_authorized"; @@ -45,7 +45,6 @@ pub enum DeviceInfoRequest { HdcpStatus, Audio, AvailableMemory, - OnInternetConnected(OnInternetConnectedRequest), InternetConnectionStatus, VoiceGuidanceEnabled, SetVoiceGuidanceEnabled(bool), diff --git a/core/sdk/src/api/device/device_request.rs b/core/sdk/src/api/device/device_request.rs index 62aa00b0d..066d25e01 100644 --- a/core/sdk/src/api/device/device_request.rs +++ b/core/sdk/src/api/device/device_request.rs @@ -122,6 +122,16 @@ pub enum InternetConnectionStatus { FullyConnected, } +impl From for InternetConnectionStatus { + fn from(value: bool) -> Self { + if value { + InternetConnectionStatus::FullyConnected + } else { + InternetConnectionStatus::NoInternet + } + } +} + #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(rename_all = "lowercase")] pub enum NetworkState { @@ -208,11 +218,6 @@ impl Resolution { } } -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct OnInternetConnectedRequest { - pub timeout: u64, -} - #[derive(Debug, Serialize, Deserialize, Default, Clone)] pub struct TimezoneProperty { // Original Regex in the Firebolt Timezone openrpc spec seems to be allowing diff --git a/core/sdk/src/extn/client/extn_processor.rs b/core/sdk/src/extn/client/extn_processor.rs index 5005c81d8..4b6194fa6 100644 --- a/core/sdk/src/extn/client/extn_processor.rs +++ b/core/sdk/src/extn/client/extn_processor.rs @@ -192,12 +192,9 @@ pub trait ExtnRequestProcessor: ExtnStreamProcessor + Send + Sync + 'static { false } - fn has_internet(&self) -> bool { - self.get_client().has_internet() - } - fn check_prerequisties(prereq: &Prerequisites, client: &ExtnClient) -> bool { - match (prereq.need_internet, client.has_internet()) { + fn check_prerequisties(prereq: &Prerequisites, _client: &ExtnClient) -> bool { + match (prereq.need_internet, false) { (true, true) | (false, _) => true, (true, false) => false, } @@ -589,13 +586,6 @@ pub mod tests { ); } - #[tokio::test] - async fn test_get_state() { - let mock_event_processor = MockEventProcessor::new(); - let state = mock_event_processor.get_state(); - assert!(!state.client.has_internet()); - } - #[tokio::test] async fn test_receiver() { let mut mock_event_processor = MockEventProcessor::new(); diff --git a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs index c43d9ae76..dd8bdf13f 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs @@ -18,7 +18,6 @@ use std::{ collections::HashMap, sync::{Arc, RwLock}, - time::Duration, }; use crate::{ @@ -54,7 +53,6 @@ use crate::{ }, log::{error, info}, serde_json::{self}, - tokio, utils::error::RippleError, }, utils::get_audio_profile_from_value, @@ -65,11 +63,10 @@ use ripple_sdk::{ context::RippleContextUpdateRequest, device::{ device_info_request::{FirmwareInfo, PlatformBuildInfo}, - device_request::{InternetConnectionStatus, PowerState}, + device_request::PowerState, }, device::device_request::TimeZone, }, - log::trace, serde_json::{Map, Value}, }; use serde::{Deserialize, Deserializer, Serialize}; @@ -219,7 +216,9 @@ impl ThunderNetworkService { if response.is_none() { return false; } - response.unwrap().as_bool().unwrap_or(false) + let v = response.unwrap().as_bool().unwrap_or(false); + let _ = state.get_client().request_transient(RippleContextUpdateRequest::InternetStatus(v.into())); + v } } #[derive(Debug, Serialize, Deserialize)] @@ -437,60 +436,6 @@ impl ThunderDeviceInfoRequestProcessor { .is_ok() } - async fn get_internet_connection_status( - state: &CachedState, - ) -> Option { - let dev_response = state - .get_thunder_client() - .call(DeviceCallRequest { - method: ThunderPlugin::Network.method("getInternetConnectionState"), - params: None, - }) - .await; - let resp = dev_response.message.get("state")?; - if let Ok(internet_status) = serde_json::from_value::(resp.clone()) { - return match internet_status { - 0 => Some(InternetConnectionStatus::NoInternet), - 1 => Some(InternetConnectionStatus::LimitedInternet), - 2 => Some(InternetConnectionStatus::CaptivePortal), - 3 => Some(InternetConnectionStatus::FullyConnected), - _ => None, - }; - } - None - } - - async fn internet_connection_status(state: CachedState, req: ExtnMessage) -> bool { - if let Some(response) = Self::get_internet_connection_status(&state).await { - trace!( - "Successfully got internetConnection status from thunder: {:?}", - response - ); - let event = RippleContextUpdateRequest::InternetStatus(response.clone()); - let _send_event_result = state.get_client().request_transient(event); - trace!( - "Result of sending ripple context event: {:?}", - _send_event_result - ); - Self::respond( - state.get_client(), - req, - if let ExtnPayload::Response(resp) = - DeviceResponse::InternetConnectionStatus(response).get_extn_payload() - { - resp - } else { - ExtnResponse::Error(RippleError::ProcessorError) - }, - ) - .await - .is_ok() - } else { - error!("Unable to get internet connection status from thunder"); - Self::handle_error(state.get_client(), req, RippleError::ProcessorError).await - } - } - async fn get_audio(state: &CachedState) -> HashMap { let response = state .get_thunder_client() @@ -657,35 +602,6 @@ impl ThunderDeviceInfoRequestProcessor { hm } - - async fn on_internet_connected(state: CachedState, req: ExtnMessage, timeout: u64) -> bool { - if tokio::time::timeout( - Duration::from_millis(timeout), - Self::respond(state.get_client(), req.clone(), { - let value = ThunderNetworkService::has_internet(&state.state).await; - - if let ExtnPayload::Response(r) = - DeviceResponse::InternetConnectionStatus(match value { - true => InternetConnectionStatus::FullyConnected, - false => InternetConnectionStatus::NoInternet, - }) - .get_extn_payload() - { - r - } else { - ExtnResponse::Error(RippleError::ProcessorError) - } - }), - ) - .await - .is_err() - { - Self::handle_error(state.get_client(), req, RippleError::ProcessorError).await - } else { - true - } - } - pub async fn get_firmware_version(state: &ThunderState) -> FireboltSemanticVersion { let version: FireboltSemanticVersion; let resp = state @@ -1152,9 +1068,6 @@ impl ExtnRequestProcessor for ThunderDeviceInfoRequestProcessor { DeviceInfoRequest::HdcpStatus => Self::hdcp_status(state.clone(), msg).await, DeviceInfoRequest::FirmwareInfo => Self::os_info(state.clone(), msg).await, DeviceInfoRequest::AvailableMemory => Self::available_memory(state.clone(), msg).await, - DeviceInfoRequest::OnInternetConnected(time_out) => { - Self::on_internet_connected(state.clone(), msg, time_out.timeout).await - } DeviceInfoRequest::SetVoiceGuidanceEnabled(v) => { Self::voice_guidance_set_enabled(state.clone(), msg, v).await } @@ -1168,7 +1081,7 @@ impl ExtnRequestProcessor for ThunderDeviceInfoRequestProcessor { Self::voice_guidance_speed(state.clone(), msg).await } DeviceInfoRequest::InternetConnectionStatus => { - Self::internet_connection_status(state.clone(), msg).await + ThunderNetworkService::has_internet(&state.state).await } DeviceInfoRequest::PowerState => Self::power_state(state.clone(), msg).await, DeviceInfoRequest::PlatformBuildInfo => { From 193fb0f242cf89056d6f33c4c35032f8ab101638 Mon Sep 17 00:00:00 2001 From: satlead Date: Mon, 31 Mar 2025 08:20:56 -0400 Subject: [PATCH 16/31] fix: unused imports --- .../sdk/src/api/device/device_info_request.rs | 10 +- core/sdk/src/extn/client/extn_processor.rs | 1 - .../src/processors/thunder_device_info.rs | 151 ++++++++---------- 3 files changed, 75 insertions(+), 87 deletions(-) diff --git a/core/sdk/src/api/device/device_info_request.rs b/core/sdk/src/api/device/device_info_request.rs index 135bf448c..796b5ef78 100644 --- a/core/sdk/src/api/device/device_info_request.rs +++ b/core/sdk/src/api/device/device_info_request.rs @@ -51,7 +51,6 @@ pub enum DeviceInfoRequest { VoiceGuidanceSpeed, SetVoiceGuidanceSpeed(f32), PowerState, - SerialNumber, PlatformBuildInfo, } @@ -101,6 +100,15 @@ pub struct FirmwareInfo { pub version: FireboltSemanticVersion, } +impl From for FirmwareInfo { + fn from(version: FireboltSemanticVersion) -> Self { + FirmwareInfo { + name: "rdk".into(), + version, + } + } +} + #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] pub enum DeviceResponse { CustomError(String), diff --git a/core/sdk/src/extn/client/extn_processor.rs b/core/sdk/src/extn/client/extn_processor.rs index 4b6194fa6..37dd872a5 100644 --- a/core/sdk/src/extn/client/extn_processor.rs +++ b/core/sdk/src/extn/client/extn_processor.rs @@ -192,7 +192,6 @@ pub trait ExtnRequestProcessor: ExtnStreamProcessor + Send + Sync + 'static { false } - fn check_prerequisties(prereq: &Prerequisites, _client: &ExtnClient) -> bool { match (prereq.need_internet, false) { (true, true) | (false, _) => true, diff --git a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs index dd8bdf13f..f008f5e08 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs @@ -27,8 +27,7 @@ use crate::{ thunder_plugin::ThunderPlugin, }, ripple_sdk::{ - api::device::device_request::AudioProfile, - extn::client::extn_client::ExtnClient, + api::device::device_request::AudioProfile, extn::client::extn_client::ExtnClient, tokio::sync::mpsc, }, thunder_state::ThunderState, @@ -61,11 +60,11 @@ use regex::{Match, Regex}; use ripple_sdk::{ api::{ context::RippleContextUpdateRequest, + device::device_request::TimeZone, device::{ device_info_request::{FirmwareInfo, PlatformBuildInfo}, device_request::PowerState, }, - device::device_request::TimeZone, }, serde_json::{Map, Value}, }; @@ -126,7 +125,6 @@ pub struct SystemVersion { #[derive(Debug, Clone, Default)] pub struct CachedDeviceInfo { mac_address: Option, - serial_number: Option, model: Option, hdcp_support: Option>, version: Option, @@ -167,15 +165,6 @@ impl CachedState { self.cached.read().unwrap().mac_address.clone() } - fn get_serial_number(&self) -> Option { - self.cached.read().unwrap().serial_number.clone() - } - - fn update_serial_number(&self, serial_number: String) { - let mut cached = self.cached.write().unwrap(); - let _ = cached.serial_number.insert(serial_number); - } - fn update_mac_address(&self, mac: String) { let mut cached = self.cached.write().unwrap(); let _ = cached.mac_address.insert(mac); @@ -217,7 +206,9 @@ impl ThunderNetworkService { return false; } let v = response.unwrap().as_bool().unwrap_or(false); - let _ = state.get_client().request_transient(RippleContextUpdateRequest::InternetStatus(v.into())); + let _ = state + .get_client() + .request_transient(RippleContextUpdateRequest::InternetStatus(v.into())); v } } @@ -339,25 +330,33 @@ impl ThunderDeviceInfoRequestProcessor { } } + pub async fn get_mac(state: &ThunderState) -> String { + let resp = state + .get_thunder_client() + .call(DeviceCallRequest { + method: ThunderPlugin::System.method("getDeviceInfo"), + params: Some(DeviceChannelParams::Json(String::from( + "{\"params\": [\"estb_mac\"]}", + ))), + }) + .await; + info!("{}", resp.message); + let resp = resp.message.get("estb_mac"); + if resp.is_none() { + return "".to_string(); + } + resp.unwrap() + .as_str() + .unwrap() + .trim_matches('"') + .to_string() + } + async fn get_mac_address(state: &CachedState) -> String { match state.get_mac_address() { Some(value) => value, None => { - let resp = state - .get_thunder_client() - .call(DeviceCallRequest { - method: ThunderPlugin::System.method("getDeviceInfo"), - params: Some(DeviceChannelParams::Json(String::from( - "{\"params\": [\"estb_mac\"]}", - ))), - }) - .await; - info!("{}", resp.message); - let resp = resp.message.get("estb_mac"); - if resp.is_none() { - return "".to_string(); - } - let mac = resp.unwrap().as_str().unwrap().trim_matches('"'); + let mac = Self::get_mac(&state.state).await; state.update_mac_address(mac.to_string()); mac.to_string() } @@ -371,62 +370,48 @@ impl ThunderDeviceInfoRequestProcessor { .is_ok() } - async fn get_serial_number(state: &CachedState) -> String { - match state.get_serial_number() { - Some(value) => value, - None => { - let resp = state - .get_thunder_client() - .call(DeviceCallRequest { - method: ThunderPlugin::System.method("getSerialNumber"), - params: None, - }) - .await; - info!("{}", resp.message); - - resp.message["serialNumber"].as_str().map_or_else( - || "".to_string(), - |serial_number| { - let serial_number = serial_number.to_string(); - state.update_serial_number(serial_number.clone()); - serial_number - }, - ) - } - } - } + pub async fn get_serial_number(state: &ThunderState) -> String { + let resp = state + .get_thunder_client() + .call(DeviceCallRequest { + method: ThunderPlugin::System.method("getSerialNumber"), + params: None, + }) + .await; + info!("{}", resp.message); - async fn serial_number(state: CachedState, req: ExtnMessage) -> bool { - let response: String = Self::get_serial_number(&state).await; + resp.message["serialNumber"] + .as_str() + .map_or_else(|| "".to_string(), |serial_number| serial_number.to_string()) + } - Self::respond(state.get_client(), req, ExtnResponse::String(response)) - .await - .is_ok() + pub async fn model_info(state: &ThunderState) -> String { + let resp = state + .get_thunder_client() + .call(DeviceCallRequest { + method: ThunderPlugin::System.method("getSystemVersions"), + params: None, + }) + .await; + info!("{}", resp.message); + let resp = resp.message.get("stbVersion"); + if resp.is_none() { + return "NA".to_owned(); + } + let resp = resp.unwrap().as_str().unwrap().trim_matches('"'); + let split_string: Vec<&str> = resp.split('_').collect(); + String::from(split_string[0]) } async fn get_model(state: &CachedState) -> String { - match state.get_model() { - Some(value) => value, - None => { - let resp = state - .get_thunder_client() - .call(DeviceCallRequest { - method: ThunderPlugin::System.method("getSystemVersions"), - params: None, - }) - .await; - info!("{}", resp.message); - let resp = resp.message.get("stbVersion"); - if resp.is_none() { - return "NA".to_owned(); - } - let resp = resp.unwrap().as_str().unwrap().trim_matches('"'); - let split_string: Vec<&str> = resp.split('_').collect(); - let model = String::from(split_string[0]); - state.update_model(model.clone()); - model - } - } + let model = if let Some(m) = state.get_model() { + m + } else { + Self::model_info(&state.state).await + }; + + state.update_model(model.clone()); + model } async fn model(state: CachedState, req: ExtnMessage) -> bool { @@ -649,10 +634,7 @@ impl ThunderDeviceInfoRequestProcessor { state.update_version(version.clone()); } } - FirmwareInfo { - name: "rdk".into(), - version, - } + version.into() } async fn os_info(state: CachedState, req: ExtnMessage) -> bool { @@ -1061,7 +1043,6 @@ impl ExtnRequestProcessor for ThunderDeviceInfoRequestProcessor { ) -> bool { match extracted_message { DeviceInfoRequest::MacAddress => Self::mac_address(state.clone(), msg).await, - DeviceInfoRequest::SerialNumber => Self::serial_number(state.clone(), msg).await, DeviceInfoRequest::Model => Self::model(state.clone(), msg).await, DeviceInfoRequest::Audio => Self::audio(state.clone(), msg).await, DeviceInfoRequest::HdcpSupport => Self::hdcp_support(state.clone(), msg).await, From 3faccae269a09d6bf4a085518e84c90212efb151 Mon Sep 17 00:00:00 2001 From: satlead Date: Mon, 31 Mar 2025 10:48:39 -0400 Subject: [PATCH 17/31] feat: Cleanup Device Events --- core/sdk/src/api/device/device_events.rs | 17 -- core/sdk/src/api/device/device_request.rs | 31 +-- core/sdk/src/api/session.rs | 3 - core/sdk/src/extn/client/extn_client.rs | 21 -- device/thunder/src/thunder_ffi.rs | 1 - .../src/events/thunder_event_processor.rs | 32 +-- .../events/thunder_event_handlers.rs | 211 +----------------- .../src/processors/thunder_device_info.rs | 38 ---- .../src/processors/thunder_events.rs | 21 +- examples/manifest/extn-manifest-example.json | 4 +- .../manifest/extn-manifest-tm-example.json | 5 +- .../manifest/jsonrpsee-manifest-example.json | 6 +- .../manifest/mock/mock-extn-manifest.json | 4 +- .../IpStb/firebolt-extn-manifest.json | 4 +- 14 files changed, 12 insertions(+), 386 deletions(-) diff --git a/core/sdk/src/api/device/device_events.rs b/core/sdk/src/api/device/device_events.rs index 1498d83da..5b385f344 100644 --- a/core/sdk/src/api/device/device_events.rs +++ b/core/sdk/src/api/device/device_events.rs @@ -29,13 +29,10 @@ pub trait DeviceEventProvider { } pub const HDCP_CHANGED_EVENT: &str = "device.onHdcpChanged"; -pub const INTERNET_CHANGED_EVENT: &str = "device.onInternetStatusChange"; pub const AUDIO_CHANGED_EVENT: &str = "device.onAudioChanged"; pub const VOICE_GUIDANCE_SETTINGS_CHANGED: &str = "accessibility.onVoiceGuidanceSettingsChanged"; pub const VOICE_GUIDANCE_ENABLED_CHANGED: &str = "voiceguidance.onEnabledChanged"; pub const VOICE_GUIDANCE_SPEED_CHANGED: &str = "voiceguidance.onSpeedChanged"; -pub const POWER_STATE_CHANGED: &str = "device.onPowerStateChanged"; -pub const TIME_ZONE_CHANGED: &str = "localization.onTimeZoneChanged"; // Is this from the device to thunder event handler??? #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] @@ -43,9 +40,6 @@ pub enum DeviceEvent { InputChanged, VoiceGuidanceEnabledChanged, AudioChanged, - SystemPowerStateChanged, - InternetConnectionStatusChanged, - TimeZoneChanged, } impl FromStr for DeviceEvent { @@ -56,9 +50,6 @@ impl FromStr for DeviceEvent { "device.onHdcpChanged" => Ok(Self::InputChanged), "voiceguidance.onEnabledChanged" => Ok(Self::VoiceGuidanceEnabledChanged), "device.onAudioChanged" => Ok(Self::AudioChanged), - "device.onPowerStateChanged" => Ok(Self::SystemPowerStateChanged), - "device.onInternetStatusChange" => Ok(Self::InternetConnectionStatusChanged), - "localization.onTimeZoneChanged" => Ok(Self::TimeZoneChanged), _ => Err(()), } } @@ -105,13 +96,6 @@ impl ExtnPayloadProvider for DeviceEventRequest { RippleContract::DeviceEvents(EventAdjective::VoiceGuidance) } DeviceEvent::AudioChanged => RippleContract::DeviceEvents(EventAdjective::Audio), - DeviceEvent::SystemPowerStateChanged => { - RippleContract::DeviceEvents(EventAdjective::SystemPowerState) - } - DeviceEvent::InternetConnectionStatusChanged => { - RippleContract::DeviceEvents(EventAdjective::Internet) - } - DeviceEvent::TimeZoneChanged => RippleContract::DeviceEvents(EventAdjective::TimeZone), } } @@ -128,7 +112,6 @@ mod tests { #[rstest(input, expected, case("device.onHdcpChanged", Ok(DeviceEvent::InputChanged)), - case("localization.onTimeZoneChanged", Ok(DeviceEvent::TimeZoneChanged)), case("invalid_event", Err(())), )] fn test_from_str(input: &str, expected: Result) { diff --git a/core/sdk/src/api/device/device_request.rs b/core/sdk/src/api/device/device_request.rs index 066d25e01..14eae3528 100644 --- a/core/sdk/src/api/device/device_request.rs +++ b/core/sdk/src/api/device/device_request.rs @@ -16,7 +16,7 @@ // use crate::{ - api::{firebolt::fb_openrpc::FireboltSemanticVersion, session::EventAdjective}, + api::firebolt::fb_openrpc::FireboltSemanticVersion, extn::extn_client_message::{ExtnEvent, ExtnPayload, ExtnPayloadProvider}, framework::ripple_contract::RippleContract, }; @@ -273,24 +273,6 @@ pub struct TimeZone { pub offset: i64, } -impl ExtnPayloadProvider for TimeZone { - fn get_extn_payload(&self) -> ExtnPayload { - ExtnPayload::Event(ExtnEvent::TimeZone(self.clone())) - } - - fn get_from_payload(payload: ExtnPayload) -> Option { - if let ExtnPayload::Event(ExtnEvent::TimeZone(r)) = payload { - return Some(r); - } - - None - } - - fn contract() -> RippleContract { - RippleContract::DeviceEvents(EventAdjective::TimeZone) - } -} - #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct VoiceGuidanceState { @@ -397,17 +379,6 @@ mod tests { // assert!(serde_json::from_str::(tz).is_ok()); // } - #[test] - fn test_extn_payload_provider_for_time_zone() { - let time_zone = TimeZone { - time_zone: String::from("America/Los_Angeles"), - offset: -28800, - }; - - let contract_type: RippleContract = RippleContract::DeviceEvents(EventAdjective::TimeZone); - test_extn_payload_provider(time_zone, contract_type); - } - #[test] fn test_extn_payload_provider_for_voice_guidance_state() { let voice_guidance_state = VoiceGuidanceState { state: true }; diff --git a/core/sdk/src/api/session.rs b/core/sdk/src/api/session.rs index 833a9c736..1eb6f2bf0 100644 --- a/core/sdk/src/api/session.rs +++ b/core/sdk/src/api/session.rs @@ -269,10 +269,7 @@ impl ContractAdjective for SessionAdjective { pub enum EventAdjective { Input, VoiceGuidance, - Internet, Audio, - SystemPowerState, - TimeZone, } impl ContractAdjective for EventAdjective { diff --git a/core/sdk/src/extn/client/extn_client.rs b/core/sdk/src/extn/client/extn_client.rs index 04a7b649e..f514d39f2 100644 --- a/core/sdk/src/extn/client/extn_client.rs +++ b/core/sdk/src/extn/client/extn_client.rs @@ -2518,27 +2518,6 @@ pub mod tests { assert_eq!(activation_status_after_reset, None); } - #[rstest( - connectivity, - expected_result, - case(InternetConnectionStatus::FullyConnected, true), - case(InternetConnectionStatus::LimitedInternet, true), - case(InternetConnectionStatus::NoInternet, false), - case(InternetConnectionStatus::CaptivePortal, false) - )] - #[tokio::test] - async fn test_has_internet(connectivity: InternetConnectionStatus, expected_result: bool) { - let extn_client = ExtnClient::mock(); - extn_client - .ripple_context - .write() - .unwrap() - .internet_connectivity = Some(connectivity); - - let has_internet = extn_client.has_internet(); - assert_eq!(has_internet, expected_result); - } - #[tokio::test] async fn test_get_timezone() { let extn_client = ExtnClient::mock(); diff --git a/device/thunder/src/thunder_ffi.rs b/device/thunder/src/thunder_ffi.rs index b5ee4a276..bc294e362 100644 --- a/device/thunder/src/thunder_ffi.rs +++ b/device/thunder/src/thunder_ffi.rs @@ -49,7 +49,6 @@ fn init_library() -> CExtnMetadata { RippleContract::DeviceEvents(EventAdjective::Input), RippleContract::DeviceEvents(EventAdjective::VoiceGuidance), RippleContract::DeviceEvents(EventAdjective::Audio), - RippleContract::DeviceEvents(EventAdjective::SystemPowerState), RippleContract::Storage(StorageAdjective::Local), RippleContract::RemoteAccessory, RippleContract::Wifi, diff --git a/device/thunder_ripple_sdk/src/events/thunder_event_processor.rs b/device/thunder_ripple_sdk/src/events/thunder_event_processor.rs index 701c58de1..ffc7b567b 100644 --- a/device/thunder_ripple_sdk/src/events/thunder_event_processor.rs +++ b/device/thunder_ripple_sdk/src/events/thunder_event_processor.rs @@ -28,8 +28,8 @@ use ripple_sdk::{ device::{ device_events::{DeviceEvent, DeviceEventCallback}, device_request::{ - AudioProfile, InternetConnectionStatus, NetworkResponse, PowerState, - SystemPowerState, VoiceGuidanceState, + AudioProfile, InternetConnectionStatus, NetworkResponse, SystemPowerState, + VoiceGuidanceState, }, }, }, @@ -90,22 +90,6 @@ impl ThunderEventMessage { return Some(ThunderEventMessage::ActiveInput(v)); } } - DeviceEvent::SystemPowerStateChanged => { - if let Some(v) = value["powerState"].as_str() { - if let Ok(power_state) = PowerState::from_str(v) { - if let Some(v) = value["currentPowerState"].as_str() { - if let Ok(current_power_state) = PowerState::from_str(v) { - return Some(ThunderEventMessage::PowerState( - SystemPowerState { - power_state, - current_power_state, - }, - )); - } - } - } - } - } DeviceEvent::VoiceGuidanceEnabledChanged => { if let Ok(v) = serde_json::from_value(value.clone()) { return Some(ThunderEventMessage::VoiceGuidance(v)); @@ -116,18 +100,6 @@ impl ThunderEventMessage { value.clone(), ))) } - DeviceEvent::InternetConnectionStatusChanged => { - if let Some(status) = value.get("status") { - if let Ok(internet_status) = serde_json::from_value(status.clone()) { - return Some(ThunderEventMessage::Internet(internet_status)); - } - } - } - DeviceEvent::TimeZoneChanged => { - if let Ok(v) = serde_json::from_value(value.clone()) { - return Some(ThunderEventMessage::TimeZone(v)); - } - } } } else { debug!( diff --git a/device/thunder_ripple_sdk/src/processors/events/thunder_event_handlers.rs b/device/thunder_ripple_sdk/src/processors/events/thunder_event_handlers.rs index 060d988f8..5a2de28ca 100644 --- a/device/thunder_ripple_sdk/src/processors/events/thunder_event_handlers.rs +++ b/device/thunder_ripple_sdk/src/processors/events/thunder_event_handlers.rs @@ -19,13 +19,9 @@ use std::collections::HashMap; use ripple_sdk::api::{ apps::{AppEvent, AppEventRequest}, - context::RippleContextUpdateRequest, device::{ device_accessibility_data::VoiceGuidanceSettings, - device_events::{ - INTERNET_CHANGED_EVENT, TIME_ZONE_CHANGED, VOICE_GUIDANCE_SETTINGS_CHANGED, - }, - device_request::{InternetConnectionStatus, TimeZone, VoiceGuidanceState}, + device_events::VOICE_GUIDANCE_SETTINGS_CHANGED, device_request::VoiceGuidanceState, }, }; use ripple_sdk::serde_json; @@ -37,8 +33,8 @@ use crate::{ }, ripple_sdk::{ api::device::{ - device_events::{DeviceEventCallback, HDCP_CHANGED_EVENT, POWER_STATE_CHANGED}, - device_request::{AudioProfile, HdcpProfile, SystemPowerState}, + device_events::{DeviceEventCallback, HDCP_CHANGED_EVENT}, + device_request::{AudioProfile, HdcpProfile}, }, extn::extn_client_message::ExtnEvent, log::debug, @@ -115,127 +111,6 @@ impl ThunderEventHandlerProvider for HDCPEventHandler { } } -// ----------------------- -// Internet Changed - -pub struct InternetEventHandler; - -impl InternetEventHandler { - pub fn handle( - state: ThunderState, - value: ThunderEventMessage, - _callback_type: DeviceEventCallback, - ) { - if let ThunderEventMessage::Internet(v) = value { - ThunderEventHandler::callback_context_update( - state, - RippleContextUpdateRequest::InternetStatus(v), - ) - } - } - - pub fn is_valid(message: ThunderEventMessage) -> bool { - if let ThunderEventMessage::Internet(_) = message { - return true; - } - false - } -} - -impl ThunderEventHandlerProvider for InternetEventHandler { - type EVENT = InternetConnectionStatus; - fn provide(id: String, callback_type: DeviceEventCallback) -> ThunderEventHandler { - ThunderEventHandler { - request: Self::get_device_request(), - handle: Self::handle, - is_valid: Self::is_valid, - listeners: vec![id], - id: Self::get_mapped_event(), - callback_type, - } - } - - // This is the thunder event name - fn event_name() -> String { - "onInternetStatusChange".into() - } - - // This is the event at the application level - fn get_mapped_event() -> String { - INTERNET_CHANGED_EVENT.into() - } - - fn module() -> String { - ThunderPlugin::Network.callsign_string() - } - fn get_extn_event( - _r: Self::EVENT, - _callback_type: DeviceEventCallback, - ) -> Result { - Err(RippleError::InvalidOutput) - } -} - -// ----------------------- -// SystemPower Changed - -pub struct SystemPowerStateChangeEventHandler; - -impl SystemPowerStateChangeEventHandler { - pub fn handle( - state: ThunderState, - value: ThunderEventMessage, - _callback_type: DeviceEventCallback, - ) { - if let ThunderEventMessage::PowerState(p) = value { - ThunderEventHandler::callback_context_update( - state, - RippleContextUpdateRequest::PowerState(p), - ) - } - } - - pub fn is_valid(value: ThunderEventMessage) -> bool { - if let ThunderEventMessage::PowerState(_) = value { - return true; - } - false - } -} - -impl ThunderEventHandlerProvider for SystemPowerStateChangeEventHandler { - type EVENT = SystemPowerState; - fn provide(id: String, callback_type: DeviceEventCallback) -> ThunderEventHandler { - ThunderEventHandler { - request: Self::get_device_request(), - handle: Self::handle, - is_valid: Self::is_valid, - listeners: vec![id], - id: Self::get_mapped_event(), - callback_type, - } - } - - fn event_name() -> String { - "onSystemPowerStateChanged".into() - } - - fn get_mapped_event() -> String { - POWER_STATE_CHANGED.into() - } - - fn module() -> String { - ThunderPlugin::System.callsign_string() - } - - fn get_extn_event( - _r: Self::EVENT, - _callback_type: DeviceEventCallback, - ) -> Result { - Err(RippleError::InvalidOutput) - } -} - // ----------------------- // VoiceGuidance Changed @@ -377,83 +252,3 @@ impl ThunderEventHandlerProvider for AudioChangedEvent { ThunderPlugin::DisplaySettings.callsign_string() } } - -pub struct TimezoneChangedEventHandler; - -impl TimezoneChangedEventHandler { - pub fn handle( - state: ThunderState, - value: ThunderEventMessage, - _callback_type: DeviceEventCallback, - ) { - if let ThunderEventMessage::TimeZone(_v) = value { - tokio::spawn(async move { - if let Some(tz) = - ThunderDeviceInfoRequestProcessor::get_timezone_and_offset(&state).await - { - let event = ExtnEvent::AppEvent(AppEventRequest::Emit(AppEvent { - event_name: TIME_ZONE_CHANGED.to_string(), - result: serde_json::to_value(tz.clone().time_zone).unwrap(), - context: None, - app_id: None, - })); - - ThunderEventHandler::callback_device_event( - state.clone(), - TIME_ZONE_CHANGED.to_string(), - event, - ); - - ThunderEventHandler::callback_context_update( - state, - RippleContextUpdateRequest::TimeZone(tz), - ); - } - }); - } - } - - pub fn is_valid(value: ThunderEventMessage) -> bool { - if let ThunderEventMessage::TimeZone(_) = value { - return true; - } - false - } -} - -impl ThunderEventHandlerProvider for TimezoneChangedEventHandler { - type EVENT = TimeZone; - fn provide(id: String, callback_type: DeviceEventCallback) -> ThunderEventHandler { - ThunderEventHandler { - request: Self::get_device_request(), - handle: Self::handle, - is_valid: Self::is_valid, - listeners: vec![id], - id: Self::get_mapped_event(), - callback_type, - } - } - - fn event_name() -> String { - "onTimeZoneDSTChanged".into() - } - - fn get_mapped_event() -> String { - TIME_ZONE_CHANGED.into() - } - - fn module() -> String { - ThunderPlugin::System.callsign_string() - } - - fn get_id(&self) -> String { - Self::get_mapped_event() - } - - fn get_extn_event( - _r: Self::EVENT, - _callback_type: DeviceEventCallback, - ) -> Result { - Err(RippleError::InvalidOutput) - } -} diff --git a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs index f008f5e08..e35a78b4a 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs @@ -692,44 +692,6 @@ impl ThunderDeviceInfoRequestProcessor { Err(RippleError::ProcessorError) } - pub async fn get_timezone_with_offset(state: CachedState, req: ExtnMessage) -> bool { - if let Some(TimeZone { time_zone, offset }) = state.get_client().get_timezone() { - if !time_zone.is_empty() { - return Self::respond( - state.get_client(), - req, - ExtnResponse::TimezoneWithOffset(time_zone, offset), - ) - .await - .is_ok(); - } - } - - // If timezone or offset is None or empty - if let Some(tz) = Self::get_timezone_and_offset(&state.state).await { - let cloned_state = state.clone(); - let cloned_tz = tz.clone(); - - cloned_state - .get_client() - .context_update(RippleContextUpdateRequest::TimeZone(TimeZone { - time_zone: cloned_tz.time_zone, - offset: cloned_tz.offset, - })); - - return Self::respond( - state.get_client(), - req, - ExtnResponse::TimezoneWithOffset(tz.time_zone, tz.offset), - ) - .await - .is_ok(); - } - - error!("get_timezone_offset: Unsupported timezone"); - Self::handle_error(state.get_client(), req, RippleError::ProcessorError).await - } - pub async fn get_timezone_and_offset(state: &ThunderState) -> Option { let timezone_result = ThunderDeviceInfoRequestProcessor::get_timezone_value(state).await; let timezones_result = ThunderDeviceInfoRequestProcessor::get_all_timezones(state).await; diff --git a/device/thunder_ripple_sdk/src/processors/thunder_events.rs b/device/thunder_ripple_sdk/src/processors/thunder_events.rs index c77f49eec..f5ee66adf 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_events.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_events.rs @@ -40,8 +40,7 @@ use crate::{ }; use super::events::thunder_event_handlers::{ - AudioChangedEvent, HDCPEventHandler, InternetEventHandler, SystemPowerStateChangeEventHandler, - TimezoneChangedEventHandler, VoiceGuidanceEnabledChangedEventHandler, + AudioChangedEvent, HDCPEventHandler, VoiceGuidanceEnabledChangedEventHandler, }; #[derive(Debug)] @@ -78,10 +77,7 @@ impl ExtnStreamProcessor for ThunderOpenEventsProcessor { Some(vec![ RippleContract::DeviceEvents(EventAdjective::Input), RippleContract::DeviceEvents(EventAdjective::VoiceGuidance), - RippleContract::DeviceEvents(EventAdjective::Internet), RippleContract::DeviceEvents(EventAdjective::Audio), - RippleContract::DeviceEvents(EventAdjective::SystemPowerState), - RippleContract::DeviceEvents(EventAdjective::TimeZone), ]) } } @@ -112,26 +108,11 @@ impl ExtnRequestProcessor for ThunderOpenEventsProcessor { id.clone(), HDCPEventHandler::provide(id, callback_type), )), - DeviceEvent::SystemPowerStateChanged => Some(state.handle_listener( - listen, - id.clone(), - SystemPowerStateChangeEventHandler::provide(id, callback_type), - )), DeviceEvent::VoiceGuidanceEnabledChanged => Some(state.handle_listener( listen, id.clone(), VoiceGuidanceEnabledChangedEventHandler::provide(id, callback_type), )), - DeviceEvent::InternetConnectionStatusChanged => Some(state.handle_listener( - listen, - id.clone(), - InternetEventHandler::provide(id, callback_type), - )), - DeviceEvent::TimeZoneChanged => Some(state.handle_listener( - listen, - id.clone(), - TimezoneChangedEventHandler::provide(id, callback_type), - )), } { v.await; Self::ack(state.get_client(), msg).await.is_ok() diff --git a/examples/manifest/extn-manifest-example.json b/examples/manifest/extn-manifest-example.json index 6d0f0834b..c02ea320b 100644 --- a/examples/manifest/extn-manifest-example.json +++ b/examples/manifest/extn-manifest-example.json @@ -25,10 +25,8 @@ "app_events", "input.device_events", "voice_guidance.device_events", - "internet.device_events", + "audio.device_events", - "system_power_state.device_events", - "time_zone.device_events" ], "config": { "rdk_telemetry": "true" diff --git a/examples/manifest/extn-manifest-tm-example.json b/examples/manifest/extn-manifest-tm-example.json index 63781d940..2beccc73c 100644 --- a/examples/manifest/extn-manifest-tm-example.json +++ b/examples/manifest/extn-manifest-tm-example.json @@ -25,10 +25,7 @@ "app_events", "input.device_events", "voice_guidance.device_events", - "internet.device_events", - "audio.device_events", - "system_power_state.device_events", - "time_zone.device_events" + "audio.device_events" ], "config": { "rdk_telemetry": "true" diff --git a/examples/manifest/jsonrpsee-manifest-example.json b/examples/manifest/jsonrpsee-manifest-example.json index 554fbc1d9..62d6f6d85 100644 --- a/examples/manifest/jsonrpsee-manifest-example.json +++ b/examples/manifest/jsonrpsee-manifest-example.json @@ -19,13 +19,9 @@ "device:windowmanager", "device:browser", "app_events", - "account.device_events", "input.device_events", "voice_guidance.device_events", - "internet.device_events", - "audio.device_events", - "system_power_state.device_events", - "time_zone.device_events" + "audio.device_events" ], "config": { "rdk_telemetry": "true" diff --git a/examples/manifest/mock/mock-extn-manifest.json b/examples/manifest/mock/mock-extn-manifest.json index fffa1d6eb..b5970f644 100644 --- a/examples/manifest/mock/mock-extn-manifest.json +++ b/examples/manifest/mock/mock-extn-manifest.json @@ -22,10 +22,8 @@ "local.storage", "input.device_events", "voice_guidance.device_events", - "internet.device_events", + "audio.device_events", - "system_power_state.device_events", - "time_zone.device_events", "remote_feature_control", "apps" ] diff --git a/examples/reference-manifest/IpStb/firebolt-extn-manifest.json b/examples/reference-manifest/IpStb/firebolt-extn-manifest.json index b95b1004a..b28fcaf4d 100644 --- a/examples/reference-manifest/IpStb/firebolt-extn-manifest.json +++ b/examples/reference-manifest/IpStb/firebolt-extn-manifest.json @@ -25,10 +25,8 @@ "app_events", "input.device_events", "voice_guidance.device_events", - "internet.device_events", + "audio.device_events", - "system_power_state.device_events", - "time_zone.device_events" ] } ] From c0f57bf2feeeefe7fad70ddc61c4b02427558f82 Mon Sep 17 00:00:00 2001 From: satlead Date: Mon, 31 Mar 2025 11:47:42 -0400 Subject: [PATCH 18/31] fix: format --- core/main/src/broker/broker_utils.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/main/src/broker/broker_utils.rs b/core/main/src/broker/broker_utils.rs index 3ea22e34a..23eb8f90d 100644 --- a/core/main/src/broker/broker_utils.rs +++ b/core/main/src/broker/broker_utils.rs @@ -78,7 +78,7 @@ impl BrokerUtils { params: Option, app_id: &str, ) -> RpcResult { - let mut rpc_request = RpcRequest::internal(method,None).with_params(params); + let mut rpc_request = RpcRequest::internal(method, None).with_params(params); rpc_request.ctx.app_id = app_id.to_owned(); Self::internal_request(state, rpc_request).await } @@ -104,8 +104,10 @@ impl BrokerUtils { Self::internal_request(state, rpc_request).await } - async fn internal_request(state: &mut PlatformState, rpc_request:RpcRequest) -> RpcResult - { + async fn internal_request( + state: &mut PlatformState, + rpc_request: RpcRequest, + ) -> RpcResult { let method = rpc_request.method.clone(); match state.internal_rpc_request(&rpc_request).await { Ok(res) => match res.as_value() { From aea90851ef1970395e0d1d5ae933f0d92e1d25a4 Mon Sep 17 00:00:00 2001 From: satlead Date: Mon, 31 Mar 2025 12:19:04 -0400 Subject: [PATCH 19/31] fix: unit tests --- core/main/src/broker/broker_utils.rs | 2 +- examples/manifest/extn-manifest-example.json | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/main/src/broker/broker_utils.rs b/core/main/src/broker/broker_utils.rs index 23eb8f90d..cfdf2ee17 100644 --- a/core/main/src/broker/broker_utils.rs +++ b/core/main/src/broker/broker_utils.rs @@ -100,7 +100,7 @@ impl BrokerUtils { let rpc_request = RpcRequest::internal(method, on_behalf_of).with_params(params); state .otel - .add_api_stats(&rpc_request.ctx.request_id, &method); + .add_api_stats(&rpc_request.ctx.request_id, method); Self::internal_request(state, rpc_request).await } diff --git a/examples/manifest/extn-manifest-example.json b/examples/manifest/extn-manifest-example.json index c02ea320b..e865dfa51 100644 --- a/examples/manifest/extn-manifest-example.json +++ b/examples/manifest/extn-manifest-example.json @@ -25,8 +25,7 @@ "app_events", "input.device_events", "voice_guidance.device_events", - - "audio.device_events", + "audio.device_events" ], "config": { "rdk_telemetry": "true" From 24a7ce72c841ee050829a8474ec00d10da48c6ac Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 2 Apr 2025 11:37:48 -0400 Subject: [PATCH 20/31] feat: Upgrade Thunder Mock to support Async events --- .../src/tests/mock_thunder_controller.rs | 66 +++++++++++++++---- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs b/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs index 108b2e6c9..91ccd3e09 100644 --- a/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs +++ b/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs @@ -1,10 +1,13 @@ -use std::{collections::HashMap, str::FromStr, sync::Arc}; +use std::{collections::HashMap, future::Future, pin::Pin, str::FromStr, sync::Arc}; use ripple_sdk::{ async_channel::{unbounded, Receiver}, extn::{ffi::ffi_message::CExtnMessage, mock_extension_client::MockExtnClient}, serde_json, - tokio::{self, sync::mpsc}, + tokio::{ + self, + sync::mpsc::{self, Sender}, + }, utils::channel_utils::{mpsc_send_and_log, oneshot_send_and_log}, uuid::Uuid, }; @@ -26,12 +29,41 @@ use crate::{ }; pub type ThunderHandlerFn = dyn Fn(ThunderCallMessage) + Send + Sync; +pub type ThunderSubscriberFn = dyn Fn( + Sender, + ) -> Pin> + Send>> + + Send + + Sync; + +#[derive(Clone)] +pub struct MockThunderSubscriberfn { + fnc: Arc, +} + +impl MockThunderSubscriberfn { + pub fn new(f: F) -> Self + where + F: Fn( + Sender, + ) -> Pin> + Send>> + + Send + + Sync + + 'static, + { + Self { + fnc: Arc::new(Box::new(f)), + } + } + + async fn call(&self, sender: Sender) -> Option { + (self.fnc)(sender).await + } +} #[derive(Default, Clone)] pub struct CustomHandler { pub custom_request_handler: HashMap>, - pub custom_subscription_handler: - HashMap DeviceResponseMessage>, + pub custom_subscription_handler: HashMap, } #[derive(Default)] @@ -113,8 +145,10 @@ impl MockThunderController { .custom_subscription_handler .get(&format!("{}.{}", msg.module, msg.event_name)) { - let response = (handler)(&msg); - mpsc_send_and_log(&msg.handler, response, "OnStatusChange").await; + let response = handler.call(msg.handler.clone()).await; + if response.is_some() { + mpsc_send_and_log(&msg.handler, response.unwrap(), "OnStatusChange").await; + } } else { println!( "No mock subscription found for {}.{}", @@ -185,14 +219,8 @@ impl MockThunderController { (CachedState::new(thunder_state), r) } - /** - * Creates state object that points to a mock thunder controller. - * Pass in the custom thunder handlers to mock the thunder responses - * Returns the state and a receiver which can be used to listen to responses that - * come back from the extension - */ - pub fn get_thunder_state_mock() -> ThunderState { - let s_thunder = MockThunderController::start_with_custom_handlers(None); + pub fn get_thunder_state_mock_with_handler(handler: Option) -> ThunderState { + let s_thunder = MockThunderController::start_with_custom_handlers(handler); let thunder_client = ThunderClient { sender: Some(s_thunder), pooled_sender: None, @@ -209,4 +237,14 @@ impl MockThunderController { let extn_client = MockExtnClient::client(s); ThunderState::new(extn_client, thunder_client) } + + /** + * Creates state object that points to a mock thunder controller. + * Pass in the custom thunder handlers to mock the thunder responses + * Returns the state and a receiver which can be used to listen to responses that + * come back from the extension + */ + pub fn get_thunder_state_mock() -> ThunderState { + Self::get_thunder_state_mock_with_handler(None) + } } From 51efb3f4413547c53a9874be627ce120b65045bb Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 2 Apr 2025 15:02:29 -0400 Subject: [PATCH 21/31] rename: Otel to Metrics --- core/main/src/broker/broker_utils.rs | 2 +- core/main/src/broker/endpoint_broker.rs | 6 ++--- .../src/broker/event_management_utility.rs | 2 +- core/main/src/firebolt/firebolt_gateway.rs | 14 ++++++------ core/main/src/firebolt/firebolt_ws.rs | 6 ++--- .../main/src/firebolt/handlers/account_rpc.rs | 2 +- core/main/src/firebolt/handlers/device_rpc.rs | 2 +- .../src/firebolt/handlers/internal_rpc.rs | 2 +- .../main/src/firebolt/handlers/privacy_rpc.rs | 2 +- core/main/src/firebolt/rpc_router.rs | 6 ++--- core/main/src/processor/metrics_processor.rs | 4 ++-- core/main/src/service/telemetry_builder.rs | 22 +++++++++---------- core/main/src/state/platform_state.rs | 4 ++-- 13 files changed, 37 insertions(+), 37 deletions(-) diff --git a/core/main/src/broker/broker_utils.rs b/core/main/src/broker/broker_utils.rs index cfdf2ee17..cac493b26 100644 --- a/core/main/src/broker/broker_utils.rs +++ b/core/main/src/broker/broker_utils.rs @@ -99,7 +99,7 @@ impl BrokerUtils { ) -> RpcResult { let rpc_request = RpcRequest::internal(method, on_behalf_of).with_params(params); state - .otel + .metrics .add_api_stats(&rpc_request.ctx.request_id, method); Self::internal_request(state, rpc_request).await } diff --git a/core/main/src/broker/endpoint_broker.rs b/core/main/src/broker/endpoint_broker.rs index 95c6121a2..ca5a3dda2 100644 --- a/core/main/src/broker/endpoint_broker.rs +++ b/core/main/src/broker/endpoint_broker.rs @@ -1227,7 +1227,7 @@ impl BrokerOutputForwarder { } } - platform_state.otel.update_api_stats_ref( + platform_state.metrics.update_api_stats_ref( &rpc_request.ctx.request_id, add_telemetry_status_code( &tm_str, @@ -1236,14 +1236,14 @@ impl BrokerOutputForwarder { ); if let Some(api_stats) = platform_state - .otel + .metrics .get_api_stats(&rpc_request.ctx.request_id) { message.stats = Some(api_stats); if rpc_request.ctx.app_id.eq_ignore_ascii_case("internal") { platform_state - .otel + .metrics .remove_api_stats(&rpc_request.ctx.request_id); } } diff --git a/core/main/src/broker/event_management_utility.rs b/core/main/src/broker/event_management_utility.rs index 297c18bc3..877c43022 100644 --- a/core/main/src/broker/event_management_utility.rs +++ b/core/main/src/broker/event_management_utility.rs @@ -90,7 +90,7 @@ impl EventManagementUtility { }; platform_state - .otel + .metrics .add_api_stats(&ctx.request_id, "advertising.policy"); let resp = platform_state diff --git a/core/main/src/firebolt/firebolt_gateway.rs b/core/main/src/firebolt/firebolt_gateway.rs index 7c325c109..4480f0f52 100644 --- a/core/main/src/firebolt/firebolt_gateway.rs +++ b/core/main/src/firebolt/firebolt_gateway.rs @@ -193,7 +193,7 @@ impl FireboltGateway { ApiMessage::new(protocol, data, rpc_request.ctx.request_id.clone()); if let Some(api_stats) = platform_state - .otel + .metrics .get_api_stats(&rpc_request.ctx.request_id.clone()) { api_message.stats = Some(api_stats); @@ -288,7 +288,7 @@ impl FireboltGateway { request_c.method = FireboltOpenRpcMethod::name_with_lowercase_module(&request.method); platform_state - .otel + .metrics .add_api_stats(&request_c.ctx.request_id, &request_c.method); let fail_open = matches!( @@ -302,7 +302,7 @@ impl FireboltGateway { let open_rpc_state = self.state.platform_state.open_rpc_state.clone(); tokio::spawn(async move { - capture_stage(&platform_state.otel, &request_c, "context_ready"); + capture_stage(&platform_state.metrics, &request_c, "context_ready"); // Validate incoming request parameters. if let Err(error_string) = validate_request(open_rpc_state, &request_c, fail_open) { let json_rpc_error = JsonRpcError { @@ -315,7 +315,7 @@ impl FireboltGateway { return; } - capture_stage(&platform_state.otel, &request_c, "openrpc_val"); + capture_stage(&platform_state.metrics, &request_c, "openrpc_val"); let result = if extn_request { // extn protocol means its an internal Ripple request skip permissions. @@ -324,7 +324,7 @@ impl FireboltGateway { FireboltGatekeeper::gate(platform_state.clone(), request_c.clone()).await }; - capture_stage(&platform_state.otel, &request_c, "permission"); + capture_stage(&platform_state.metrics, &request_c, "permission"); match result { Ok(p) => { @@ -538,14 +538,14 @@ async fn send_json_rpc_error( request.clone().ctx.request_id, ); - if let Some(api_stats) = platform_state.otel.get_api_stats(&request.ctx.request_id) { + if let Some(api_stats) = platform_state.metrics.get_api_stats(&request.ctx.request_id) { api_message.stats = Some(ApiStats { api: request.method.clone(), stats_ref: get_rpc_header_with_status(request, status_code), stats: api_stats.stats.clone(), }); } - platform_state.otel.update_api_stats_ref( + platform_state.metrics.update_api_stats_ref( &request.ctx.request_id, get_rpc_header_with_status(request, status_code), ); diff --git a/core/main/src/firebolt/firebolt_ws.rs b/core/main/src/firebolt/firebolt_ws.rs index 1304bf369..97e4ae857 100644 --- a/core/main/src/firebolt/firebolt_ws.rs +++ b/core/main/src/firebolt/firebolt_ws.rs @@ -288,7 +288,7 @@ impl FireboltWs { match send_result { Ok(_) => { platform_state - .otel + .metrics .update_api_stage(&api_message.request_id, "response"); LogSignal::new( @@ -300,7 +300,7 @@ impl FireboltWs { .with_diagnostic_context_item("result", &api_message.jsonrpc_msg.clone()) .emit_debug(); if let Some(stats) = - platform_state.otel.get_api_stats(&api_message.request_id) + platform_state.metrics.get_api_stats(&api_message.request_id) { info!( "Sending Firebolt response: {:?},{}", @@ -313,7 +313,7 @@ impl FireboltWs { stats.stats.get_stage_durations() ); platform_state - .otel + .metrics .remove_api_stats(&api_message.request_id); } diff --git a/core/main/src/firebolt/handlers/account_rpc.rs b/core/main/src/firebolt/handlers/account_rpc.rs index 2e64a58f3..c77ea1af8 100644 --- a/core/main/src/firebolt/handlers/account_rpc.rs +++ b/core/main/src/firebolt/handlers/account_rpc.rs @@ -66,7 +66,7 @@ impl AccountServer for AccountImpl { let mut platform_state = self.platform_state.clone(); platform_state - .otel + .metrics .add_api_stats(&_ctx.request_id, "account.setServiceAccessToken"); let success = rpc_request_setter( diff --git a/core/main/src/firebolt/handlers/device_rpc.rs b/core/main/src/firebolt/handlers/device_rpc.rs index 33e43400d..f1143aad2 100644 --- a/core/main/src/firebolt/handlers/device_rpc.rs +++ b/core/main/src/firebolt/handlers/device_rpc.rs @@ -373,7 +373,7 @@ impl DeviceServer for DeviceImpl { let mut platform_state = self.state.clone(); platform_state - .otel + .metrics .add_api_stats(&_ctx.request_id, "account.setServiceAccountId"); let success = rpc_request_setter( diff --git a/core/main/src/firebolt/handlers/internal_rpc.rs b/core/main/src/firebolt/handlers/internal_rpc.rs index 9ccca65d3..a0ed47963 100644 --- a/core/main/src/firebolt/handlers/internal_rpc.rs +++ b/core/main/src/firebolt/handlers/internal_rpc.rs @@ -69,7 +69,7 @@ impl InternalServer for InternalImpl { } fn set_telemetry_session_id(&self, _ctx: CallContext, session_id: String) -> RpcResult<()> { - self.state.otel.update_session_id(Some(session_id)); + self.state.metrics.update_session_id(Some(session_id)); Ok(()) } diff --git a/core/main/src/firebolt/handlers/privacy_rpc.rs b/core/main/src/firebolt/handlers/privacy_rpc.rs index 5bf05fed0..5a376123a 100644 --- a/core/main/src/firebolt/handlers/privacy_rpc.rs +++ b/core/main/src/firebolt/handlers/privacy_rpc.rs @@ -89,7 +89,7 @@ impl AllowAppContentAdTargetingSettings { new_ctx.protocol = ApiProtocol::Extn; platform_state - .otel + .metrics .add_api_stats(&ctx.request_id, "localization.countryCode"); let rpc_request = RpcRequest { diff --git a/core/main/src/firebolt/rpc_router.rs b/core/main/src/firebolt/rpc_router.rs index fdf93cace..b7e4b2b63 100644 --- a/core/main/src/firebolt/rpc_router.rs +++ b/core/main/src/firebolt/rpc_router.rs @@ -183,15 +183,15 @@ async fn resolve_route( 1 }; - capture_stage(&platform_state.otel, &req, "routing"); + capture_stage(&platform_state.metrics, &req, "routing"); - platform_state.otel.update_api_stats_ref( + platform_state.metrics.update_api_stats_ref( &request_id, add_telemetry_status_code(&rpc_header, status_code.to_string().as_str()), ); let mut msg = ApiMessage::new(protocol, r, request_id.clone()); - if let Some(api_stats) = platform_state.otel.get_api_stats(&request_id) { + if let Some(api_stats) = platform_state.metrics.get_api_stats(&request_id) { msg.stats = Some(api_stats); } diff --git a/core/main/src/processor/metrics_processor.rs b/core/main/src/processor/metrics_processor.rs index 1ff445db9..3acf4370c 100644 --- a/core/main/src/processor/metrics_processor.rs +++ b/core/main/src/processor/metrics_processor.rs @@ -76,10 +76,10 @@ impl ExtnRequestProcessor for OpMetricsProcessor { let requestor = msg.requestor.to_string(); match extracted_message { OperationalMetricRequest::Subscribe => { - state.otel.operational_telemetry_listener(&requestor, true) + state.metrics.operational_telemetry_listener(&requestor, true) } OperationalMetricRequest::UnSubscribe => { - state.otel.operational_telemetry_listener(&requestor, false) + state.metrics.operational_telemetry_listener(&requestor, false) } } Self::ack(state.get_client().get_extn_client(), msg) diff --git a/core/main/src/service/telemetry_builder.rs b/core/main/src/service/telemetry_builder.rs index 22d1bb456..fd00cd8ee 100644 --- a/core/main/src/service/telemetry_builder.rs +++ b/core/main/src/service/telemetry_builder.rs @@ -51,7 +51,7 @@ impl TelemetryBuilder { app_id, app_version, start_time: start_time.unwrap_or_default().timestamp_millis(), - ripple_session_id: ps.otel.get_device_session_id(), + ripple_session_id: ps.metrics.get_device_session_id(), ripple_version: ps .version .clone() @@ -70,7 +70,7 @@ impl TelemetryBuilder { app_id, stop_time: Utc::now().timestamp_millis(), app_session_id: None, - ripple_session_id: ps.otel.get_device_session_id(), + ripple_session_id: ps.metrics.get_device_session_id(), success, }), ) { @@ -82,7 +82,7 @@ impl TelemetryBuilder { ps: &PlatformState, mut t: TelemetryPayload, ) -> RippleResponse { - let session_id = ps.otel.get_device_session_id(); + let session_id = ps.metrics.get_device_session_id(); t.update_session_id(session_id); Self::send_telemetry(ps, t) } @@ -90,7 +90,7 @@ impl TelemetryBuilder { pub fn send_telemetry(ps: &PlatformState, t: TelemetryPayload) -> RippleResponse { trace!("send_telemetry: t={:?}", t); - let listeners = ps.otel.get_listeners(); + let listeners = ps.metrics.get_listeners(); let client = ps.get_client().get_extn_client(); let mut result = Ok(()); for id in listeners { @@ -111,14 +111,14 @@ impl TelemetryBuilder { .clone() .unwrap_or(String::from(SEMVER_LIGHTWEIGHT)), ), - Some(ps.otel.start_time), + Some(ps.metrics.start_time), ); Self::send_app_load_stop(ps, "ripple".to_string(), true); } pub fn send_error(ps: &PlatformState, app_id: String, error_params: ErrorParams) { let mut app_error: TelemetryAppError = error_params.into(); - app_error.ripple_session_id = ps.otel.get_device_session_id(); + app_error.ripple_session_id = ps.metrics.get_device_session_id(); app_error.app_id = app_id; if let Err(e) = Self::send_telemetry(ps, TelemetryPayload::AppError(app_error)) { @@ -128,7 +128,7 @@ impl TelemetryBuilder { pub fn send_system_error(ps: &PlatformState, error_params: SystemErrorParams) { let mut system_error: TelemetrySystemError = error_params.into(); - system_error.ripple_session_id = ps.otel.get_device_session_id(); + system_error.ripple_session_id = ps.metrics.get_device_session_id(); if let Err(e) = Self::send_telemetry(ps, TelemetryPayload::SystemError(system_error)) { error!("send_telemetry={:?}", e) @@ -140,7 +140,7 @@ impl TelemetryBuilder { ps, TelemetryPayload::SignIn(TelemetrySignIn { app_id: ctx.app_id.to_owned(), - ripple_session_id: ps.otel.get_device_session_id(), + ripple_session_id: ps.metrics.get_device_session_id(), app_session_id: Some(ctx.session_id.to_owned()), }), ) { @@ -153,7 +153,7 @@ impl TelemetryBuilder { ps, TelemetryPayload::SignOut(TelemetrySignOut { app_id: ctx.app_id.to_owned(), - ripple_session_id: ps.otel.get_device_session_id(), + ripple_session_id: ps.metrics.get_device_session_id(), app_session_id: Some(ctx.session_id.to_owned()), }), ) { @@ -170,7 +170,7 @@ impl TelemetryBuilder { ps, TelemetryPayload::InternalInitialize(InternalInitialize { app_id: ctx.app_id.to_owned(), - ripple_session_id: ps.otel.get_device_session_id(), + ripple_session_id: ps.metrics.get_device_session_id(), app_session_id: Some(ctx.session_id.to_owned()), semantic_version: params.version.to_string(), }), @@ -204,7 +204,7 @@ impl TelemetryBuilder { ps, TelemetryPayload::FireboltInteraction(FireboltInteraction { app_id: ctx.app_id.to_owned(), - ripple_session_id: ps.otel.get_device_session_id(), + ripple_session_id: ps.metrics.get_device_session_id(), app_session_id: Some(ctx.session_id), tt, method, diff --git a/core/main/src/state/platform_state.rs b/core/main/src/state/platform_state.rs index acf4ee692..da9741497 100644 --- a/core/main/src/state/platform_state.rs +++ b/core/main/src/state/platform_state.rs @@ -102,7 +102,7 @@ pub struct PlatformState { pub app_manager_state: AppManagerState, pub open_rpc_state: OpenRpcState, pub router_state: RouterState, - pub otel: OtelState, + pub metrics: OtelState, pub device_session_id: DeviceSessionIdentifier, pub ripple_cache: RippleCache, pub version: Option, @@ -135,7 +135,7 @@ impl PlatformState { app_manager_state: AppManagerState::new(&manifest.configuration.saved_dir), open_rpc_state: OpenRpcState::new(Some(exclusory), extn_sdks, provider_registations), router_state: RouterState::new(), - otel: metrics_state.clone(), + metrics: metrics_state.clone(), device_session_id: DeviceSessionIdentifier::default(), ripple_cache: RippleCache::default(), version, From f98e9f9219c1da24cb0fc07ee7fbcaf6a8f9aaff Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 2 Apr 2025 15:03:09 -0400 Subject: [PATCH 22/31] rename: OpMetrics --- core/main/src/broker/endpoint_broker.rs | 12 ++++++------ core/main/src/state/otel_state.rs | 4 ++-- core/main/src/state/platform_state.rs | 6 +++--- core/main/src/utils/router_utils.rs | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core/main/src/broker/endpoint_broker.rs b/core/main/src/broker/endpoint_broker.rs index ca5a3dda2..f2d02f4ab 100644 --- a/core/main/src/broker/endpoint_broker.rs +++ b/core/main/src/broker/endpoint_broker.rs @@ -49,7 +49,7 @@ use crate::{ broker::broker_utils::BrokerUtils, firebolt::firebolt_gateway::{FireboltGatewayCommand, JsonRpcError}, service::extn::ripple_client::RippleClient, - state::{otel_state::OtelState, platform_state::PlatformState, session_state::Session}, + state::{otel_state::OpMetricState, platform_state::PlatformState, session_state::Session}, utils::router_utils::{ add_telemetry_status_code, capture_stage, get_rpc_header, return_extn_response, }, @@ -372,7 +372,7 @@ pub struct EndpointBrokerState { cleaner_list: Arc>>, reconnect_tx: Sender, provider_broker_state: ProvideBrokerState, - metrics_state: OtelState, + metrics_state: OpMetricState, } impl Default for EndpointBrokerState { fn default() -> Self { @@ -385,14 +385,14 @@ impl Default for EndpointBrokerState { cleaner_list: Arc::new(RwLock::new(Vec::new())), reconnect_tx: mpsc::channel(2).0, provider_broker_state: ProvideBrokerState::default(), - metrics_state: OtelState::default(), + metrics_state: OpMetricState::default(), } } } impl EndpointBrokerState { pub fn new( - metrics_state: OtelState, + metrics_state: OpMetricState, tx: Sender, rule_engine: RuleEngine, ripple_client: RippleClient, @@ -1611,7 +1611,7 @@ mod tests { endpoint_broker::tests::RippleClient, rules_engine::{Rule, RuleEngine, RuleSet, RuleTransform}, }, - state::{bootstrap_state::ChannelsState, otel_state::OtelState}, + state::{bootstrap_state::ChannelsState, otel_state::OpMetricState}, }; use super::EndpointBrokerState; @@ -1621,7 +1621,7 @@ mod tests { let (tx, _) = channel(2); let client = RippleClient::new(ChannelsState::new()); let state = EndpointBrokerState::new( - OtelState::default(), + OpMetricState::default(), tx, RuleEngine { rules: RuleSet::default(), diff --git a/core/main/src/state/otel_state.rs b/core/main/src/state/otel_state.rs index b1ff131bf..e48ed5e39 100644 --- a/core/main/src/state/otel_state.rs +++ b/core/main/src/state/otel_state.rs @@ -31,14 +31,14 @@ include!(concat!(env!("OUT_DIR"), "/version.rs")); const API_STATS_MAP_SIZE_WARNING: usize = 10; #[derive(Debug, Clone, Default)] -pub struct OtelState { +pub struct OpMetricState { pub start_time: DateTime, operational_telemetry_listeners: Arc>>, api_stats_map: Arc>>, device_session_id: Arc>>, } -impl OtelState { +impl OpMetricState { pub fn get_device_session_id(&self) -> String { self.device_session_id.read().unwrap().clone().unwrap() } diff --git a/core/main/src/state/platform_state.rs b/core/main/src/state/platform_state.rs index da9741497..40e1925e5 100644 --- a/core/main/src/state/platform_state.rs +++ b/core/main/src/state/platform_state.rs @@ -49,7 +49,7 @@ use crate::{ }; use super::{ - cap::cap_state::CapState, openrpc_state::OpenRpcState, otel_state::OtelState, + cap::cap_state::CapState, openrpc_state::OpenRpcState, otel_state::OpMetricState, ripple_cache::RippleCache, session_state::SessionState, }; @@ -102,7 +102,7 @@ pub struct PlatformState { pub app_manager_state: AppManagerState, pub open_rpc_state: OpenRpcState, pub router_state: RouterState, - pub metrics: OtelState, + pub metrics: OpMetricState, pub device_session_id: DeviceSessionIdentifier, pub ripple_cache: RippleCache, pub version: Option, @@ -122,7 +122,7 @@ impl PlatformState { let rule_engine = RuleEngine::build(&extn_manifest); let extn_sdks = extn_manifest.extn_sdks.clone(); let provider_registations = extn_manifest.provider_registrations.clone(); - let metrics_state = OtelState::default(); + let metrics_state = OpMetricState::default(); Self { extn_manifest, cap_state: CapState::new(manifest.clone()), diff --git a/core/main/src/utils/router_utils.rs b/core/main/src/utils/router_utils.rs index 13c0a86af..b5000ba4f 100644 --- a/core/main/src/utils/router_utils.rs +++ b/core/main/src/utils/router_utils.rs @@ -22,7 +22,7 @@ use ripple_sdk::{ utils::error::RippleError, }; -use crate::state::otel_state::OtelState; +use crate::state::otel_state::OpMetricState; pub fn return_extn_response(msg: ApiMessage, extn_msg: ExtnMessage) { let callback = match extn_msg.clone().callback { @@ -70,7 +70,7 @@ pub fn add_telemetry_status_code(original_ref: &str, status_code: &str) -> Optio Some(format!("{},{}", original_ref, status_code)) } -pub fn capture_stage(metrics_state: &OtelState, request: &RpcRequest, stage: &str) { +pub fn capture_stage(metrics_state: &OpMetricState, request: &RpcRequest, stage: &str) { let mut state = metrics_state.clone(); let duration = state.update_api_stage(&request.ctx.request_id, stage); From 6bd31ce23bd644854347b9be3243b51dedbab294 Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 2 Apr 2025 18:14:01 -0400 Subject: [PATCH 23/31] fix: Remove Refresh context --- core/main/src/firebolt/firebolt_gateway.rs | 5 ++++- core/main/src/firebolt/firebolt_ws.rs | 5 +++-- core/main/src/processor/metrics_processor.rs | 12 ++++++------ core/sdk/src/api/context.rs | 5 ----- core/sdk/src/extn/client/extn_client.rs | 18 ++---------------- 5 files changed, 15 insertions(+), 30 deletions(-) diff --git a/core/main/src/firebolt/firebolt_gateway.rs b/core/main/src/firebolt/firebolt_gateway.rs index 4480f0f52..8beb53b61 100644 --- a/core/main/src/firebolt/firebolt_gateway.rs +++ b/core/main/src/firebolt/firebolt_gateway.rs @@ -538,7 +538,10 @@ async fn send_json_rpc_error( request.clone().ctx.request_id, ); - if let Some(api_stats) = platform_state.metrics.get_api_stats(&request.ctx.request_id) { + if let Some(api_stats) = platform_state + .metrics + .get_api_stats(&request.ctx.request_id) + { api_message.stats = Some(ApiStats { api: request.method.clone(), stats_ref: get_rpc_header_with_status(request, status_code), diff --git a/core/main/src/firebolt/firebolt_ws.rs b/core/main/src/firebolt/firebolt_ws.rs index 97e4ae857..0d9a94f3a 100644 --- a/core/main/src/firebolt/firebolt_ws.rs +++ b/core/main/src/firebolt/firebolt_ws.rs @@ -299,8 +299,9 @@ impl FireboltWs { .with_diagnostic_context_item("cid", &connection_id_c.clone()) .with_diagnostic_context_item("result", &api_message.jsonrpc_msg.clone()) .emit_debug(); - if let Some(stats) = - platform_state.metrics.get_api_stats(&api_message.request_id) + if let Some(stats) = platform_state + .metrics + .get_api_stats(&api_message.request_id) { info!( "Sending Firebolt response: {:?},{}", diff --git a/core/main/src/processor/metrics_processor.rs b/core/main/src/processor/metrics_processor.rs index 3acf4370c..c1a969e22 100644 --- a/core/main/src/processor/metrics_processor.rs +++ b/core/main/src/processor/metrics_processor.rs @@ -75,12 +75,12 @@ impl ExtnRequestProcessor for OpMetricsProcessor { ) -> bool { let requestor = msg.requestor.to_string(); match extracted_message { - OperationalMetricRequest::Subscribe => { - state.metrics.operational_telemetry_listener(&requestor, true) - } - OperationalMetricRequest::UnSubscribe => { - state.metrics.operational_telemetry_listener(&requestor, false) - } + OperationalMetricRequest::Subscribe => state + .metrics + .operational_telemetry_listener(&requestor, true), + OperationalMetricRequest::UnSubscribe => state + .metrics + .operational_telemetry_listener(&requestor, false), } Self::ack(state.get_client().get_extn_client(), msg) .await diff --git a/core/sdk/src/api/context.rs b/core/sdk/src/api/context.rs index 9741429df..e4536de09 100644 --- a/core/sdk/src/api/context.rs +++ b/core/sdk/src/api/context.rs @@ -175,10 +175,6 @@ impl RippleContext { self.update_type = Some(RippleContextUpdateType::TimeZoneChanged); true } - RippleContextUpdateRequest::RefreshContext(_context) => { - false - // This is not an update request so need not to honour it - } RippleContextUpdateRequest::UpdateFeatures(features) => { let mut changed = false; for feature in features { @@ -274,7 +270,6 @@ pub enum RippleContextUpdateRequest { PowerState(SystemPowerState), TimeZone(TimeZone), UpdateFeatures(Vec), - RefreshContext(Option), } impl RippleContextUpdateRequest { diff --git a/core/sdk/src/extn/client/extn_client.rs b/core/sdk/src/extn/client/extn_client.rs index fe783f8aa..c33e4f3d5 100644 --- a/core/sdk/src/extn/client/extn_client.rs +++ b/core/sdk/src/extn/client/extn_client.rs @@ -36,13 +36,8 @@ use tokio::sync::{ use crate::{ api::{ - context::{ - ActivationStatus, RippleContext, RippleContextUpdateRequest, RippleContextUpdateType, - }, - device::{ - device_info_request::DeviceInfoRequest, - device_request::{InternetConnectionStatus, TimeZone}, - }, + context::{ActivationStatus, RippleContext, RippleContextUpdateRequest}, + device::device_request::{InternetConnectionStatus, TimeZone}, manifest::extn_manifest::ExtnSymbol, }, extn::{ @@ -359,15 +354,6 @@ impl ExtnClient { error!("Updating context is not allowed outside main"); return; } - if let RippleContextUpdateRequest::RefreshContext(refresh_context) = &request { - if let Some(RippleContextUpdateType::InternetConnectionChanged) = refresh_context { - let resp = self.request_transient(DeviceInfoRequest::InternetConnectionStatus); - if let Err(_err) = resp { - error!("Error in starting internet monitoring"); - } - } - return; - } // Main's Extn client will receive Context events and if it results in changing any of its // context members then it propagates the event to other extension's extn client. // Propagating 'known information' to other clients increases processing but no meaningful task is performed. From 6dd62752a87a49c7577a54ae47d1c88e74c1e895 Mon Sep 17 00:00:00 2001 From: satlead Date: Fri, 4 Apr 2025 08:16:26 -0400 Subject: [PATCH 24/31] Cleanup metrics --- .../apps/delegated_launcher_handler.rs | 2 +- core/sdk/src/api/firebolt/fb_metrics.rs | 650 ++---------------- .../src/processors/thunder_analytics.rs | 19 +- 3 files changed, 75 insertions(+), 596 deletions(-) diff --git a/core/main/src/service/apps/delegated_launcher_handler.rs b/core/main/src/service/apps/delegated_launcher_handler.rs index abdb2c7f1..df6f1461c 100644 --- a/core/main/src/service/apps/delegated_launcher_handler.rs +++ b/core/main/src/service/apps/delegated_launcher_handler.rs @@ -569,7 +569,7 @@ impl DelegatedLauncherHandler { None => None, }; let params = serde_json::to_value(AppLifecycleStateChange { - context: app_id.into(), + app_id: app_id.to_owned(), new_state: to_state.unwrap(), previous_state: from_state, }) diff --git a/core/sdk/src/api/firebolt/fb_metrics.rs b/core/sdk/src/api/firebolt/fb_metrics.rs index 6ea4bbd1d..2bffd74f2 100644 --- a/core/sdk/src/api/firebolt/fb_metrics.rs +++ b/core/sdk/src/api/firebolt/fb_metrics.rs @@ -15,196 +15,28 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::collections::{HashMap, HashSet}; - -use async_trait::async_trait; use serde::{Deserialize, Serialize}; -use serde_json::Value; - -use crate::api::gateway::rpc_gateway_api::CallContext; - +use std::collections::HashMap; //https://developer.comcast.com/firebolt/core/sdk/latest/api/metrics #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct BehavioralMetricContext { - pub app_id: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub app_version: Option, - pub product_version: String, - pub partner_id: String, - pub app_session_id: String, - pub app_user_session_id: Option, - pub durable_app_id: String, - pub governance_state: Option, -} - -impl From for BehavioralMetricContext { - fn from(call_context: CallContext) -> Self { - BehavioralMetricContext { - app_id: call_context.app_id.clone(), - product_version: String::from("product.version.not.implemented"), - partner_id: String::from("partner.id.not.set"), - app_session_id: String::from("app_session_id.not.set"), - durable_app_id: call_context.app_id, - app_version: None, - app_user_session_id: None, - governance_state: None, - } - } -} - -impl From<&str> for BehavioralMetricContext { - fn from(app_id: &str) -> Self { - BehavioralMetricContext { - app_id: app_id.to_owned(), - product_version: String::from("product.version.not.implemented"), - partner_id: String::from("partner.id.not.set"), - app_session_id: String::from("app_session_id.not.set"), - durable_app_id: app_id.to_owned(), - app_version: None, - app_user_session_id: None, - governance_state: None, - } - } -} - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default)] -pub struct AppDataGovernanceState { - pub data_tags_to_apply: HashSet, -} -impl AppDataGovernanceState { - pub fn new(tags: HashSet) -> AppDataGovernanceState { - AppDataGovernanceState { - data_tags_to_apply: tags, - } - } -} -#[derive(Deserialize, Debug, Clone)] -pub struct InternalInitializeParams { - #[serde(deserialize_with = "deserialize_version")] - pub version: Version, -} - -#[derive(Deserialize, Debug, Clone, Serialize)] -pub struct InternalInitializeResponse { - pub version: Version, -} - -#[async_trait] -pub trait MetricsContextProvider: core::fmt::Debug { - async fn provide_context(&mut self) -> Option; -} - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct Ready { - pub context: BehavioralMetricContext, - pub ttmu_ms: u32, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub enum MediaPositionType { - None, - PercentageProgress(f32), - AbsolutePosition(i32), -} -impl MediaPositionType { - pub fn as_absolute(self) -> Option { - match self { - MediaPositionType::None => None, - MediaPositionType::PercentageProgress(_) => None, - MediaPositionType::AbsolutePosition(absolute) => Some(absolute), - } - } - pub fn as_percentage(self) -> Option { - match self { - MediaPositionType::None => None, - MediaPositionType::PercentageProgress(percentage) => Some(percentage), - MediaPositionType::AbsolutePosition(_) => None, - } - } -} - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct SignIn { - pub context: BehavioralMetricContext, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct SignOut { - pub context: BehavioralMetricContext, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct StartContent { - pub context: BehavioralMetricContext, - pub entity_id: Option, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct StopContent { - pub context: BehavioralMetricContext, - pub entity_id: Option, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct Page { - pub context: BehavioralMetricContext, - pub page_id: String, -} - -#[allow(non_camel_case_types)] -#[derive(Debug, Serialize, Deserialize, Clone)] -pub enum ActionType { - user, - app, -} -#[allow(non_camel_case_types)] -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub enum CategoryType { - user, - app, -} - -#[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize, Clone)] -#[serde(untagged)] -pub enum FlatMapValue { - String(String), - Number(f64), - Boolean(bool), -} - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct Param { - pub name: String, - pub value: FlatMapValue, -} - -// custom comparison function used only in unit tests -#[cfg(test)] -impl Param { - fn cmp(&self, other: &Param) -> std::cmp::Ordering { - self.name.cmp(&other.name) - } -} - -pub fn hashmap_to_param_vec(the_map: Option>) -> Vec { - let mut result = Vec::new(); - - let params_map = match the_map { - Some(params_map) => params_map, - None => return Vec::new(), - }; - - for (key, value) in params_map { - result.push(Param { name: key, value }); - } - - result -} - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct Action { - pub context: BehavioralMetricContext, - pub category: CategoryType, - #[serde(rename = "type")] - pub _type: String, - pub parameters: Vec, +pub enum AppLifecycleState { + #[serde(rename = "launching")] + Launching, + #[serde(rename = "foreground")] + Foreground, + #[serde(rename = "background")] + Background, + #[serde(rename = "inactive")] + Inactive, + #[serde(rename = "suspended")] + Suspended, + #[serde(rename = "not_running")] + NotRunning, + #[serde(rename = "initializing")] + Initializing, + #[serde(rename = "ready")] + Ready, } #[derive(Deserialize, Debug, Clone, Serialize)] @@ -241,250 +73,51 @@ impl std::fmt::Display for Version { } } -#[allow(non_camel_case_types)] -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub enum ErrorType { - network, - media, - restriction, - entitlement, - other, -} - #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MetricsError { - pub context: BehavioralMetricContext, - #[serde(alias = "type")] - pub error_type: ErrorType, - pub code: String, - pub description: String, - pub visible: bool, - pub parameters: Option>, - pub durable_app_id: String, - pub third_party_error: bool, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaLoadStart { - pub context: BehavioralMetricContext, - pub entity_id: String, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaPlay { - pub context: BehavioralMetricContext, - pub entity_id: String, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaPlaying { - pub context: BehavioralMetricContext, - pub entity_id: String, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaPause { - pub context: BehavioralMetricContext, - pub entity_id: String, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaWaiting { - pub context: BehavioralMetricContext, - pub entity_id: String, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaProgress { - pub context: BehavioralMetricContext, - pub entity_id: String, - pub progress: Option, -} -impl From<&MediaProgress> for Option { - fn from(progress: &MediaProgress) -> Self { - match progress.progress.clone() { - Some(prog) => prog.as_absolute(), - None => None, - } - } +pub struct Param { + pub name: String, + pub value: FlatMapValue, } -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaSeeking { - pub context: BehavioralMetricContext, - pub entity_id: String, - pub target: Option, -} -impl From<&MediaSeeking> for Option { - fn from(progress: &MediaSeeking) -> Self { - match progress.target.clone() { - Some(prog) => prog.as_absolute(), - None => None, - } +// custom comparison function used only in unit tests +#[cfg(test)] +impl Param { + fn cmp(&self, other: &Param) -> std::cmp::Ordering { + self.name.cmp(&other.name) } } -impl From<&MediaSeeking> for Option { - fn from(progress: &MediaSeeking) -> Self { - match progress.target.clone() { - Some(prog) => prog.as_percentage(), - None => None, - } - } -} +pub fn hashmap_to_param_vec(the_map: Option>) -> Vec { + let mut result = Vec::new(); -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaSeeked { - pub context: BehavioralMetricContext, - pub entity_id: String, - pub position: Option, -} -impl From<&MediaSeeked> for Option { - fn from(progress: &MediaSeeked) -> Self { - match progress.position.clone() { - Some(prog) => prog.as_absolute(), - None => None, - } - } -} + let params_map = match the_map { + Some(params_map) => params_map, + None => return Vec::new(), + }; -impl From<&MediaSeeked> for Option { - fn from(progress: &MediaSeeked) -> Self { - match progress.position.clone() { - Some(prog) => prog.as_percentage(), - None => None, - } + for (key, value) in params_map { + result.push(Param { name: key, value }); } -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaRateChanged { - pub context: BehavioralMetricContext, - pub entity_id: String, - pub rate: u32, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaRenditionChanged { - pub context: BehavioralMetricContext, - pub entity_id: String, - pub bitrate: u32, - pub width: u32, - pub height: u32, - pub profile: Option, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct MediaEnded { - pub context: BehavioralMetricContext, - pub entity_id: String, + result } -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct RawBehaviorMetricRequest { - pub context: BehavioralMetricContext, - pub value: Value, -} -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub enum AppLifecycleState { - #[serde(rename = "launching")] - Launching, - #[serde(rename = "foreground")] - Foreground, - #[serde(rename = "background")] - Background, - #[serde(rename = "inactive")] - Inactive, - #[serde(rename = "suspended")] - Suspended, - #[serde(rename = "not_running")] - NotRunning, - #[serde(rename = "initializing")] - Initializing, - #[serde(rename = "ready")] - Ready, -} #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub struct AppLifecycleStateChange { - pub context: BehavioralMetricContext, + pub app_id: String, pub previous_state: Option, pub new_state: AppLifecycleState, } -pub trait IUpdateContext { - fn update_context(&mut self, context: BehavioralMetricContext); - fn get_context(&self) -> BehavioralMetricContext; -} - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub enum BehavioralMetricPayload { - Ready(Ready), - SignIn(SignIn), - SignOut(SignOut), - StartContent(StartContent), - StopContent(StopContent), - Page(Page), - Action(Action), - Error(MetricsError), - MediaLoadStart(MediaLoadStart), - MediaPlay(MediaPlay), - MediaPlaying(MediaPlaying), - MediaPause(MediaPause), - MediaWaiting(MediaWaiting), - MediaProgress(MediaProgress), - MediaSeeking(MediaSeeking), - MediaSeeked(MediaSeeked), - MediaRateChanged(MediaRateChanged), - MediaRenditionChanged(MediaRenditionChanged), - MediaEnded(MediaEnded), - AppStateChange(AppLifecycleStateChange), - Raw(RawBehaviorMetricRequest), +#[derive(Deserialize, Debug, Clone)] +pub struct InternalInitializeParams { + #[serde(deserialize_with = "deserialize_version")] + pub version: Version, } -impl IUpdateContext for BehavioralMetricPayload { - fn update_context(&mut self, context: BehavioralMetricContext) { - match self { - Self::Ready(r) => r.context = context, - Self::SignIn(s) => s.context = context, - Self::SignOut(s) => s.context = context, - Self::StartContent(s) => s.context = context, - Self::StopContent(s) => s.context = context, - Self::Page(p) => p.context = context, - Self::Action(a) => a.context = context, - Self::Error(e) => e.context = context, - Self::MediaLoadStart(m) => m.context = context, - Self::MediaPlay(m) => m.context = context, - Self::MediaPlaying(m) => m.context = context, - Self::MediaPause(m) => m.context = context, - Self::MediaWaiting(m) => m.context = context, - Self::MediaProgress(m) => m.context = context, - Self::MediaSeeking(m) => m.context = context, - Self::MediaSeeked(m) => m.context = context, - Self::MediaRateChanged(m) => m.context = context, - Self::MediaRenditionChanged(m) => m.context = context, - Self::MediaEnded(m) => m.context = context, - Self::AppStateChange(a) => a.context = context, - Self::Raw(r) => r.context = context, - } - } - - fn get_context(&self) -> BehavioralMetricContext { - match self { - Self::Ready(r) => r.context.clone(), - Self::SignIn(s) => s.context.clone(), - Self::SignOut(s) => s.context.clone(), - Self::StartContent(s) => s.context.clone(), - Self::StopContent(s) => s.context.clone(), - Self::Page(p) => p.context.clone(), - Self::Action(a) => a.context.clone(), - Self::Error(e) => e.context.clone(), - Self::MediaLoadStart(m) => m.context.clone(), - Self::MediaPlay(m) => m.context.clone(), - Self::MediaPlaying(m) => m.context.clone(), - Self::MediaPause(m) => m.context.clone(), - Self::MediaWaiting(m) => m.context.clone(), - Self::MediaProgress(m) => m.context.clone(), - Self::MediaSeeking(m) => m.context.clone(), - Self::MediaSeeked(m) => m.context.clone(), - Self::MediaRateChanged(m) => m.context.clone(), - Self::MediaRenditionChanged(m) => m.context.clone(), - Self::MediaEnded(m) => m.context.clone(), - Self::AppStateChange(a) => a.context.clone(), - Self::Raw(r) => r.context.clone(), - } - } +#[derive(Deserialize, Debug, Clone, Serialize)] +pub struct InternalInitializeResponse { + pub version: Version, } /* @@ -714,129 +347,22 @@ impl std::fmt::Display for MetricsEnvironment { } } -/// all the things that are provided by platform that need to -/// be updated, and eventually in/outjected into/out of a payload -/// These items may (or may not) be available when the ripple -/// process starts, so this service may need a way to wait for the values -/// to become available -/// This design assumes that all of the items will be available at the same times -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default)] -pub struct MetricsContext { - pub enabled: bool, - pub device_language: String, - pub device_model: String, - pub device_id: Option, - pub account_id: Option, - pub device_timezone: String, - pub device_timezone_offset: String, - pub device_name: Option, - pub platform: String, - pub os_name: String, - pub os_ver: String, - pub distribution_tenant_id: String, - pub device_session_id: String, - pub mac_address: String, - pub serial_number: String, - pub firmware: String, - pub ripple_version: String, - pub data_governance_tags: Option>, - pub activated: Option, - pub proposition: String, - pub retailer: Option, - pub primary_provider: Option, - pub coam: Option, - pub country: Option, - pub region: Option, - pub account_type: Option, - pub operator: Option, - pub account_detail_type: Option, - pub device_type: String, - pub device_manufacturer: String, - pub authenticated: Option, -} - #[allow(non_camel_case_types)] -pub enum MetricsContextField { - enabled, - device_language, - device_model, - device_id, - account_id, - device_timezone, - device_timezone_offset, - device_name, - platform, - os_name, - os_ver, - distributor_id, - session_id, - mac_address, - serial_number, - firmware, - ripple_version, - env, - cet_list, - activated, - proposition, - retailer, - primary_provider, - coam, - country, - region, - account_type, - operator, - account_detail_type, -} - -impl MetricsContext { - pub fn new() -> MetricsContext { - MetricsContext { - enabled: false, - device_language: String::from(""), - device_model: String::from(""), - device_id: None, - device_timezone: String::from(""), - device_timezone_offset: String::from(""), - device_name: None, - mac_address: String::from(""), - serial_number: String::from(""), - account_id: None, - platform: String::from("entos:rdk"), - os_name: String::from(""), - os_ver: String::from(""), - device_session_id: String::from(""), - distribution_tenant_id: String::from(""), - firmware: String::from(""), - ripple_version: String::from(""), - data_governance_tags: None, - activated: None, - proposition: String::from(""), - retailer: None, - primary_provider: None, - coam: None, - country: None, - region: None, - account_type: None, - operator: None, - account_detail_type: None, - device_type: String::from(""), - device_manufacturer: String::from(""), - authenticated: None, - } - } +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub enum ErrorType { + network, + media, + restriction, + entitlement, + other, } -#[async_trait] -pub trait BehavioralMetricsService { - async fn send_metric(&self, metrics: BehavioralMetricPayload) -> (); -} -#[async_trait] -pub trait ContextualMetricsService { - async fn update_metrics_context(&mut self, new_context: Option) -> (); -} -#[async_trait] -pub trait MetricsManager: Send + Sync { - async fn send_metric(&mut self, metrics: BehavioralMetricPayload) -> (); +#[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize, Clone)] +#[serde(untagged)] +pub enum FlatMapValue { + String(String), + Number(f64), + Boolean(bool), } #[derive(Deserialize, Debug, Clone)] @@ -902,22 +428,6 @@ impl Tag { } } -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default)] -#[serde(rename_all = "camelCase")] -pub struct BehavioralMetricsEvent { - pub event_name: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub event_version: Option, - pub event_source: String, - pub event_source_version: String, - pub cet_list: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub epoch_timestamp: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub uptime_timestamp: Option, - pub event_payload: Value, -} - #[cfg(test)] mod tests { use super::*; @@ -1017,54 +527,6 @@ mod tests { assert_eq!(flatmap3, FlatMapValue::Boolean(true)); } - #[test] - fn test_behavioral_metric_payload() { - let behavioral_metric_context = BehavioralMetricContext { - app_id: "test_app_id".to_string(), - product_version: "test_product_version".to_string(), - partner_id: "test_partner_id".to_string(), - app_session_id: "test_app_session_id".to_string(), - app_user_session_id: Some("test_user_session_id".to_string()), - durable_app_id: "test_durable_app_id".to_string(), - app_version: Some("test_app_version".to_string()), - governance_state: Some(AppDataGovernanceState { - data_tags_to_apply: HashSet::new(), - }), - }; - - let ready_payload = Ready { - context: behavioral_metric_context.clone(), - ttmu_ms: 100, - }; - - let mut behavioral_metric_payload = BehavioralMetricPayload::Ready(ready_payload); - - assert_eq!( - behavioral_metric_payload.get_context(), - behavioral_metric_context - ); - - let new_behavioral_metric_context = BehavioralMetricContext { - app_id: "new_test_app_id".to_string(), - product_version: "new_test_product_version".to_string(), - partner_id: "new_test_partner_id".to_string(), - app_session_id: "new_test_app_session_id".to_string(), - app_user_session_id: Some("new_test_user_session_id".to_string()), - durable_app_id: "new_test_durable_app_id".to_string(), - app_version: Some("test_app_version".to_string()), - governance_state: Some(AppDataGovernanceState { - data_tags_to_apply: HashSet::new(), - }), - }; - - behavioral_metric_payload.update_context(new_behavioral_metric_context.clone()); - - assert_eq!( - behavioral_metric_payload.get_context(), - new_behavioral_metric_context - ); - } - #[test] fn test_timer_start() { let timer = Timer::start("test_timer".to_string(), None, None); diff --git a/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs b/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs index 034570442..faa093bb9 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs @@ -15,7 +15,8 @@ // SPDX-License-Identifier: Apache-2.0 // -use ripple_sdk::{api::firebolt::fb_metrics::BehavioralMetricsEvent, serde_json}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; use crate::{ client::{ @@ -27,6 +28,22 @@ use crate::{ thunder_state::ThunderState, }; +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct BehavioralMetricsEvent { + pub event_name: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub event_version: Option, + pub event_source: String, + pub event_source_version: String, + pub cet_list: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub epoch_timestamp: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub uptime_timestamp: Option, + pub event_payload: Value, +} + pub async fn send_to_analytics_plugin( thunder_state: ThunderState, metrics_event: BehavioralMetricsEvent, From c2edfa2a3716f5d13875ec6067812a980de9dc6a Mon Sep 17 00:00:00 2001 From: satlead Date: Mon, 7 Apr 2025 14:49:47 -0400 Subject: [PATCH 25/31] fix: PR comments --- .../sdk/src/api/default_storage_properties.rs | 50 +++++++++---------- device/thunder_ripple_sdk/Cargo.toml | 1 - 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/core/sdk/src/api/default_storage_properties.rs b/core/sdk/src/api/default_storage_properties.rs index b77593b24..cd67e17cb 100644 --- a/core/sdk/src/api/default_storage_properties.rs +++ b/core/sdk/src/api/default_storage_properties.rs @@ -47,44 +47,44 @@ pub struct DefaultStorageProperties; impl DefaultStorageProperties { pub fn get_bool( - state: &DefaultValues, + value: &DefaultValues, namespace: &String, key: &'static str, ) -> Result { trace!("get_bool: namespace={}, key={}", namespace, key); if namespace.eq(NAMESPACE_CLOSED_CAPTIONS) { match key { - KEY_ENABLED => Ok(state.captions.enabled), + KEY_ENABLED => Ok(value.captions.enabled), _ => Err(DefaultStoragePropertiesError::UnreconizedKey( key.to_owned(), )), } } else if namespace.eq(NAMESPACE_PRIVACY) { match key { - KEY_ALLOW_ACR_COLLECTION => Ok(state.allow_acr_collection), - KEY_ALLOW_APP_CONTENT_AD_TARGETING => Ok(state.allow_app_content_ad_targeting), - KEY_ALLOW_BUSINESS_ANALYTICS => Ok(state.allow_business_analytics), - KEY_ALLOW_CAMERA_ANALYTICS => Ok(state.allow_camera_analytics), - KEY_ALLOW_PERSONALIZATION => Ok(state.allow_personalization), + KEY_ALLOW_ACR_COLLECTION => Ok(value.allow_acr_collection), + KEY_ALLOW_APP_CONTENT_AD_TARGETING => Ok(value.allow_app_content_ad_targeting), + KEY_ALLOW_BUSINESS_ANALYTICS => Ok(value.allow_business_analytics), + KEY_ALLOW_CAMERA_ANALYTICS => Ok(value.allow_camera_analytics), + KEY_ALLOW_PERSONALIZATION => Ok(value.allow_personalization), KEY_ALLOW_PRIMARY_BROWSE_AD_TARGETING => { - Ok(state.allow_primary_browse_ad_targeting) + Ok(value.allow_primary_browse_ad_targeting) } KEY_ALLOW_PRIMARY_CONTENT_AD_TARGETING => { - Ok(state.allow_primary_content_ad_targeting) + Ok(value.allow_primary_content_ad_targeting) } - KEY_ALLOW_PRODUCT_ANALYTICS => Ok(state.allow_product_analytics), - KEY_ALLOW_REMOTE_DIAGNOSTICS => Ok(state.allow_remote_diagnostics), - KEY_ALLOW_RESUME_POINTS => Ok(state.allow_resume_points), - KEY_ALLOW_UNENTITLED_PERSONALIZATION => Ok(state.allow_unentitled_personalization), - KEY_ALLOW_UNENTITLED_RESUME_POINTS => Ok(state.allow_unentitled_resume_points), - KEY_ALLOW_WATCH_HISTORY => Ok(state.allow_watch_history), + KEY_ALLOW_PRODUCT_ANALYTICS => Ok(value.allow_product_analytics), + KEY_ALLOW_REMOTE_DIAGNOSTICS => Ok(value.allow_remote_diagnostics), + KEY_ALLOW_RESUME_POINTS => Ok(value.allow_resume_points), + KEY_ALLOW_UNENTITLED_PERSONALIZATION => Ok(value.allow_unentitled_personalization), + KEY_ALLOW_UNENTITLED_RESUME_POINTS => Ok(value.allow_unentitled_resume_points), + KEY_ALLOW_WATCH_HISTORY => Ok(value.allow_watch_history), _ => Err(DefaultStoragePropertiesError::UnreconizedKey( key.to_owned(), )), } } else if namespace.eq(NAMESPACE_AUDIO_DESCRIPTION) { match key { - KEY_AUDIO_DESCRIPTION_ENABLED => Ok(state.accessibility_audio_description_settings), + KEY_AUDIO_DESCRIPTION_ENABLED => Ok(value.accessibility_audio_description_settings), _ => Err(DefaultStoragePropertiesError::UnreconizedKey( key.to_owned(), )), @@ -97,13 +97,13 @@ impl DefaultStorageProperties { } pub fn get_string( - state: &DefaultValues, + value: &DefaultValues, namespace: &String, key: &'static str, ) -> Result { trace!("get_string: namespace={}, key={}", namespace, key); if namespace.eq(NAMESPACE_CLOSED_CAPTIONS) { - let captions = state.clone().captions; + let captions = value.clone().captions; let not_found = DefaultStoragePropertiesError::NotFound(key.to_owned()); match key { KEY_FONT_FAMILY => match captions.font_family { @@ -144,14 +144,14 @@ impl DefaultStorageProperties { } } else if namespace.eq(NAMESPACE_DEVICE_NAME) { match key { - KEY_NAME => Ok(state.clone().name), + KEY_NAME => Ok(value.clone().name), _ => Err(DefaultStoragePropertiesError::UnreconizedKey( key.to_owned(), )), } } else if namespace.eq(NAMESPACE_LOCALIZATION) { match key { - KEY_LOCALE => Ok(state.clone().locale), + KEY_LOCALE => Ok(value.clone().locale), // Not used anywhere just yet // KEY_ADDITIONAL_INFO => { // let a_info_map: HashMap = state.clone().configuration.default_values.additional_info; @@ -163,7 +163,7 @@ impl DefaultStorageProperties { } } else if namespace.eq(NAMESPACE_ADVERTISING) { match key { - KEY_SKIP_RESTRICTION => Ok(state.clone().skip_restriction), + KEY_SKIP_RESTRICTION => Ok(value.clone().skip_restriction), _ => Err(DefaultStoragePropertiesError::UnreconizedKey( key.to_owned(), )), @@ -176,13 +176,13 @@ impl DefaultStorageProperties { } pub fn get_number_as_u32( - state: &DefaultValues, + value: &DefaultValues, namespace: &String, key: &'static str, ) -> Result { trace!("get_number_as_u32: namespace={}, key={}", namespace, key); if namespace.eq(NAMESPACE_CLOSED_CAPTIONS) { - let captions = state.clone().captions; + let captions = value.clone().captions; let not_found = DefaultStoragePropertiesError::NotFound(key.to_owned()); match key { KEY_FONT_OPACITY => match captions.font_opacity { @@ -209,13 +209,13 @@ impl DefaultStorageProperties { } pub fn get_number_as_f32( - state: &DefaultValues, + value: &DefaultValues, namespace: &String, key: &'static str, ) -> Result { trace!("get_number_as_f32: namespace={}, key={}", namespace, key); if namespace.eq(NAMESPACE_CLOSED_CAPTIONS) { - let captions = state.clone().captions; + let captions = value.clone().captions; let not_found = DefaultStoragePropertiesError::NotFound(key.to_owned()); match key { KEY_FONT_SIZE => match captions.font_size { diff --git a/device/thunder_ripple_sdk/Cargo.toml b/device/thunder_ripple_sdk/Cargo.toml index 215372d43..62fd747e9 100644 --- a/device/thunder_ripple_sdk/Cargo.toml +++ b/device/thunder_ripple_sdk/Cargo.toml @@ -79,7 +79,6 @@ home = { version = "=0.5.5", optional = true } tree_magic_mini = { version = "=3.0.3", optional = true } rstest = { version = "0.18.2", optional = true, default-features = false } futures-util = { version = "0.3.28", features = ["sink", "std"], default-features = false, optional = true} -chrono = { workspace = true, features = ["clock"]} [dev-dependencies] From 9abefd693111cccdae47618d60071a130a201ce2 Mon Sep 17 00:00:00 2001 From: satlead Date: Tue, 8 Apr 2025 22:32:50 -0400 Subject: [PATCH 26/31] fix: merge and other issues --- .../apps/delegated_launcher_handler.rs | 68 +++++++++---------- core/main/src/state/cap/permitted_state.rs | 11 +++ core/main/src/state/otel_state.rs | 6 +- .../src/processor/rpc_request_processor.rs | 4 ++ device/mock_device/src/mock_data.rs | 1 - 5 files changed, 53 insertions(+), 37 deletions(-) diff --git a/core/main/src/service/apps/delegated_launcher_handler.rs b/core/main/src/service/apps/delegated_launcher_handler.rs index df6f1461c..27daf0018 100644 --- a/core/main/src/service/apps/delegated_launcher_handler.rs +++ b/core/main/src/service/apps/delegated_launcher_handler.rs @@ -516,8 +516,11 @@ impl DelegatedLauncherHandler { }; if let Some(id) = app_id { - self.report_app_state_transition(&id, &method, resp.clone()) - .await; + let mut ps_c = self.platform_state.clone(); + let resp_c = resp.clone(); + tokio::spawn(async move { + Self::report_app_state_transition(&mut ps_c, &id, &method, resp_c).await; + }); } if let Err(e) = resp { @@ -531,28 +534,44 @@ impl DelegatedLauncherHandler { } async fn report_app_state_transition( - &mut self, + platform_state: &mut PlatformState, app_id: &str, method: &AppMethod, app_manager_response: Result, ) { - if self - .platform_state + if let AppMethod::BrowserSession(_) = method { + if platform_state + .endpoint_state + .has_rule("ripple.reportSessionUpdate") + { + if let Ok(AppManagerResponse::Session(a)) = app_manager_response { + let params = serde_json::to_value(a).unwrap(); + if BrokerUtils::process_internal_main_request( + platform_state, + "ripple.reportSessionUpdate", + Some(params), + ) + .await + .is_err() + { + error!("Error reporting lifecycle state") + } + } + } + } + + if platform_state .endpoint_state .has_rule("ripple.reportLifecycleStateChange") { - let previous_state = self - .platform_state - .app_manager_state - .get_internal_state(app_id); + let previous_state = platform_state.app_manager_state.get_internal_state(app_id); /* Do not forward internal errors from the launch handler as AppErrors. Only forward third-party application error messages as AppErrors. TBD: Collaborate with the SIFT team to obtain the appropriate SIFT code for sharing error messages from the AppLauncher. */ - let inactive = self - .platform_state + let inactive = platform_state .app_manager_state .get(app_id) .map_or(false, |app| app.initial_session.launch.inactive); @@ -574,8 +593,9 @@ impl DelegatedLauncherHandler { previous_state: from_state, }) .unwrap(); + println!("Sending to eos"); if BrokerUtils::process_for_app_main_request( - &mut self.platform_state.clone(), + platform_state, "ripple.reportLifecycleStateChange", Some(params), app_id, @@ -587,29 +607,7 @@ impl DelegatedLauncherHandler { } } - if let AppMethod::BrowserSession(_) = method { - if self - .platform_state - .endpoint_state - .has_rule("ripple.reportSessionUpdate") - { - if let Ok(AppManagerResponse::Session(a)) = app_manager_response { - let params = serde_json::to_value(a).unwrap(); - if BrokerUtils::process_internal_main_request( - &mut self.platform_state.clone(), - "ripple.reportSessionUpdate", - Some(params), - ) - .await - .is_err() - { - error!("Error reporting lifecycle state") - } - } - } - } - - self.platform_state + platform_state .app_manager_state .set_internal_state(app_id, method.clone()); } diff --git a/core/main/src/state/cap/permitted_state.rs b/core/main/src/state/cap/permitted_state.rs index ba9b242d9..4e549377f 100644 --- a/core/main/src/state/cap/permitted_state.rs +++ b/core/main/src/state/cap/permitted_state.rs @@ -297,6 +297,17 @@ impl PermissionHandler { state: &PlatformState, app_id: &String, ) -> Result<(), RippleError> { + // Needs permissions + if let Some(ex) = state.get_device_manifest().configuration.exclusory { + if ex + .app_authorization_rules + .app_ignore_rules + .contains_key(app_id.to_lowercase().as_str()) + { + return Ok(()); + } + } + // This call should hit the server and fetch permissions for the app. // Local cache will be updated with the fetched permissions let has_stored = state diff --git a/core/main/src/state/otel_state.rs b/core/main/src/state/otel_state.rs index e48ed5e39..b0dede3d7 100644 --- a/core/main/src/state/otel_state.rs +++ b/core/main/src/state/otel_state.rs @@ -40,7 +40,11 @@ pub struct OpMetricState { impl OpMetricState { pub fn get_device_session_id(&self) -> String { - self.device_session_id.read().unwrap().clone().unwrap() + self.device_session_id + .read() + .unwrap() + .clone() + .unwrap_or(String::default()) } pub fn operational_telemetry_listener(&self, target: &str, listen: bool) { diff --git a/core/sdk/src/processor/rpc_request_processor.rs b/core/sdk/src/processor/rpc_request_processor.rs index a1f88e21c..c1a52054f 100644 --- a/core/sdk/src/processor/rpc_request_processor.rs +++ b/core/sdk/src/processor/rpc_request_processor.rs @@ -35,6 +35,7 @@ use crate::{ }; use async_trait::async_trait; use jsonrpsee::core::server::rpc_module::Methods; +use log::info; #[derive(Debug, Clone)] pub struct RPCRequestState { @@ -54,6 +55,9 @@ impl RPCRequestProcessor { pub fn new(client: ExtnClient, methods: Methods, extn_id: ExtnId) -> RPCRequestProcessor { let router_state = RouterState::new(); router_state.update_methods(methods.clone()); + for method in methods.method_names() { + info!("Adding RPC method {}", method); + } RPCRequestProcessor { state: RPCRequestState { diff --git a/device/mock_device/src/mock_data.rs b/device/mock_device/src/mock_data.rs index 414fdd6d8..8e2d4b2af 100644 --- a/device/mock_device/src/mock_data.rs +++ b/device/mock_device/src/mock_data.rs @@ -46,7 +46,6 @@ impl ParamResponse { pub fn get_key(&self, key: &Value) -> Option { match &self.params { Some(v) => { - debug!("get_key check {:?}={:?}", v, key); if v.eq(key) { return Some(self.clone()); } From 04a20e0d68e8ba23e333a48a06f001fdf97e1249 Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 9 Apr 2025 14:03:13 -0400 Subject: [PATCH 27/31] fix: clippy --- core/main/src/state/otel_state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/main/src/state/otel_state.rs b/core/main/src/state/otel_state.rs index b0dede3d7..68f2d7bf4 100644 --- a/core/main/src/state/otel_state.rs +++ b/core/main/src/state/otel_state.rs @@ -44,7 +44,7 @@ impl OpMetricState { .read() .unwrap() .clone() - .unwrap_or(String::default()) + .unwrap_or_default() } pub fn operational_telemetry_listener(&self, target: &str, listen: bool) { From 4c45f8566073d15ee3678631a14015203ed52339 Mon Sep 17 00:00:00 2001 From: satlead Date: Wed, 9 Apr 2025 23:59:23 -0400 Subject: [PATCH 28/31] fix: cleanup error noise --- core/main/src/utils/router_utils.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/main/src/utils/router_utils.rs b/core/main/src/utils/router_utils.rs index b5000ba4f..8419a833a 100644 --- a/core/main/src/utils/router_utils.rs +++ b/core/main/src/utils/router_utils.rs @@ -18,8 +18,7 @@ use ripple_sdk::{ api::gateway::rpc_gateway_api::{ApiMessage, JsonRpcApiResponse, RpcRequest}, extn::extn_client_message::{ExtnMessage, ExtnResponse}, log::{error, trace}, - serde_json::{self, Result as SResult}, - utils::error::RippleError, + serde_json::{self, Result as SResult} }; use crate::state::otel_state::OpMetricState; @@ -41,7 +40,8 @@ pub fn return_extn_response(msg: ApiMessage, extn_msg: ExtnMessage) { } else if let Some(error) = resp.error { error } else { - serde_json::to_value(RippleError::InvalidOutput).unwrap() + // Most of handler calls return Null resulting in None + serde_json::Value::Null }; let return_value = ExtnResponse::Value(response_value); From 5b984fe429b986d89b6b8b405f3b57ffca43d865 Mon Sep 17 00:00:00 2001 From: satlead Date: Thu, 10 Apr 2025 00:02:15 -0400 Subject: [PATCH 29/31] fix: format --- core/main/src/utils/router_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/main/src/utils/router_utils.rs b/core/main/src/utils/router_utils.rs index 8419a833a..5019bdb2d 100644 --- a/core/main/src/utils/router_utils.rs +++ b/core/main/src/utils/router_utils.rs @@ -18,7 +18,7 @@ use ripple_sdk::{ api::gateway::rpc_gateway_api::{ApiMessage, JsonRpcApiResponse, RpcRequest}, extn::extn_client_message::{ExtnMessage, ExtnResponse}, log::{error, trace}, - serde_json::{self, Result as SResult} + serde_json::{self, Result as SResult}, }; use crate::state::otel_state::OpMetricState; From d9b8a1eca2d0b6dfae98f1cfab8b2ba7e54999ad Mon Sep 17 00:00:00 2001 From: satlead Date: Thu, 10 Apr 2025 08:49:47 -0400 Subject: [PATCH 30/31] fix: Event dispatching --- core/main/src/firebolt/handlers/internal_rpc.rs | 8 +++++--- core/sdk/src/api/firebolt/fb_general.rs | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/main/src/firebolt/handlers/internal_rpc.rs b/core/main/src/firebolt/handlers/internal_rpc.rs index a0ed47963..a7d59383e 100644 --- a/core/main/src/firebolt/handlers/internal_rpc.rs +++ b/core/main/src/firebolt/handlers/internal_rpc.rs @@ -23,7 +23,7 @@ use ripple_sdk::{ gateway::rpc_gateway_api::CallContext, }, async_trait::async_trait, - log::error, + log::{debug, error}, tokio::sync::oneshot, }; @@ -74,6 +74,7 @@ impl InternalServer for InternalImpl { } async fn send_app_event(&self, _ctx: CallContext, event: AppEvent) -> RpcResult<()> { + debug!("Sending App event {:?}", &event); AppEvents::emit_with_context(&self.state, &event.event_name, &event.result, event.context) .await; Ok(()) @@ -81,11 +82,12 @@ impl InternalServer for InternalImpl { async fn register_app_event( &self, - ctx: CallContext, + _ctx: CallContext, request: ListenRequestWithEvent, ) -> RpcResult<()> { + debug!("registering App event {:?}", &request); let event = request.event.clone(); - AppEvents::add_listener(&self.state, event, ctx, request.request); + AppEvents::add_listener(&self.state, event, request.context.clone(), request.request); Ok(()) } diff --git a/core/sdk/src/api/firebolt/fb_general.rs b/core/sdk/src/api/firebolt/fb_general.rs index 98feedd81..9e65f485d 100644 --- a/core/sdk/src/api/firebolt/fb_general.rs +++ b/core/sdk/src/api/firebolt/fb_general.rs @@ -17,6 +17,8 @@ use serde::{Deserialize, Serialize}; +use crate::api::gateway::rpc_gateway_api::CallContext; + #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub struct ListenRequest { pub listen: bool, @@ -26,6 +28,7 @@ pub struct ListenRequest { pub struct ListenRequestWithEvent { pub event: String, pub request: ListenRequest, + pub context: CallContext, } #[derive(Serialize, Deserialize, Debug)] From 7469d5aa492dd25242ed172097c0c31b01a8cc2e Mon Sep 17 00:00:00 2001 From: satlead Date: Sun, 13 Apr 2025 22:52:10 -0400 Subject: [PATCH 31/31] feat: Add Privacy Adapter Methods --- .../api/distributor/distributor_privacy.rs | 45 +++++++++++++++++++ core/sdk/src/api/ripple_cache.rs | 14 +++++- core/sdk/src/api/storage_property.rs | 23 ++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/core/sdk/src/api/distributor/distributor_privacy.rs b/core/sdk/src/api/distributor/distributor_privacy.rs index e7b9d94be..3e5c099e3 100644 --- a/core/sdk/src/api/distributor/distributor_privacy.rs +++ b/core/sdk/src/api/distributor/distributor_privacy.rs @@ -86,6 +86,33 @@ impl PrivacySettings { } } + pub fn update_privacy_setting(&mut self, setting: PrivacySetting, value: bool) { + match setting { + PrivacySetting::Acr => self.allow_acr_collection = value, + PrivacySetting::AppContentAdTargeting => self.allow_app_content_ad_targeting = value, + PrivacySetting::BusinessAnalytics => self.allow_business_analytics = value, + PrivacySetting::CameraAnalytics => self.allow_camera_analytics = value, + PrivacySetting::ContinueWatching => self.allow_resume_points = value, + PrivacySetting::Personalization => self.allow_personalization = value, + PrivacySetting::PrimaryBrowseAdTargeting => { + self.allow_primary_browse_ad_targeting = value + } + PrivacySetting::PrimaryContentAdTargeting => { + self.allow_primary_content_ad_targeting = value + } + PrivacySetting::ProductAnalytics => self.allow_product_analytics = value, + PrivacySetting::RemoteDiagnostics => self.allow_remote_diagnostics = value, + PrivacySetting::UnentitledContinueWatching => { + self.allow_unentitled_resume_points = value + } + PrivacySetting::UnentitledPersonalization => { + self.allow_unentitled_personalization = value + } + PrivacySetting::WatchHistory => self.allow_watch_history = value, + _ => {} + } + } + pub fn update(&mut self, data: PrivacySettings) { self.allow_acr_collection = data.allow_acr_collection; self.allow_resume_points = data.allow_resume_points; @@ -144,6 +171,24 @@ pub struct PrivacySettingsData { pub allow_watch_history: Option, } +impl PrivacySettingsData { + pub fn update(&mut self, data: &PrivacySettings) { + self.allow_acr_collection = Some(data.allow_acr_collection); + self.allow_resume_points = Some(data.allow_resume_points); + self.allow_app_content_ad_targeting = Some(data.allow_app_content_ad_targeting); + self.allow_business_analytics = Some(data.allow_business_analytics); + self.allow_camera_analytics = Some(data.allow_camera_analytics); + self.allow_personalization = Some(data.allow_personalization); + self.allow_primary_browse_ad_targeting = Some(data.allow_primary_browse_ad_targeting); + self.allow_primary_content_ad_targeting = Some(data.allow_primary_content_ad_targeting); + self.allow_product_analytics = Some(data.allow_product_analytics); + self.allow_remote_diagnostics = Some(data.allow_remote_diagnostics); + self.allow_unentitled_personalization = Some(data.allow_unentitled_personalization); + self.allow_unentitled_resume_points = Some(data.allow_unentitled_resume_points); + self.allow_watch_history = Some(data.allow_watch_history); + } +} + impl From for PrivacySettingsData { fn from(data: PrivacySettings) -> Self { PrivacySettingsData { diff --git a/core/sdk/src/api/ripple_cache.rs b/core/sdk/src/api/ripple_cache.rs index 1f2314077..5085b262a 100644 --- a/core/sdk/src/api/ripple_cache.rs +++ b/core/sdk/src/api/ripple_cache.rs @@ -16,11 +16,13 @@ // use std::sync::{Arc, RwLock}; +use log::debug; + use crate::api::{ distributor::distributor_privacy::PrivacySettingsData, storage_property::StorageProperty, }; -use super::storage_manager::IStorageOperator; +use super::{distributor::distributor_privacy::PrivacySettings, storage_manager::IStorageOperator}; #[derive(Debug, Clone, Default)] pub struct RippleCache { @@ -53,6 +55,10 @@ impl RippleCache { ) { { // update the privacy setting property in cache + debug!( + "Updating cache for storage property privacy setting {:?} and value {}", + property, value + ); { let mut cache = self.privacy_settings_cache.write().unwrap(); property.set_privacy_setting_value(&mut cache, value); @@ -60,4 +66,10 @@ impl RippleCache { state.on_privacy_updated(self.clone()); } } + + pub fn update_all_privacy_cache(&self, data: &PrivacySettings) { + debug!("Updating all privacy cache {:?}", data); + let mut cache = self.privacy_settings_cache.write().unwrap(); + cache.update(data); + } } diff --git a/core/sdk/src/api/storage_property.rs b/core/sdk/src/api/storage_property.rs index 581bc8119..d8a9946aa 100644 --- a/core/sdk/src/api/storage_property.rs +++ b/core/sdk/src/api/storage_property.rs @@ -20,6 +20,7 @@ use serde::{Deserialize, Serialize}; use crate::{ extn::extn_client_message::{ExtnPayload, ExtnPayloadProvider, ExtnRequest}, framework::ripple_contract::{ContractAdjective, RippleContract}, + utils::error::RippleError, }; use super::{ @@ -446,6 +447,28 @@ pub enum StorageProperty { CCPreferredLanguages, } +impl TryFrom for StorageProperty { + type Error = RippleError; + fn try_from(value: PrivacySetting) -> Result { + match value { + PrivacySetting::Acr => Ok(Self::AllowAcrCollection), + PrivacySetting::AppContentAdTargeting => Ok(Self::AllowAppContentAdTargeting), + PrivacySetting::BusinessAnalytics => Ok(Self::AllowBusinessAnalytics), + PrivacySetting::CameraAnalytics => Ok(Self::AllowCameraAnalytics), + PrivacySetting::ContinueWatching => Ok(Self::AllowResumePoints), + PrivacySetting::Personalization => Ok(Self::AllowPersonalization), + PrivacySetting::PrimaryBrowseAdTargeting => Ok(Self::AllowPrimaryBrowseAdTargeting), + PrivacySetting::PrimaryContentAdTargeting => Ok(Self::AllowPrimaryContentAdTargeting), + PrivacySetting::ProductAnalytics => Ok(Self::AllowProductAnalytics), + PrivacySetting::RemoteDiagnostics => Ok(Self::AllowRemoteDiagnostics), + PrivacySetting::UnentitledContinueWatching => Ok(Self::AllowUnentitledResumePoints), + PrivacySetting::UnentitledPersonalization => Ok(Self::AllowUnentitledPersonalization), + PrivacySetting::WatchHistory => Ok(Self::AllowWatchHistory), + _ => Err(RippleError::InvalidInput), + } + } +} + impl StorageProperty { pub fn as_data(&self) -> PropertyData { match self {